2

I already have found a working solution for my question, but the problem is that it neutralizes another function that adds the category base into the custom post type permalinks, and I need boths, so I must to merge them somehow. How to do that?

This is the code that adds the .html extention to the custom post types:

//Create the rewrite rules like post-type/post-name.html
add_action( 'rewrite_rules_array', 'rewrite_rules' );
function rewrite_rules( $rules ) {
    $new_rules = array();
    foreach ( get_post_types() as $t )
        $new_rules[ $t . '/([^/]+)\.html$' ] = 'index.php?post_type=' . $t . '&name=$matches[1]';
    return $new_rules + $rules;
}

//Format the new permalink structure for these post types.
add_filter( 'post_type_link', 'custom_post_permalink' ); // for cpt post_type_link (rather than post_link)
function custom_post_permalink ( $post_link ) {
    global $post;
    $type = get_post_type( $post->ID );
    return home_url( $type . '/' . $post->post_name . '.html' );
}

//And then stop redirecting the canonical URLs to remove the trailing slash.
add_filter( 'redirect_canonical', '__return_false' );

And this is the code that adds the category base to a cources custom post type (see a similar solution, and another):

//Change your rewrite to add the course query var:
'rewrite' => array('slug' => 'courses/%course%')

//Then filter post_type_link to insert the selected course into the permalink:
function wpa_course_post_link( $post_link, $id = 0 ){
    $post = get_post($id);  
    if ( is_object( $post ) ){
        $terms = wp_get_object_terms( $post->ID, 'course' );
        if( $terms ){
            return str_replace( '%course%' , $terms[0]->slug , $post_link );
        }
    }
    return $post_link;  
}
add_filter( 'post_type_link', 'wpa_course_post_link', 1, 3 );
4

Lets take these functions and paraphrase them into english, then put them in the order they're ran. I'm going to deliberately avoid using PHP in this answer, but a basic understanding of PHP will be necessary:

When the `post_type_link` filter runs: // the add_action calls
    run: `wpa_course_post_link` as it has priority 3 // function wpa_course_post_link(....
        if the object is a post
            and that post has a course term
                search for %course% in the URL string and replace it
    Then, run `custom_post_permalink` as it has priority 10: // function custom_post_permalink(...
        Ignore the URL we got given and construct a brand new one by returning the post_type + "/" + posts name + ".html"

So custom_post_permalink doesn't add .html to the end of your URLs as you thought it did, it creates a whole new URL. If you changed the priority from 3 to 11, your .html URLs will work, but your course URLs will not as %course% was replaced.

Luckily the wpa_course_post_link function provides a much better template for how to do this. Insted of grabbing the course terms and doing a string replace, just add .html to the end of the $post_link string and return it

So instead if we write it out as pseudocode in plain english, we might get this:

When the `post_type_link` filter runs:
    run: `wpa_course_post_link` as it has priority 3
        if the object is a post, then:
            if that post has a course term then:
                search for %course% in the URL string and replace it
            then add ".html" to the end

I leave conversion to PHP as a task for the reader, all the needed PHP is already available in the question.

  • Logically, I understand you (I hope), but how to implement this, I don't. I want to add the .html extension, but I need also to replace the %course% with a course taxonomy term. Right now I am able only to achieve one of them, but not both at the same time. I can experiment more, but I need more help. @tom-j-nowell – Iurie Malai Mar 31 '17 at 20:24
  • 1
    Write it out as a set of plain english instructions, all the code you need to do it is already there, requiring beginner level programming knowledge, but I'm not writing PHP code you can copy paste edit: I wrote out the plain english instructions for you, if you don't know how to write basic PHP, you can learn the required level of knowledge from scratch in an hour using an online course, joining strings together, a basic function call, and what if statements are should be all you need, all the necessary calls are already mentioned in your question – Tom J Nowell Apr 1 '17 at 15:22
  • Tom, I agree with you! The best approach to help someone is to help him to LEARN how to do what he needs. I updated my question with a working solution. Thank you! @tom-j-nowell – Iurie Malai Apr 2 '17 at 6:32
  • Can you post your solution as an answer instead? – Tom J Nowell Apr 2 '17 at 18:09
2

With the help of @tom-j-nowell I have a working solution. I suppose it is not yet perfect, but it works.

//When your create a custom post type change your rewrite to:
'rewrite' => array('slug' => 'courses/%course_category%')

//Then filter post_type_link to insert the category of selected course into the permalink:
function wpa_course_post_link( $post_link, $id = 0 ){
    $post = get_post($id);
    if ( is_object( $post ) ){
        $terms = wp_get_object_terms( $post->ID, 'course_category' );
        if( $terms ){
            $post_link = str_replace( '%course_category%' , $terms[0]->slug , $post_link );
            //and add the .html extension to the returned post link:
            return $post_link . '.html';
        }
    }
    return $post_link;  
}
add_filter( 'post_type_link', 'wpa_course_post_link', 1, 3 );

//Then create the rewrite rules for the post-type/post-category/post-name.html permalink structure:
add_action( 'rewrite_rules_array', 'rewrite_rules' );
function rewrite_rules( $rules ) {
    $new_rules = array();
    $new_rules[ 'courses/([^/]+)/(.+)\.html$' ] = 'index.php?courses=$matches[2]';
    return $new_rules + $rules;
}

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.