WordPress map custom url to a function

A simplier solution is to just create a new template redirect.

So assuming you loading example.com/custom-url

/**
 * Process the requests that comes to custom url.
 */
function process_request() {
    // Check if we're on the correct url
    global $wp;
    $current_slug = add_query_arg( array(), $wp->request );
    if($current_slug !== 'custom-url') {
        return false;
    }

    // Check if it's a valid request.
    $nonce = filter_input(INPUT_GET, '_wpnonce', FILTER_SANITIZE_STRING);
    if ( ! wp_verify_nonce( $nonce,  'NONCE_KEY')) {
        die( __( 'Security check', 'textdomain' ) );
    }

    // Do your stuff here
    

    //
    die('Process completed' );
}
add_action( 'template_redirect', 'process_request', 0);

After much googling and reading a few good resources, I have found the solution.

Step 1: Use add_rewrite_endpoint to create a base url that will be mapped to a query variable:

add_action( 'init', function(){
    add_rewrite_endpoint( 'machines', EP_ROOT );
} );

Step 2: Visit the permalinks settings page and click "Save Changes" to flush the rewrite rules.

Step 3: Hook into the action 'template_redirect' to actually do something when the url is hit:

add_action( 'template_redirect', function() {
    if ( $machinesUrl = get_query_var( 'machines' ) ) {
        // var_dump($machinesUrl, $_GET);
        // $machinesURl contains the url part after example.com/machines
        // e.g. if url is example.com/machines/some/thing/else
        // then $machinesUrl == 'some/thing/else'
        // and params can be retrieved via $_GET

        // after parsing url and calling api, it's just a matter of loading a template:
        locate_template( 'singe-machine.php', TRUE, TRUE );

        // then stop processing
        die();
    }
});

Step 4: The only other thing to do is handle a hit to a url with no further parts to it e.g. example.com/machines. It turns out that at some point within WordPress's guts, the empty string gets evaluated to false and thus skipped, so the final step is to hook into the filter 'request' and set a default value:

add_filter( 'request', function( $vars = [] ) {
    if ( isset( $vars['machines'] ) && empty( $vars['machines'] ) ) {
        $vars['machines'] = 'default';
    }
    return $vars;
});

This can easily be improved by wrapping it all in a class(es). The url parsing and template loading logic can be passed to a basic router, even a rudimentary MVC setup, loading routes from a file etc, but the above is the starting point.

Tags:

Php

Wordpress