In my plugin, I want to be able to catch a slug - say 'testpath', as in www.mysite.com/testpath and output whatever I want from my plugin into the page.

I in WP Admin I could create a page called 'testpath', and put a shortcode in it (say, [testpath]), which is then implemented by the plugin, but I don't want the user of the plugin to have to create that page and enter the shortcode - it should all be handled by the plugin.

I can also create a post programmatically on plugin activation, then intercept it in the plugin, like

function create_custom_page($page_name) {
  $pages = get_pages();     
  foreach ($pages as $page) { 
    if ($page->post_name == $page_name) return;
  wp_insert_post ([
  'post_type' =>'page',        
  'post_name' => $page_name,
  'post_status' => 'publish',

And then:

add_filter( 'page_template', 'add_test_template' );
function add_test_template( $page_template ) {
  if ( is_page( 'testpath' ) ) {
    $page_template = __DIR__.'/testpath.html';
  return $page_template;

This works as I want - but it seems very kludgy. I'm thinking something with the Rewrite API or appropriate actions might be a better way to go. Are there any standard (or clever) approaches to this?

1 Answer 1

Plugin Name: Custom output
Description: A module to test the custom output. To test: http://your_wordpress_site.com/customop_uri_path
Version: 1.0
Author: Danilo Silva
Author URI: http://danilocgsilva.me

// Write a new permalink entry on code activation
register_activation_hook( __FILE__, 'customop_activation' );
function customop_activation() {
        flush_rewrite_rules(); // Update the permalink entries in the database, so the permalink structure needn't be redone every page load

// If the plugin is deactivated, clean the permalink structure
register_deactivation_hook( __FILE__, 'customop_deactivation' );
function customop_deactivation() {

// And now, the code that do the magic!!!
// This code create a new permalink entry
add_action( 'init', 'customop_custom_output' );
function customop_custom_output() {
        add_rewrite_tag( '%customop_uri_path%', '([^/]+)' );
        add_permastruct( 'customop_uri_path', '/%customop_uri_path%' );

// The following controls the output content
add_action( 'template_redirect', 'customop_display' );
function customop_display() {
        if ($query_var = get_query_var('customop_uri_path')) {
                header("Content-Type: text/plain");
                echo 'This is my custom content!!!!';
                exit; // Don't forget the exit. If so, WordPress will continue executing the template rendering and will not fing anything, throwing the 'not found page' 

Create a plugin with this exact code. Activate the plugin and test typing in the browser http://your_wordpress_site.com/customop_uri_path.

The registers functions deals with permalink structure, and are executed just in the plugin activation or plugin deactivation (to clean the permalinks entries, in case of not using anymore the plugin).

The real magic is done by the following code. There are two functions: one used in the plugin activation to create a new rewrite rule and add a permalink entry, and the other constrols the output display. The get_query_var function scans for uri arguments if there are your custom uri path created previously. If so, then, it executes the code to write your custom output. DON'T FORGET THE FINAL EXIT, or it will fall in the not found content page.

Scans for any ocurrence of 'customop_uri_path' in the code to customize your own uri address of your custom output. Honestly talking, I still did not understood whats going on in the add_rewrite_tag and add_permastruct arguments. So, just replace with your own uri path.

Also, assure that your apache rewrite module are working properly and your WordPress installation are setted to use the permalinks, or you will not see the module works.

  • if you're not going to use the main query, there's no reason to wait until template_redirect, you could hook parse_request instead and save some time and memory.
    – Milo
    Commented Jun 20, 2016 at 3:22
  • @danilocgsilva Could your example be used and cause the active theme's default page template to be used while still having control of the_content within the plugin?
    – rwkiii
    Commented Sep 18, 2016 at 20:56
  • At least for WP 5.4.2 I see this is overriding the response for all of the not defined rewrite rules. I mean, besides posts and pages links, it's affecting every url, not only the expected wpsite.test.com/customop_uri_path. I think we can use add_rewrite_rule to define a specific regular expression (to match just one path), and then associate it with a php file, and resolve as we please this way.
    – JCarlosR
    Commented Jun 19, 2020 at 22:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.