Take a look at my answer to the following question. You can modify my parse_request()
to get what you need:
And you can read the following to see why what you want can cause issues in WordPress and requires a complex solution:
UPDATE
Based on the comment I decided to go ahead and implement this as the next revision of the plugin. It’s really only tested for the use-case for this question and the one from the prior referenced question. Over time I plan to implement it for all potential use-cases, as questions or clients occur to drive the demand.
Here is the code you’d place in your theme’s functions.php file to set it up for the post_type 'custom'
:
add_action('init','init_url_routes');
function init_url_routes() {
$post_type="custom"; // Change this to your actual post_type name
register_url_route(array('post_type'=>$post_type));
}
And here is the plugin which you can place in /wp-content/mu-plugins/
:
<?php
/*
Filename: wp-extended.php
Plugin Name: WP Extended for Taxonomy URL Routes
Author: Mike Schinkel
Version: 0.2
*/
function register_url_route($args=array()) {
WP_Extended::register_url_route($args);
}
class WP_Extended extends WP {
static $root = array();
static function on_load() {
add_action('setup_theme',array(__CLASS__,'setup_theme'));
}
static function register_url_route($args) {
if (isset($args['taxonomy']))
self::$root['taxonomy'][$args['taxonomy']] = get_taxonomy($args['taxonomy']);
if (isset($args['post_type']))
self::$root['posts'][$args['post_type']] = get_post_type_object($args['post_type']);
}
static function setup_theme() { // Setup theme is 1st code run after WP is created.
global $wp;
$wp = new WP_Extended(); // Replace the global $wp
}
function parse_request($extra_query_vars="") {
$path = $_SERVER['REQUEST_URI'];
$domain = str_replace('.','\.',$_SERVER['SERVER_NAME']);
$root_path = preg_replace("#^https?://{$domain}(/.*)$#",'$1',WP_SITEURL);
if (substr($path,0,strlen($root_path))==$root_path)
$path = substr($path,strlen($root_path));
list($path) = explode('?',$path);
$path_segments = explode("https://wordpress.stackexchange.com/",trim($path,"https://wordpress.stackexchange.com/"));
// This does not handle ordering priority of type to match yet
$matched = $this->parse_post_type_request($path_segments);
if (!$matched)
$matched = $this->parse_taxonomy_request($path_segments);
if ($matched) {
// This is hamfisted but necessary in some cases.
// TODO: Look into ways to have more finesse with this.
remove_action('template_redirect','redirect_canonical');
} else {
parent::parse_request($extra_query_vars); // Delegate to WP class
}
}
function parse_post_type_request($path_segments) {
// This does not handle heirarchical pages yet
$post_id = false;
global $wpdb;
$sql =<<<SQL
SELECT
ID
FROM
{$wpdb->posts}
WHERE 1=1
AND post_status="publish"
AND post_type="%s"
AND post_name="%s"
SQL;
if (is_array(self::$root['posts'])) {
foreach(self::$root['posts'] as $post_type => $post_type_object) {
$sql = $wpdb->prepare($sql,$post_type,$path_segments[0]);
$post_id = $wpdb->get_var($sql);
if ($post_id) {
$this->query_vars[($post_type=='page' ? 'page_id' : 'p')] = $post_id;
unset($path_segments[0]); // Remove from future consideration
break;
}
}
}
return ($post_id);
}
function parse_taxonomy_request($path_segments) {
$taxonomy_term = array();
$parent_id = 0;
if (is_array(self::$root['taxonomy'])) {
foreach(self::$root['taxonomy'] as $taxonomy_slug => $taxonomy) {
$terms = get_terms($taxonomy_slug);
foreach($path_segments as $segment_index => $path_segment) {
foreach($terms as $term_index => $term) {
if ($term->slug==$path_segment) {
if ($term->parent!=$parent_id) { // Make sure we test parents
$taxonomy_term = array();
} else {
$parent_id = $term->term_id; // Capture parent ID for verification
$taxonomy_term[] = $term->slug; // Collect slug as path segment
unset($terms[$term_index]); // No need to scan it again
}
unset($path_segments[$segment_index]); // Remove from future consideration
break;
}
}
}
if (count($taxonomy_term))
break;
}
if (count($taxonomy_term)) {
$path = implode("https://wordpress.stackexchange.com/",$taxonomy_term);
switch ($taxonomy_slug) {
case 'category':
$this->query_vars['category_name'] = $path;
break;
case 'post_tag':
$this->query_vars['tag'] = $path;
break;
default:
$this->query_vars['taxonomy'] = $taxonomy_slug;
$this->query_vars['term'] = $path;
break;
}
}
}
return count($taxonomy_term);
}
}
WP_Extended::on_load();