3

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 = "/" . 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?

3

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 );
1

I was able to resolve this problem. It would appear that the 'save_post' action occurs prior to the init that is registering the custom post type. Therefore, the post type's rewrite slug is not updated prior to the request to flush_rewrite_rules, essentially resulting in no update. This also explains why it works if the post is saved a second time, since the post type has a chance to update its rewrite rules.

Therefore, I solve it by changing my code as such:

add_action( 'save_post', array(__CLASS__, 'flush_permalinks'));
function flush_permalinks( $post_id ) { 
  if($post_id == get_option( $custom_page_id )){
    update_option( 'unique_page_updated_key', 'true');
  }
}

I then added the following just below my register_post_type code:

if((bool)get_option( 'unique_page_updated_key' )){
  flush_rewrite_rules(); 
  update_option( 'unique_page_updated_key', 'false');
}

This prevents the rewrite rules from being flushed on each and every init.

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.