Category Archives: Functions

Additions to functions.php

Could not Edit Menus

I was having an annoying issue where a site’s menus could not be edited through the WordPress admin interface. The menu structure would load but drag and drop simply refused to work even when the cursor changed to the 4-way move arrow.

Checking the console in Chrome’s web inspector revealed some sort of JavaScript problem. Changing the theme to a default one made the problem go away, thus the problem had to be with the custom theme.

I started debugging by commenting out the add_action() functions enqueuing some extra js files used for the jQuery accordion. That fixed it. Putting back the accordion init script revealed that it was not the problem, so that left the custom jQuery UI file, version 1.8.13.

The latest stable version is now 1.10.2, so I got that by selecting the accordion widget on jQuery UI’s download page, letting the other checkboxes auto populate. Extracted the file into the scripts folder, updated functions.php to point to the new file, and the menus admin page now works again!!

Update the jQuery UI file.

Custom Post Type Permalinks

After creating the custom post type in my plugin, I tried visiting, but got a 404 error page instead.

I came across a blog post by Kovshenin which explains how to get permalinks working with custom post types. The key thing is to specify the slug with the ‘rewrite’ parameter when registering the CPT. After that, remember to reset the permalinks by visiting the permalinks settings page in Settings -> Permalinks. Quite a lot of 404 grief can be solved by doing so.

It makes sense to automate this in the plugin. To do so, I added flush_rewrite_rules() to the activation and deactivation hooks. This would ensure that the permalinks are reset only when the CPT becomes active or inactive.

Do not let the function run on every page load. It is very resource intensive and will slow your site down.

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.

Hiding the Editor Part 2

A previous post explained how to hide the WordPress editor for custom post types.

I just noticed that this no longer works in WordPress 3.3.1. It looks like the CSS Ids have changed for the editor. The whole editor is now enclosed by a div with the id ‘postdivrich’.

Thus the hide_editor() function now reads as below. Much simpler.

	function hide_editor() {
				#postdivrich {display:none;}

Adding another Custom Post Type

A new requirement came in for the site I manage. There was a need to add about 3 years worth of question and answer PDF files to the site. The nature of this was similar to the newsletters. Each post would contain a link to a PDF file. The title would hold the question, but the writing area would not be deactivated so the question could be split if it is too long.

It is very likely that there would be similar files in the future, so I decided to make this a custom post type so a non techie administrator can handle future uploads. I considered doing this as a plugin, but I’m still not sure how to include page templates as part of plugins, so I decided to just incorporate it into my custom theme, like the other post types.

The first thing to do was to register the post type using the register_post_type() function. Straightforward stuff.

In the following paragraphs, {cpt} should be replaced with the name of the post type. If the custom post type is named “Books”, loop-{cpt}.php means loop-books.php.

The loop-{cpt}.php template file is where I customize the look of each custom post type. This is where I choose what to display and how to show it. In this case, I printed the words “Download the answer: “, followed by a link to the PDF file with the answer. As this is handled by the template, the look of every post will be consistent and this will not depend on the uploader entering the proper wording into the content area.

Next came the {cpt}-template.php file. This modifies the query so it only selects posts of the custom post type I’m interested in displaying. It then calls the loop template file using get_template_part( 'loop', {cpt} ); A blank page is then created in the admin area and assigned this page template. A link is added to the menu so this page shows up in the menu system.

A single-{cpt}.php file is also created. It calls the loop template using get_template_part() as well.

I also had to edit the sidebar.php file. My sidebar shows date archives for each custom post type. Which one to show depends on which post type is currently displayed. I registered a new widget area in functions.php, then modified the if-elseif statements in the sidebar.php file so it could support new post type. To see which post type is currently displayed, the get_post_type() WordPress function is used. I can’t remember what I was previously using, but it wasn’t good enough.

Another change was to style.css. Instead of targeting each widget area by ID to make them align right and set the sidebar width, I realized I could just use the widget-area class instead.

On the admin side, a meta box had to be added. I had already done this before so it was a simple matter of copying and editing the existing code. The meta_box class described in earlier posts is flexible enough to handle this with no problems. I did make sure to look through the save() function to make sure it could support the new file name format without any unpleasant surprises.

After all these code additions, I now have a new custom post type I can use to add question and answer PDF files through the admin interface. I added the existing content manually, and will teach the administrator to upload future ones.

The new custom post type gave 404 errors when first used. I found that it was necessary to place flush_rewrite_rules() into the functions.php file as the usual method of resaving the permalinks didn’t work. However, after refreshing the page, the 404 errors went away and I could take out the flush_rewrite_rules() line. It is important to remove this line once the site works, or the site will be severely slowed by the constant regeneration of rewrite rules.

Custom Post Type Archives jQuery Accordion

As more and more past entries are migrated over to the WordPress site, the year/month drop down list for the archives will get longer and longer.

It’s much cooler to show a list of the years, then when a year is clicked, it slides open to show links to the months. Turns out this can be done with a jQuery accordion.

Modifying HTML Markup

The wp_get_archives() function returns an unordered list in HTML with links to every year-month with an entry. This will have to be parsed and modified so that the years are added as headings.

The basic approach is to use a regular expression to get an array of all the years, then count how many times each year appears. These numbers will be used later to count the number of entries before a year heading should be added.

//get an array of all the years
	//the generated html is in reverse chronological order
	//this can be used to determine when to insert a year header
	preg_match_all("|<li><a .*>.*([0-9]{4}).*</a></li>|", $html, $out, PREG_PATTERN_ORDER);

	$html = "";
	$year_counts = array();

	//counts the number of months with archives for each year
	foreach ( $out[1] as $entry ) {
		if ( isset( $year_counts[ $entry ] ) ) {		//increment count for the year
			$year_counts[ $entry ] = $year_counts[ $entry ] + 1;
		else {
			$year_counts[ $entry ] = 1;					//1st time this year is encountered

	$years = array_keys( $year_counts );
	$counts = array_values( $year_counts );
	$i = 0;
	$k = 0;

	foreach ( $years as $year ) {
		$html .= '<h3>' . $year . '</h3><ul>';		//create a heading for each year
		for ( $j = 0; $j < $counts[ $i ]; $j++) {		//create an entry for each month in the year
			$html .= $out[ 0 ][ $k ];
		$html .= '</ul>';

It is also necessary to wrap the entire thing in <div> tags with an ID of ‘accordion’.

jQuery Javascript Code

jQuery(document).ready(function() {
					autoHeight: false,
					collapsible: true

Save this bit of code as a js file.

Including the Scripts

Download the jQuery accordion script from the website. This script and the one written in the previous section must both be included into the WordPress environment. wp_enqueue_script() should be used for this.

function enqueue_accordion_script() {
	wp_register_script( 'enqueue-accordion-script', get_stylesheet_directory_uri() . '/scripts/jquery-ui-1.8.13.custom.min.js',
						array( 'jquery' ) );
	wp_enqueue_script( 'enqueue-accordion-script' );

add_action( 'init', 'enqueue_accordion_script' );

function add_jquery_accordion() {
	wp_enqueue_script( 'add-jquery-accordion', get_stylesheet_directory_uri() . '/scripts/jquery-accordion-init.js', 
						array( 'jquery', 'enqueue-accordion-script' ) );
add_action( 'init', 'add_jquery_accordion' );

For a good tutorial on how to load scripts, see scribu’s site.


That’s all you need to get a working jQuery accordion! You can now target the elements with CSS to achieve the desired look.

Custom Sermon Upload Interface

The main content of the sermon custom post type is the link to the MP3 file. When the post is displayed on the main webpage, it also uses an audio player plugin to get a cool flash based player right in the post itself. This is done from the backend with a shortcode. Other than the actual link to the uploaded MP3 file, the content should be identical.

Of course, this is best done by getting rid of the default editor, which leaves plenty of room for user error. I replaced the whole thing with a couple of meta boxes. However, editor support for the post is still needed. The trick is to use CSS to hide the editor interface, not to remove support for it entirely. I’ve explained this in a previous post titled “Hiding the Editor“.

The main interface now consists of just 2 meta boxes, one for the scripture text and the other for file upload. How to create a file upload meta box was explained in my previous post on Newsletter Creation.

All the user has to do now is to fill in all the boxes correctly and check the correct taxonomy items. The save() function from the meta box class will handle all the file processing and automatically generate the correct post content to get the desired output.

Since the same code handles both the sermons and the newsletters for both the English and the Chinese sites, it has to differentiate them all by the filename. Sermons get the audio shortcode and link in the post content, while newsletters are added by attaching them to the post. The theme files will then handle the display of newsletters. Although they can both be done by putting the data in post content, I hadn’t figured out how to hide the editor when I did newsletters, so I had to remove editor support and work around it by using the theme to display the metadata properly. This would have been unlikely to work for the audio plugin which uses a shortcode.

There is now a simple interface for adding both sermons and newsletter post types!

Hiding the Editor

The usual post editor can be hidden after all! Without removing support for it when registering the post type.

Add the following code to the constructor for the meta box class described in previous posts on creating custom meta boxes.

//hide editor if adding a new post of sermon type
		if( isset( $_GET['post_type'] ) && 'sermon' == $_GET['post_type'] ) {
			add_action( 'admin_head', array( &$this, 'hide_editor' ) );

Add this as a function in the class.

	function hide_editor() {
				#editor-toolbar { display: none; }
				#editorcontainer {display: none; }
				#quicktags {display:none;}
				#post-status-info {display:none;}

The code for hiding the editor was taken from


This post is on internationalization, specifically for the Chinese subsite. Those who have been following along will know that I have a custom post type for newsletters, and that this is displaying a link to the PDF file to be downloaded by getting the URL from the _wp_attached_file meta value. For the English version, it displays some text before the link (“Download MM: “). Obviously, this text should be in Chinese for the Chinese subsite. Looks like internationalization is a good way to achieve this.

Declare Theme Text Domain

Put this on top of the functions.php file.

load_theme_textdomain('theme_name', STYLESHEETPATH . '/languages');

Mark String as Translatable

The next step is to mark the ‘Download MM’ string as something to be translated. This is done by putting it in a special function __()

__( 'Download MM', 'theme_name' )


This is a program which will get all the translatable strings out of the source code and create a .po file. It also provides an interface for supplying the translation and automatically generates the .mo file.

Rename Files

The final step is to copy the .po and .mo files to the theme’s languages folder (newly created). It is also necessary to rename them to and zh_CN.po so that the translated string would get picked up correctly.

Resources Used

The link on the WordPress Codex to the guides on the Urban Giraffe are excellent.

Incorrect Download link for Subsites


A custom content form for my custom newsletter post type wasn’t saving post content, thus my solution was to ignore the post content and generate it on the fly by getting the attached files instead. This worked beautifully in the main site, unfortunately, on the chinese subsite, wp_get_attachment_url returned something different.

Cause of Problem

It turns out that the _wp_attached_file meta value in the postmeta table is storing the full path to the link in the subsite. The corresponding value for posts in the main site only have the year/month/filename. They don’t contain the full domain name too. What this meant is that for the subsite, wp_get_attachment_url will add the domain to the front of the full link, thus generating an invalid link.


An email to the wp-hackers list had no responses, I’m not sure if it’s because nobody knows anything about it or whether the email got lost. Thus my solution is to filter the function output to strip out the extra baseurl which prepends the domain name. If this is necessary, the post meta is also updated so the next time this is needed, the correct output will be returned and there will no need to strip out the extra domain name again.

add_filter( 'wp_get_attachment_url', 'mbpc_wp_get_attachment_url_filter', 10, 2);

function mbpc_wp_get_attachment_url_filter($url, $postID) {
	$upload_dir = wp_upload_dir();

	//search through the url and see if it contains a 2nd instance of the baseurl
	$pos = strpos( $url, $upload_dir['baseurl'] , 1);

	if ( $pos !== false) {		//2nd instance exists
		$url = substr ($url, $pos);
		//update post meta so it won't have to find the substring on subsequent calls
		update_post_meta( $postID, '_wp_attached_file', substr( $url, strlen( $upload_dir['baseurl'] ) + 1 ));
	return $url;

Newsletters for Subsite

Previously, newsletters on the subsite were put up with default Posts because I hadn’t done the necessary work for the subsite as well. However, to allow for a uniform admin interface, it makes more sense for the chinese newsletters to go up as ‘newsletter’ custom post types as well. Using phpmyadmin and SQL, I changed all the Posts in the subsite to newsletters.

Content Manager Rights

The whole idea is to let a layperson upload the weekly newsletters. This function already exists for the main site. However, to make it work for the subsite, I had to setup the Members plugin and roles all over again. Since everything is stored in the wp_options table, I just had to copy and paste the wp_user_roles option to wp_x_user_roles on the subsite, and copy and paste the members_settings option wp_options to the corresponding options table for the subsite. This has the effect of activating and configuring the members plugin with all the role types I had previously setup on the main site correctly configured on the subsite.