WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

After hours seeking through the WordPress sources it I was unable to find ANY reasonable method of creating a front end page from a plugin. My goal was simple, I wanted http://mysite.com/friends to show a page generated by my plugin. This is a multi-site installation and I do not want blog owners to be able to eliminate this page. My final implementation doesn't involve users blogs but it could.

wp-includes/theme.php: I added this function

function get_extension_page_template() {
    $page = get_queried_object();
    $templates = array($page->ID.'.php');
    return get_query_template($page->ID,$templates);

wp-includes/template-loader.php: I added this just ofter the if(is_404() line(near line 8)

elseif ( is_extension_page() && $template = get_extension_page_template()) :

wp-includes/query.php: I added two functions

function set_extension_page($page,$object) {
    global $wp_query;
    return $wp_query->set_extension_page($page,$object);

function is_extension_page() {
  global $wp_query;
    return $wp_query->is_extension_page();

wp-includes/query.php: I added two properties to the WP_Query class

var $extension_page = null;
var $extension_page_object = null;

wp-includes/query.php: I added two methods to the WP_Query class

  function set_extension_page($page,$object) {
      $this->extension_page_object = $object;
      $this->extension_page = $page;
  function is_extension_page() {
     return isset($this->extension_page);

wp-includes/query.php: I changed the get_queried_object method in the WP_Query class

function get_queried_object() {
        if ( isset($this->queried_object) )
            return $this->queried_object;

    if (isset($this->extension_page_object)) {
        return $this->extension_page_object;
        $this->queried_object = NULL;
        $this->queried_object_id = 0;

        if ( $this->is_category || $this->is_tag || $this->is_tax ) {
            $tax_query_in_and = wp_list_filter( $this->tax_query->queries, array( 'operator' => 'NOT IN' ), 'NOT' );

            $query = reset( $tax_query_in_and );

            if ( 'term_id' == $query['field'] )
                $term = get_term( reset( $query['terms'] ), $query['taxonomy'] );
                $term = get_term_by( $query['field'], reset( $query['terms'] ), $query['taxonomy'] );

            if ( $term && ! is_wp_error($term) )  {
                $this->queried_object = $term;
                $this->queried_object_id = (int) $term->term_id;

                if ( $this->is_category )
                    _make_cat_compat( $this->queried_object );
        } elseif ( $this->is_post_type_archive ) {
            $this->queried_object = get_post_type_object( $this->get('post_type') );
        } elseif ( $this->is_posts_page ) {
            $page_for_posts = get_option('page_for_posts');
            $this->queried_object = & get_page( $page_for_posts );
            $this->queried_object_id = (int) $this->queried_object->ID;
        } elseif ( $this->is_singular && !is_null($this->post) ) {
            $this->queried_object = $this->post;
            $this->queried_object_id = (int) $this->post->ID;
        } elseif ( $this->is_author ) {
            $this->queried_object_id = (int) $this->get('author');
            $this->queried_object = get_userdata( $this->queried_object_id );

        return $this->queried_object;

wp-includes/class-wp.php: I changed the handle_404 method to the following

function handle_404() {
        global $wp_query;

        if ( !is_admin() && ( 0 == count( $wp_query->posts ) ) && !is_404() && !is_robots() && !is_search() && !is_home() ) {
            // Don't 404 for these queries if they matched an object.
            if ( ( is_extension_page() || is_tag() || is_category() || is_tax() || is_author() || is_post_type_archive() ) && $wp_query->get_queried_object() && !is_paged() ) {
                if ( !is_404() )
                    status_header( 200 );

            status_header( 404 );
        } elseif ( !is_404() ) {
            status_header( 200 );

The final result is that I can create an object in plugins on patched sites and test for certain conditions, such as $blogpage = $this->ID and then call set_extension_page($this->ID,$this); to register the page to be displayed. The theme must also have a template setup for that plugin which is named (first parameter of set_extension_page).php but its better than nothing.

I admit this is just an ugly hack, but it works. It would be nice to see a feature like this added to wordpress in the future.

share|improve this question
Do you realize that if you modify the wordpress core, your modifications will get overwritten on every wordpress update you run? – Johannes Pille Dec 5 '11 at 15:32

I had a similar thing just last week and I've got a solution and pushed the code up to github: https://github.com/deadlyhifi/wp_query_intercepter

Basically, it allows you to intercept an URL and choose to send a custom template file, or run anything you like based on the request.

It's updated since my question on Rewrite loading custom template file but is_home() returns true, and there's no 404

You should be able to change it to suit your situation.

And yes, Johannes Pille is correct, you shouldn't change the core files. They will get overwritten at the next WP update and could cause other unexpected behaviour. You really shouldn't need to anyway as just about everything in WP can be plugged into, filtered, or overwritten somehow.

share|improve this answer

Your Answer


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.