Last active
November 10, 2019 16:40
-
-
Save tylerlwsmith/f09479f71698fb86cec90697ec45e157 to your computer and use it in GitHub Desktop.
Custom Post Rewrites for Josh
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 | |
/* | |
Plugin Name: Example Custom Post Types | |
Plugin URI: https://deadhandmedia.com/ | |
Description: Adds custom post types and taxonomies. | |
Version: 1.0.0 | |
Author: Tyler Smith | |
Author URI: https://deadhandmedia.com/ | |
License: GPL2 | |
License URI: https://www.gnu.org/licenses/gpl-2.0.html | |
Text Domain: example-text-domain | |
Domain Path: /languages | |
*/ | |
require_once ( dirname( __FILE__ ) . '/cpt-label-helper.php' ); | |
class CPT_Example { | |
private $text_domain = 'example-text-domain'; | |
public function __construct() { | |
add_action( 'init', [ $this, 'register_post_types' ] ); | |
add_action( 'init', [ $this, 'register_taxonomies' ] ); | |
add_action( 'init', [ $this, 'add_rewrite_rules' ] ); | |
add_filter( 'term_link', [ $this, 'update_term_link' ], 10, 3 ); | |
add_filter( 'post_type_link', [ $this, 'update_post_type_link' ], 10, 2 ); | |
add_filter( 'template_redirect', [ $this, 'redirect_on_wrong_url' ] ); | |
register_activation_hook( __FILE__, [ $this, 'activate' ] ); | |
register_deactivation_hook( __FILE__, 'flush_rewrite_rules' ); | |
} | |
/** | |
* Add custom post types and taxomonies then flush permalinks. | |
* | |
* @link https://developer.wordpress.org/reference/functions/flush_rewrite_rules/#comment-597 | |
*/ | |
public function activate() { | |
// Register rewrite rules before init hook so WordPress has access to | |
// the post type and taxonomy slugs. | |
$this->register_post_types(); | |
$this->register_taxonomies(); | |
// Flush the rewrite rules so these types are included. | |
flush_rewrite_rules(); | |
} | |
/** | |
* Register custom post types. | |
* | |
* @link https://codex.wordpress.org/Function_Reference/register_post_type | |
* @link https://developer.wordpress.org/resource/dashicons/ | |
*/ | |
public function register_post_types() { | |
// Register Careers | |
$args = [ | |
'labels' => CPT_Label_Helper::post_type('Career', 'Careers', $this->text_domain), | |
'public' => true, | |
'publicly_queryable' => true, | |
'show_ui' => true, | |
'show_in_menu' => true, | |
'query_var' => true, | |
'rewrite' => array( 'slug' => 'careers' ), | |
'capability_type' => 'post', | |
'has_archive' => false, | |
'hierarchical' => false, | |
'menu_position' => null, | |
'menu_icon' => 'dashicons-universal-access-alt', | |
'supports' => array( 'title', 'editor', 'thumbnail') | |
]; | |
register_post_type( 'career', $args ); | |
} | |
/** | |
* Register custom taxonomies. | |
* | |
* @link https://codex.wordpress.org/Function_Reference/register_taxonomy | |
*/ | |
public function register_taxonomies() { | |
// Career Type | |
$args = [ | |
'hierarchical' => true, | |
'labels' => CPT_Label_Helper::hierarchical_taxonomy('Career Type', 'Career Types', $this->text_domain), | |
'show_ui' => true, | |
'show_admin_column' => true, | |
'update_count_callback' => '_update_post_term_count', | |
'query_var' => true, | |
'rewrite' => [ | |
'slug' => 'career-type', | |
], | |
]; | |
register_taxonomy( 'career-type', array( 'career' ), $args ); | |
} | |
/** | |
* Adds rewrite rules for WordPress to match against and set the query | |
* variables. | |
* | |
* @link https://developer.wordpress.org/reference/functions/add_rewrite_rule/ | |
*/ | |
public function add_rewrite_rules() { | |
// For single career page. Example: | |
// https://jobs.com/careers/tech/wordpress-developer/ | |
add_rewrite_rule( | |
'careers/([^/]+)/([^/]*)?/?$', | |
'index.php?post_type=career&career-type=$matches[1]&name=$matches[2]', | |
'top' | |
); | |
// For career type taxonomy page. Example: | |
// https://jobs.com/careers/tech/ | |
add_rewrite_rule( | |
'careers/([^/]+)?/?$', | |
'index.php?post_type=career&career-type=$matches[1]', | |
'top' | |
); | |
} | |
/** | |
* Updates the post link. Even though we have the rewrite rules above, | |
* WordPress only uses that to create a query and delivery the posts | |
* matching that query. In order to make sure that system permalinks | |
* match the desired URL, we must explicitly set in in WordPress. | |
* | |
* There is some added complexity to ensure that WordPress still allows | |
* the user to edit the post slug, which is why there is specific logic | |
* for that below. I've included links for further reading on the reasoning | |
* behind this code. | |
* | |
* @link https://kellenmace.com/edit-slug-button-missing-in-wordpress/ | |
* @link https://wordpress.stackexchange.com/questions/275687/how-to-retain-the-ability-to-modify-the-post-slug-after-applying-a-post-type-lin | |
* @link https://codex.wordpress.org/Plugin_API/Filter_Reference/post_type_link | |
*/ | |
public function update_post_type_link( $url, $post ) { | |
if ( false !== strpos( $url, "%career%" ) ) { | |
$slug = '%career%'; | |
} elseif ( $post->post_name ) { | |
$slug = $post->post_name; | |
} else { | |
$slug = sanitize_title( $post->post_title ); | |
} | |
$term = get_the_terms( $post->ID, 'career-type' ); | |
// Set fallback if no category is selected. | |
$term_slug = $term[0]->slug ?? 'other'; | |
return user_trailingslashit( home_url( "careers/{$term_slug}/{$slug}" ) ); | |
} | |
/** | |
* Updates the taxonomy link. Like posts, even though we have new rewrite | |
* rules added, WordPress must be explicitly told what we want the the | |
* term permalink to be. | |
* | |
* @link https://codex.wordpress.org/Plugin_API/Filter_Reference/post_type_link | |
*/ | |
public function update_term_link( $url, $term, $taxonomy ) { | |
return user_trailingslashit( home_url( "careers/{$term->slug}" ) ); | |
} | |
/** | |
* In the update_post_type_link() method, we tell WordPress what the post | |
* link should be. However, the WordPress query is only matching by a | |
* regex pattern. This means that any characters in the preappended | |
* taxonomy could match and pull up the page, because the query is | |
* matching by the slug. This could create endless duplicate pages | |
* with similar URLs, which has bad implications for SEO. | |
* | |
* To mitigate this, we will check if the currently url matches what we | |
* expect, and if it does not we'll redirect the user to the correct URL. | |
* | |
* @link https://codex.wordpress.org/Plugin_API/Action_Reference/template_redirect | |
*/ | |
public function redirect_on_wrong_url() { | |
if ( 'career' != get_post_type() ) return; | |
if ( is_archive() ) return; | |
global $wp; | |
$permalink = user_trailingslashit( get_the_permalink() ); | |
$current_page = user_trailingslashit( home_url( $wp->request ) ); | |
if( $current_page != $permalink ){ | |
wp_redirect( $permalink ); | |
die(); | |
} | |
} | |
} | |
new CPT_Example; |
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 CPT_Label_Helper { | |
public static function post_type ($singular, $plural, $textdomain = '') { | |
$labels = array( | |
'name' => __( $plural, $textdomain ), | |
'singular_name' => __( $singular, $textdomain ), | |
'menu_name' => __( $plural, $textdomain ), | |
'name_admin_bar' => __( $singular, $textdomain ), | |
'add_new' => __( 'Add New', $textdomain ), | |
'add_new_item' => __( 'Add New ' . $singular, $textdomain ), | |
'new_item' => __( 'New ' . $singular, $textdomain ), | |
'edit_item' => __( 'Edit ' . $singular, $textdomain ), | |
'view_item' => __( 'View ' . $singular, $textdomain ), | |
'all_items' => __( 'All ' . $plural, $textdomain ), | |
'search_items' => __( 'Search ' . $plural, $textdomain ), | |
'parent_item_colon' => __( 'Parent ' . $plural . ':', $textdomain ), | |
'not_found' => __( 'No ' . strtolower($plural) . ' found.', $textdomain ), | |
'not_found_in_trash' => __( 'No ' . strtolower($plural) . ' found in Trash.', $textdomain ) | |
); | |
return $labels; | |
} | |
public static function hierarchical_taxonomy($singular, $plural, $textdomain = '') { | |
$labels = array( | |
'name' => __( $plural, $textdomain ), | |
'singular_name' => __( $singular, $textdomain ), | |
'search_items' => __( 'Search ' . $plural, $textdomain ), | |
'popular_items' => __( 'Popular ' . $plural, $textdomain ), | |
'all_items' => __( 'All ' . $plural, $textdomain ), | |
'parent_item' => null, | |
'parent_item_colon' => null, | |
'edit_item' => __( 'Edit ' . $singular, $textdomain ), | |
'update_item' => __( 'Update ' . $singular, $textdomain ), | |
'add_new_item' => __( 'Add New ' . $singular, $textdomain ), | |
'new_item_name' => __( 'New ' . $singular . ' Name', $textdomain ), | |
'menu_name' => __( $plural, $textdomain ), | |
); | |
return $labels; | |
} | |
public static function non_hierarchical_taxonomy($singular, $plural, $textdomain = '') { | |
$labels = array( | |
'name' => __( $plural, $textdomain ), | |
'singular_name' => __( $singular, $textdomain ), | |
'search_items' => __( 'Search ' . $plural, $textdomain ), | |
'popular_items' => __( 'Popular ' . $plural, $textdomain ), | |
'all_items' => __( 'All ' . $plural, $textdomain ), | |
'parent_item' => null, | |
'parent_item_colon' => null, | |
'edit_item' => __( 'Edit ' . $singular, $textdomain ), | |
'update_item' => __( 'Update ' . $singular, $textdomain ), | |
'add_new_item' => __( 'Add New ' . $singular, $textdomain ), | |
'new_item_name' => __( 'New ' . $singular . ' Name', $textdomain ), | |
'separate_items_with_commas' => __( 'Separate ' . strtolower($plural) . ' with commas', $textdomain ), | |
'add_or_remove_items' => __( 'Add or remove ' . strtolower($plural), $textdomain ), | |
'choose_from_most_used' => __( 'Choose from the most used ' . strtolower($plural), $textdomain ), | |
'not_found' => __( 'No ' . strtolower($plural) .' found.', $textdomain ), | |
'menu_name' => __( $plural, $textdomain ), | |
); | |
return $labels; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment