add_rewrite_endpoint() not working for custom post type archives

i’m working on somekind of wiki/encyclopedia system based on wordpress.

there are two custom post types. i’ll show my configuration for one of them:

$labels = array(
    'name' => _x('Objects', 'post type general name'),
    'singular_name' => _x('Object', 'post type singular name'),
    'add_new' => _x('Add New', 'object'),
    'add_new_item' => __('Add New Object'),
    'edit_item' => __('Edit Object'),
    'new_item' => __('New Object'),
    'view_item' => __('View Object'),
    'search_items' => __('Search Objects'),
    'not_found' =>  __('Nothing found'),
    'not_found_in_trash' => __('Nothing found in Trash'),
    'parent_item_colon' => ''
);

$args = array(
    'labels' => $labels,
    'public' => true,
    'publicly_queryable' => true,
    'show_ui' => true,
    'query_var' => true,
    'has_archive' => 'objects', // this is the archive-slug (could be "objects/index"!!)
    'rewrite' => array( 'slug' => 'objects' ), // this is the prepended slug (like "objects/my-object")
    'capability_type' => 'post',
    'hierarchical' => false,
    'menu_position' => null,
    'supports' => array('title','thumbnail')
  ); 

register_post_type( 'dr_object' , $args );

everything is working as expected: mysite.de/objects gives me an overview (archive-dr_object.php template), mysite.de/objects/my-object shows the object details.

to have some nice urls for the frontend editing functions, i added rewrite endpoints.

add_rewrite_endpoint('do', EP_PERMALINK | EP_PAGES ); // for do/edit, do/remove, etc

this works great for urls like mysite.de/objects/my-object/do/edit

here comes my problem:

the archives should have some editing capabilities, too. but mysite.de/objects/do/edit gives me a 404: “Page not found”.

i print_r’ed $wp_query and it looks like wp queries an attachment named “edit”

hope somebody can help me – by now i’ll stick with ugly ?do=edit urls for the archives.

thanks in advance,
hans

//update 09/03/2012

stripped code of my-plugin.php

add_action('init', 'object_register');

function object_register() {

$labels = array(
    'name' => _x('Objects', 'post type general name'),
    'singular_name' => _x('Object', 'post type singular name'),
    'add_new' => _x('Add New', 'object'),
    'add_new_item' => __('Add New Object'),
    'edit_item' => __('Edit Object'),
    'new_item' => __('New Object'),
    'view_item' => __('View Object'),
    'search_items' => __('Search Objects'),
    'not_found' =>  __('Nothing found'),
    'not_found_in_trash' => __('Nothing found in Trash'),
    'parent_item_colon' => ''
);

$args = array(
    'labels' => $labels,
    'public' => true,
    'publicly_queryable' => true,
    'show_ui' => true,
    'query_var' => true,
    'has_archive' => 'objects', // this is the archive-slug (could be "objects/index"!!)
    'rewrite' => array( 'slug' => 'objects' ), // this is the prepended slug (like "objects/my-object")
    'capability_type' => 'post',
    'hierarchical' => false,
    'menu_position' => null,
    'supports' => array('title','thumbnail')
  ); 

register_post_type( 'dr_object' , $args );
}

add_action('init', 'cluster_register');

function cluster_register() {

$labels = array(
    'name' => _x('Cluster', 'post type general name'),
    'singular_name' => _x('Cluster', 'post type singular name'),
    'add_new' => _x('Add New', 'cluster'),
    'add_new_item' => __('Add New Cluster'),
    'edit_item' => __('Edit Cluster'),
    'new_item' => __('New Cluster'),
    'view_item' => __('View Cluster'),
    'search_items' => __('Search Cluster'),
    'not_found' =>  __('Nothing found'),
    'not_found_in_trash' => __('Nothing found in Trash'),
    'parent_item_colon' => ''
);

$args = array(
    'labels' => $labels,
    'public' => true,
    'publicly_queryable' => true,
    'show_ui' => true,
    'query_var' => true,
    'has_archive' => true,
    'rewrite' => array( 'slug' => 'cluster' ),
    'capability_type' => 'post',
    'hierarchical' => false,
    'menu_position' => null,
    'supports' => array('title')
  ); 

register_post_type( 'dr_cluster' , $args );
}
add_action( 'init', 'build_taxonomies', 0 );  

function build_taxonomies() { 

register_taxonomy( 'dr_designers', array("dr_object"), array("hierarchical" => false, "label" => "Designers", "singular_label" => "Designer", "rewrite" => array('slug' => 'designer'))); 
register_taxonomy( 'dr_tags', array("dr_object", "dr_cluster"), array("hierarchical" => false, "label" => "Tags", "singular_label" => "Tag", "rewrite" => array('slug' => 'tags')));  
register_taxonomy( 'dr_manufactors', array("dr_object"), array("hierarchical" => false, "label" => "Manufactors", "singular_label" => "Manufactor", "rewrite" => array('slug' => 'manufactors')));  

}

function dr_rewrite_settings(){
// this enables to get action form objects, cluster etc by adding sth like "objects/my-object/do/edit" -- YEAH!
add_rewrite_endpoint('do', EP_PERMALINK | EP_PAGES );

// ATTENTION: This is *only* done during plugin activation hook in this example!
// You should *NEVER EVER* do this on every page load!!
flush_rewrite_rules();
}
//register_activation_hook( __FILE__, 'dr_rewrite_settings' ); this should happen
add_action('init', dr_rewrite_settings);

as you can see – i had problem flushing the rewrite in a proper way (register_activation_hook).

apart form that i should mention that i’m using another plugin to create a fakepage: mysite.de/objects/new and it goes like this:

<?php
/**
 * Plugin Name: Fake Page Plugin 2
 * Plugin URI: http://scott.sherrillmix.com/blog/blogger/creating-a-better-fake-post-with-a-wordpress-plugin/
 * Description: Creates a fake page without a 404 error (based on <a href="http://headzoo.com/tutorials/wordpress-creating-a-fake-post-with-a-plugin">Sean Hickey's Fake Plugin Page</a>)
 * Author: Scott Sherrill-Mix
 * Author URI: http://scott.sherrillmix.com/blog/
 * Version: 1.1
 */

class FakePage
{
    /**
     * The slug for the fake post.  This is the URL for your plugin, like:
     * http://site.com/about-me or http://site.com/?page_id=about-me
     * @var string
     */
    var $page_slug = 'objects/new';

    /**
     * The title for your fake post.
     * @var string
     */
    var $page_title="New Object";

    /**
     * Allow pings?
     * @var string
     */
    var $ping_status="open";

    /**
     * Class constructor
     */
    function FakePage()
    {
        /**
         * We'll wait til WordPress has looked for posts, and then
         * check to see if the requested url matches our target.
         */
        add_filter('the_posts',array(&$this,'detectPost'));
    }


    /**
     * Called by the 'detectPost' action
     */
    function createPost()
    {

        /**
         * What we are going to do here, is create a fake post.  A post
         * that doesn't actually exist. We're gonna fill it up with
         * whatever values you want.  The content of the post will be
         * the output from your plugin.
         */      

        /**
         * Create a fake post.
         */
        $post = new stdClass;

        /**
         * The author ID for the post.  Usually 1 is the sys admin.  Your
         * plugin can find out the real author ID without any trouble.
         */
        $post->post_author = 1;

        /**
         * The safe name for the post.  This is the post slug.
         */
        $post->post_name = $this->page_slug;

        /**
         * Not sure if this is even important.  But gonna fill it up anyway.
         */
        $post->guid = get_bloginfo('wpurl') . "https://wordpress.stackexchange.com/" . $this->page_slug;


        /**
         * The title of the page.
         */
        $post->post_title = $this->page_title;

        /**
         * This is the content of the post.  This is where the output of
         * your plugin should go.  Just store the output from all your
         * plugin function calls, and put the output into this var.
         */
        $post->post_content = $this->getContent();

        /**
         * Fake post ID to prevent WP from trying to show comments for
         * a post that doesn't really exist.
         */
        $post->ID = -1;

        /**
         * Static means a page, not a post.
         */
        $post->post_status="static";

        /**
         * Turning off comments for the post.
         */
        $post->comment_status="closed";

        /**
         * Let people ping the post?  Probably doesn't matter since
         * comments are turned off, so not sure if WP would even
         * show the pings.
         */
        $post->ping_status = $this->ping_status;

        $post->comment_count = 0;

        /**
         * You can pretty much fill these up with anything you want.  The
         * current date is fine.  It's a fake post right?  Maybe the date
         * the plugin was activated?
         */
        $post->post_date = current_time('mysql');
        $post->post_date_gmt = current_time('mysql', 1);

        add_post_meta($post->ID, '_wp_page_template', 'objects-new.php', true);

        return($post);      
    }

    function getContent()
    {
        return '<p>Hi there!  You are viewing my fake post!</p>';
    }

    function detectPost($posts){
        global $wp;
        global $wp_query;
        /**
         * Check if the requested page matches our target 
         */
        if (strtolower($wp->request) == strtolower($this->page_slug)){ //09.03 removed:  || $wp->query_vars['page_id'] == $this->page_slug
            //Add the fake post
            $posts=NULL;
            $posts[]=$this->createPost();

            /**
             * Trick wp_query into thinking this is a page (necessary for wp_title() at least)
             * Not sure if it's cheating or not to modify global variables in a filter 
             * but it appears to work and the codex doesn't directly say not to.
             */
            $wp_query->is_page = true;
            //Not sure if this one is necessary but might as well set it like a true page
            $wp_query->is_singular = true;
            $wp_query->is_home = false;
            $wp_query->is_archive = false;
            $wp_query->is_category = false;
            //Longer permalink structures may not match the fake post slug and cause a 404 error so we catch the error here
            unset($wp_query->query["error"]);
            $wp_query->query_vars["error"]="";
            $wp_query->is_404=false;

        }
        return $posts;
    }
}

/**
 * Create an instance of our class.
 */
new FakePage;
?>

i made two modifications to the standard plugin. maybe they interfer with the rewrite_rules? (i tried deactivating this plugin – didn’t change a thing)

1) using a “hierarchical” slug. it works but: is it allowed?
2) let the fakepage use a custom template: add_post_meta($post->ID, '_wp_page_template', 'objects-new.php', true); (right before returning the post in createPost())

0

Leave a Comment