I'm building a plugin which will basically build a knowledge base dynamically, by retrieving categories, articles, etc. from an external API where all documentation is being kept.
I've added a few custom rewrite rules, which capture the following:
- When /kb is hit,
- When /kb/category-name is hit (category-name can of course be anything)
- When /kb/category-name/article-name is hit (again, article-name can be anything)
What I want to achieve is the following:
- To avoid having to load custom templates, I simply want to add a shortcode (e.g. [kb_list_categories], [kb_list_articles] and [kb_article]) on a page, and then load that page when one of the rewrite rules matches.
So, I'd like to end up with a few pages:
- A knowledge-base page, containing the shorticode [kb_list_categories],
- A category page, containing the shortcode [kb_list_articles],
- A article page, containing the shortcode [kb_article].
The shortcode will be responsible for retrieving and displaying the content, based on the query vars retrieved from the URL.
I know how to create shortcodes, and everything. And I will eventually create a configuration page, so a user can define which pages are supposed to be used.
My question is strictly: How do I make WordPress load a certain page (NOT a page template), when one of the rewrite rules matches?
I found WooCommerce does the same with e.g. their checkout and account pages, and I've been digging through its code, but wasn't able to find anything useful, except for the use of add_rewrite_endpoint()
instead of add_rewrite_rule()
.
Here's the revelant code of what I have so far:
class Kb
{
const ARTICLE_REWRITE_RULE = 'kb/(.+)/(.+)/?';
const CATEGORY_REWRITE_RULE = 'kb/(.+)/?';
/**
* Set Fields.
*
* @return void
*/
public function __construct()
{
$this->init();
}
/**
* Start Plugin
*
* @return void
*/
private function init()
{
add_action('init', [$this, 'maybe_flush_rules'], 9);
add_filter('init', [$this, 'add_rewrite_rules']);
add_filter('query_vars', [$this, 'insert_query_vars']);
add_filter('template_include', [$this, 'include_template']);
}
/**
* Decide whether we should display our templates.
*
* @param mixed $template
*
* @return mixed
*/
public function include_template($template)
{
$category = get_query_var('docs_category');
$article = get_query_var('docs_article');
/**
* Here I'm loading templates, but that's what I want to get rid off.
*/
if ($category && !$article) {
return KB_PLUGIN_DIR . 'templates/category.php';
}
if ($category && $article) {
return KB_PLUGIN_DIR . 'templates/article.php';
}
return $template;
}
public function add_rewrite_rules()
{
add_rewrite_rule(self::ARTICLE_REWRITE_RULE, 'index.php?docs_category=$matches[1]&docs_article=$matches[2]', 'top');
add_rewrite_rule(self::CATEGORY_REWRITE_RULE, 'index.php?docs_category=$matches[1]', 'top');
}
public function insert_query_vars($vars)
{
array_push($vars, 'docs_category', 'docs_article');
return $vars;
}
/**
* Flush rewrite rules if this rule hasn't been set (yet)
*/
public function maybe_flush_rules()
{
$rules = get_option('rewrite_rules');
if (!isset($rules[self::ARTICLE_REWRITE_RULE]) || !isset($rules[self::CATEGORY_REWRITE_RULE])) {
global $wp_rewrite;
$wp_rewrite->flush_rules();
}
}
}