Wordpress: Create a plugin that automatically creates publicly facing page

  • by Amando Abreu
  • on 25 May 2017

Creating a front-end page for a plugin without manually creating a page

Many times a developer wants a plugin to have a page in a specific url, e.g.: site.com/plugin-page, but to be forced to create a page and select a custom template isn’t the best nor fastest way to do it, I will show you how to make this page available as soon as the plugin is activated, and gone when the plugin is deactivated. This is useful for example for a “contest” type plugin, site.com/contest

To automatically create a page for a plugin, we need to add some query vars, then rewrite the URLs, and load a template based on the query vars, that’s it!

Let’s get into code, I will use OOP PHP.

First, I will create the following directory and structure inside wp-content/plugins/:

  • /plugin-with-page/
    • /includes/
      • plugin-with-page.class.php
    • /templates/
      • pwp.php
    • plugin-with-page.php

The theory is the following: includes/plugin-with-page.class.php contains the PHP class of the plugin, plugin-with-page.php contains the plugin metadata(name, etc, as WP plugins do), and instantiates a new object of the class. The class contains functions that register a query var/rewrite rules to make the template templates/pwp.php available under for example: example.com/plugin-with-page.

Inside plugin-with-page.class.php we have our class that contains the following:

class pluginWithPage {
  public $pageName = "plugin-with-page"; // This will be the name/URL of the page, eg: example.com/plugin-with-page
  public function __construct(){

  public function init(){
    add_filter( 'query_vars', array($this, 'pwp_register_query_var' ));
    add_filter( 'template_include', array($this, 'pwp_template_include'), 1, 1); // Override normal template logic
    add_action( 'init', array($this, 'pwp_rewrite_rules' ));

  private function pwp_rewrite_rules() { // Rewrite rules for frontend page
      add_rewrite_rule( $this->pageName . '/?$', 'index.php?' . $this->pageName . '=true', 'top' );

  private function pwp_register_query_var( $vars ) { // query vars for rewrite rules
      $vars[] = $this->pageName;
      return $vars;

  private function pwp_template_include($template)
      global $wp_query; //Load $wp_query object
      @$page_value = $wp_query->query_vars[$this->pageName]; //Check for query var

      if (($page_value && $page_value == "true")) {
          $file = PWP_PLUGIN_PATH.'/templates/pwp.php';
          return $file;

      return $template; //Load normal template when $page_value != "true" as a fallback

What’s happening here exactly?

public $pageName = "plugin-with-page";

This variable holds the value plugin-with-page which is the name or “slug” the page will have, and the page will be accessible via example.com/plugin-with-page. Every time you change this, you shold refresh permalinks manually.

The init() function adds all the filters and actions for the functions to be called to override the default template logic, and registering custom query vars and rewrite rules.

plugin-with-page.php includes the plugin’s name, URI, etc, as WP plugins do, and instantiates a new object of the class.

    Plugin Name: Plugin with page
    Plugin URI:
    Version: 1.0.0
    Author: Amando Abreu
    Author URI:
define( 'PWP_PLUGIN_PATH', plugin_dir_path( __FILE__ ) );
$pwp = new pluginWithPage();

templates/pwp.php will include any special functionality you want the user to see!

Permalinks should be refreshed when the plugin is activated, it would be possible to add functionality to do so automatically and have the plugin’s slug saved in the database, but that’s out of the scope of this write-up.

About the author

Amando Abreu is a serial entrepreneur, Fractional CTO, and engineer who has been involved in several startups and launched dozens of products. He has worked with companies such as trivago, Portugal Telecom, and Vizrt. He has experience in several industries, most notably e-commerce, SaaS, media, travel, insurance, property development, and construction.
No comments, just