if is amp change internal links to amp version (WordPress) - php

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;
}

Related

Hide a certain paragraph for non-logged in users and avoid WP Cache mess

I want to hide a certain paragraph from the SINGLE POST in WordPress via PHP content filter.
I developed this filtering script, which works like a sunshine:
function hideDaStuff( $content ) {
$paragraphs = explode( '</p>', $content );
foreach ($paragraphs as $index => $paragraph) {
if(6 == $index){
$paragraphs[$index] = '<p>Hidden for you ma friend.</p>';
}else{
$paragraphs[$index] .= '</p>';
}
}
return implode( '', $paragraphs );
}
add_filter( 'the_content', 'hideDaStuffForDaStranger' );
function hideDaStuffForDaStranger( $content ) {
if ( is_single() && ! is_user_logged_in() ) {
$content = hideDaStuff( $content );
}
return $content;
}
The problem is that WP cache caches the page whatever happens. So if a logged in user visits the page, then the content will show for everybody, and viceversa.
How can I make this specific part cache-independent, while keeping an efficient cache?
Using latest WP version and WP cache.
Thank you.
Put only single condition
function hideDaStuffForDaStranger( $content ) {
if (! is_user_logged_in() ) {
$content = hideDaStuff( $content );
}
return $content;
}
Actually no need of these filters. Use this format
if(is_user_logged_in()){ ?>
<p>oggedin data</p>
<?php }

How to exclude specific post from wp functions.php code?

I used this code to show responsive ad from adsense after 5th paragraph.
Adding Ads After First And Second Paragraph of WordPress Post
This is the code I use on my site:
function prefix_insert_after_paragraph2( $ads, $content ) {
if ( ! is_array( $ads ) ) {
return $content;
}
$closing_p = '</p>';
$paragraphs = explode( $closing_p, $content );
foreach ($paragraphs as $index => $paragraph) {
if ( trim( $paragraph ) ) {
$paragraphs[$index] .= $closing_p;
}
$n = $index + 1;
if ( isset( $ads[ $n ] ) ) {
$paragraphs[$index] .= $ads[ $n ];
}
}
return implode( '', $paragraphs );
}
add_filter( 'the_content', 'prefix_insert_post_ads' );
function prefix_insert_post_ads( $content ) {
if ( is_single() && ! is_admin() ) {
$content = prefix_insert_after_paragraph2( array(
// The format is: '{PARAGRAPH_NUMBER}' => 'AD_CODE',
'5' => '<div>Ad code after FIRST paragraph goes here</div>',
), $content );
}
return $content;
}
I would like to exclude this code only for specific posts. How can I add the proper code to be able to exclude this function for post id=280?
Thank you.
Why do you want to exclude this function inside functions.php?
I think it's much easier to do it inside the post loop.
For example, to exclude the POST ID 280, if you're inside the page.php, or similar you can do this:
global $post;
if ($post->ID == 280){ remove_filter( 'the_content', 'prefix_insert_post_ads' ); }
This way you have the 'add_filter' on your functions.php file, and if you find the exception inside the post (ID=280), you remove the filter.
Just U have to check the current post_id. E.g. :
function prefix_insert_post_ads( $content ) {
global $post;
$post_id = $post->ID;
$post_ids_excluded = [280,....]; // excluded posts ids
if ( in_array($post_id,$post_ids_excluded) ){
return $content;
}
/*
... the same code .....
*/
}

Remove exact embed code(wordpress) with preg_replace

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');

How to run a function instead of text in this wordpress plugin?

Here is a simple code which shows the Adsense or any ad code after second paragraph on single post page. But I want to know how to modify it so that it can run a dynamic function.
//Insert ads after second paragraph of single post content.
add_filter( 'the_content', 'prefix_insert_post_ads' );
function prefix_insert_post_ads( $content ) {
$ad_code = '<div>Ads code goes here</div>';
if ( is_single() && ! is_admin() ) {
return prefix_insert_after_paragraph( $ad_code, 2, $content );
}
return $content;
}
// Parent Function that makes the magic happen
function prefix_insert_after_paragraph( $insertion, $paragraph_id, $content ) {
$closing_p = '</p>';
$paragraphs = explode( $closing_p, $content );
foreach ($paragraphs as $index => $paragraph) {
if ( trim( $paragraph ) ) {
$paragraphs[$index] .= $closing_p;
}
if ( $paragraph_id == $index + 1 ) {
$paragraphs[$index] .= $insertion;
}
}
return implode( '', $paragraphs );
}
In fact I want to replace
$ad_code = '<div>Ads code goes here</div>';
with
$ad_code = '<?php if(function_exists('echo_ald_crp')) echo_ald_crp(); ?>';
Is there any way to do it??
Well, you can't assign PHP to a string var and expect it to execute. You could create a function with the code in it, have it return something, and then set the variable equal to the function call. Like this:
function output_function() {
//do something here
return $thing_you_want_to_return;
}
function prefix_insert_post_ads( $content ) {
$ad_code = output_function();
if ( is_single() && ! is_admin() ) {
return prefix_insert_after_paragraph( $ad_code, 2, $content );
}
return $content;
}
That way, when the variable is assigned, it'll run your function and return what you want to be echoed out with prefix_insert_after_paragraph().

Using strpos, check if given URL has 'any one' of the strings in the array?

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.

Categories