I'm using the following code to find first YouTube/Vimeo embed in the post content:
function compare_by_offset( $a, $b ) {
return $a['order'] - $b['order'];
}
function first_video_url($post_id = null) {
if ( $post_id == null OR $post_id == '' ) $post_id = get_the_ID();
$post_array = get_post( $post_id );
$markup = $post_array->post_content;
$regexes = array(
'#(?:https?:)?//www\.youtube(?:\-nocookie)?\.com/(?:v|e|embed)/([A-Za-z0-9\-_]+)#', // Comprehensive search for both iFrame and old school embeds
'#(?:https?(?:a|vh?)?://)?(?:www\.)?youtube(?:\-nocookie)?\.com/watch\?.*v=([A-Za-z0-9\-_]+)#', // Any YouTube URL. After http(s) support a or v for Youtube Lyte and v or vh for Smart Youtube plugin
'#(?:https?(?:a|vh?)?://)?youtu\.be/([A-Za-z0-9\-_]+)#', // Any shortened youtu.be URL. After http(s) a or v for Youtube Lyte and v or vh for Smart Youtube plugin
'#<div class="lyte" id="([A-Za-z0-9\-_]+)"#', // YouTube Lyte
'#data-youtube-id="([A-Za-z0-9\-_]+)"#', // LazyYT.js
'#<object[^>]+>.+?http://vimeo\.com/moogaloop.swf\?clip_id=([A-Za-z0-9\-_]+)&.+?</object>#s', // Standard Vimeo embed code
'#(?:https?:)?//player\.vimeo\.com/video/([0-9]+)#', // Vimeo iframe player
'#\[vimeo id=([A-Za-z0-9\-_]+)]#', // JR_embed shortcode
'#\[vimeo clip_id="([A-Za-z0-9\-_]+)"[^>]*]#', // Another shortcode
'#\[vimeo video_id="([A-Za-z0-9\-_]+)"[^>]*]#', // Yet another shortcode
'#(?:https?://)?(?:www\.)?vimeo\.com/([0-9]+)#', // Vimeo URL
'#(?:https?://)?(?:www\.)?vimeo\.com/channels/(?:[A-Za-z0-9]+)/([0-9]+)#' // Channel URL
);
$provider_videos = array();
foreach ( $regexes as $regex ) {
if ( preg_match_all( $regex, $markup, $matches, PREG_OFFSET_CAPTURE ) ) {
$provider_videos = array_merge( $provider_videos, $matches[0] );
}
}
if ( empty( $provider_videos ) ) return;
foreach ( $provider_videos as $video ) {
$videos[] = array(
'url' => $video[0],
'order' => $video[1]
);
}
usort( $videos, 'compare_by_offset' );
$first_video_url = current(array_column($videos, 'url'));
if ( empty( $first_video_url ) ) return;
return $first_video_url;
}
Now when I got the link to the first video in the post I want to remove it from the post content. And that's where I'm stuck. My attempt so far:
function remove_first_image ($content) {
$url = first_video_url();
$parsed = parse_url($url);
$video_id = $parsed['query'];
$embed_code = wp_oembed_get($url);
$pattern = 'a pattern for that embed which I fail to make';
$content = preg_replace($pattern, '', $content);
return $content;
}
add_filter('the_content', 'remove_first_image');
Thanks!
I guess one couldn't answer his own stupid question until he asks it. Here comes the answer:
function remove_first_image ($content) {
if ( is_single() && has_post_format('video') ) {
$url = first_video_url();
$embed_code = wp_oembed_get($url);
$content = str_replace($embed_code, '', $content);
}
return $content;
}
add_filter('the_content', 'remove_first_image');
Related
I have this shortcode:
I do this shortcode in template, I tried several WordPress themes, and it does not return HTML, but just text in continuous row.
I used this shortcode way abck and it worked, I do not know what happened meanwhile in a year so it does not work in WordPress anymore.
Anyone has a clue?
function paywall_level_b( $atts, $content = null ) {
$post = get_queried_object();
if ( function_exists( 'pmpro_has_membership_access' )) {
// Check if the user has access to the post.
$hasaccess = pmpro_has_membership_access( $post->ID );
// Display Content if the user has access to the post.
if( ! empty( $hasaccess ) ) {
$content = apply_filters('the_content', get_the_content());
echo $content;
// Display Text if the user has no access to the post, but is logged in.
} elseif ( is_user_logged_in() ) {
$content = apply_filters('the_content', get_the_content());
$sentences = explode(".", $content);
$first_slice = implode(".", array_splice($sentences, 0, 5));
$second_slice = implode(".", array_splice($sentences, 0));
echo '<div class="non-paywall">'. html_entity_decode ( $first_slice ) .'.</div><div class="pmpro_content_message">Text</div>';
// Display Text if the user has no access to the post, and is not logged in.
} else {
$content = apply_filters('the_content', get_the_content());
$sentences = explode(".", $content);
$first_slice = implode(".", array_splice($sentences, 0, 5));
$second_slice = implode(".", array_splice($sentences, 0));
echo '<div class="non-paywall">'. html_entity_decode ( $first_slice ) .'.</div><div class="pmpro_content_message">Text 2</div>';
}
}
}
add_shortcode( 'paywall_level_b', 'paywall_level_b' );
I am using a shortcode to display video from custom field "tube_video_url".
Now what I wish to do is to automaticly add mqdefault image to custom filed "fifu_image_url" of the same video.
I made this shortcode for myself...
function video( $atts, $content = "" ) {
$string = get_post_meta(get_the_ID(), 'tube_video_url', TRUE);
$search = '/youtube\.com\/watch\?v=([a-zA-Z0-9]+)/smi';
$replace = 'youtube.com/embed/$1';
$content = preg_replace($search, $replace, $string);
return '<iframe id="video-frame" width="560" height="315" src="'.$content.'" frameborder="0" allowfullscreen></iframe>';
}
add_shortcode( 'video', 'video' );
Now I am not sure how to turn this...
https://www.youtube.com/watch?v=2yJS-byLHrU
into this...
https://i.ytimg.com/vi/2yJS-byLHrU/mqdefault.jpg
I tried something like
$string = 'https://www.youtube.com/watch?v=2yJS-byLHrU';
$search = '/youtube\.com\/watch\?v=([a-zA-Z0-9]+)/smi';
$replace = 'i.ytimg.com/vi/$1/mqdefault.jpg';
$content = preg_replace($search, $replace, $string);
echo $content;
Result comes to https://www.i.ytimg.com/vi/2yJS/mqdefault.jpg-byLHrU, note how -byLHrUis put after jpg, and also how do I fill the custom field "fifu_image_url' with this value of image once submit button is pressed or at first post visit?
You can extract youtube video id using url as following
$link = "https://www.youtube.com/watch?v=2yJS-byLHrU";
$video_id = explode("?v=", $link);
if (empty($video_id[1]))
$video_id = explode("/v/", $link);
$video_id = explode("&", $video_id[1]);
$video_id = $video_id[0]; // will print the output -> 2yJS-byLHrU
Found answer, I will post it if anyone needs in future...
/* Do something with the data entered */
add_action( 'save_post', 'myplugin_save_postdata' );
/* When the post is saved, saves our custom data */
function myplugin_save_postdata( $post_id ) {
// First we need to check if the current user is authorised to do this action.
if ( 'page' == $_POST['post_type'] ) {
if ( ! current_user_can( 'edit_page', $post_id ) )
return;
} else {
if ( ! current_user_can( 'edit_post', $post_id ) )
return;
}
$url = get_post_meta(get_the_ID(), 'tube_video_url', TRUE);
preg_match('%(?:youtube(?:-nocookie)?\.com/(?:[^/]+/.+/|(?:v|e(?:mbed)?)/|.*[?&]v=)|youtu\.be/)([^"&?/ ]{11})%i', $url, $match);
$youtube_id = $match[1];
$mydata = 'https://i.ytimg.com/vi/'. $youtube_id. '/mqdefault.jpg'; // Do something with $mydata
update_post_meta( $post_id, 'fifu_image_url', $mydata );
}
Unfortunatelly this works only posting from back-end.
We use WordPress and would like to link amp to amp if the linked page has an amp version. We have amp structured like that: test.de/test/amp
Unfortunately this code in my functions.php isnt applying to links hard-coded inside of the post content. What do I have to change, so its working for every internal link:
add_filter( 'post_link', function( $url, $post ) {
static $recursing = false;
if ( $recursing ) {
return $url;
}
$recursing = true;
if ( ! function_exists( 'post_supports_amp' ) || ! post_supports_amp( $post ) ) {
return $url;
}
if ( function_exists( 'is_amp_endpoint' ) && is_amp_endpoint() ) {
$url = amp_get_permalink( $post->ID );
}
$recursing = false;
return $url;
}, 10, 2 );
At the moment its also applying to the canonical link, which is really bad for seo. How to prevent this?
Add these functions to your theme's 'functions.php'.
/* post link filter */
add_filter( 'post_link', 'change_amp_url', 10, 2 );
function change_amp_url( $url, $postobj ) {
static $recursing = false;
if ( $recursing ) {
return $url;
}
$recursing = true;
if ( function_exists( 'is_amp_endpoint' ) && is_amp_endpoint() ) {
if ( function_exists( 'post_supports_amp' ) && post_supports_amp( $postobj ) ) {
$url = amp_get_permalink( $postobj->ID );
}
}
$recursing = false;
return $url;
}
/* content link filter */
add_filter( 'the_content', 'change_amp_url_content' );
function change_amp_url_content($content)
{
$dom = new DOMDocument();
$dom->loadHTML($content);
$tags = $dom->getElementsByTagName('a');
foreach ($tags as $tag) {
$link = $tag->getAttribute('href'); // original url
$extralink = '';
if(stristr($link,'#')) {
$pagelinktemp = explode("#",$link);
$pagelink = $pagelinktemp[0];
$extralink = '#'.$pagelinktemp[1];
} else {
$pagelink = $link;
}
if($pagelink!="") {
$postid = url_to_postid($pagelink);
$postobj = get_post($postid); // getting appropriate post object
if($postobj) {
$newlink = change_amp_url( $pagelink, $postobj ); //new url
}
else {
$newlink = $link;
}
}
else {
$newlink = $link;
}
if($link != $newlink) // change if only links are different
{
$content = str_replace($link, $newlink.$extralink, $content);
}
}
return $content;
}
/* override canonical link */
add_filter( 'wpseo_canonical', 'amp_override_canonical' );
function amp_override_canonical($url) {
if ( substr($url,-4)=="/amp" ) {
$url = substr($url,0,-4);
}
return $url;
}
The first function will provide the AMP URL if exists.
The second one will loop through each URL in the content and change to AMP URL if valid.
The last one will rewrite the canonical URL that displayed via Yoast SEO plugin.
If you want to replace hardcoded links inside of your post content I would suggest you use the "the_content" filter for wordpress.
https://codex.wordpress.org/Plugin_API/Filter_Reference/the_content
add_filter( 'the_content', 'filter_function_name' )
From this you should be able to regular expression match the link and append /amp to it.
Pseudo code example:
function my_the_content_filter($content)
{
if (function_exists('is_amp_endpoint') && is_amp_endpoint()) {
$patterns = array(
//patterns
);
$replacements = array(
//replacements
);
$content = preg_replace($patterns, $replacements, $content);
}
return $content;
}
add_filter('the_content', 'my_the_content_filter');
I have tested the code submitted by Outsource WordPress, and in general it works fine but the 'amp_override_canonical function overwrites all the urls of the page removing the /amp.
I have made some changes to this piece of code but they do not work as I expect. It seems that the 'wpseo_canonical' function is being invoked in a different context.
add_filter( 'wpseo_canonical', 'amp_override_canonical' );
function amp_override_canonical($url) {
if ( substr($url,-4)=="/amp" ) {
$url = substr($url,0,-4);
}
return $url;
}
I have a variable $url (who I have no control over) whose value is a URL (as a string). For example:
$url = 'http://www.youtube.com/watch?v=rSnzy2dZtsE';
I have a list of hosts (example.com) that I'd like to check against the $url, and see if any one of them matches the host in the URL.
I am doing it like this:
<?php
function itsme_custom_oembed( $html, $url, $attr, $post_id ) {
// Supported video embeds
$hosts = array( 'blip.tv', 'money.cnn.com', 'dailymotion.com', 'flickr.com', 'hulu.com', 'kickstarter.com', 'vimeo.com', 'vine.co', 'youtube.com' );
foreach( $hosts as $host ) {
// check if it's a supported video embed
if( strpos( $url, $host ) === false )
return $html;
return '<div class="flex-video">'. $html .'</div>';
}
}
add_filter( 'embed_oembed_html', 'itsme_custom_oembed', 10, 4 );
?>
But it's not working (i.e. strpos( $url, $host ) is always returning false), and as I see it, the problem is with the foreach construct. Especially because this works:
<?php
function itsme_custom_oembed( $html, $url, $attr, $post_id ) {
// Supported video embeds
$host = 'youtube.com';
// check if it's a supported video embed
if( strpos( $url, $host ) === false )
return $html;
return '<div class="flex-video">'. $html .'</div>';
}
add_filter( 'embed_oembed_html', 'itsme_custom_oembed', 10, 4 );
?>
Clearly, foreach isn't meant for this purpose.
So, how am I supposed to check if given URL has any one of the strings in the array? (i.e. true if any one of the hosts in the list matches the host in the URL.)
Problem is that you are returning inside the loop. Once you return from a function, the function stops. So you end up checking the first value on the first run through the loop and return stopping the function from checking any subsequent iterations.
To fix it, you could just move the second return outside the loop. This would make the function loop over each value in the array until it found a match. If match found, function exits (return). If no match is found, it will hit the return after the loop.
function itsme_custom_oembed( $html, $url, $attr, $post_id ) {
// Supported video embeds
$hosts = array( 'blip.tv', 'money.cnn.com', 'dailymotion.com', 'flickr.com', 'hulu.com', 'kickstarter.com', 'vimeo.com', 'vine.co', 'youtube.com' );
//loop over all the hosts
foreach( $hosts as $host ) {
// check if it's a supported video embed
if( strpos( $url, $host ) === false )
return $html; //it was supported, so return from the original html from the function
}
//no hosts matched so return the original html wrapped in a div.
return '<div class="flex-video">'. $html .'</div>';
}
I am not sure what you want to return but you can try to use this!
function itsme_custom_oembed( $html, $url, $attr, $post_id ) {
$hosts = array('blip.tv', 'money.cnn.com', 'dailymotion.com', 'flickr.com', 'hulu.com', 'kickstarter.com', 'vimeo.com', 'vine.co', 'youtube.com');
$success = false;
foreach ($hosts as $host) {
if (stripos($url, $host) !== false) {
$success = true;
break;
}
}
if ($success) {
// put your return when it DOES contain the host here
}
else {
// put your return when it DOES NOT contain the host here
}
}
(Based on Jonathan Kuhn's answer and suggestions.) This does it:
<?php
function itsme_custom_oembed( $html, $url, $attr, $post_ID ) {
// Supported video embeds
$hosts = array( 'blip.tv', 'money.cnn.com', 'dailymotion.com', 'flickr.com', 'hulu.com', 'kickstarter.com', 'vimeo.com', 'vine.co', 'youtube.com' );
foreach( $hosts as $host ) {
// check if it's a supported video embed
if( strpos( $url, $host ) !== false )
return '<div class="flex-video">'. $html .'</div>';
}
}
return $html;
}
add_filter( 'embed_oembed_html', 'itsme_custom_oembed', 10, 4 );
?>
Then an idea struck me; that I could do it in a much simpler way, like this:
<?php
function itsme_custom_oembed( $html, $url, $attr, $post_ID ) {
// Supported video embeds
$hosts = array( 'blip.tv', 'money.cnn.com', 'dailymotion.com', 'flickr.com', 'hulu.com', 'kickstarter.com', 'vimeo.com', 'vine.co', 'youtube.com' );
foreach( $hosts as $host ) {
// check if it's a supported video embed
if( strpos( $url, $host ) !== false ) {
$html = '<div class="flex-video">'. $html .'</div>';
break;
}
}
return $html;
}
add_filter( 'embed_oembed_html', 'itsme_custom_oembed', 10, 4 );
?>
Seems like a much better way to do what I am after.
I use often this function to extract the image of a post:
function first_post_image($content) {
$first_img = '';
$output = preg_match_all('/<img.+src=[\'"]([^\'"]+)[\'"].*>/i', $content, $matches);
$first_img = $matches [1] [0];
return $first_img;
}
then I show the image with the following code
<?php $postimage = first_post_image(get_the_content()); ?> // catch the image
<img src="<?php echo $postimage; ?>" /> //view the image
Now I tryed to use this function in my last template (wp), but the image doesn't appear. I can see the tag img and the src attribute, but it is empty.
Someone can help me? Thanks
Have you done a var_dump( $postimage ); to see what the function is returning?
Here is one that works and instead of returning an empty array if there are no images it will return false so you can specify a backup or default image.
/**
* Extracts the first image in the post content
*
* #param object $post the post object
* #return bool|string false if no images or img src
*/
function extract_image( $post ) {
$html = $post->post_content;
if ( stripos( $html, '<img' ) !== false ) {
$regex = '#<\s*img [^\>]*src\s*=\s*(["\'])(.*?)\1#im';
preg_match( $regex, $html, $matches );
unset( $regex );
unset( $html );
if ( is_array( $matches ) && ! empty( $matches ) ) {
return $matches[2];
} else {
return false;
}
} else {
return false;
}
}
I have made some test and finally I solve the problem. I don't know if I make a mistake, but the code is the same and now work correctly.
Thanks.