Last active
April 10, 2022 00:05
-
-
Save RadGH/874017aae0d9dcd19114 to your computer and use it in GitHub Desktop.
WP Utility functions to get youtube/vimeo images and store their thumbnails as attachments
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
function video_get_service( $video_url ) { | |
if ( stristr( $video_url, 'vimeo.com') ) { | |
return 'vimeo'; | |
} | |
if ( stristr( $video_url, 'youtube.com' ) || stristr( $video_url, 'youtu.be' ) ) { | |
return 'youtube'; | |
} | |
return false; | |
} | |
function youtube_get_video_id( $video_url ) { | |
if ( preg_match( '/(?:https?:\/{2})?(?:w{3}\.)?youtu(?:be)?\.(?:com|be)(?:\/watch\?v=|\/)([^\s&]+)/', $video_url, $matches ) ) { | |
return $matches[1]; | |
} | |
return false; | |
} | |
function vimeo_get_video_id( $video_url ) { | |
if ( preg_match( '/(https?:\/\/)?(www\.)?(player\.)?vimeo\.com\/([a-z]*\/)*([0-9]{6,11})[?]?.*/', $video_url, $matches ) ) { | |
return $matches[5]; | |
} | |
return false; | |
} | |
function video_get_embed_code( $video_url, $user_options = null ) { | |
static $player_id_increment = 0; | |
$player_id_increment++; | |
$service = video_get_service( $video_url ); | |
$default_options = array( | |
'width' => 1280, | |
'height' => null, // Calculates to proper aspect ratio, which would be 720. | |
'autoplay' => false, | |
'player_id' => 'video-player-' . $player_id_increment, | |
// Vimeo Specific | |
'vimeo_autopause' => false, | |
'vimeo_badge' => false, | |
'vimeo_byline' => false, | |
'vimeo_color' => '00adef', | |
'vimeo_portrait' => false, | |
'vimeo_title' => false, | |
// Youtube Specific | |
'youtube_autohide' => 2, | |
'youtube_color' => 'red', | |
'youtube_enablejsapi' => 1, | |
'youtube_modestbranding' => 1, | |
); | |
$options = wp_parse_args( $user_options, $default_options ); | |
if ( $options['height'] === null ) { | |
$options['height'] = round( $options['width'] * (720/1280) ); | |
} | |
if ( $service == 'vimeo' ) { | |
$video_id = vimeo_get_video_id( $video_url ); | |
if ( !$video_id ) return false; | |
$iframe_args = array( | |
'autoplay' => $options['autoplay'] ? '1' : '0', | |
'autopause' => $options['vimeo_autopause'] ? '1' : '0', | |
'badge' => $options['vimeo_badge'] ? '1' : '0', | |
'byline' => $options['vimeo_byline'] ? '1' : '0', | |
'color' => substr(str_replace('#', '', $options['vimeo_color']), 0, 6), | |
'player_id' => $options['player_id'], | |
'portrait' => $options['vimeo_portrait'] ? '1' : '0', | |
'title' => $options['vimeo_title'] ? '1' : '0', | |
); | |
$player_url = add_query_arg( $iframe_args, '//player.vimeo.com/video/' . $video_id ); | |
return sprintf( | |
'<iframe id="%s" src="%s" width="%s" height="%s" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>', | |
esc_attr( $options['player_id'] ), | |
esc_attr( $player_url ), | |
esc_attr( $options['width'] ), | |
esc_attr( $options['height'] ) | |
); | |
} | |
if ( $service == 'youtube' ) { | |
$video_id = youtube_get_video_id( $video_url ); | |
if ( !$video_id ) return false; | |
$iframe_args = array( | |
'autoplay' => $options['autoplay'] ? '1' : '0', | |
'origin' => site_url(), | |
'color' => $options['youtube_color'] == 'white' ? 'white' : 'red', | |
'autohide' => (int) $options['youtube_autohide'], | |
'enablejsapi' => $options['youtube_enablejsapi'] ? '1' : '0', | |
'playerapiid' => $options['player_id'], | |
'modestbranding' => $options['youtube_modestbranding'] ? '1' : '0', | |
); | |
$player_url = add_query_arg( $iframe_args, '//www.youtube.com/embed/' . $video_id ); | |
return sprintf( | |
'<iframe id="%s" src="%s" width="%s" height="%s" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>', | |
esc_attr( $options['player_id'] ), | |
esc_attr( $player_url ), | |
esc_attr( $options['width'] ), | |
esc_attr( $options['height'] ) | |
); | |
} | |
return false; | |
} | |
function video_get_image( $video_url ) { | |
$service = video_get_service( $video_url ); | |
if ( $service == 'vimeo' ) { | |
$data = vimeo_get_image_attachment( $video_url ); | |
}else if ( $service == 'youtube' ) { | |
$data = youtube_get_image_attachment( $video_url ); | |
}else{ | |
return false; | |
} | |
return empty($data['attachment_id']) ? false : $data['attachment_id']; | |
} | |
function youtube_get_image_attachment( $url ) { | |
$video_id = youtube_get_video_id( $url ); | |
if ( !$video_id ) return false; | |
$video_image_option = 'youtube-image-' . $video_id; | |
// Return the image that has already been uploaded for this video ID | |
if ( $v = get_option( $video_image_option ) ) { | |
if ( isset($v['attachment_id']) && get_post( (int) $v['attachment_id'] ) ) { | |
return $v; | |
} | |
} | |
$image_url = 'http://img.youtube.com/vi/'. $video_id .'/0.jpg'; | |
$attachment = ld_handle_upload_from_url( $image_url ); | |
if ( !empty($attachment['attachment_id']) ) { | |
update_option( $video_image_option, $attachment, false ); | |
return $attachment; | |
} | |
return false; | |
} | |
function vimeo_get_image_attachment( $url ) { | |
$video_id = vimeo_get_video_id( $url ); | |
if ( !$video_id ) return false; | |
$video_image_option = 'vimeo-image-' . $video_id; | |
// Return the image that has already been uploaded for this video ID | |
if ( $v = get_option( $video_image_option ) ) { | |
if ( isset($v['attachment_id']) && get_post( (int) $v['attachment_id'] ) ) { | |
return $v; | |
} | |
} | |
$video_data = vimeo_get_info_by_url( $url ); | |
if ( $video_data && !empty($video_data['thumbnail_url']) ) { | |
$image_url = $video_data['thumbnail_url']; | |
$attachment = ld_handle_upload_from_url( $image_url ); | |
if ( !empty($attachment['attachment_id']) ) { | |
update_option( $video_image_option, $attachment, false ); | |
return $attachment; | |
} | |
} | |
return false; | |
} | |
function vimeo_get_info_by_url( $url, $option_id = null ) { | |
/* | |
Here is the result on a successful request, and also what will be cached. The ellipsis are added by me, you'll get full responses: | |
{ | |
type: "video", | |
version: "1.0", | |
provider_name: "Vimeo", | |
provider_url: "https://vimeo.com/", | |
title: "PORTRAIT", | |
author_name: "MILKYEYES - donato sansone", | |
author_url: "http://vimeo.com/milkyeyes", | |
is_plus: "0", | |
html: "<iframe src="//player.vimeo.com/video/84241262" width="1280" ...></iframe>", | |
width: 1280, | |
height: 600, | |
duration: 171, | |
description: "A slow and surreal video|slideshow of nightmareish, grotesque and a...", | |
thumbnail_url: "http://b.vimeocdn.com/ts/461/023/461023899_1280.jpg", | |
thumbnail_width: 1280, | |
thumbnail_height: 600, | |
video_id: 84241262 | |
// WordPress imports the thumbnail, giving you a full size embed code as well as the attachment ID so you can obtain your own. | |
// Note that this image is attached to the post obtained by get_the_ID() | |
media: "<img src=\"http://dyscover.limelightmethod.com/wp-content/uploads/2013/10/461023899_128020.jpg\" alt=\"Vimeo: PORTRAIT\">", | |
media_id: 437, | |
} | |
*/ | |
// If no specific option ID is provided, create our own using the URL as input. | |
if ( $option_id === null ) { | |
$option_id = 'vimeo-' . sanitize_title( preg_replace( '/(https?:\/\/(www\.)?vimeo\.com\/)?/', '', $url ) ); | |
} | |
if ( $option_id == 'vimeo-' ) { | |
return false; | |
} | |
// Get the results from cache if we have it | |
$from_cache = get_option( $option_id ); | |
if ( $from_cache ) { | |
return $from_cache; | |
} | |
// We don't have cache, perform an oembed API request | |
$oembed_url = sprintf( 'http://vimeo.com/api/oembed.json?url=%s', $url ); | |
$ch = curl_init(); | |
curl_setopt( $ch, CURLOPT_URL, $oembed_url ); | |
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true ); | |
curl_setopt( $ch, CURLOPT_SSL_VERIFYHOST, false ); | |
curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, false ); | |
curl_setopt( $ch, CURLOPT_CONNECTTIMEOUT, 10 ); | |
$data_raw = curl_exec( $ch ); | |
curl_close( $ch ); | |
if ( !$data_raw ) { | |
return false; | |
} | |
$data = json_decode( $data_raw, true ); | |
if ( !$data ) { | |
return false; | |
} | |
if ( $data['thumbnail_url'] ) { | |
// Sideload image using media_sideload_image: http://codex.wordpress.org/Function_Reference/media_sideload_image | |
require_once( ABSPATH . 'wp-admin/includes/media.php' ); | |
require_once( ABSPATH . 'wp-admin/includes/file.php' ); | |
require_once( ABSPATH . 'wp-admin/includes/image.php' ); | |
$data['media'] = media_sideload_image( $data['thumbnail_url'], get_the_ID(), 'Vimeo: ' . $data['title'] ); | |
$data['media_id'] = image_get_attachment_id( $data['media'] ); | |
} | |
update_option( $option_id, $data, false ); | |
return $data; | |
} | |
/** | |
* Retrives an image from a URL and uploads it using ld_handle_upload_from_path. See that function for more details. | |
* | |
* Note: This function should also work for local file paths as well, but the implementation is slightly different than ld_handle_upload_from_path. | |
* | |
* @param $image_url | |
* @param int $attach_to_post | |
* @param bool|true $add_to_media | |
* @return array | |
*/ | |
function ld_handle_upload_from_url( $image_url, $attach_to_post = 0, $add_to_media = true ) { | |
$remote_image = fopen($image_url, 'r'); | |
if ( !$remote_image ) return false; | |
$meta = stream_get_meta_data( $remote_image ); | |
$image_meta = false; | |
$image_filetype = false; | |
if ( $meta && !empty($meta['wrapper_data']) ) { | |
foreach( $meta['wrapper_data'] as $v ) { | |
if ( preg_match('/Content\-Type: ?((image)\/?(jpe?g|png|gif|bmp))/i', $v, $matches ) ) { | |
$image_meta = $matches[1]; | |
$image_filetype = $matches[3]; | |
} | |
} | |
} | |
// Resource did not provide an image. | |
if ( !$image_meta ) return false; | |
$v = basename($image_url); | |
if ( $v && strlen($v) > 6 ) { | |
// Create a filename from the URL's file, if it is long enough | |
$path = $v; | |
}else{ | |
// Short filenames should use the path from the URL (not domain) | |
$url_parsed = parse_url( $image_url ); | |
$path = isset($url_parsed['path']) ? $url_parsed['path'] : $image_url; | |
} | |
$path = preg_replace('/(https?:|\/|www\.|\.[a-zA-Z]{2,4}$)/i', '', $path ); | |
$filename_no_ext = sanitize_title_with_dashes( $path, '', 'save' ); | |
$extension = $image_filetype; | |
$filename = $filename_no_ext . "." . $extension; | |
// Simulate uploading a file through $_FILES. We need a temporary file for this. | |
$stream_content = stream_get_contents( $remote_image ); | |
$tmp = tmpfile(); | |
$tmp_path = stream_get_meta_data( $tmp )['uri']; | |
fwrite( $tmp, $stream_content ); | |
fseek( $tmp, 0 ); // If we don't do this, WordPress thinks the file is empty | |
$fake_FILE = array( | |
'name' => $filename, | |
'type' => 'image/' . $extension, | |
'tmp_name' => $tmp_path, | |
'error' => UPLOAD_ERR_OK, | |
'size' => strlen( $stream_content ), | |
); | |
// Trick is_uploaded_file() by adding it to the superglobal | |
$_FILES[basename( $tmp_path )] = $fake_FILE; | |
// For wp_handle_upload to work: | |
include_once ABSPATH . 'wp-admin/includes/media.php'; | |
include_once ABSPATH . 'wp-admin/includes/file.php'; | |
include_once ABSPATH . 'wp-admin/includes/image.php'; | |
$result = wp_handle_upload( $fake_FILE, array( | |
'test_form' => false, | |
'action' => 'local', | |
) ); | |
fclose( $tmp ); // Close tmp file | |
@unlink( $tmp_path ); // Delete the tmp file. Closing it should also delete it, so hide any warnings with @ | |
unset( $_FILES[basename( $tmp_path )] ); // Clean up our $_FILES mess. | |
fclose( $remote_image ); // Close the opened image resource | |
$result['attachment_id'] = 0; | |
if ( empty( $result['error'] ) && $add_to_media ) { | |
$args = array( | |
'post_title' => $filename_no_ext, | |
'post_content' => '', | |
'post_status' => 'publish', | |
'post_mime_type' => $result['type'], | |
); | |
$result['attachment_id'] = wp_insert_attachment( $args, $result['file'], $attach_to_post ); | |
$attach_data = wp_generate_attachment_metadata( $result['attachment_id'], $result['file'] ); | |
wp_update_attachment_metadata( $result['attachment_id'], $attach_data ); | |
if ( is_wp_error( $result['attachment_id'] ) ) { | |
$result['attachment_id'] = 0; | |
} | |
} | |
return $result; | |
} | |
/** | |
* Takes a path to a file, simulates an upload and passes it through wp_handle_upload. If $add_to_media | |
* is set to true (default), the file will appear under Media in the dashboard. Otherwise, it's hidden, | |
* but stored in the uploads folder. | |
* | |
* Return Values: Similar to wp_handle_upload, but with attachment_id: | |
* - Success: Returns an array including file, url, type, attachment_id. | |
* - Failure: Returns an array with the key "error" and a value including the error message. | |
* | |
* @param $path | |
* @param int $attach_to_post | |
* @param bool $add_to_media | |
* | |
* @return array | |
*/ | |
function ld_handle_upload_from_path( $path, $attach_to_post = 0, $add_to_media = true ) { | |
if ( !file_exists( $path ) ) { | |
return array( 'error' => 'File does not exist.' ); | |
} | |
$filename = basename( $path ); | |
$filename_no_ext = pathinfo( $path, PATHINFO_FILENAME ); | |
$extension = pathinfo( $path, PATHINFO_EXTENSION ); | |
// Simulate uploading a file through $_FILES. We need a temporary file for this. | |
$tmp = tmpfile(); | |
$tmp_path = stream_get_meta_data( $tmp )['uri']; | |
fwrite( $tmp, file_get_contents( $path ) ); | |
fseek( $tmp, 0 ); // If we don't do this, WordPress thinks the file is empty | |
$fake_FILE = array( | |
'name' => $filename, | |
'type' => 'image/' . $extension, | |
'tmp_name' => $tmp_path, | |
'error' => UPLOAD_ERR_OK, | |
'size' => filesize( $path ), | |
); | |
// Trick is_uploaded_file() by adding it to the superglobal | |
$_FILES[basename( $tmp_path )] = $fake_FILE; | |
// For wp_handle_upload to work: | |
include_once ABSPATH . 'wp-admin/includes/media.php'; | |
include_once ABSPATH . 'wp-admin/includes/file.php'; | |
include_once ABSPATH . 'wp-admin/includes/image.php'; | |
$result = wp_handle_upload( $fake_FILE, array( | |
'test_form' => false, | |
'action' => 'local', | |
) ); | |
fclose( $tmp ); // Close tmp file | |
@unlink( $tmp_path ); // Delete the tmp file. Closing it should also delete it, so hide any warnings with @ | |
unset( $_FILES[basename( $tmp_path )] ); // Clean up our $_FILES mess. | |
$result['attachment_id'] = 0; | |
if ( empty( $result['error'] ) && $add_to_media ) { | |
$args = array( | |
'post_title' => $filename_no_ext, | |
'post_content' => '', | |
'post_status' => 'publish', | |
'post_mime_type' => $result['type'], | |
); | |
$result['attachment_id'] = wp_insert_attachment( $args, $result['file'], $attach_to_post ); | |
$attach_data = wp_generate_attachment_metadata( $result['attachment_id'], $result['file'] ); | |
wp_update_attachment_metadata( $result['attachment_id'], $attach_data ); | |
if ( is_wp_error( $result['attachment_id'] ) ) { | |
$result['attachment_id'] = 0; | |
} | |
} | |
return $result; | |
} |
I ended up using oembed using ACF's video field, and pulling images from there, and adding as a featured image on save. Thanks for the answer!
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Yeah but take a look at oembed, a standardized way to get video thumbnails and other data:
https://wordpress.org/support/article/embeds/
I would not recommend using my original code, it's quite old