-
-
Save samhernandez/8062848 to your computer and use it in GitHub Desktop.
<?php | |
/** | |
* NOTE: This gist is very old. You might want to check out recent forks | |
* like this one: https://github.com/Alexlytle/Wordpress_custom_route/blob/main/Wordpress_Custom_route.php | |
* (thanks @Alexlytle) If you have an improvement to this gist, please | |
* post a link in a comment for others who might benefit. Thanks! | |
* | |
* A class to create simple custom routes. | |
* | |
* Example usage: | |
* | |
* $theme_routes = new CustomRoutes(); | |
* $theme_routes->addRoute( | |
* | |
* // required, regex to match the route | |
* '^api/([^/]*)/([^/]*)/?', | |
* | |
* // required, a callback function name or | |
* // callable array like `array($object, 'method')` | |
* 'api_callback', | |
* | |
* // optional template path or array of template path candidates | |
* get_template_directory() . '/api-template.php', | |
* | |
* // query vars based on regex matches | |
* // will be passed to the callback function in the same order | |
* array($param1 => 1, $param2 => 2), | |
* ); | |
* | |
* function api_callback($param1, $param2) { | |
* // called before the optional template is invoked | |
* } | |
* | |
* Also: | |
* | |
* // Force flush rewrite rules. | |
* $theme_routes->forceFlush(); | |
* | |
* @author Sam Hernandez ([email protected]) | |
*/ | |
class CustomRoutes { | |
/** | |
* An array of route data indexed by regex. | |
* | |
* Example value: | |
* | |
* $routes['^widgets/([^/]*)/([^/]*)/?'] = array( | |
* 'callback' => 'some_function', // or array($object, 'someMethod') | |
* 'template' => '/template/path/to/file.php', | |
* 'query_vars' => array('param1' => 1, 'param2' => 2) | |
* ); | |
* | |
* @var array | |
*/ | |
protected $routes = array(); | |
/** | |
* Flag to force flushing existing rewrite rules. | |
* @var boolean | |
*/ | |
protected $force_flush = false; | |
/** | |
* Constructor | |
*/ | |
public function __construct() | |
{ | |
add_action('parse_request', array($this, 'parseRequestAction')); | |
add_filter('query_vars', array($this, 'queryVarsFilter')); | |
add_filter('rewrite_rules_array', array($this, 'rewriteRulesArrayFilter')); | |
add_action('wp_loaded', array($this, 'wpLoadedAction')); | |
} | |
/* | |
* | |
* Public methods | |
* | |
*/ | |
/** | |
* Force flush existing rewrite rules. | |
*/ | |
public function forceFlush() { | |
$this->force_flush = true; | |
} | |
/** | |
* Action callback for 'parse_request'. Handles the execution | |
* of custom routes by invoking the optional callback and optional | |
* template file if they are given for the matched route. | |
* | |
* @param WP $query | |
*/ | |
public function parseRequestAction($query) | |
{ | |
if ($query->matched_rule and isset($this->routes[$query->matched_rule])) | |
{ | |
$route = $this->routes[$query->matched_rule]; | |
$this->doCallback($route, $query); | |
if ($route['template']) { | |
$html = $this->doTemplate($route); | |
} | |
exit; | |
} | |
} | |
/** | |
* Add a route with params. | |
* | |
* @param string $match A regular expression for the url match | |
* @param string $callback Callback; function name or callable array such as `array($object, 'method')` | |
* @param string $template Optional template path | |
* @param array $query_vars An array of url query vars indexed by the var name, value being the regex match number. | |
*/ | |
public function addRoute($match, $callback, $template = null, $query_vars = array()) | |
{ | |
$this->routes[$match] = compact('callback', 'template', 'query_vars'); | |
} | |
/* | |
* | |
* Action and filter callbacks | |
* | |
*/ | |
/** | |
* Action callback for 'wp_loaded'. | |
* Flushes the current rewrite rules if a newly defined rule | |
* is missing or if the `$force_flush` flag is raised. | |
*/ | |
public function wpLoadedAction() | |
{ | |
$rules = get_option('rewrite_rules'); | |
$missing_routes = false; | |
foreach ($this->routes as $key => $value) { | |
$missing_routes += !isset($rules[$key]); | |
} | |
if ($missing_routes || $this->force_flush) { | |
global $wp_rewrite; | |
$wp_rewrite->flush_rules(); | |
} | |
} | |
/** | |
* Filter callback for 'rewrite_rules_array'. | |
* Adds new rules for newly defined routes. | |
* | |
* @param array $rules | |
* @return array | |
*/ | |
public function rewriteRulesArrayFilter($rules) | |
{ | |
$newrules = array(); | |
foreach ($this->routes as $match => $route) { | |
$newrules[$match] = $this->makeRuleUrl($route); | |
} | |
return $newrules + $rules; | |
} | |
/** | |
* Filter callback for 'query_vars'. | |
* @param array $vars | |
* @return array | |
*/ | |
public function queryVarsFilter($vars) | |
{ | |
foreach($this->routes as $route) | |
{ | |
foreach($route['query_vars'] as $key => $value) { | |
$vars[] = $key; | |
} | |
} | |
return $vars; | |
} | |
/* | |
* | |
* Protected methods | |
* | |
*/ | |
/** | |
* Invoke the callback for a given route. | |
* | |
* @param array $route An item from $this->routes | |
* @param WP $query | |
*/ | |
protected function doCallback($route, $query) | |
{ | |
$params = array(); | |
// params are in the same order as given in the array | |
foreach($route['query_vars'] as $name => $match) { | |
$params[] = $query->query_vars[$name]; | |
} | |
call_user_func_array($route['callback'], $params); | |
} | |
/** | |
* Includes a template for a given route if one is found. | |
* @param array $route An item from $this->routes | |
*/ | |
protected function doTemplate($route) | |
{ | |
$candidates = (array) $route['template']; | |
foreach($candidates as $candidate) | |
{ | |
if (file_exists($candidate)) | |
{ | |
include $candidate; | |
break; | |
} | |
} | |
} | |
/** | |
* Returns a url with query string key/value pairs as | |
* needed for rewrite rules. | |
* | |
* @param array $route An item from $this->routes | |
* @return string | |
*/ | |
protected function makeRuleUrl($route) | |
{ | |
$q_vars = array(); | |
foreach($route['query_vars'] as $name => $match) { | |
$q_vars[] = $name . '=$matches[' . $match . ']'; | |
} | |
return 'index.php?' . implode('&', $q_vars); | |
} | |
} |
Thank you so much this will completely change my work flow
How can I view the query_vars in the template:
My code:
// new route $theme_routes = new CustomRoutes(); $theme_routes->addRoute( "^parent/([^/]*)/?", [$this, 'api_callback'], get_stylesheet_directory() . '/parent-template.blade.php', array('param1' => 1, 'param2' => 2,) );
in my parent-template.blade.php I get null from
global $wp_query; var_dump($wp_query->query_vars);
Bit stumped - any ideas? Thanks for useful class!
Worked it out. Needed to set them in my api_callback()
set_query_var('param1', $param1);
Thank you for the api call back of setting a query he should of put this in the example comment
They only problem with this is that it hides the admin on the routes being used
@Alexlytle I am so sorry, I wish I could help, but I haven't done any WordPress work since I published this gist 8 years ago and I'm not familiar with it any more. If you have any improvements, I'm happy to publish them here or to link to a gist that you publish.
@samhernandez samhernandez
Oh wow no problem. I didn't realize it was so long ago
Here is a link to my GitHub of a updated version of this class!
https://github.com/Alexlytle/Wordpress_custom_route/blob/main/Wordpress_Custom_route.php
@Alexlytle thanks for the link! I updated the gist with a comment at the top.
If anyone else has an improvement please post a link to your work.
Hi! Thanks for this very nice class for custom GET routes, I used it many times!
To create API endpoints with the other REST methods, it's possible to combine the
rest_url_prefix
hook filter and theWP_REST_Server::register_route
method.First, customize the REST API prefix to match what you want,
/api
for example :And finally add your routes without namespace by passing them directly to the
WP_REST_Server
instance :This will add
/api/myendpoint
POST route to native REST API.