Set Any Page as a Custom 404 Page in WordPress

The following code snippet replaces your current 404 page with a custom one. In other words, it tells WordPress to use a specific existing page as the new 404 page.

Add the snippet either to your theme’s functions.php file, or, better yet, use the Code Snippets plugin.

Remember to set the correct page ID in $custom_404_page_id

/*
A custom function that assigns any of your published pages to be the 404 page.

This works with classic themes only. 
If you're on a block theme, you can set a custom 404 through the Site Editor.
*/
function kk_custom_404_template($template) {
    // Replace with your desired page ID
    $custom_404_page_id = 1;
    ////////////////////////////////////
    
    if (is_404()) {
        $page = get_post($custom_404_page_id);
        
        if ($page && $page->post_status == 'publish') {
            // Set up global variables
            global $wp_query, $post;
            $post = $page;
            
            // Set up the main query
            $wp_query->posts = array($page);
            $wp_query->post = $page;
            $wp_query->post_count = 1;
            $wp_query->found_posts = 1;
            $wp_query->max_num_pages = 1;
            $wp_query->is_404 = true;        // Keep 404 status
            $wp_query->is_page = true;       // Treat as page
            $wp_query->is_singular = true;   // Treat as singular
            $wp_query->is_archive = false;   // Not an archive
            $wp_query->is_home = false;      // Not home
            
            // Set up post data
            setup_postdata($post);
            
            status_header(404);
            nocache_headers();

            if (wp_is_block_theme()) {
                // Block theme handling - pass through
                return ABSPATH . WPINC . '/template-canvas.php';
            } else {
                // Classic theme handling
                $new_template = get_page_template_slug($custom_404_page_id);
                
                if ($new_template) {
                    return get_template_directory() . '/' . $new_template;
                } else {
                    return get_template_directory() . '/page.php';
                }
            }
        }
    }
    
    return $template;
}
add_filter('template_include', 'kk_custom_404_template', 99);