Category Archives: WordPress

Replace Post Excerpts with the Yoast META Description

Someone sent a question through this site to me yesterday.

Hi Mark,
Thanks for your site. I’ve been using yoast meta descriptions since beginning my site (800 posts) and now want to use the post excerpt in archives. Is there a way to use the yoast meta desc. as the wordpress excerpt? I find documentation on using excerpts as meta, but not the other way around.
Thanks for your help,

If you’re wondering Yoast SEO is the most popular WordPress SEO Plugin and it allows you to override a lot of default WordPress post values to better optimise your on-page SEO. If you’re wondering what a META description is then you should read this article on Wikipedia.

As it turns out, the solution isn’t too hard. First, check the WordPress documentation to see if there’s a filter that can be used when the post excerpt is retrieved (there is). Second, have a poke around the wp_postmeta MySQL database table and check what meta_key Yoast uses to store his post META description. Turns out that key is _yoast_wpseo_metadesc. Once we know that it’s simply a matter of writing a couple of lines of PHP and dropping it into the functions.php file:

add_filter( 'get_the_excerpt', 'replace_post_excerpt_filter' );

function replace_post_excerpt_filter($output)
{
        $output=get_post_meta(get_the_ID(), '_yoast_wpseo_metadesc', true);
        return $output;
}

In the first line we’re adding the get_the_excerpt filter and in the third adding the new filter procedure. The procedure itself is fairly simply, the get_post_meta function allows us to pull the Yoast META description for the post. Then we’re replacing the excerpt passed to the function with the Yoast value.

Of course this is going to replace the post excerpt everywhere. If you just wanted to change the value in your WordPress archives then you could just edit your child theme’s archive.php file (assuming your theme has an archive.php file). Just look for the main loop and some code that looks something like the_excerpt(); and replace it with:

echo get_post_meta(get_the_ID(), '_yoast_wpseo_metadesc', true);

GZIP Compression and WordPress

I had an issue back in November 2014 trying to enable GZIP compression with WordPress. A spare half an hour was found last week that allow me to solve the problem. I resorted to a .htaccess file change. I simply added this to the top of the .htaccess file:

# BEGIN GZIP
<ifmodule mod_deflate.c>
AddOutputFilterByType DEFLATE text/text text/html text/plain text/xml text/css application/x-javascript application/javascript
</ifmodule>
# END GZIP

Now the WordPress site is being delivered to clients in GZIP format. This results in a significant speed improvement in page rendering as well as a significant decrease in the bandwidth my server needs to deliver. Furthermore, it’s superior to the ob_gzhandler method suggested by WordPress themselves because CSS and javascript files are compressed as well as the HTML. The ob_gzhandler method appears to only compress the HTML.

Filter Posts from Tag Archives in WordPress

I’ve been using a commercial WordPress plugin to manage customer testimonials for one of my products. One of the features of the plugin is a tag cloud. The cloud is generated from tags for each testimonial. I’ve used the tags to produce industry specific archives of customer testimonials, which is great for SEO purposes. However, in some cases I’ve created multiple testimonials for the same customer, allowing me to use a short extract or a sentence or two on a landing page rather than having to use the entire testimonial. This resulted in duplicate testimonials from the same customer appearing in the testimonial tag archives. I needed to find a way from stopping this. Here’s how I solved the problem.

First, I added a custom meta field to each duplicate testimonial that I didn’t want to appear in the tag archive. That looks like this:

Defining a Custom Meta Tag

Defining a Custom Meta Field

Given that the testimonials are custom post types I could filter the testimonials from the tag archives by testing for the existence of the new meta field (in this case I called it testimonial-widget-hide-on-tag-archive). The actual value you assign to the new meta field doesn’t matter. We just want the field to be present for the testimonials we do not want to display on the tag archives. To do that I needed to add an action to the pre_get_posts event and add a filter for the new meta key. Here’s the code I added to my functions.php file:

function modify_testimonial_tag_archive_query( $query ) 
{
	if (is_tag() && $query->is_main_query()) 
	{
		$meta_query[] = array(
                    'key'=>'testimonial-widget-hide-on-tag-archive',
                    'compare'=>'NOT EXISTS',
                );	
		$query->set('meta_query',$meta_query);
  }
}
add_action( "pre_get_posts", "modify_testimonial_tag_archive_query" );

Some key things to note here are the use of is_tag() to check that the query is tag based. Then the use of the $query->is_main_query() call to make sure the filter is used for the main query only (the one that works out what posts to display). The $meta_query array is used to put in the key for the new meta field for the posts we created above, and then we’re using the NOT EXISTS comparison. The result of all this is that only posts that DO NOT have the meta value testimonial-widget-hide-on-tag-archive will be displayed on tag based archives.

Including CSS on a Particular WordPress Page or Post

I deployed a site recently that made use of the Testimonials WordPress plugin. This plugin adds a CRUD interface to the WP dashboard where you can add/edit/delete customer testimonials. They can then be displayed in posts or pages using shortcodes. There’s a lot of parameters for the shortcodes but (somewhat strangely) there’s no apparent way of giving a particular instance of a testimonial a CSS class or ID. So there’s no easy way to style a testimonial on a given page of the site. This is particularly annoying if you want the testimonial bigger on a particular page for marketing reasons.

Now, a little aside here, I did PAY for the commercial version of the plugin. I shot off a couple of support emails to the author in the first couple of days of use and he completely didn’t answer one of them (he linked me to a FAQ page that didn’t answer my question), but he did answer a second question. However, when I asked him about the custom CSS class or ID for a testimonial he initially didn’t understand the question (which could have been entirely my fault) and then suggested I PAY for more support if I wanted his help. Now given that I had only just paid for the plugin a week or two before hand I thought that was a little rich. So, needless to say that’s the last email he’ll ever get from me, time to work this out myself.

I picked apart the HTML generated by the testimonial shortcodes. Each one is contained in a DIV with the CSS ID like .post-6666 where 6666 is the ID of the testimonial. The actual body text of the testimonial is contained in a <p> in the parent DIV.  All I needed to do was inject some CSS into the particular page where I needed a different style for the testimonial.  Turns out it’s not too hard.  Just add the following to your child theme functions.php file.

add_action( 'wp_head', 'custom_include_script' );

function custom_include_script()
{
   if(is_page( 'some-page-name' ))
   {    
    ?>
	<style type="text/css">.post-6666 p {font-size: 18px;font-weight: 500;font-style: italic;}</style>
    <?php  
   }		
}

The PHP Is pretty simple to understand. We’ve added an action to the wp_head call. The action checks if the page is the page we are interested in, if it is then it echoes out the CSS for the particular testimonial DIV. Hey presto different text size for the testimonial on a particular page.

Including a Javascript File in a Specific WordPress Page

Including a particular Javascript file for a specific page or post in WordPress is something that can be useful so that you do not needlessly load the file for every page of the site. Let’s take the example where we want to include the file “page-specific.js” file in the WordPress page “A Specific Page”. In this case I’m assuming the path to your page-specific.js file is:

/wp-content/themes/your-child-theme/js/page-specific.js

In the functions.php file of the child theme enter this code:

add_action( 'wp_head', 'custom_include_script' );

function custom_include_script()
{
    if(is_page( 'a-specific-page' ))
    {    
    ?>
	<script src="<?php echo esc_url( get_stylesheet_directory_uri() . '/js/page-specific.js"' ); ?>" type="text/javascript"></script>
    <?php  
    }
}

The PHP Is pretty simple to understand. We’ve added an action to the wp_head call. The action checks if the page is the page we are interested in, and if it is, it echoes out the HTML required to include the JS file. The get_stylesheet_directory_uri() call gets the directory of the child theme we’re using.

PHP in WordPress

I’ve been using PHP in a lot of WordPress posts and pages recently. Usually I just make use of the Exec-PHP plugin. This allows you to put PHP in any page or post using the usual <?php opening and ?> closing tags.  It’s a little clunky for a few reasons, firstly if you edit the page or post in the WordPress Visual editor it messes up the code. You work-around that using the Disable Visual Editor WYSIWYG plugin. A second reason not to do it this way is that editing PHP in the WordPress is horrid. I’d much prefer editing in my IDE of choice where I get nice syntax highlighting and can format the code nicely.

However, there’s a big reason not to include complex PHP directly in your pages or posts. That’s because the PHP is included in the database record for the page or post. Never a great idea from a security point of view. It turns out if you have a need for a complex PHP driven page there’s an easier way. Take the case where we want to create a PHP driven page called “My PHP Page”.

  • In your child theme folder (you are using a child theme I hope) create a copy of your page.php file and call it page-my-php-page.php.
  • Create a new page in WordPress and call it “My PHP Page”.

Now when WordPress renders the new page called “My PHP Page” and it finds the page-my-php-page.php file in the theme directory it will use that file to generate the page content.

I have found this approach particularly useful if you are building a simple CRUD system in WordPress. I’ve created a series of files called (for example) page-add-record.php, page-delete-record.php, page-edit-record.php, page-view-records.php. Each file contains the code required to add/edit/delete/display the database records I am interested in. Then I just need to create corresponding pages in WordPress with the names “Add Record”, “Edit Record”, “Delete Record”, and “Display Records”.

ob_gzhandler and Divi WordPress Theme are not happy bed-fellows

I’ve just finished rolling out a new WordPress site which uses the very nice Divi theme by Elegant Themes.  The site is hosted on Pair, and they do not have gzip compression enabled for Apache.  No problem I thought, someone must have solved that problem.  And sure enough Jon Henshaw had done exactly that.  There’s something not quite right with the way his blog is rendering (because it’s removed the underscores from the code) but basically all I had to do was put this at the top of my child theme header.php file:

ob_start("ob_gzhandler");

Once I’d done that I verified (using Google Chrome) that the download size of the each page on the site had decreased, and sure enough the 500K home page was now just a 100k download. Woot. Or so I thought.

Next morning I got up to a slew of emails asking me what happened to the site as all people could see was a blank page. I checked the site in Chrome, nope, it’s there. Checked it in Firefox, nope it’s there. Checked in IE10, nope there too. All there while I was logged into WordPress. With a growing sense of dread I logged out of WordPress in IE10, refreshed the home page of the site and….a blank page. Same for FireFox and for some reason, Chrome rendered the site just fine. I tracked the problem down to somewhere in the wp_head() call in the header.php file, but I really wasn’t interested in having the site down any longer so I removed the offending code above and the site started working correctly.

Today, with a bit of time on my hands I tested the same call in a couple of other themes (WP 2014 and on this blog) and it didn’t cause an issue. So, the only thing I can conclude at this stage is that ob_gzhandler and the Divi WordPress theme do not play well together.

WordPress Posts with Identical Dates

I’m building a catalog site in WordPress for one of my collections. The catalog currently exists in a large Excel spreadsheet and I’ve been usng it to create a CSV file that can be imported using the WP CSV plugin. This greatly speeds up the creation of the content for the catalog. My plan is that each item in my catalog is a post and the CSV file contains all of the information for each post. One of the imported values in the CSV file includes is the post date. I imported each item with an identical post date without giving it too much thought. This is because the catalog site isn’t going to actually display any post dates. Anyway, it turns out that this was a bad idea because the Next Post and Previous Post links in the single.php template will not bring up any of the posts with the same post date. A bit of digging about and I’ve worked out why.

My single.php theme file contains calls to previous_post_link() and next_post_link() which are supposed to render the next/previous links. I drilled down into these functions which can be found in the /wp-includes/link-template.php file. Both functions call the function get_adjecent_post(). Looking at that a bit closer it includes a bunch of SQL criteria code (for selecting posts from the same taxonomy for example) and, as you’d expect it creates a date criteria clause. That bit of php looks like this:

$adjacent = $previous ? 'previous' : 'next';
 $op = $previous ? '<' : '>';
 $order = $previous ? 'DESC' : 'ASC';

Those little ‘<' and '>‘ symbols give the answer why my imported posts with identical post dates don’t display in the next/previous post links. The date criteria to select the next/previous post is “greater than” or “less than” and obviously if the post dates are identical they are NOT greater than or less than. So, the solution is to NOT import posts with identical post dates. Unfortunately I’d already done this so I opened up the wp_posts table in MySQL workbench and edited the post date of each post I’d imported. Next time I do a bulk import I’ll make sure to increment the post date column values in the CSV BEFORE I do the import.

Sorting WordPress Category Archives

By default WordPress category archives are sorted by date.  This is fine when you’re publishing a blog but if you’re using WP for other reasons you might want to adjust the way the archives are sorted.  This is done rather easily by creating a new filter in your functions.php file like this:

//filter to alphabetically sort category archives
add_filter('posts_orderby','sort_category_archive_alphabetically');

And then creating a new sort function like this:

function sort_category_archive_alphabetically($orderby )
{
 if (is_category())
 {
 return "post_title ASC";
 }
 return $orderby;
}

In this example I’m alphabetically sorting all categories.  You could restrict it to a specific category by changing the is_category() call to include a category ID (is_category(8)) or by including a category name (is_category(‘Your Category Name’)).

I’m doing a simple sort by post_title here but more complex sorts are possible.  For example, the WordPress API gives a more complex example that explains how to do a LEFT JOIN in the SQL to select posts and sort by values in tables other than the WP_POSTS table.

Default Image Captions in WordPress

I’m building a numismatic reference website in WordPress for the Perth Numismatic Society that is eventually going to list several thousand items along with images. The images will be presented as thumbnails which can be clicked on to show larger images using the Responsive Lightbox plugin. The client wanted a default caption under each image instructing users to click on the image to view a larger one. I honestly thought adding a default image caption would be easy but it turns out it isn’t. Nothing I Googled up actually worked including this example in the WordPress Codex or this plugin. So I actually had to use the old grey matter and work it out myself.

So I had a poke around the and ended up in the /wp-admin/includes/media.php file and found this function and filter:

function image_add_caption( $html, $id, $caption, $title, $align, $url, $size, $alt = '' )
{
//function code removed
}
add_filter( 'image_send_to_editor', 'image_add_caption', 20, 8 );

Ahah, simple. Remove the existing image_add_caption filter and replace it with my own. So, I’ve grabbed that code and added it and a couple of other things to my child theme functions.php file as:

remove_filter( 'image_send_to_editor', 'image_add_caption');
add_filter( 'image_send_to_editor', 'add_default_caption', 100, 8);
function add_default_caption( $html, $id, $caption, $title, $align, $url, $size, $alt = '' ) {

	/**
	 * Filter whether to disable captions.
	 *
	 * Prevents image captions from being appended to image HTML when inserted into the editor.
	 *
	 * @since 2.6.0
	 *
	 * @param bool $bool Whether to disable appending captions. Returning true to the filter
	 *                   will disable captions. Default empty string.
	 */
        if (substr($html,0,strlen('([0-9]+)/', $html, $matches ) )
		return $html;

	$width = $matches[1];

	$caption = str_replace( array("rn", "r"), "n", $caption);
	$caption = preg_replace_callback( '/<[a-zA-Z0-9]+(?: [^<>]+>)*/', '_cleanup_image_add_caption', $caption );
	// convert any remaining line breaks to <br>
	$caption = preg_replace( '/[ nt]*n[ t]*/', '<br />', $caption );

	$html = preg_replace( '/(class=["'][^'"]*)align(none|left|right|center)s?/', '$1', $html );
	if ( empty($align) )
		$align = 'none';

	$shcode = '' . $html . ' ' . $caption . '';

	/**
	 * Filter the image HTML markup including the caption shortcode.
	 *
	 * @since 2.6.0
	 *
	 * @param string $shcode The image HTML markup with caption shortcode.
	 * @param string $html   The image HTML markup.
	 */
	return apply_filters( 'image_add_caption_shortcode', $shcode, $html );
}

You can see I start by removing the existing image_add_caption filter but it turns out this is an utter waste of time because the filter executes even though I’ve removed it. So I’ve got around this by declaring the new filter with a lower priority than the existing one (so it happens AFTER) the existing filter. And then checked the $html to see if it starts with the caption shortcode. That’s this line:

if (substr($html,0,strlen('[caption'))=='[caption')
 return $html;

So, if a caption has already been applied we just exit from our new filter.  However, if there’s no caption we can now apply our default caption like this:

if (empty($caption))
 $caption="Click Image to Enlarge";