Override wordpress routing / url rewriting?

Viewed 1082

I would like to serve different content based on the URL. I started with a custom page setup via a custom template but I am open to something else.

The main goal is to have one PHP page that can serve different contents programmatically based on the URL.

For example:

https://some-url.com/my-plugin/ -> run my page
https://some-url.com/my-plugin/foo/ -> run my page
https://some-url.com/my-plugin/foo2/abc/ -> run my page
etc...

I have been looking at add_rewrite_rule, add_rewrite_tag, flush_rewrite_rules and WP_Rewrite API but I am getting confused about which one I should use?

I found an example here but I could not make it work, I get 404s, any idea why?:

 /*
   Plugin Name: Products Plugin
   Plugin URI: http://clivern.com/
   Description: Register URL rules for our products
   Version: 1.0
   Author: Clivern
   Author URI: http://clivern.com
   License: MIT
  */
 function products_plugin_activate() {
  products_plugin_rules();
  flush_rewrite_rules();
 }

 function products_plugin_deactivate() {
  flush_rewrite_rules();
 }

 function products_plugin_rules() {
  add_rewrite_rule('products/?([^/]*)', 'index.php?pagename=products&product_id=$matches[1]', 'top');
 }

 function products_plugin_query_vars($vars) {
  $vars[] = 'product_id';
  return $vars;
 }

 function products_plugin_display() {
  $products_page = get_query_var('pagename');
  $product_id = get_query_var('product_id');
  if ('products' == $products_page && '' == $product_id):
   //show all products
   exit;
  elseif ('products' == $products_page && '' != $product_id):
   //show product page
   exit;
  endif;
 }

 //register activation function
 register_activation_hook(__FILE__, 'products_plugin_activate');
 //register deactivation function
 register_deactivation_hook(__FILE__, 'products_plugin_deactivate');
 //add rewrite rules in case another plugin flushes rules
 add_action('init', 'products_plugin_rules');
 //add plugin query vars (product_id) to wordpress
 add_filter('query_vars', 'products_plugin_query_vars');
 //register plugin custom pages display
 add_filter('template_redirect', 'products_plugin_display');
2 Answers

First of all, make sure your pretty permalinks are enabled, in this case the option "Plain" in Settings - Permalinks should be unselected: Select one of these options to enable pretty permalinks

You can check whether pretty permalinks are enabled in the code like so:

function is_enabled_pretty_permalinks() {
    return !empty( get_option( 'permalink_structure' ) );
}

if ( is_enabled_pretty_permalinks() ) {
    echo 'Pretty permalinks enabled';
}

Next add a new rewrite rule:

function add_my_rewrite_rule() {
   $page_slug = 'products'; // slug of the page you want to be shown to
   $param     = 'do';       // param name you want to handle on the page

   add_rewrite_rule('my-plugin/?([^/]*)', 'index.php?pagename=' . $page_slug . '&' . $param . '=$matches[1]', 'top');
}
add_action('init', 'add_my_rewrite_rule');

Add your parameter to query vars so you will be able to handle it on the page:

function add_my_query_vars($vars) {
    $vars[] = 'do'; // param name you want to handle on the page
    return $vars;
}
add_filter('query_vars', 'add_my_query_vars');

Then you can access your query var do in the page template or in a shortcode, for example:

function my_plugin_shortcode_handler( $atts ){
  $do = get_query_var( 'do' );
  if ( $do === 'this' ) {
     return 'do this';
  } else {
     return 'do that';
  }
}
add_shortcode( 'myshortcode', 'my_plugin_shortcode_handler' );

Then place the shortcode to the content via Gutenberg.

Check out the links:

https://some-url.com/my-plugin/this/ - outputs "do this"
https://some-url.com/my-plugin/that/ - outputs "do that".

This can be solved by using query params. Like you mentioned you have set up custom page via a custom template. You can read the URL and check for the parameters and based on that you can send data from the PHP template page.

e.g,

 function cleanTheInput($data) {
     $data = trim($data);
     $data = stripslashes($data);
     $data = htmlspecialchars($data);
     $data = htmlentities($data);
     return $data;
 }

 if (isset($_GET['page_url'])) {
    $theUrl = cleanTheInput($_GET['page_url']);
 }

 if($theUrl == 266)){
  // data for https://some-url.com/?page_url=266
 }
  if($theUrl == 366)){
  // data for https://some-url.com/?page_url=366
 }
Related