Skip to content

Instantly share code, notes, and snippets.

@kjbenk
Last active February 16, 2018 14:36
Show Gist options
  • Save kjbenk/89d05d337c9d523c9e9070d56a3c3e18 to your computer and use it in GitHub Desktop.
Save kjbenk/89d05d337c9d523c9e9070d56a3c3e18 to your computer and use it in GitHub Desktop.
WordPress: Post Permalink using primary category
<?php
/**
* Alters the default post permalink structure to be:
*
* `/{primary-category}/{post-slug}/`
*/
/**
* The Primary_Category_Post_URL class.
*/
class Primary_Category_Post_URL {
/**
* The permalink structure.
*
* @var string
*/
public $permalink_structure = '/%primary_category%/%postname%/';
/**
* Existing instance.
*
* @var array
*/
protected static $instance;
/**
* Get class instance.
*
* @return object
*/
public static function instance() {
if ( ! isset( static::$instance ) ) {
static::$instance = new static();
static::$instance->setup();
}
return static::$instance;
}
/**
* Setup the singleton.
*/
public function setup() {
// Set the main permalink structures.
if ( function_exists( 'wpcom_vip_load_permastruct' ) ) {
wpcom_vip_load_permastruct( $this->permalink_structure );
} else {
add_filter( 'init', function() {
global $wp_rewrite;
$wp_rewrite->set_permalink_structure( $this->permalink_structure );
} );
}
// Add rewrite tags.
add_action( 'init', [ $this, 'add_rewrite_tags' ] );
// Update post permalinks.
add_filter( 'post_link', [ $this, 'custom_permalink' ], 10, 2 );
add_filter( 'post_type_link', [ $this, 'custom_permalink' ], 10, 2 );
// Filter the post rewrite rules to account for our custom permalink.
add_filter( 'post_rewrite_rules', [ $this, 'generate_post_rewrite_rules' ] );
// Add the primary category field.
add_action( 'fm_post_post', [ $this, 'add_fields' ] );
}
/**
* Add the custom rewrite tags.
*/
public function add_rewrite_tags() {
add_rewrite_tag( '%primary_category%', '([^/]+)' );
}
/**
* Replace the wildcard url structure with the correct content
*
* @param string $url The current URL.
* @param \WP_Post $post The post object.
* @return string $url The new URL.
*/
public function custom_permalink( $url, $post ) {
/**
* Filter the array of applicable post types.
*
* @param array $post_types The array of applicable post types.
* @return array $post_types The array of applicable post types.
*/
$applicable_post_types = apply_filters(
'custom_permalink_applicable_post_types',
[ 'post' ]
);
if ( $post instanceof \WP_Post && in_array( $post->post_type, $applicable_post_types, true ) ) {
$primary_category_id = get_post_meta( $post->ID, 'primary_category', true );
if ( ! empty( $primary_category_id ) ) {
$primary_category = get_term( $primary_category_id );
if ( ! empty( $primary_category->slug ) ) {
$url = str_replace( '%primary_category%', $primary_category->slug, $url );
}
}
}
return $url;
}
/**
* Since we are using a custom permalink structure for this site we wanted to
* make sure that its value was correct at all times, which is why we use
* `wpcom_vip_load_permastruct( '/%primary_category%/%postname%/' )` in the
* `setup()` function. This will then create new rewrite rules where walk_dirs
* is true which is something that we do not want to do.
*
* This function will add the correct post rewrite rules with walk_dirs false,
* and filter only runs when the rewrite rules are created or on `flush_rewrite_rules()`.
*
* @param \WP_Rewrite $post_rewrite Current WP_Rewrite instance, passed by reference.
*/
public function generate_post_rewrite_rules( $post_rewrite ) {
global $wp_rewrite;
return $wp_rewrite->generate_rewrite_rules( $this->permalink_structure, EP_PERMALINK, true, true, false, false );
}
/**
* Add the Primary Category FM field.
*/
public function add_fields() {
$fm = new \Fieldmanager_Select( [
'attributes' => array(
'style' => 'width: 95%',
),
'remove_default_meta_boxes' => false,
'name' => 'primary_category',
'limit' => 1,
'first_empty' => true,
'description' => __( '(Required) Used as the first level of the post URL.' ),
'validation_rules' => 'required',
'validation_messages' => __( 'Please select a Primary Category' ),
'datasource' => new \Fieldmanager_Datasource_Term( [
'taxonomy' => 'category',
'only_save_to_taxonomy' => false,
'append_taxonomy' => true,
] ),
] );
$fm->add_meta_box( __( 'Primary Category' ), [ 'post' ], 'side' );
}
}
/**
* Get the singleton instance.
*
* @return Primary_Category_Post_URL
*/
function primary_category_post_url() {
return Primary_Category_Post_URL::instance();
}
add_action( 'after_setup_theme', 'primary_category_post_url' );
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment