How to set a custom post type post as static front page?

I had time to look at your issue and the options-reading.php page which is the template used to render the reading settings page in backend.

There are unfortunately no filters to filter or add custom posts as sticky posts in a selectable dropdown. There are two hidden filters though which we can use, they are

IMHO, I think get_pages here is a better option. This way we will let wp_dropdown_pages() to take care of all the markup. We need to take care here though when we use the get_pages filter

  • We will need to make sure we only target the admin area and in particular the reading settings page otherwise we will alter any function/page that uses the get_pages() function

You need to decide whether you would need pages to show with the custom post type posts or just need the custom post types

You can try the following:

add_filter( 'get_pages', function ( $pages, $args )
{
    // First make sure this is an admin page, if not, bail
    if ( !is_admin() )
        return $pages;

    // Make sure that we are on the reading settings page, if not, bail
    global $pagenow;
    if ( 'options-reading.php' !== $pagenow )
        return $pages;

    // Remove the filter to avoid infinite loop
    remove_filter( current_filter(), __FUNCTION__ );

    $args = [
        'post_type'      => 'my_frontpage',
        'posts_per_page' => -1
    ];
    // Get the post type posts with get_posts to allow non hierarchical post types
    $new_pages = get_posts( $args );    

    /**
     * You need to decide if you want to add custom post type posts to the pages
     * already in the dropdown, or just want the custom post type posts in
     * the dropdown. I will handle both, just remove what is not needed
     */
    // If we only need custom post types
    $pages = $new_pages;

    // If we need to add custom post type posts to the pages
    // $pages = array_merge( $new_pages, $pages );

    return $pages;
}, 10, 2 );

You should now see your custom post type posts in the dropdown. Take note, this code will affect the dropdown for the blog page as well.

To avoid that, you can use a static counter to count the amount of times the filter has run and then bail just before the filter is applied to the blogpage dropdown. The filter will run a total of 3 times as get_pages() runs 3 times:

  • first to check if we actually have pages to set as a static front page.

  • second run will be inside wp_dropdown_pages() which is used by the static front page dropdown

  • the last run will be inside wp_dropdown_pages() which is used by the blogpage dropdown

So, based on this, we can try

add_filter( 'get_pages', function ( $pages, $args )
{
    // First make sure this is an admin page, if not, bail
    if ( !is_admin() )
        return $pages;

    // Make sure that we are on the reading settings page, if not, bail
    global $pagenow;
    if ( 'options-reading.php' !== $pagenow )
        return $pages;

    // Remove the filter to avoid infinite loop
    remove_filter( current_filter(), __FUNCTION__ );

    // Setup our static counter
    static $counter = 0;

    // Bail on the third run all runs after this. The third run will be 2
    if ( 2 <= $counter )
        return $pages;

    // Update our counter
    $counter++;

    $args = [
        'post_type'      => 'my_frontpage',
        'posts_per_page' => -1
    ];
    // Get the post type posts with get_posts to allow non hierarchical post types
    $new_pages = get_posts( $args );    

    /**
     * You need to decide if you want to add custom post type posts to the pages
     * already in the dropdown, or just want the custom post type posts in
     * the dropdown. I will handle both, just remove what is not needed
     */
    // If we only need custom post types
    $pages = $new_pages;

    // If we need to add custom post type posts to the pages
    // $pages = array_merge( $new_pages, $pages );

    return $pages;
}, 10, 2 );

If you visit the front end and visit the front page, you’ll find that it will redirect to the single post page. That is because, by default, the main query on a static front page is set to query the page post type. This causes a 404 being returned and redirect_canonical() then redirects to the single post page. This is easy to solve, all we must do is to adjust the main query on the static front page.

add_action( 'pre_get_posts', function ( $q )
{
    if (    !is_admin() // Only target the front end
         && $q->is_main_query() // Only target the main query
         && 'page' === get_option( 'show_on_front' ) // Only target the static front page
    ) {
        $q->set( 'post_type', 'my_frontpage' );
    }
});

You will now have your static front page displaying correctly.

All you are left to do is to set a template. You can simply create a front-page.php, WordPress will automatically use it

Leave a Comment