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.

We are using CPT's to manage a frequently asked questions page on a site, where the question is the post title and the answer is the post content. There is a main page for the FAQs that shows all posts (FAQ archive page). With this structure we really have no need for the single view for any FAQ and in fact would like to omit it from the site structure. To address permalinks we'd like to set them to be something like example.com/faq/#uniqueIdentifier, thinking that we'll use the #uniqueIdentifier to match a div on the archive page containing the answer and call attention to it in some fashion. The uniqueIdentifier could be post ID, faq question title, data from a meta box, or something else.

So let me recap what I need we need to accomplish:

(1) rewrite the faq permalinks to be /faq/#something, and

(2) make sure all /faq/ links route to archive template and not single

I'm mostly a noob but pretty good at fumbling my way through things. Have never attempted any rewrites though so would appreciate some particular direction on that.

Thank you.

share|improve this question
add comment

1 Answer

up vote 8 down vote accepted

Hi @daxitude:

Let me first suggest you reconsider. If you don't have individual FAQ pages for each FAQ:

  1. You reduce your surface are for search engine optimization and reduce the potential traffic that you might get, and

  2. You make it impossible for someone to share a specific FAQ with a friend over email and/or share with their network on Facebook, Twitter, etc. (As a user I'm always frustrated by site developers who disallow me to have a direct URL to an item and instead force me to link to the page that lists all items.)

However, if you still want to do so then do two things:

1.) Use the 'post_type_link' hook

Use the 'post_type_link' hook to modify the URL like in the following example *(I'm assuming your custom post type is 'faq'). Add the following to your theme's functions.php file:

add_action('post_type_link','yoursite_post_type_link',10,2);
function yoursite_post_type_link($link,$post) {
  $post_type = 'faq';
  if ($post->post_type==$post_type) {
    $link = get_post_type_archive_link($post_type) ."#{$post->post_name}";
  }
  return $link;
}

2.) unset($wp_rewrite->extra_permastructs['faq'])

This is a hack, but it's a required hack to do what you want. Use an 'init' hook to unset($wp_rewrite->extra_permastructs['faq']). It removes the rewrite rule that register_post_type() adds. I'm including a call to register_post_type() so I can provide a complete example for both you and others:

add_action('init','yoursite_init');
function yoursite_init() {
  register_post_type('faq',array(
      'labels' => array(
      'name' => _x('FAQs', 'post type general name'),
      'singular_name' => _x('FAQ', 'post type singular name'),
      'add_new' => _x('Add New', 'faq'),
      'add_new_item' => __('Add New FAQ'),
      'edit_item' => __('Edit FAQ'),
      'new_item' => __('New FAQ'),
      'view_item' => __('View FAQ'),
      'search_items' => __('Search FAQs'),
      'not_found' =>  __('No FAQs found'),
      'not_found_in_trash' => __('No FAQs found in Trash'),
      'parent_item_colon' => '',
      'menu_name' => 'FAQs'
    ),
    'public' => true,
    'publicly_queryable' => true,
    'show_ui' => true,
    'show_in_menu' => true,
    'query_var' => true,
    'rewrite' => array('slug'=>'faqs'),
    'capability_type' => 'post',
    'has_archive' => 'faqs',
    'hierarchical' => false,
    'supports' => array('title','editor','author','thumbnail','excerpt')
  ));

  global $wp_rewrite;
  unset($wp_rewrite->extra_permastructs['faq']);  // Removed URL rewrite for specific FAQ 
  $wp_rewrite->flush_rules(); // THIS SHOULD BE DONE IN A PLUGIN ACTIVATION HOOK, NOT HERE!
}

That's about it.

Of course the above use of $wp_rewrite->flush_rules() in an 'init' hook is really bad practice and should really only be done once so I've implemented a complete and self-contained plugin called FAQ_Post_Type to do it right. This plugin adds a FAQ post type with the URL rules that you want and it uses a register_activation_hook() to flush the rewrite rules; activation being obviously one of the few things that requires plugin code instead of code that can run in a theme's functions.php file.

Here's the code for the FAQ_Post_Type plugin; feel free to modify for your requirements:

<?php
/*
Plugin Name: FAQ Post Type
Description: Answers the question "Custom post type, no need for single view, plus want permalink rewrites that include hash in URI" on WordPress Answers.
Plugin URL: http://wordpress.stackexchange.com/questions/12762/custom-post-type-no-need-for-single-view-plus-want-permalink-rewrites-that-incl
*/
if (!class_exists('FAQ_Post_Type')) {
  class FAQ_Post_Type {
    static function on_load() {
      add_action('post_type_link', array(__CLASS__,'post_type_link'),10,2);
      add_action('init', array(__CLASS__,'init'));
    }
    static function post_type_link($link,$post) {
      if ('faq'==$post->post_type) {
        $link = get_post_type_archive_link('faq') ."#{$post->post_name}";
      }
      return $link;
    }
    static function init() {
      register_post_type('faq',array(
          'labels' => array(
          'name' => _x('FAQs', 'post type general name'),
          'singular_name' => _x('FAQ', 'post type singular name'),
          'add_new' => _x('Add New', 'faq'),
          'add_new_item' => __('Add New FAQ'),
          'edit_item' => __('Edit FAQ'),
          'new_item' => __('New FAQ'),
          'view_item' => __('View FAQ'),
          'search_items' => __('Search FAQs'),
          'not_found' =>  __('No FAQs found'),
          'not_found_in_trash' => __('No FAQs found in Trash'),
          'parent_item_colon' => '',
          'menu_name' => 'FAQs'
        ),
        'public' => true,
        'publicly_queryable' => true,
        'show_ui' => true,
        'show_in_menu' => true,
        'query_var' => true,
        'rewrite' => array('slug'=>'faqs'),
        'capability_type' => 'post',
        'has_archive' => 'faqs',
        'hierarchical' => false,
        'supports' => array('title','editor','author','thumbnail','excerpt'),
      ));
      global $wp_rewrite;
      unset($wp_rewrite->extra_permastructs['faq']);  // Remove URL rewrite for specific FAQ
    }
    static function activate() {
      global $wp_rewrite;
      $wp_rewrite->flush_rules();
    }
  }
  FAQ_Post_Type::on_load();
  register_activation_hook(__FILE__,array('FAQ_Post_Type','activate'));
}

You could also possibly kept the flush rules inside the 'init' by using a check for an option value if you prefer this:

// Add this code in your 'init' hook at your register_post_type('faq',...)
if (!get_option('faq_rewrite_rules_updated')) {
  global $wp_rewrite;
  unset($wp_rewrite->extra_permastructs['faq']);  // Remove URL rewrite for specific FAQ
  $wp_rewrite->flush_rules();
  update_option('faq_rewrite_rules_updated',true);
}

Your choice.

Anyway, let me know if there are use-cases you discover that this does not address.

share|improve this answer
    
Hi @MikeSchinkel. WOW! You certainly are a helpful individual. I whole heartedly agree on your reconsider points #1 and #2, but I believe we have mostly addressed these concerns. For #1 - since we are displaying the full question and answer on the cpt archive page, wouldn't a single view for each faq be duplicate content and thus not necessarily favorable for SEO? In addition to this, we have felt that a whole page for just one faq question is a bit of arm waving and we'd rather deliver folks the content faster vs. having to click thru more links to get there. –  daxitude Mar 22 '11 at 23:34
    
(apparently there are char limits to comments and I am a verbose individual!) For #2 - everything after the hash in the uri is matched to a div on the page that contains the answer. all other answers are hidden on page load and the matched answer slides open. In this manner we do fully preserve the ability to share and save links...as long as we don't get fickle and change this structure for some silly reason. –  daxitude Mar 22 '11 at 23:35
    
As to your reply, step 1 is fantastic! I was not previously familiar with this hook and had not anticipated such a neat solution. As a curiosity, I realize that you can implement step 1 and not step 2. This sends faq links to the appropriate uri but also preserves the single pages..and we just never link to them thru the site. Does this seem like a reasonable way to go? Thank you. –  daxitude Mar 22 '11 at 23:40
    
@daxitude - It's better to disallow search engines indexing on an archive page and to allow them to index the individual pages. The two most import things for SEO are page <title> and <h1>Heading</h1> and you'll get only one of those on an archive page but you've get one each for individual FAQ pages. I agree that all FAQ content is best on the archive page, but you can provide all the content on the main page and a drill down page for those who want it (which includes search engines), and it certainly doesn't hurt anything; just add a "Permalink" close to the FAQ question. –  MikeSchinkel Mar 22 '11 at 23:53
    
@daxitude - Why do you think I did not implement #2? That's the purpose of the code that follows the heading "2.) unset($wp_rewrite->extra_permastructs['faq'])" which, of course, I'm arguing that you do not use. :) –  MikeSchinkel Mar 22 '11 at 23:55
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.