WordPress: Adding “Page Links To” to Custom Post Types

If you use WordPress (especially as a content management system) and you haven’t heard of Mark Jaquith’s “Page Links To” plugin, you should definitely check it out. Basically, the plugin allows you to set up a WordPress page or post to redirect to a different URL. It can be very handy for setting up redirects, adding menu items for pages that wouldn’t normally appear in those menus, etc.

One issue with the plugin, however, is that it does not (as of version 2.4.1) support custom post types. It only supports WordPress posts and pages. If you want to set a custom post type to redirect to a URL other than its permalink, you can’t do so with this plugin.

However, there is a pretty simple way to add support for custom post types to this plugin; and the changes do not require you to edit the plugin itself. Instead, you can make all of the necessary changes in your theme’s functions.php file.

To begin with, you will need to write your own copy of the plugin’s add_meta_box() function and hook it into the do_meta_boxes action. The current version of Page Links To includes the following do_meta_boxes() function:

	/**
	 * Adds the meta box to the post or page edit screen
	 * @param string $page the name of the current page
	 * @param string $context the current context
	 */
	function do_meta_boxes( $page, $context ) {
		if ( ( 'page' === $page || 'post' === $page ) && 'advanced' === $context )
			add_meta_box( 'page-links-to', 'Page Links To', array( &$this, 'meta_box' ), $page, 'advanced', 'low' );
	}

You need to make your own copy of that function, giving it a unique function name (for instance, something like my_theme_add_plt_mb) and add your custom post types in place of “page” and “post” in the new function. That would look something like:

/**
 * Adds the meta box to the post or page edit screen
 * @param string $page the name of the current page
 * @param string $context the current context
 */ 
function my_theme_add_plt_mb( $page, $context ) { 
	if ( ( 'custom_post_type_1' === $page || 'custom_post_type_2' === $page || 'custom_post_type_3' === $page ) && 'advanced' === $context ) 
		add_meta_box( 'page-links-to', 'Page Links To', array( 'CWS_PageLinksTo', 'meta_box' ), $page, 'advanced', 'low' ); 
}
if( class_exists( 'CWS_PageLinksTo' ) )
	add_action( 'do_meta_boxes', 'mspan_add_plt_meta_box', 10, 2 );

Next, you will need to tell WordPress to replace the standard permalink for the custom post type with the link specified by Page Links To. To do that, you need to hook into the post_type_link filter. Because Page Links To doesn’t actually instantiate a variable when creating a new CWS_PageLinksTo object, you’ll need to do so before filtering the permalink (otherwise, you’ll get a PHP reference error, because the link method in the CWS_PageLinksTo class calls another method in the same class). Therefore, you should add something like the following to your functions.php file:

if( class_exists( 'CWS_PageLinksTo' ) )
	add_filter( 'post_type_link', 'my_theme_init_plt_obj', 20, 2 ); 
function my_theme_init_plt_obj( $link, $post ) { 
	$tmp = new CWS_PageLinksTo; 
	return $tmp->link( $link, $post ); 
}

The code above hooks the my_theme_init_plt_obj() function into the post_type_link filter. Then, the my_theme_init_plt_obj() function declares a variable and assigns a new CWS_PageLinksTo object to that variable; and finally calls and returns the CWS_PageLinksTo::link() function.

Because the CWS_PageLinksTo::__construct() function adds a handful of hooks, etc.; you should not instantiate the variable any earlier than you need to use it (otherwise, you might end up with 2 Page Links To meta boxes on your post edit screen, or the links might get filtered twice, etc.).