TransWikia.com

Question about repurposing WordPress 404 handler

WordPress Development Asked by Yvan Gagnon on February 18, 2021

I’ve been experimenting with repurposing WordPress’s 404 handler/template file for a Real Estate site that I’m developing. I understand that when a non-existent URL is requested, the 404 page gets served up and that it returns a 404 status code (instead of a 200). But I’ve recently found a way to adapt the 404 template file so that it does something a bit more creative. More specifically, I’m first parsing the non-existent URL that was requested, and then using the returned value to query an external API and then display the returned data. So far it’s working much better than I’d expected, though I’m aware of one significant issue that I’m hoping I can address.

In those situations where the 404 handler is served up, yet data is returned from querying the external API, .. how can I then — and only then — re-write the "404" header information so that it’s a "200" status code? I ask because I don’t want these "Page Not Found" entries littering our Google Analytics reports and mucking up the site’s SEO ranking.

Here is an example non-existent URL which triggers the serving up of the 404 handler:

https://example.com/property/123-four-street/

I am parsing this URL using the following PHP code snippet:

$url = $_SERVER['REQUEST_URI'];
$path_parts = explode('/', $url);   
$address = $path_parts[2];  
$parsedaddress = str_replace("-", " ", $address);                   
echo $parsedaddress;    

The "parsedaddress" value is then used to query the external API, and what I’d then like to have happen logic-wise is something along the lines of …

if (query returns valid MLS data)

then (force a "200" status code and display the MLS data)

else (retain the "404" status code and display the 404 error page)

I’ve already added this custom function to my functions.php file, which is successfully changing the default page title for the 404 handler … so I know that I can hook in to it. But how might I adapt this so that it conditionally rewrites the header information?

function theme_slug_filter_wp_title( $title_parts ) {
    if ( is_404() ) {               
        
        $url = $_SERVER['REQUEST_URI'];
        $path_parts = explode('/', $url);   
        $address = $path_parts[2];  
        $parsedaddress = str_replace("-", " ", $address);           
        
        $title_parts['title'] = ucwords($parsedaddress) . ' | AAA Real Estate;
    }

    return $title_parts;
} 
add_filter( 'document_title_parts', 'theme_slug_filter_wp_title' );

Any help or advice would be appreciated.

Thanks,
— Yvan

One Answer

Here is the tested code, you can use it as a mu-plugin:

<?php
/**
 * Filters whether to short-circuit default header status handling.
 *
 * Returning a non-false value from the filter will short-circuit the handling
 * and return early.
 *
 * @param bool     $preempt  Whether to short-circuit default header status handling. Default false.
 * @param WP_Query $wp_query WordPress Query object.
 *
 * @return bool
 * @since 4.5.0
 */
function pre_handle_404_filter( bool $preempt, WP_Query $wp_query ) {
    global $parsed_address, $api_results;

    $parsed_address = get_parsed_address();

    if ( ! $parsed_address ) {
        return $preempt;
    }

    // Make a request to  API, get status.
    $status      = true; // For debug purposes.
    $api_results = null;

    if ( $status ) {
        // Save results to $api_results.
        // Return true to avoid 404 processing by WP.
        return true;
    }

    return $preempt;
}

add_filter( 'pre_handle_404', 'pre_handle_404_filter', 10, 2 );

/**
 * Handle 404.
 */
function handle_404() {
    global $parsed_address, $api_results, $wp_query;

    if ( ! $parsed_address ) {
        return;
    }

    // Set 404 here to prevent bugs in get_header().
    $wp_query->set_404();

    get_header();
    echo 'API Results'; // Output $api_results here.
    get_footer();
    exit();
}

add_action( 'template_redirect', 'handle_404', - PHP_INT_MAX );

/**
 * Get parsed address from the request URI.
 * Make sure we have an address in the URI, otherwise return an empty string.
 *
 * @return string
 */
function get_parsed_address() {
    $request_uri =
        isset( $_SERVER['REQUEST_URI'] ) ?
            filter_var( wp_unslash( $_SERVER['REQUEST_URI'] ), FILTER_SANITIZE_STRING ) :
            '';

    if ( url_to_postid( $request_uri ) ) {
        return '';
    }

    $path_parts = explode( '/', $request_uri );
    $part1      = isset( $path_parts[1] ) ? $path_parts[1] : '';

    if ( 'property' !== $part1 ) {
        return '';
    }

    $address = isset( $path_parts[2] ) ? $path_parts[2] : '';

    return str_replace( '-', ' ', $address );
}

/**
 * Filter page title.
 *
 * @param array $title_parts Title parts.
 *
 * @return mixed
 */
function theme_slug_filter_wp_title( $title_parts ) {
    global $parsed_address, $api_results, $wp_query;

    if ( ! $parsed_address ) {
        return $title_parts;
    }

    $title_parts['title'] = ucwords( $parsed_address ) . ' | AAA Real Estate';

    return $title_parts;
}

add_filter( 'document_title_parts', 'theme_slug_filter_wp_title' );

We catch 404 via pre_handle_404, make the API request and save results. Please note that it works when we have parsed address in the URI only.

Later, on template_redirect event, we check again that have parsed address and set back 404 status to prevent bugs in the get_header(). Please note that we intercept template_redirect as early as possible, at - PHP_INT_MAX priority to execute our code before standard template_redirect hook in the WP core.

Correct answer by KAGG Design on February 18, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP