I’m creating custom post type in a plugin for the first time. So far, it’s been done directly in the child theme. Not the best place as functionality should be separate from display.

The first thing was to copy, edit and paste one of the register_post_type() calls I had written before. Right away something was strange. The CPT showed up on my development site, but not on a blank install. After much commenting out of various lines, I found that the problem lay with the ‘capability_type’ argument.

My development site is multisite, and it looks like network admins have much more capabilities than normal site admins, or perhaps it was the role management plugin magically granting it rights. I looked into the code for the role management plugin (Members by Justin Tadlock) and discovered that it added some extra capabilities upon plugin activation. Sounds like just what I needed.

register_activation_hook( __FILE__, 'mbpc_feba_cpt_install' );

// Start by giving the administrator role access to the CPT
function prefix_cpt_install() {
	/* Get the administrator role. */
	$role =& get_role( 'administrator' );

	/* If the administrator role exists, add required capabilities for the plugin. */
	if ( !empty( $role ) ) {
		/* Role management capabilities. */
		$role->add_cap( 'publish_cptname' );
		$role->add_cap( 'create_cptname' );
		$role->add_cap( 'delete_cptname' );
		$role->add_cap( 'edit_cptname' );


I’ve edited some of the names used. When you’re writing your own, remember to prefix your functions so they’ll be unique, and of course replace ‘cptname’ with a meaningful name.

Unfortunately, the code above did not work for me. It looked like the activation function was not being called. Putting echo statements inside didn’t do anything, and even putting die() inside did nothing.

When there’s a problem, start with the Codex. The page for register_activation_hook() had line near the bottom referencing a support forum thread. Turns out that ‘echo’ really doesn’t work, and the way to check if the activation hook is being called is to use exit().

Another user pointed out that __FILE__ doesn’t work when the plugin directory is only symlinked. That’s exactly what I’m doing! The solution is to pass it the path to the symlink.

register_activation_hook( WP_PLUGIN_DIR . '/plugin-name/plugin-name.php', 'prefix_cpt_install' );

And now the CPT shows up in the admin menus! wp_user_roles in the options table also has the new capabilities added by the activation function.

Permalinks on Mac OS

Mac OS X has Apache and PHP built in. I installed MySQL and set up a localhost WordPress install on it. Everything looked good, until I tried to enable pretty permalinks. The pretty links just didn’t work.

The Codex page indicates that FollowSymLinks must be enabled and AllowOverride should be All (or FileInfo). I tried putting that into the httpd.conf file but that didn’t work.

It took a while to realise that I was putting those directives into the section for the web root directory and not the user specific folder where I had actually put the site. Following the trail of includes in the well commented config files, I found my user Apache config in /etc/apache2/users/.conf

Added those options into the config file and permalinks are working 🙂

EDIT: Upgraded to OSX Mountain Lion and it uses a different set of configuration files. It looks like user config files aren’t created by default so I just changed the default directive.


I run a few localhost installs of WordPress for testing and experimentation. They are installed using the svn method, as outlined in the Codex.

At first, I would go in manually to each folder to svn up occasionally. This got tiresome after a while so I wrote a simple bash script to cd to each folder and run svn up

Recently, I discovered that there’s a shortcut. All I have to do is to go to the parent directory and type svn up *

This will run the command on all the subfolders and thus bring all my sites up to date.

Menu Behind Youtube Video

After embedding a Youtube video on the front page, I noticed that the drop down menus were appearing behind the video, making some pages inaccessible from the menus. Not good.

Some poking around Google led to

I found that only step 3 (setting wmode=”transparent” in the embed tag) is necessary. To get that version of the embed code, it is necessary to select the “Use old embed code” checkbox in Youtube’s embed settings. However, this means that only Flash playback is supported.

Prior to this, I also tried wrapping the embed code in a <div> and using the z-index CSS setting. That didn’t work at all. Perhaps there’s another solution that will work with the iframe embed method so HTML5 video can also be supported.

Podcast Feed

Since my site has weekly MP3 uploads, it makes sense to create a podcast feed for it. Unfortunately, those updates were implemented with custom post types, which don’t generate podcast feeds automatically with the <enclosure> tags. Thus I would have to generate a custom feed myself.

The Codex page on Customizing Feeds explains how to get a custom post type to use my own custom feed. Since I’m using a child theme, I used get_stylesheet_directory() instead of get_template_directory().

When I first setup the custom post type and imported the existing content, the meta value _wp_attached_file included the full URL. It still does as the custom insert post functions for the custom post type have been written that way. Thus to generate the path to the file (to get the filesize for the RSS feed), I had to modify the output of get_attached_file() by using the get_attached_file filter.

Using the default RSS2 template as a starting point, I modified the template to produce a feed which more or less follows the iTunes format. The major challenge was getting the filesize of the MP3 files, this was done with the PHP filesize() function.

$size = filesize( get_attached_file( $child->ID ) );

The author and subtitle fields were field with the available post meta stored with the custom post type.

A strange problem I encountered was that this worked perfectly with iTunes on my test setup, but iTunes refused to recognize the feed properly on the live site. This was solved by using feedburner, and subscribing to the feedburner feed instead. However, this still doesn’t explain what’s wrong with the feed on the actual site which prevents iTunes from getting it properly.

Amazon Web Services

Amazon Web Services (AWS) provides computing resources in the cloud. You can get access to as many ‘machines’ as you’re willing to pay for, as well as storage, database services and many others. All these can be combined to create a rapidly scalable application.

AWS does provide a free usage tier, allowing anyone to sign up and try out the service for free for a year, as long as the application remains below limits. Full details of these limits can be found on their website.

The free usage tier includes 750 hours of an EC2 micro instance, enough to run a little web server. The rest of this post will give a brief overview of how to get WordPress running on EC2.

Start by creating a new instance in the region of your choice. The Amazon Machine Images (AMIs) which are free to use are marked with a yellow star. AWS has recently started offering Ubuntu as a free image. This has made it much easier for me to get stuff working.

AWS provides instructions on how to create a SSH key and use it to login to the instance. If you want to allow others or other machines to login, generate SSH keys for them and place the public portion in the /home/ubuntu/.ssh/authorized_keys file.

Install Apache, PHP and MySQL using apt-get. This is basic LAMP setup stuff.

Install SVN. This is optional, but I like using SVN to install WordPress because it’s so easy to update.

To change the location of the webroot folder, change the DocumentRoot setting of /etc/apache2/sites-enabled/000-default

For permalinks to work, mod_rewrite must be enabled. Also, the AllowOverride setting in the 000-default apache configuration file must be set to ‘all’.

From the AWS Management Console, click on the instance to see its public DNS information. This address is the publicly accessible IP address. The full domain name ending in can be used for the WordPress site and home URLs. You can also create a shorter address with DynDNS and point it to the IP address given.

Before your web server can be reached from the internet, there’s one more thing to do. Go to Security Groups in the AWS Management Console, it’s under the Network & Security section. Select the security group used by your instance. Add a new inbound rule for port 80 (HTTP). This is necessary for the web server to be publicly accessible.

Now that everything is ready, use any method you like to install WordPress. Remember to create a database and user first.

SSL Certificates

Strictly speaking, this isn’t a WordPress post. However, it is related to the server setup I use for WordPress development and testing.

I’ve been using Apache’s built in snakeoil SSL certificate because the server was only accessible on port 443. However, this gave that ugly and very scary looking untrusted SSL certificate error whenever I accessed my own development server. One day, I got sick of that extra click to confirm that I wanted to continue, so I decided to do something about it.

Generating a new Certificate

Information about generating self-signed SSL certificates is available in the documentation located at /usr/share/doc/apache2.2-common/README.Debian.gz

Run the command

make-ssl-cert /usr/share/ssl-cert/ssleay.cnf /path/to/cert-file.crt

This will prompt for the hostname, where I put the domain name of the dyndns address. This command generates both the public and private key and puts them in the same file. The documentation suggests putting it in /etc/ssl/private

Configuring Apache

Modify the apache2 configuration in /etc/apache2/sites-enabled/default-ssl
Change the value of “SSLCertificateFile” to the path of the newly generated certificate. Comment out “SSLCertificateKeyFile” as both parts are in the certificate file.

Generating the Public Key for the Cert

Generate the public key portion of the certificate by running

openssl x509 -in /path/to/cert-file.crt -out /path/to/output -pubkey

Importing the Certificate

Copy the public certificate file to the host machine. You can also do this on other machines used regularly to access the web server.

From Start -> Run, type in ‘mmc’. Go to File->Add/Remove Snap-in, and add the certificate snap-in.
Expand Trusted Root Certification Authorities ->Certificates, then go to Action->All Tasks->Import in the menu.

Import the public key file. The default location is Trusted Root Certification Authority.

After this, Chrome and IE will no longer give scary looking warnings about untrusted certificates.