Hi @daxitude:
Let me first suggest you reconsider. If you don’t have individual FAQ pages for each FAQ:
-
You reduce your surface are for search engine optimization and reduce the potential traffic that you might get, and
-
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.