Dynamically Overriding a Page’s Template

It is easy to override the template for a post or page in WordPress in a few ways. For example, the naming of page template files can be used to override a single page’s template:

  • page-{id}.php
  • page-{slug}.php

Or, a page template can be chosen in the Page Attributes section when editing a page:

Choose a Template

This works great when you always want a page template to be used for a particular page. But what if you need to change a page’s template based on something that might change? Like the current user’s role, for example? Well, you can use the template_include filter in WordPress to override the normally-used template in a function.

Start out by attaching a function to the filter:

add_filter( 'template_include', 'dynamic_page_template' );

This can be added to your theme’s functions.php file or to a custom plug-in. In this example, the function called dynamic_page_template will be invoked. This function will accept the parameter, $page_template, which is the $page_template that is to be used. If you want the page template defined in a way above (by the template name or the selected template in the Page Attribute area) to work as normal, simply returning $page_template will accomplish this. However, we can also set $page_template to something different and return that instead. Here is a simple example:

function dynamic_page_template( $page_template ){
  global $post;
  if (100 == $post->ID) :
    $page_template = get_template_directory() . "/page-test.php";
  endif;

  return $page_template;
}

In this example, we are pulling in the $post (or page) information by calling it globally. Then, we can check for the post ID value. If the ID is 100, we are setting the page template dynamically to the page-test.php file in our theme. The get_template_directory call gets us the directory for our theme. Now, even if we have a file named page-100.php, our function will take precedence.

Hiding the categories of a post when it is “uncategorized”

If you’ve ever had some posts on your WordPress blog, you will have noticed that the “Uncategorized” category is displayed with a link to an archive of uncategorized posts.

Uncategorized

The easiest way to solve this, of course, is to categorize every blog post. But, if you don’t want to for some reason, you can use some PHP in your theme to hide the category of these posts. The example below is a customization I did for a theme in Bones but it should be easy to follow for other themes as well. The original line for the display of the categories in Bones is:

printf( __( 'filed under', 'bonestheme' ).': %1$s', get_the_category_list(', ') );

So, it is just using the WordPress function, get_the_category_list, to list a comma-separated list of categories for the post. How do we hide this if the post is uncategorized? Well, one way to do it is to get a list of categories for the post. If the number of categories is one, and that category is “Uncategorized” then we just won’t use the get_the_category_list display. Here is the code:

$show_categories = true;
$categories = wp_get_post_categories( $post->ID );
// We don't want to show the categories if there is a single category and it is "uncategorized"
if ( count( $categories ) == 1 && in_array( 1, $categories ) ) :
  $show_categories = false;
endif;
if ( has_category( null, $post->ID ) && $show_categories ) :
  echo ' & ' . __('filed under ', 'bonestheme') . get_the_category_list(', ');
endif;

We start off with the assumption that we’ll display the categories so we set a flag as true to begin with. Then, we retrieve the categories for a post. wp_get_post_categories will return the post’s categories as an array. Terms, or categories, for WordPress are stored in the wp_terms database table. And “Uncategorized” is actually a stored term with the term_id of 1:

Uncategorized term in database

With this knowledge, we check the number of categories of our post (retrieved with wp_get_post_categories) with a count call. If the result is one and the category array contains the “Uncategorized” category (term_id of 1) then we know we don’t have any categories we want to display. So, we’ll set our flag to false.

Finally, we make sure that the post does have categories and that our flag to display categories is set to true. WordPress’s has_category function, if given no category to check against, will just tell us if the post has any categories. If the post has categories and the flag is set to true, then we will use the category display line in our theme and display the post’s categories.

Hiding the WordPress admin bar on certain pages

There may be times when you would like to hide the WordPress admin bar on certain pages. Maybe the admin bar interferes with the design, for example. This can be especially true for things like pages opening up in a lightbox. Fortunately, it is not too difficult to hide the admin bar on certain pages with a filter in WordPress.

There is actually a filter in WordPress named, logically enough, show_admin_bar. This filter will show the admin bar if true is returned but not show the admin bar if the returned value is false. You pass the $bool value in which is WordPress’s own determination if the admin bar should be shown or not. So, in your theme’s functions.php file, you can add the following code:

function my_theme_hide_admin_bar($bool) {
  if ( is_page_template( 'page-pop-up.php' ) ) :
    return false;
  else :
    return $bool;
  endif;
}
add_filter('show_admin_bar', 'my_theme_hide_admin_bar');

In the code above, we are simply checking to see if the page we’re on is using the template file, page-pop-up.php. This is a theme file that I used to display pages opening up in a lightbox. If the page is using that template, we return false to suppress the showing of the admin bar. If not, we return the usual $bool value set in WordPress and it will act as normal. Of course, the template conditional is just one example. You could also use other WordPress conditionals to turn the admin bar off for a myriad of other circumstances.

Using MailCatcher for local mail testing

When developing web applications on your local machine, you will often want to test e-mails. For the longest time, I would use an environmental switch in PHP depending on the domain (for example, I would set different values if the domain was stirrell.second-cup-of-coffee or www.second-cup-of-coffee.com) and include values for email addresses. I had my local MAMP really sending out emails and this worked fine. Of course, there is always the chance you’re going to miss an email somewhere and inadvertently send out a real email when you just want to test.

A good solution to this problem is to use a “fake” SMTP server – a program that simulates sending an email and allows you to see what would have been sent – but only exists on your local machine. I had been using one on the Macintosh – MockSMTP which is available on the Mac App Store. It had been working fine for me. I set it up according to the instructions here and it all worked swimmingly… until I upgraded to the newest Mac OS X, Mavericks. I did not receive any errors but I also never received any test emails. Bummer. I sent a tweet to the folks who make MockSMTP but never got a response – the app itself has not been updated since 2011 so I fear that an update might not be coming.

I searched around for an alternative to MockSMTP. Many of the ones I saw were Java-based multi-platform solutions which did not appeal to me. I finally decided to give the free MailCatcher a try. MailCatcher is a Ruby Gem so is installed via the command line and called through the command line. I followed the instructions at their site and it worked straight away.

To get MailCatcher working with PHP, I edited the php.ini configuration files to use catchmail for the sendmail path. In MAMP, you simply go to File > Edit Template > PHP and then choose the version of PHP you are using. You can tell what version of PHP you are using with MAMP by going to the “Server” tab:

PHP version

I added the following line to my configuration file:

sendmail_path = /usr/bin/env catchmail

Update for macOS Sierra – I found that I needed to change this line to:

sendmail_path = /usr/bin/env /usr/local/bin/catchmail -f catcher@mailcatcher.me

Once that is set, all email sent by PHP will go to MailCatcher. You can view mail sent to MailCatcher using a browser to connect to your local machine on port 1080 (http://127.0.0.1:1080/). You will get a simple web interface for viewing the mails that have come in. From then on, simply type “mailcatcher” in the Terminal to start up MailCatcher. This will give you a simple way of testing emails on your local machine without worry of emails getting sent to the client.

Passing PHP variables to JavaScript

I was recently working on a project in CodeIgniter and I was setting numeric variables with constants for things like locations (1 = Maine, 2 = New Hampshire, etc.). This all worked fine but when it came to doing some JavaScript AJAX work I didn’t have access to these constants. One of the advantages to using these constants is that I did not want to have to change the value in more than one place if a value changed or I wanted to add a new location, for example. My way to solve this was to pass my PHP variables through to JavaScript using json_encode.

In my CodeIgniter controller, I set the variables I wanted to use in JavaScript:

$footerData['javascriptVariables'] = array(
  'sheetID' => $sheetID
);

Then, in the footer, I checked for the existence of $javascriptVariables and, if it is not empty, I echoed out the json_encoded value:

// Were there any variables set via PHP for use in the JavaScript?
if (!empty($javascriptVariables)) {
  echo '<script type="text/javascript">';
  echo "var php_variables = " . json_encode($javascriptVariables) . "\n";
  echo '</script>';

This results in something like:

<script type='text/javascript'>
var php_variables = {"sheetID":"8"}
</script>

Then, in my JavaScript, I can easily get access to the sheetID set in PHP:

php_variables.sheetID

I suspect that I could also automate the process of making all my PHP constants available in JavaScript by using get_defined_constants.

Display the caption of a featured image in WordPress

Have you ever wanted to display the caption of a Featured Image in WordPress? I recently had need to do this and figured out a way to accomplish this.

When you set the Featured Image for a post in WordPress, you can add additional information for the image: Title, Caption, Alt Text and Description.

Set caption for featured image

It makes sense to me that you might want to display the caption for a Featured Image, if entered. My solution to this was to add a function to my functions file to use to display the caption. My function looks like this:

function my_display_featured_image( ) {
    global $post;

    $thumbnail_id = get_post_thumbnail_id($post->ID);
    $thumbnail_details = get_posts(array('p' => $thumbnail_id, 'post_type' => 'attachment'));
    $thumbnail_src = wp_get_attachment_image_src( $thumbnail_id, 'full' );
    $thumbnail_width = $thumbnail_src[1];

    if ($thumbnail_src && isset($thumbnail_src[0])) {
        echo '<div class="featured-image';
        if ( !empty( $thumbnail_details[0]->post_excerpt ) ) echo ' wp-caption';
        echo '" style="max-width: ' . $thumbnail_width . 'px;">';
        if ( !empty( $thumbnail_details[0]->post_excerpt ) ) {
          echo '<p class="featured-image-caption">';
          echo $thumbnail_details[0]->post_excerpt;
          echo '</p>';
      }
      the_post_thumbnail( $post->ID );
      echo '</div>';
    }
}

First, we get the information for the post we’re on. We do this by making the $post global. This will give us access to the id of the post we’re on. From there, we can call get_post_thumbnail_id to get the id of the Featured Image. Once we have the id of the Featured Image, or attachment, that we want, we can then use WordPress’s get_posts to grab the record of the Featured Image. The details of the Featured Image are stored in the variable $thumbnail_details using the call:

$thumbnail_details = get_posts(array('p' => $thumbnail_id, 'post_type' => 'attachment'));

get_posts accepts the arguments of WP_Query so, in our example, ‘p’ is the post id (the id of the Featured Image) which we were able to get using get_post_thumbnail_id. This query returns an object which includes the Featured Image’s caption in the ‘post_excerpt’ value and the description is available in the ‘post_content.’

if ( !empty( $thumbnail_details[0]->post_excerpt ) ) {
  echo '<p class="featured-image-caption">';

I am also grabbing the source of the attachment image and using the width of the image to set some inline CSS (in my particular case I wanted to float the image so I wanted to set the width). wp_get_attachment_image_src gets the url and image dimensions and returns the values in an array.

So, now I have the image’s URL, dimensions and caption. With this information, we can display the image. To check if there is a caption present, I just need to check the value of the post_excerpt returned by my get_posts call.

Finally, I use the_post_thumbnail to display the featured image. In my template file, if the post has a Featured Image, I call my function to display the Featured Image.

if ( has_post_thumbnail() ) : my_display_featured_image(); endif;

That is how I display a Featured Image’s caption.

Adding a Prefixr command to TextMate 2

I was recently looking into how to add a Prefixr command to TextMate 2. For those of you not familiar, Prefixr is a way (created by Jeffrey Way of NetTuts) to take a new-ish CSS property like box-shadow or transform and add all the vendor-specific prefixes automatically. So:

transform: rotate(-7deg);

becomes:

-webkit-transform: rotate(-7deg);
-moz-transform: rotate(-7deg);
-o-transform: rotate(-7deg);
-ms-transform: rotate(-7deg);
transform: rotate(-7deg);

to accomodate the prefixes for Webkit browsers (Safari and Chrome), Firefox, Opera and Internet Explorer. These prefixes are used by the different browser vendors to experiment with newer CSS properties before the standard has been finalized. So, ideally, these prefixes would eventually go away as the these properties become standardized across browsers.

Jeffrey actually has an example of how to add a command to TextMate 1 in his introduction article to Prefixr and this works perfectly in TextMate 2. I simply went to “Bundles > Edit Bundles” and chose the CSS bundle. I then clicked “New” and chose “Command.” In my new command, I pasted in the command from Jeffrey’s article:

curl -sSd "css=$TM_SELECTED_TEXT" "http://prefixr.com/api/index.php"

I chose Selection for the Input so that my highlighted text would be acted on. I also entered “source.css” for the scope and… it worked great! But, I tested it in a SASS document (.SCSS) and, because of the scope… nada. It wasn’t available as an option when searching all my commands. Well, one can add more than one scope by separating them with commas. So I changed the scope to:

source.css,source.scss

And the command is now available to me in both CSS and SASS.

Sitewide settings in CodeIgniter

I recently wanted to set up a system to allow a client to edit sitewide configuration settings on a custom CodeIgniter site. I didn’t want to hardcode it in a configuration file and I wasn’t sure exactly how it would need to be added to in the future. I decided to use a system much like WordPress with a custom key/value table in the database – like WordPress’s wp_options table. So, I created a similar table – a primary, auto-incremented key, a settingKey varchar field, a settingValue text field and a modified date field with a trigger (just to be able to monitor changes on the setting). My MySQL for the table looks like this:

SET NAMES utf8;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for `siteSettings`
-- ----------------------------
DROP TABLE IF EXISTS `siteSettings`;
CREATE TABLE `siteSettings` (
`settingID` int(4) NOT NULL AUTO_INCREMENT,
`settingKey` varchar(50) NOT NULL,
`settingValue` text,
`recordLastModDate` datetime DEFAULT NULL,
PRIMARY KEY (`settingID`)
) ENGINE=MyISAM AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
delimiter ;;
CREATE TRIGGER `siteSettingsUpdateLastModDate` BEFORE UPDATE ON `siteSettings` FOR EACH ROW BEGIN
SET NEW.recordLastModDate = CURRENT_TIMESTAMP;
END;
;;
delimiter ;

Once the table was in place, I looked into ways to always have these configuration settings available to me through the CodeIgniter site. I saw some cool stuff online using hooks and I think that would have worked but it seemed a little intense for the simple site I was working on. So, I decided instead to create a model, settings_model.php, and then add the model to the autoload.php file so that it would always trigger:

$autoload['model'] = array('settings_model');

In the model itself, I had a function, LoadSitewideSettings that would simply get the settings from the database table and add them to CodeIgniter’s configuration settings. Here is my LoadSitewideSettings function:

public function LoadSitewideSettings() {
$settings = array();

// Get the settings from the database
$query = $this->db->get('siteSettings');
foreach ($query->result() as $settingRow) {
$settings[$settingRow->settingKey] = $settingRow->settingValue;
}

$this->config->set_item('siteSettings', $settings);
}

So, I just grab all the data from that database table, run through each item to get the keys, and then use CodeIgniter’s config->set_item function to assign the values to CodeIgniter’s configuration variables. I create an array and save all of those elements in the variable, ‘siteSettings,’ to try to avoid any naming collisions with other CodeIgniter variable names.

Finally, I call my LoadSitewideSettings function in the constructor of my model to make sure I grab the configuration values. When I want to access these configuration variables, I use CodeIgniter’s config->item command like this:

$this->config->item('defaultOrderEmails', 'siteSettings');

So, the record in my configuration file with the key, defaultOrderEmails, will be grabbed and made available to me anywhere on the site.

Setting UTF-encoding with a PHP header

Sometimes, I need to write a one-off PHP script to export/import data from a database, for example. Since I am not using any kind of front-end interface, I have found that I sometimes have to specifically set the encoding on the page to avoid any extended character issues with the database. I use:

header('Content-Type: text/html; charset=utf-8');

And that seems to work just fine.

Protect a cron job from outside access

I recently set up a PHP file that generates an XML-formatted sitemap for a dynamic site and set up a cron job to update the sitemap from time-to-time. I didn’t see any reason to allow outside access to executing the script, so I looked into using .htaccess to restrict access to the script. It turns out that it is pretty easy:

Order deny,allow
Allow from 127.0.0.1
Allow from additional_ip
Deny from all

You can also add in additional IP addresses if you still want to be able to hit the script from your office or home machine. Just put more IP addresses on their own lines. It is that easy. If you wanted to protect only certain files, you could wrap your rules in something like:

<Files index.html> or use wildcards like: <Files *.php> to block all access to PHP scripts.