Add the .html extension to custom post types

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 . "https://wordpress.stackexchange.com/" . $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 );

2 Answers
2

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 + "https://wordpress.stackexchange.com/" + 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.

Leave a Comment