I am going to try and sum up what I am trying to achieve...

Basically I have a custom post type called 'marketing_list' which will have custom fields holding information relating to marketing lists available for purchase.

Each marketing list will belong to a category (custom taxonomy).

So currently my URL's look like this:

  • /marketing-lists -> archive page
  • /marketing-lists/post-slug -> single marketing lists entry
  • /marketing-lists/category/category-slug -> custom taxonomy

What I want to achieve is:

  • /marketing-lists -> archive page but editable within the admin in case the client wants to update text, like a Page.
  • /marketing-lists/category-slug -> custom taxonomy
  • /marketing-lists/category-slug/post-slug -> single entry

On top of that I would like to create some additional pages which have a base of /marketing-lists i.e

  • /marketing-lists/consumer-marketing-lists -> single page
  • /marketing-lists/business-marketing-lists -> single page

Is this at all possible? Perhaps their is a better way to achieve this?

The bulk of your question is fairly easy and has been covered here many times before. I also gave a talk at WordCamp Portland on the topic, which you can watch, download slides, code, etc. here.

The last part of your question,

On top of that I would like to create some additional pages which have a base of /marketing-lists i.e

/marketing-lists/consumer-marketing-lists -> single page /marketing-lists/business-marketing-lists -> single page

... is a little trickier. If there will only be a few and they won't often change, you have two options that I can see:

  1. Add specific rewrite rules to the top of the stack to address them
  2. Make them taxonomy terms (that you never use as taxonomy terms) and leverage the template hierarchy to do with them as you please.

Personally, I'd go with #1. If you do, your code may look something like this,

function wpse_119673_rewrite_rules() {
    add_rewrite_rule( 'marketing-lists/(consumer-marketing-lists|business-marketing-lists)/?', 'index.php?pagename=$matches[1]', 'top' );
}
add_action( 'init', 'wpse_119673_rewrite_rules' );

See add_rewrite_rule for reference.

If, on the other hand, you'll have many of these pages and you need to create them on a whim, it becomes significantly more difficult. Essentially, you'd then have a significant rewrite conflict for which you'd need to account in every matching query. Here's another question which is very different from yours, but where I account for a rewrite conflict (search for "check_rewrite_conflicts") in my answer. In that answer, on every query where the "state" is present, I'm checking to see if that should actually be a page. It's an additional database query, and I would advise against it.

The problematic part of permalink structure you asking for is for permalinks like

/marketing-lists/{$something}/

where sometimes $something should be a category, sometimes a page slug.

So, to make it works you should run a database query to know what $something is and that will slow down performance

After that, if the url example.com/marketing-lists/viral-marketing and you have a page with slug viral-marketing and a category with slug viral-marketing what WordPress should show, the page or the category archive?

Even if run a db query, you'll find a page and a category with that slug, so who win?

Moreover, using standard WordPress rewrite rules your work will be very hard... because a lot of conflict will happen.

I develop a plugin, Clever Rules can help you a lot for the task, but - again - with no db query is impossible say if the part just after /marketing-lists/ is a a page slug or a category...

Using that plugin this code should works, but it require a db query and in case of conflict the page slug will win:

/*
 * Plugin Name: My Custom Rules
 */

add_action('plugins_loaded', 'register_my_rules');
add_filter('skip_clever_rule', 'rule_pages_for_pages', 20, 3);

function register_my_rules() {

    if ( ! function_exists('register_clever_rule') ) return;

    $args = array( 'id' => 'rule_pages','route' => '/marketing-lists/%s');
    register_clever_rule( $args )->query('pagename=[0]')->priority(1);

    $args = array( 'id' => 'rule_cats','route' => '/marketing-lists/%s');
    register_clever_rule( $args )->query('category_name=[0]')->priority(2);

    $args = array( 'id' => 'rule_singles','route' => '/marketing-lists/%s/%s/');
    register_clever_rule( $args )->query('name=[1]');

}

function rule_pages_for_pages( $skip, $rule, $pieces ) {
  if ( $rule['args']['id'] === 'rule_pages' ) {
    global $wpdb;
    $pages = $wpdb->get_col("SELECT post_name FROM $wpdb->posts WHERE post_type = 'page' AND post_status = 'publish'");
    if ( ! in_array( $pieces[1], $pages ) ) $skip = true;
  }
  return $skip;
}

Note that that code goes in a plugin and can't work in themes.

  • Thanks, your plugin looks interesting. I'll give it a try. – Philip Benton Oct 22 '13 at 14:38

Your Answer

 
discard

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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