1

I'm stuck in need of a rewrite rule. I have set up a custom post type for 'Books', each book has a repeatable field (using ACF Pro) for chapters.

I have added a query_var for chapter using the code below...

// Add chapter to query vars array
function add_query_vars_filter( $vars ){
  $vars[] = "chapter";
  return $vars;
}
add_filter( 'query_vars', 'add_query_vars_filter' );

On the single-books.php template page, I have a code to capture the query_var and either display the book overview or the chapter meta fields...

if (get_query_var('chapter') == '') {

    // show book title and content

} elseif (get_query_var('chapter') >= 1) {

    $chapter_no = (get_query_var( 'chapter', 1 ) - 1); //minus one as first array row has index of 0.

    $rows = get_field('chapter'); // get all the rows
    $chapter = $rows[$chapter_no]; // get the row given from query_var

    // show chapter fields from ACF array.
    // $chapter['title']
    // $chapter['content']
    // $chapter['image']

};

So the url for Chapter 1 would look like this...

www.example.com/books/book-title/?chapter=1

This works fine, but for SEO purposes I want the url to look prettier, like the example below...

www.example.com/books/book-title/1/chapter-title/

I've looked at the codex and tried the following...

function custom_rewrite_basic() {
  add_rewrite_rule('^books/([^/]*)/([0-9]+)/?', 'index.php?post_type=books&chapter=$matches[1]', 'top');
}
add_action('init', 'custom_rewrite_basic');

I'm not getting anything from it, not really sure what I need to do/if it's possible. Can anyone point me in the right direction, or show me how to create the rewrite rule.

Thanks.

4
  • You refer to your post type as both book and books, what is the actual post type slug it is registered with? Your rule doesn't set the specific book that's requested, and the chapter title slug segment is missing.
    – Milo
    Nov 12 '15 at 22:16
  • it's registered with books that should also say single-books.php. I'm not sure how to set the specific book. I missed off the title segment as I was just trying to get it to work by pulling in the chapter number before I figures out how to get the chapter title in there from the custom field.
    – dijon
    Nov 12 '15 at 22:21
  • I don't believe that a meta field is the appropriate place for you to store the chapter, a taxonomy would be more appropriate, it would also be easier to implement what you're wanting
    – Tom J Nowell
    Nov 12 '15 at 23:05
  • I used the Advanced Custom Field repeater field, with sub fields for title, content and image. So the chapters can be added, ranked and edited on the corresponding books page. I also need to be able to add a content to the actual book post alongside some other meta. Not sure how I could achieve this with taxonomies, I considered linking two custom post types (books and chapters) but the ACF custom field seemed like the easier and most user friendly. But I might be wrong.
    – dijon
    Nov 12 '15 at 23:18
2

The post type query var is the same as the post type slug by default. Untested, but this should work-

function custom_rewrite_basic() {
    add_rewrite_rule(
        '^books/([^/]+)/([0-9]+)/([^/]+)/?',
        'index.php?books=$matches[1]&chapter=$matches[2]',
        'top'
    );
}
add_action('init', 'custom_rewrite_basic');

$matches[3] will contain the chapter slug, but if you don't need that to retrieve the chapter, then you don't have to set it.

Rewrite rules need to be flushed after they're added / changed. Visiting the Settings > Permalinks page will flush them without having to call flush_rewrite_rules yourself.

Rewrite rules only handle incoming requests, it's up to you to generate the correct URLs for each chapter, but that should just be a matter of grabbing your chapter data and appending the numbers/titles to the post permalink. Something like this:

$rows = get_field('chapter');
foreach( $rows as $index => $row ){
    echo get_permalink() . '/' . ( $index + 1 ) . '/' . sanitize_title( $row['title'] ) . '/';
}

Also- to keep your templates tidy, you can filter single_template, check if the chapter query var is set, and load a different template for chapters vs the main book page.

2
  • That has worked to some extent, but now when I visit example.com/books/book-1/1/ it doesn't work, but if I add any string after the trailing slash it works???? How would I get it to only work for the correct chapter number and chapter title? Can you point me in the right direction for how I would generate the permalink properly for each chapter?
    – dijon
    Nov 12 '15 at 22:38
  • 1
    It doesn't work because it doesn't match the pattern in the rewrite rule, all segments have to be populated. FYI- the pattern postname/number already exists to support paginated posts, which will probably be broken under this scheme, if that's a concern. To enforce that it's actually an existing chapter, you'll need to hook parse_query and check that yourself, see this answer for an example.
    – Milo
    Nov 12 '15 at 22:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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