├── acf-youtube.php ├── README.md ├── lang └── acf-youtube.pot ├── acf-youtube-settings.php ├── acf-youtube-funcs.php ├── acf-youtube-v4.php └── acf-youtube-v5.php /acf-youtube.php: -------------------------------------------------------------------------------- 1 | \n" 13 | "Language-Team: LANGUAGE \n" 14 | 15 | #: acf-youtube-v4.php:10 acf-youtube-v5.php:22 16 | msgid "YouTube Video" 17 | msgstr "" 18 | 19 | #: acf-youtube-v4.php:11 20 | msgid "Basic" 21 | msgstr "" 22 | 23 | #: acf-youtube-v4.php:38 acf-youtube-v5.php:60 24 | msgid "Return Value" 25 | msgstr "" 26 | 27 | #: acf-youtube-v4.php:39 acf-youtube-v5.php:61 28 | msgid "Type of data returned when using the_field()" 29 | msgstr "" 30 | 31 | #: acf-youtube-v4.php:49 acf-youtube-v5.php:69 32 | msgid "Embed" 33 | msgstr "" 34 | 35 | #: acf-youtube-v4.php:50 acf-youtube-v5.php:70 36 | msgid "Video Object" 37 | msgstr "" 38 | 39 | #: acf-youtube-v4.php:51 acf-youtube-v5.php:71 40 | msgid "YouTube ID" 41 | msgstr "" 42 | 43 | #: acf-youtube-v4.php:52 acf-youtube-v5.php:72 44 | msgid "URL" 45 | msgstr "" 46 | 47 | #: acf-youtube-v4.php:53 acf-youtube-v5.php:73 48 | msgid "Thumbnail" 49 | msgstr "" 50 | 51 | #: acf-youtube-v4.php:54 acf-youtube-v5.php:74 52 | msgid "Thumbnail Object" 53 | msgstr "" 54 | 55 | #: acf-youtube-v4.php:63 acf-youtube-v5.php:79 56 | msgid "Thumbnail Size" 57 | msgstr "" 58 | 59 | #: acf-youtube-v4.php:73 acf-youtube-v5.php:88 60 | msgid "default" 61 | msgstr "" 62 | 63 | #: acf-youtube-v4.php:74 acf-youtube-v5.php:89 64 | msgid "hqdefault" 65 | msgstr "" 66 | 67 | #: acf-youtube-v4.php:75 acf-youtube-v5.php:90 68 | msgid "mqdefault" 69 | msgstr "" 70 | 71 | #: acf-youtube-v4.php:76 acf-youtube-v5.php:91 72 | msgid "sddefault" 73 | msgstr "" 74 | 75 | #: acf-youtube-v4.php:77 acf-youtube-v5.php:92 76 | msgid "maxresdefault" 77 | msgstr "" 78 | 79 | #: acf-youtube-v4.php:78 acf-youtube-v5.php:93 80 | msgid "0" 81 | msgstr "" 82 | 83 | #: acf-youtube-v4.php:79 acf-youtube-v5.php:94 84 | msgid "1" 85 | msgstr "" 86 | 87 | #: acf-youtube-v4.php:80 acf-youtube-v5.php:95 88 | msgid "2" 89 | msgstr "" 90 | 91 | #: acf-youtube-v4.php:81 acf-youtube-v5.php:96 92 | msgid "3" 93 | msgstr "" 94 | #. Plugin Name of the plugin/theme 95 | msgid "Advanced Custom Fields: YouTube Field" 96 | msgstr "" 97 | 98 | #. Plugin URI of the plugin/theme 99 | msgid "http://halgatewood.com/downloads/acf-youtube-field" 100 | msgstr "" 101 | 102 | #. Description of the plugin/theme 103 | msgid "Adds the YouTube field." 104 | msgstr "" 105 | 106 | #. Author of the plugin/theme 107 | msgid "Hal Gatewood" 108 | msgstr "" 109 | 110 | #. Author URI of the plugin/theme 111 | msgid "http://halgatewood.com" 112 | msgstr "" 113 | -------------------------------------------------------------------------------- /acf-youtube-settings.php: -------------------------------------------------------------------------------- 1 | 17 |
18 |

19 |
20 | 21 | 22 | 23 |
24 |
25 | "; 47 | echo "

"; 48 | echo __("As of April 20th, 2015 this is required to get data from the new YouTube Data API V3.", 'acf-youtube'); 49 | echo "

"; 50 | } 51 | 52 | function acf_youtube_all_parts() 53 | { 54 | return array('fileDetails','liveStreamingDetails','player','processingDetails','recordingDetails','status','suggestions','topicDetails'); 55 | } 56 | 57 | function acf_youtube_required_parts() 58 | { 59 | return array('contentDetails','snippet','statistics'); 60 | } 61 | 62 | 63 | function acf_youtube_api_parts() 64 | { 65 | $parts = get_option( 'acf-youtube-api-parts' ); 66 | if(!$parts) $parts = array(); 67 | 68 | $all_parts = acf_youtube_all_parts(); 69 | 70 | echo "

"; 71 | foreach( $all_parts as $part ) 72 | { 73 | $chked = in_array($part, $parts) ? " checked=\"checked\"" : ""; 74 | echo " {$part}     "; 75 | } 76 | echo "

"; 77 | 78 | echo "

"; 79 | echo __("What 'part' should be requested through the YouTube API. Some parts require more credentials than others. More Info about this section is available in the YouTube documentation. The required parts for this plugin (contentDetails,statistics,snippet) are always requested. ", 'acf-youtube'); 80 | echo "

"; 81 | echo "
"; 82 | echo "

"; 83 | echo __("Note: If you make changes to the Extra Parts API setting you will need to clear the transient cache saved for each video. You can clear the transient cache on any video by adding ?refresh to the URL or use a plugin like Transient Manager. ", "acf-youtube"); 84 | echo "

"; 85 | } 86 | 87 | function acf_youtube_api_parts_save( $options ) 88 | { 89 | // NOTHING RETURN ONLY THE DEFAULT (REQUIRED) PARTS 90 | if( !is_array( $options ) || empty( $options ) || ( false === $options ) ) 91 | { 92 | $options = array(); 93 | } 94 | 95 | // MERGE WITH REQUIRED PARTS 96 | return array_merge(acf_youtube_required_parts(), $options); 97 | } 98 | -------------------------------------------------------------------------------- /acf-youtube-funcs.php: -------------------------------------------------------------------------------- 1 | data_source = "acf"; 28 | 29 | $content_parts = implode(",", get_option('acf-youtube-api-parts')); 30 | 31 | // IF WE HAVE DATA FROM YOUTUBE API USE ADD IT TO THE OBJECT 32 | // V2: $request = wp_remote_get( "http://gdata.youtube.com/feeds/api/videos/" . $youtube_id . "?v=2&alt=json" ); 33 | $request = wp_remote_get("https://www.googleapis.com/youtube/v3/videos?part=" . $content_parts . "&id=" . $youtube_id . "&key=" . get_option( 'acf-youtube-api-key' )); 34 | 35 | if( !is_wp_error($request) || wp_remote_retrieve_response_code($request) === 200 ) 36 | { 37 | $request = json_decode( wp_remote_retrieve_body( $request ) ); 38 | 39 | if( isset( $request->error ) AND current_user_can( 'manage_options' ) ) 40 | { 41 | $video->title = $request->error->errors[0]->reason; 42 | $video->desc = $request->error->errors[0]->message; 43 | } 44 | else if( $request->pageInfo->totalResults ) 45 | { 46 | $v = reset($request->items); 47 | 48 | if( $v->snippet ) 49 | { 50 | $video_info = $v->snippet; 51 | $video_stats = $v->statistics; 52 | 53 | $video->data_source = "youtube-api"; 54 | $video->title = $video_info->title; 55 | $video->desc = $video_info->description; 56 | $video->category_id = $video_info->categoryId; 57 | $video->localized = $video_info->localized; 58 | $video->status = $v->status; 59 | $video->details = $v->contentDetails; 60 | 61 | 62 | $video->duration = acf_youtube_parse_yt_textdate( $video->details->duration ); 63 | $video->length = acf_youtube_seconds_to_time( $video->duration ); 64 | $video->author_name = $video_info->channelTitle; 65 | $video->author_id = $video_info->channelId; 66 | $video->views = $video_stats->viewCount; 67 | $video->favorites = $video_stats->favoriteCount; 68 | $video->likes = $video_stats->likeCount; 69 | $video->dislikes = $video_stats->dislikeCount; 70 | $video->comment_count = $video_stats->commentCount; 71 | $video->published = $video_info->publishedAt; 72 | } 73 | 74 | 75 | 76 | } 77 | } 78 | 79 | 80 | // DEFAULTS 81 | $video->youtube_id = $youtube_id; 82 | $video->embed = ''; 83 | $video->image = "http://i1.ytimg.com/vi/" . $youtube_id . "/hqdefault.jpg"; 84 | $video->image_med = "http://i1.ytimg.com/vi/" . $youtube_id . "/mqdefault.jpg"; 85 | $video->image_sd = "http://i1.ytimg.com/vi/" . $youtube_id . "/sddefault.jpg"; 86 | $video->image_max = "http://i1.ytimg.com/vi/" . $youtube_id . "/maxresdefault.jpg"; 87 | 88 | return $video; 89 | } 90 | 91 | 92 | function acf_youtube_parse_yt_textdate( $d ) 93 | { 94 | // FROM: http://stackoverflow.com/questions/19562195/converting-youtube-data-api-v3-video-duration-format-to-standard-time-in-php/26178914#26178914 95 | preg_match_all('/[0-9]+[HMS]/',$d,$matches); 96 | $duration=0; 97 | foreach($matches as $match) 98 | { 99 | foreach($match as $portion) 100 | { 101 | $unit = substr( $portion, strlen($portion)-1 ); 102 | switch($unit) 103 | { 104 | case 'H': 105 | $duration += substr($portion,0,strlen($portion)-1)*60*60; 106 | break; 107 | case 'M': 108 | $duration += substr($portion,0,strlen($portion)-1)*60; 109 | break; 110 | case 'S': 111 | $duration += substr($portion,0,strlen($portion)-1); 112 | break; 113 | } 114 | } 115 | } 116 | return $duration; 117 | } 118 | 119 | // CONVERTS SECONDS TO UNIX TIME 120 | function acf_youtube_seconds_to_time($time) 121 | { 122 | if( is_numeric($time) ) 123 | { 124 | $value = array("years" => 0,"days" => 0,"hours" => 0,"minutes" => 0,"seconds" => 0); 125 | if($time >= 31556926){ $value["years"] = floor($time/31556926); $time = ($time%31556926); } 126 | if($time >= 86400){ $value["days"] = floor($time/86400); $time = ($time%86400); } 127 | if($time >= 3600){ $value["hours"] = floor($time/3600); $time = ($time%3600); } 128 | if($time >= 60){ $value["minutes"] = floor($time/60); $time = ($time%60); } 129 | $value["seconds"] = floor($time); 130 | return (array) $value; 131 | } 132 | else 133 | { 134 | return (bool) FALSE; 135 | } 136 | } 137 | 138 | 139 | // CONVERTS SECONDS TO A NICELY FORMATED TIME LIKE 12:34:56 140 | function acf_youtube_seconds_to_duration($seconds) 141 | { 142 | $length_array = acf_youtube_seconds_to_time($seconds); 143 | 144 | $length = ""; 145 | if($length_array['hours'] != "") { $length = $length_array['hours'] . ":"; } 146 | if($length_array['minutes'] < 1) $length_array['minutes'] = "0"; 147 | $length .= $length_array['minutes'] . ":"; 148 | if($length_array['seconds'] < 10) { $length_array['seconds'] = "0" . $length_array['seconds']; } 149 | $length .= $length_array['seconds']; 150 | 151 | return $length; 152 | } 153 | 154 | 155 | // BUILD THUMBNAIL OBJECT 156 | function acf_youtube_thumbnail_object( $youtube_id ) 157 | { 158 | $thumbnails = new stdClass(); 159 | $thumbnails->default = "http://i1.ytimg.com/vi/" . $youtube_id . "/default.jpg"; 160 | $thumbnails->hqdefault = "http://i1.ytimg.com/vi/" . $youtube_id . "/hqdefault.jpg"; 161 | $thumbnails->mqdefault = "http://i1.ytimg.com/vi/" . $youtube_id . "/mqdefault.jpg"; 162 | $thumbnails->sddefault = "http://i1.ytimg.com/vi/" . $youtube_id . "/sddefault.jpg"; 163 | $thumbnails->maxresdefault = "http://i1.ytimg.com/vi/" . $youtube_id . "/maxresdefault.jpg"; 164 | 165 | $thumbnails->small = array(); 166 | $thumbnails->small[0] = "http://i1.ytimg.com/vi/" . $youtube_id . "/0.jpg"; 167 | $thumbnails->small[1] = "http://i1.ytimg.com/vi/" . $youtube_id . "/1.jpg"; 168 | $thumbnails->small[2] = "http://i1.ytimg.com/vi/" . $youtube_id . "/2.jpg"; 169 | $thumbnails->small[3] = "http://i1.ytimg.com/vi/" . $youtube_id . "/3.jpg"; 170 | 171 | return $thumbnails; 172 | } -------------------------------------------------------------------------------- /acf-youtube-v4.php: -------------------------------------------------------------------------------- 1 | name = 'youtube'; 10 | $this->label = __('YouTube Video', 'acf-youtube'); 11 | $this->category = __("Basic",'acf'); 12 | $this->reg_ex = ACF_YOUTUBE_REG_EX; 13 | $this->transient_time = apply_filters( 'acf_youtube_transient_time', 28800 ); 14 | $this->youtube_video_id_length = ACF_YOUTUBE_VIDEO_LENGTH; 15 | 16 | $this->defaults = array( 17 | 'return_format' => 'embed', 18 | 'thumbnail_size' => 'hqdefault' 19 | ); 20 | 21 | 22 | parent::__construct(); // do not delete! 23 | 24 | $this->settings = array( 25 | 'path' => apply_filters('acf/helpers/get_path', __FILE__), 26 | 'dir' => apply_filters('acf/helpers/get_dir', __FILE__), 27 | 'version' => '1.0.0' 28 | ); 29 | 30 | } 31 | 32 | function create_options( $field ) 33 | { 34 | $key = $field['name']; 35 | ?> 36 | 37 | 38 | 39 |

40 | 41 | 42 | 'radio', 45 | 'name' => 'fields['.$key.'][return_format]', 46 | 'value' => $field['return_format'], 47 | 'layout' => 'horizontal', 48 | 'choices' => array( 49 | 'embed' => __("Embed",'acf-youtube'), 50 | 'object' => __("Video Object",'acf-youtube'), 51 | 'id' => __("YouTube ID",'acf-youtube'), 52 | 'url' => __("URL",'acf-youtube'), 53 | 'thumbnail' => __("Thumbnail",'acf-youtube'), 54 | 'thumbnail-object' => __("Thumbnail Object",'acf-youtube') 55 | ) 56 | )); 57 | ?> 58 | 59 | 60 | 61 | class="field_option field_option_name; ?>"> 62 | 63 | 64 | 65 | 66 | 'radio', 69 | 'name' => 'fields['.$key.'][thumbnail_size]', 70 | 'value' => $field['thumbnail_size'], 71 | 'layout' => 'horizontal', 72 | 'choices' => array( 73 | 'default' => __("default",'acf-youtube'), 74 | 'hqdefault' => __("hqdefault",'acf-youtube'), 75 | 'mqdefault' => __("mqdefault",'acf-youtube'), 76 | 'sddefault' => __("sddefault",'acf-youtube'), 77 | 'maxresdefault' => __("maxresdefault",'acf-youtube'), 78 | '0' => __("0",'acf-youtube'), 79 | '1' => __("1",'acf-youtube'), 80 | '2' => __("2",'acf-youtube'), 81 | '3' => __("3",'acf-youtube') 82 | ) 83 | )); 84 | ?> 85 | 86 | 103 | 104 | 105 | 106 | '; 116 | $e .= ''; 127 | 128 | if( $field['value'] ) 129 | { 130 | $current_youtube_id = acf_youtube_parse_youtube_id( $field['value'] ); 131 | if($current_youtube_id) 132 | { 133 | $e .= ""; 134 | } 135 | } 136 | 137 | $e .= ''; 138 | 139 | $e .= " 140 | 141 | 185 | 186 | "; 187 | 188 | echo $e; 189 | } 190 | 191 | function format_value_for_api( $value, $post_id, $field ) 192 | { 193 | $youtube_id = acf_youtube_parse_youtube_id( $value ); 194 | 195 | 196 | // IF NO VIDEO ID RETURN NOTHING 197 | if( !$youtube_id ) { return false; } 198 | 199 | 200 | // RETURN URL 201 | if( $field['return_format'] == "url" ) 202 | { 203 | return 'http://www.youtube.com/watch?v=' . $youtube_id; 204 | } 205 | 206 | 207 | // RETURN EMBED 208 | if( $field['return_format'] == "embed" ) 209 | { 210 | return ''; 211 | } 212 | 213 | 214 | // RETURN THUMBNAIL 215 | if( $field['return_format'] == "thumbnail" ) 216 | { 217 | return "http://i1.ytimg.com/vi/" . $youtube_id . "/" . $field['thumbnail_size'] . ".jpg"; 218 | } 219 | 220 | 221 | // RETURN THUMBNAIL 222 | if( $field['return_format'] == "thumbnail-object" ) 223 | { 224 | return acf_youtube_thumbnail_object( $youtube_id ); 225 | } 226 | 227 | 228 | // RETURN JUST YOUTUBE ID 229 | if( $field['return_format'] == "id" ) 230 | { 231 | return $youtube_id; 232 | } 233 | 234 | 235 | // RETURN A YOUTUBE OBJECT 236 | if( $field['return_format'] == "object" ) 237 | { 238 | 239 | // CHECK FOR TRANSIENT 240 | $transient_name = "acf_youtube_" . $youtube_id; 241 | 242 | if( get_transient( $transient_name ) AND !isset($_GET['refresh'] )) 243 | { 244 | // SET TRANSIENT 245 | $value = get_transient( $transient_name ); 246 | } 247 | else 248 | { 249 | // GET YOUTUBE DATA 250 | $value = acf_youtube_build_video_object( $youtube_id ); 251 | 252 | // SET TRANSIENT 253 | set_transient( $transient_name, $value, $this->transient_time ); 254 | } 255 | } 256 | 257 | return $value; 258 | } 259 | 260 | } 261 | 262 | 263 | // CREATE FIELD 264 | new acf_field_youtube(); 265 | ?> -------------------------------------------------------------------------------- /acf-youtube-v5.php: -------------------------------------------------------------------------------- 1 | name = 'youtube'; 22 | $this->label = __('YouTube Video', 'acf-youtube'); 23 | $this->category = 'basic'; 24 | $this->reg_ex = ACF_YOUTUBE_REG_EX; 25 | $this->transient_time = apply_filters( 'acf_youtube_transient_time', 28800 ); 26 | $this->youtube_video_id_length = ACF_YOUTUBE_VIDEO_LENGTH; 27 | 28 | 29 | $this->defaults = array( 30 | 'return_format' => 'embed', 31 | 'thumbnail_size' => 'hqdefault' 32 | ); 33 | 34 | $this->l10n = array(); 35 | 36 | 37 | // do not delete! 38 | parent::__construct(); 39 | } 40 | 41 | 42 | /* 43 | * render_field_options() 44 | * 45 | * Create extra options for your field. These are visible when editing a field. 46 | * All parameters of `acf_render_field_option` can be changed except 'prefix' 47 | * 48 | * @type action 49 | * @since 3.6 50 | * @date 23/01/13 51 | * 52 | * @param $field (array) the $field being edited 53 | * @return n/a 54 | */ 55 | 56 | function render_field_settings( $field ) 57 | { 58 | 59 | acf_render_field_setting( $field, array( 60 | 'label' => __('Return Value','acf-youtube'), 61 | 'instructions' => __('Type of data returned when using the_field()','acf-youtube'), 62 | 'type' => 'radio', 63 | 'name' => 'return_format', 64 | 'value' => $field['return_format'], 65 | 'prepend' => '', 66 | 'prefix' => $field['prefix'], 67 | 'layout' => 'horizontal', 68 | 'choices' => array( 69 | 'embed' => __("Embed",'acf-youtube'), 70 | 'object' => __("Video Object",'acf-youtube'), 71 | 'id' => __("YouTube ID",'acf-youtube'), 72 | 'url' => __("URL",'acf-youtube'), 73 | 'thumbnail' => __("Thumbnail",'acf-youtube'), 74 | 'thumbnail-object' => __("Thumbnail Object",'acf-youtube') 75 | ) 76 | )); 77 | 78 | acf_render_field_setting( $field, array( 79 | 'label' => __('Thumbnail Size','acf-youtube'), 80 | 'instructions' => '', 81 | 'type' => 'radio', 82 | 'name' => 'thumbnail_size', 83 | 'value' => $field['thumbnail_size'], 84 | 'prepend' => '', 85 | 'prefix' => $field['prefix'], 86 | 'layout' => 'horizontal', 87 | 'choices' => array( 88 | 'default' => __("default",'acf-youtube'), 89 | 'hqdefault' => __("hqdefault",'acf-youtube'), 90 | 'mqdefault' => __("mqdefault",'acf-youtube'), 91 | 'sddefault' => __("sddefault",'acf-youtube'), 92 | 'maxresdefault' => __("maxresdefault",'acf-youtube'), 93 | '0' => __("0",'acf-youtube'), 94 | '1' => __("1",'acf-youtube'), 95 | '2' => __("2",'acf-youtube'), 96 | '3' => __("3",'acf-youtube') 97 | ) 98 | )); 99 | ?> 100 | 119 | '; 147 | $e .= ''; 158 | 159 | if( $field['value'] ) 160 | { 161 | $current_youtube_id = acf_youtube_parse_youtube_id( $field['value'] ); 162 | if($current_youtube_id) 163 | { 164 | $e .= ""; 165 | } 166 | } 167 | 168 | $e .= ''; 169 | 170 | $e .= " 171 | 172 | 216 | "; 217 | 218 | echo $e; 219 | } 220 | 221 | 222 | 223 | /* 224 | * format_value() 225 | * 226 | * This filter is applied to the $value after it is loaded from the db and before it is passed to the render_field() function 227 | * 228 | * @type filter 229 | * @since 3.6 230 | * @date 23/01/13 231 | * 232 | * @param $value (mixed) the value which was loaded from the database 233 | * @param $post_id (mixed) the $post_id from which the value was loaded 234 | * @param $field (array) the field array holding all the field options 235 | * @param $template (boolean) true if value requires formatting for front end template function 236 | * @return $value 237 | */ 238 | 239 | function format_value( $value, $post_id, $field ) 240 | { 241 | 242 | $youtube_id = acf_youtube_parse_youtube_id( $value ); 243 | 244 | 245 | // RETURN URL 246 | if( $field['return_format'] == "url" ) 247 | { 248 | return 'http://www.youtube.com/watch?v=' . $youtube_id; 249 | } 250 | 251 | 252 | // RETURN EMBED 253 | if( $field['return_format'] == "embed" ) 254 | { 255 | return ''; 256 | } 257 | 258 | 259 | // RETURN THUMBNAIL 260 | if( $field['return_format'] == "thumbnail" ) 261 | { 262 | return "http://i1.ytimg.com/vi/" . $youtube_id . "/" . $field['thumbnail_size'] . ".jpg"; 263 | } 264 | 265 | 266 | // RETURN THUMBNAIL 267 | if( $field['return_format'] == "thumbnail-object" ) 268 | { 269 | return acf_youtube_thumbnail_object( $youtube_id ); 270 | } 271 | 272 | 273 | // RETURN JUST YOUTUBE ID 274 | if( $field['return_format'] == "id" ) 275 | { 276 | return $youtube_id; 277 | } 278 | 279 | 280 | // RETURN A YOUTUBE OBJECT 281 | if( $field['return_format'] == "object" ) 282 | { 283 | 284 | // CHECK FOR TRANSIENT 285 | $transient_name = "acf_youtube_" . $youtube_id; 286 | 287 | if( get_transient( $transient_name ) AND !isset($_GET['refresh'] )) 288 | { 289 | // SET TRANSIENT 290 | $value = get_transient( $transient_name ); 291 | } 292 | else 293 | { 294 | // GET YOUTUBE DATA 295 | $value = acf_youtube_build_video_object( $youtube_id ); 296 | 297 | // SET TRANSIENT 298 | set_transient( $transient_name, $value, $this->transient_time ); 299 | } 300 | 301 | return $value; 302 | } 303 | 304 | 305 | return $youtube_id; 306 | } 307 | 308 | } 309 | 310 | 311 | // create field 312 | new acf_field_youtube(); 313 | 314 | ?> --------------------------------------------------------------------------------