Last active
December 22, 2016 15:01
-
-
Save khromov/8485b713876469088329 to your computer and use it in GitHub Desktop.
WordPress - Remove the front permastruct / base slug from a custom post type (CPT)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
class Plugin | |
{ | |
/** | |
* This will let a CPT with the slug 'story' be used without a base slug, ie: | |
* Before: | |
* /story/hello | |
* | |
* After: | |
* /hello | |
*/ | |
function __construct() | |
{ | |
} | |
function initialize() | |
{ | |
//Handle CPT rewrites for Story to remove base | |
add_filter('post_type_link', array( | |
&$this, | |
'story_preview_url_remove_base' | |
), 10, 3); | |
add_action('pre_get_posts', array( | |
&$this, | |
'story_modify_query_remove_base' | |
)); | |
add_filter('wp_unique_post_slug', array( | |
&$this, | |
'story_fix_slug' | |
), 100, 6); | |
//Add the Story post type to the front page static page dropdown under Settings > Reading | |
add_filter('get_pages', array( | |
&$this, | |
'story_add_to_frontpage_dropdown' | |
), 10, 2); | |
//Let story be used as the front page on the routing level | |
add_action('pre_get_posts', array( | |
&$this, | |
'story_enable_frontpage' | |
), 11); | |
} | |
/** | |
* Let's the Story CPT be used as the front page properly. | |
* | |
* @param $query | |
*/ | |
function story_enable_frontpage($query) | |
{ | |
// Only touch the main query | |
if (!$query->is_main_query()) | |
return; | |
//Look for empty post_type, meaning start page (?) TODO: Really? | |
//http://wordpress.stackexchange.com/questions/18013/how-do-you-use-a-cpt-as-the-default-home-page | |
if (empty($query->query_vars['post_type']) && 0 != $query->query_vars['page_id']) { | |
$query->set('post_type', array( | |
'story', | |
'page' | |
)); | |
} | |
} | |
/** | |
* Add the Story post type to the front page static page dropdown under Settings > Reading | |
* | |
* http://wordpress.stackexchange.com/questions/18013/how-do-you-use-a-cpt-as-the-default-home-page | |
* | |
* @param $pages | |
* @param $r | |
* | |
* @return array | |
*/ | |
function story_add_to_frontpage_dropdown($pages, $r) | |
{ | |
if ((isset($r['name']) && ('page_on_front' === $r['name']))) { | |
$args = array( | |
'post_type' => 'story' | |
); | |
$stacks = get_posts($args); | |
$pages = array_merge($pages, $stacks); | |
} | |
return $pages; | |
} | |
/** | |
* Fix the Story CPT slug so it does not conflict with pages or posts. | |
* | |
* @param $slug | |
* @param $post_ID | |
* @param $post_status | |
* @param $post_type | |
* @param $post_parent | |
* @param $original_slug | |
* | |
* @return mixed | |
*/ | |
function story_fix_slug($slug, $post_ID, $post_status, $post_type, $post_parent, $original_slug) | |
{ | |
global $wpdb; | |
//These post types will never clash | |
$post_types_no_conflict = array( | |
'story', | |
'post', | |
'page', | |
'attachment' | |
); | |
$post_types_sql = function() use ($post_types_no_conflict) | |
{ | |
$ret = ''; | |
foreach ($post_types_no_conflict as $post_type) | |
$ret .= "'{$post_type}', "; | |
return substr($ret, 0, -2); | |
}; | |
//If we are creating the unique slug for an affected post type | |
if (in_array($post_type, $post_types_no_conflict)) { | |
$unique = false; | |
//While we haven't found a unique link | |
while ($unique !== true) { | |
$post_name_check = $wpdb->get_var($wpdb->prepare("SELECT post_name FROM $wpdb->posts WHERE post_name = %s AND post_type IN (" . $post_types_sql() . ") AND ID != %d LIMIT 1", $slug, $post_ID)); | |
//Not unique? Append some numbers and let's try again! | |
if ($post_name_check) { | |
$slug = "{$slug}-2"; | |
} else { | |
//If unique, we're done | |
$unique = true; | |
} | |
} | |
return $slug; | |
} else | |
return $slug; | |
} | |
/** | |
* Remove the slug from published post permalinks. Only affect our CPT though. | |
* | |
* http://kellenmace.com/remove-custom-post-type-slug-from-permalinks/ | |
*/ | |
function story_preview_url_remove_base($post_link, $post) | |
{ | |
if ('story' != $post->post_type || 'publish' != $post->post_status) { | |
return $post_link; | |
} | |
$post_link = str_replace('/' . $post->post_type . '/', '/', $post_link); | |
return $post_link; | |
} | |
/** | |
* Have WordPress match postname to any of our public post types (page, post, race) | |
* All of our public post types can have /post-name/ as the slug, so they better be unique across all posts | |
* By default, core only accounts for posts and pages where the slug is /post-name/ | |
* | |
* TODO: Make sure this is 100% safe, especially the "2 != count( $query->query )" | |
* | |
* @param $query | |
*/ | |
function story_modify_query_remove_base($query) | |
{ | |
// Only touch the main query | |
if (!$query->is_main_query()) | |
return; | |
// Only noop our very specific rewrite rule match | |
if (2 != count($query->query) || !isset($query->query['page'])) { | |
return; | |
} | |
// 'name' will be set if post permalinks are just post_name, otherwise the page rule will match | |
if (!empty($query->query['name'])) { | |
$query->set('post_type', array( | |
'story', | |
'page', | |
'post' | |
)); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment