Take the 2-minute tour ×
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

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

share|improve this question
add comment

1 Answer

up vote 4 down vote accepted

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 -*-
declare ( encoding = '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.

share|improve this answer
    
I knew you could figure it out ;) Thank you very much –  Brady Mar 6 '12 at 14:06
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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