I am developing a plugin for my own rapid development that creates a custom post type. The ‘list’ for this post type is displayed on a specific page that is created and managed by the plugin. This page can be place anywhere within the site’s page hierarchy, so the slug for the single posts need to update if the site admin changes the list page location.

When creating the post type during the init, I accomplish this by assigning the following rewrite rules to the custom post type (code trimmed for brevity):

$post_type_slug = "https://wordpress.stackexchange.com/" . get_page_uri( $page_id );
register_post_type( 'post_type_name',
        ... 
        'rewrite'   => array( 'slug' => $post_type_slug, 'with_front' => true),
        ...
      )
);  

This seems to work perfectly for setting everything up initially. When the user saves the ‘list’ page, I run the following code to update the rewrite rules:

add_action( 'save_post', array(__CLASS__, 'flush_permalinks'), 2000 );
function flush_permalinks( $post_id ) {
  if($post_id == get_option( $custom_page_id )){
    flush_rewrite_rules(false);
  }
}

However, when the user changes the location of the page, the newly updated permalinks return 404 (even though the list page displays the links correctly). But if I save the page a second time, it works perfectly! I’ve attempted changing the priority of the save_post action (from 1 to 2000), but that does not seem to make a different. I’ve also tried to both hard and soft flush the rewrite rules, but that doesn’t change the two-save (first save doesn’t change the rewrite rules, but the second does) behavior either.

Any suggestions on what I might be doing wrong?

2 Answers
2

I know this has already been answered, but I felt as if it wasn’t 100% real clear what the actual solution was.

Here’s my answer to add some clarification.

He’s right… You can’t flush rewrite rules on save_post, because that action hook is fired AFTER the init action hook has been fired.

As you know, Post Types and Taxonomies are registered on the init hook.

TLDR; You can’t flush_rewrite_rules(); on save_post action hook.

There’s a workaround…

You need to set an option value to 1 on save_post action hook. Then check that option for value of 1 and flush rewrite rules on init action hook.

Example:

function mbe_late_init_example() {

    if ( ! $option = get_option( 'my-plugin-flush-rewrite-rules' ) ) {
        return false;
    }

    if ( $option == 1 ) {

        flush_rewrite_rules();
        update_option( 'my-plugin-flush-rewrite-rules', 0 );

    }

    return true;

}

add_action( 'init', 'mbe_late_init_example', 999999 );


function mbe_save_post_example( Int $post_id = null, \WP_Post $post_object = null ) {

    if ( ! $post_id || ! $post_object ) {
        return false;
    }

    # Specific Post Type
    if ( $post_object->post_type != 'my-plugin-settings' ) {
        return false;
    }

    # Specific Post Object (OPTIONAL)
    if ( $post_object->post_name != 'general-settings' ) {
        return false;
    }

    update_option( 'my-plugin-flush-rewrite-rules', 1 );

    return true;

}

add_action( 'save_post', 'mbe_save_post_example', 10, 2 );

Leave a Reply

Your email address will not be published. Required fields are marked *