Skip to content

Instantly share code, notes, and snippets.

@mikeschinkel
Created November 5, 2011 23:16
  • Star 8 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save mikeschinkel/1342165 to your computer and use it in GitHub Desktop.
Plugin demonstrates how to route parent post/child post URLs WordPress 3.3
<?php
/**
* Plugin Name: MMC Parks and Features
* Description: This plugin demonstrates how to route parent/child URLs like http://example.com/parks/yosemite/half-dome/in WordPress 3.3
* Author: Mike Schinkel
* Author URL: http://about.me/mikeschinkel
* Notes:
* To answer http://lists.automattic.com/pipermail/wp-hackers/2011-November/041486.html
* Assumes a metabox that sets $post->post_parent field for a park feature with it's park's $post->ID.
*
*/
class MMC_Parks_and_Features {
static $PARK_FEATURE_URL_REGEX = 'parks/([^/]*)/([^/]*)/?';
static function on_load() {
add_action( 'init', array( __CLASS__, 'init' ) );
add_filter( 'request', array( __CLASS__, 'request' ) );
add_filter( 'post_type_link', array( __CLASS__, 'post_type_link' ), 10, 4 );
register_activation_hook( __FILE__, array( __CLASS__, 'activate_activate' ) );
}
static function activate_activate() {
add_rewrite_rule(
self::$PARK_FEATURE_URL_REGEX,
'index.php?post_type=mmc_park_feature&mmc_park_qv=$matches[1]&mmc_park_feature_qv=$matches[2]',
'top'
);
flush_rewrite_rules();
}
/**
* Changes the permalink type for any post whose post_type is 'mmc_park_feature'
*
* @param string $link
* @param object $post
* @param bool $leavename
* @param string $sample
* @return string
*/
static function post_type_link( $link, $post, $leavename, $sample ) {
if ( 'mmc_park_feature' == $post->post_type ) {
$parent = get_post( $post->post_parent );
$parent_slug = isset( $parent->post_name ) ? $parent->post_name : '%park%';
$page_slug = $sample ? '%postname%' : $post->post_name;
$link = preg_replace( '#^(https?://[^/]+/).*$#', "$1parks/{$parent_slug}/{$page_slug}/", $link );
}
return $link;
}
/**
* Test to make sure the URL is valid per the specified park and park feature referenced in the URL.
*
* @param $query_vars
* @return array
*/
static function request( $query_vars ) {
global $wp;
/**
* Trigger this test if the match URL rewrite rule is the one added by this plugin
*/
if ( $wp->matched_rule == self::$PARK_FEATURE_URL_REGEX ) {
/**
* Lookup the park's post
*/
$park = get_page_by_path( $query_vars['mmc_park_qv'], OBJECT, 'mmc_park' );
/**
* Lookup the park feature's post, scoped to the park
*/
$park_feature_query = new WP_Query( array(
'name' => $query_vars['mmc_park_feature_qv'],
'post_type' => 'mmc_park_feature',
'fields' => 'ids',
'post_parent' => $park->ID,
'posts_per_page' => 1,
'suppress_filters' => true,
));
/**
* If the park feature was not found for the park, trigger 404 error.
*/
if ( 0 == count( $park_feature_query->posts ) ) {
$query_vars = array( 'error' => '404' );
}
}
return $query_vars;
}
/**
* Register both mmc_park and mmc_park_feature post types.
*
* Note: I mostly copied this code from the question, I would typically use a helper function for labels.
*
* @return void
*/
static function init() {
/**
* Add the rewrite rule to be checked before other rewrite rules (i.e. 'top')
*/
register_post_type( 'mmc_park', array(
'labels' => array(
'name' => _x( 'Parks', 'mmc_pack' ),
'singular_name' => _x( 'Park', 'mmc_pack' ),
'add_new' => _x( 'Add New', 'mmc_pack' ),
'add_new_item' => _x( 'Add New Park', 'mmc_pack' ),
'all_items' => _x( 'Parks', 'mmc_pack' ),
'edit_item' => _x( 'Edit Park', 'mmc_pack' ),
'new_item' => _x( 'New Park', 'mmc_pack' ),
'view_item' => _x( 'View Park', 'mmc_pack' ),
'search_items' => _x( 'Search Parks', 'mmc_pack' ),
'not_found' => _x( 'No Parks found', 'mmc_pack' ),
'not_found_in_trash' => _x( 'No Parks found in Trash', 'mmc_pack' ),
'parent_item_colon' => _x( 'Parent Park', 'mmc_pack' ),
'menu_name' => _x( 'Parks', 'mmc_pack' ),
),
'hierarchical' => true,
'description' => '',
'supports' => array( 'title', 'editor', 'author', 'revisions',
'custom-fields', 'comments', 'thumbnail' ),
'public' => true,
'show_ui' => true,
// 'show_in_menu' => 'mmc_menu',
'show_in_nav_menus' => true,
'publicly_queryable' => true,
'exclude_from_search' => false,
'has_archive' => true,
'query_var' => 'mmc_park_qv',
'can_export' => true,
'rewrite' => array( 'slug' => 'parks', 'with_front' => false ),
'capability_type' => 'page'
));
register_post_type( 'mmc_park_feature', array(
'labels' => array(
'name' => _x( 'Features', 'mmc_park_feature' ),
'singular_name' => _x( 'Feature', 'mmc_park_feature' ),
'add_new' => _x( 'Add New', 'mmc_park_feature' ),
'add_new_item' => _x( 'Add New Feature', 'mmc_park_feature' ),
'all_items' => _x( 'Features', 'mmc_park_feature' ),
'edit_item' => _x( 'Edit Feature', 'mmc_park_feature' ),
'new_item' => _x( 'New Feature', 'mmc_park_feature' ),
'view_item' => _x( 'View Feature', 'mmc_park_feature' ),
'search_items' => _x( 'Search Features', 'mmc_park_feature' ),
'not_found' => _x( 'No Features found', 'mmc_park_feature' ),
'not_found_in_trash' => _x( 'No Features found in Trash', 'mmc_park_feature' ),
'parent_item_colon' => _x( 'Parent Feature', 'mmc_park_feature' ),
'menu_name' => _x( 'Features', 'mmc_park_feature' ),
),
'hierarchical' => true,
'supports' => array( 'title', 'permalink', 'editor', 'author', 'revisions', 'custom-fields', 'comments', 'thumbnail' ),
'public' => true,
'show_ui' => true,
// 'show_in_menu' => 'mmc_menu',
'show_in_nav_menus' => true,
'publicly_queryable' => true,
'exclude_from_search' => false,
'has_archive' => true,
'query_var' => 'mmc_park_feature_qv',
'can_export' => true,
'rewrite' => array( 'slug' => 'features', 'with_front' => false ),
'capability_type' => 'page'
));
}
}
MMC_Parks_and_Features::on_load();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment