Why my custom post posts aren’t showing (404 error / page not found)

Actually, this is a common problem.

When you add a custom post type, you’re also registering a new rewrite rule with WordPress. However you must flush your rewrite rules after registering things in order to get WordPress to recognize them.

With a plugin, this is fixed by hooking your CPT registration to both init (so it’s usable) and the plugin’s activation hook. Then, inside the plugin activation hook, you manually call flush_rewrite_rules() to reset things.

Since there is no analogous theme activation/deactivation setup, you can use options to set when the theme has been loaded. For example:

function my_theme_register_cpt() {
    $args = array(
        // ... your initialization stuff
    );

    register_post_type( 'news', $news );
}
add_action( 'init', 'my_theme_register_cpt' );

function my_theme_deactivate() {
    delete_option( 'my_theme_active' );
}
add_action( 'switch_theme', 'my_theme_deactivation' );

$is_active = get_option( 'my_theme_active' );
if ( 'set' !== $check ) {
    my_theme_register_cpt();
    flush_rewrite_rules();

    add_option( 'my_theme_active', 'set', '', 'no' );
}

In a nutshell. This code will:

  • Register your CPT on init as usual.
  • When you change themes, it clears a stored value stating your theme is active
  • If your theme becomes active and this stored value is not set, the theme will fire your CPT registration code (again) and immediately flush the rewrite rules. Then it sets the stored value so it doesn’t fire flush_rewrite_rules() multiple times.