4

I recently asked this question Custom post types - Use post_id in permalink structure and solved it but as I have enabled 'has_archive' => true the solution given no longer works. Let me explain:

I'm after this structure:

  • archive-events.php => /news/events/
  • single-events.php => /news/events/%post_id%/%postname%

To get post_id in a single event permalink I've had to add %post_id% to the CPT slug but when enabling has_archive => true the archive page becomes the slug; in this case becoming /news/events/%post_id%/ which is invalid.

So my question:

How do I have post_id in permalink structure when using has_archive => true

5

To get what you need you have to add a custom rewrite rule and to filter the permalink construction. The following code does both:

<?php # -*- coding: utf-8 -*-
/**
 * Plugin Name: Event Permalinks
 */
// Not a WordPress context? Stop.
! defined( 'ABSPATH' ) and exit;

// Wait until all needed functions are loaded.
add_action( 'init', array ( 'Bradys_Events', 'init' ) );

class Bradys_Events
{
    /**
     * Creates a new instance.
     * 
     * @wp-hook init
     * @see    __construct()
     * @return void
     */
    public static function init()
    {
        new self;
    }

    /**
     * Constructor
     */
    public function __construct()
    {
        $args = array(
            'label' => 'events',
            'public' => true,
            'hierarchical' => false,
            'has_archive' => true,
            'rewrite' => array(
                'with_front' => false,
                'slug' => "news/events"
            ),
            'supports' => array( 'title', 'editor', 'thumbnail' )
        );
        register_post_type("events", $args);

        // Prevent WordPress from sending a 404 for our new perma structure.
        add_rewrite_rule(
        '^news/events/(\d+)/[^/]+/?$',
        'index.php?post_type=events&p=$matches[1]',
        'top'
        );

        // Inject our custom structure.
        add_filter( 'post_type_link', array ( $this, 'fix_permalink' ), 1, 2 );
    }

    /**
     * Filter permalink construction.
     * 
     * @wp-hook post_type_link
     * @param  string $post_link default link.
     * @param  int    $id Post ID
     * @return string
     */
    public function fix_permalink( $post_link, $id = 0 )
    {
        $post = &get_post($id);
        if ( is_wp_error($post) || $post->post_type != 'events' )
        {
            return $post_link;
        }
        // preview
        empty ( $post->slug )
            and $post->slug = sanitize_title_with_dashes( $post->post_title );

        return home_url(
            user_trailingslashit( "news/events/$post->ID/$post->slug" )
        );
    }
}

Visit wp-admin/options-permalink.php one time to let WordPress update its rewrite rules.

  • I knew you could figure it out ;) Thank you very much – Brady Mar 6 '12 at 14:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.