Render wordpress shortcode within page content

I have written a wordpress plugin. It is a collection of shortcodes which fetch, parse and render data from an API.
I am now currently writing a theme to support this plugin. I’m noticing that WordPress seperates shortcode content from editor content and renders them seperately.
Here is an illustration of my issue:
Editing a Page or a Post in the admin panel:

<div class="row">
   <div class="col-lg-12">
     <p>HERE</p>
     [PluginShortcode_1]
   </div>
 </div>

Let’s say that PluginShortcode_1 generates the following html:

Read More
<h1>This is the output of PluginShortcode_1</h1>
  <p>Got Here!</p>

I would like to expect the output to be:

<div class="row">
   <div class="col-lg-12">
     <p>HERE</p>
     <h1>This is the output of PluginShortcode_1</h1>
        <p>Got Here!</p>
   </div>
 </div>

But rather, the following is sent to the browser:

<h1>This is the output of PluginShortcode_1</h1>
  <p>Got Here!</p>
<div class="row">
   <div class="col-lg-12">
     <p>HERE</p>
   </div>
 </div>

Apparently wordpress does the following:

  1. Parse and render shortcode content
  2. Render post content

I’ve seen references to do_shortcode() But my plugin defines many shortcodes and would not explicitly know in the template.php which shortcode or shortcodes are on the page without parsing the content beforehand, selecting all of the shortcodes and applying the filters.

UPDATE:

The shortcode functions are within a set of classes which handle all of the rendering. Most of the shortcode content is store seperately in a “view” script which renders the content.

The example above would be invoked in the following way:

shortcodes.ini – a list of shortcodes and their associated functions:

[shortcode_values]
PluginShortcode_1 = shortcodeOne
AnotherShortcode  = anotherShortcode

Shortcodes.php – container for shortcode functions and invocation:

public function __construct() {
  $ini_array = parse_ini_file(__DIR__. '/shortcodes.ini', true);
  $this->codeLib = $ini_array['shortcode_values'];
  foreach ($this->codeLib as $codeTag => $codeMethod) {
    add_shortcode($codeTag, array(&$this, $codeMethod));
  }
}

public function shortcodeOne() {
  require_once(__DIR__ . 'views/shortcodeOneView.php');
}

views/shortcodeOneView.php

<?php
?>
  <h1>This is the output of PluginShortcode_1</h1>
    <p>Got here!</p>

Where the shortcode function would actually be responsible for fetching data, setting variables which would be exposed to the view.

UPDATE
To complicate matters further, since this plugin makes API requests, I restrict it to only be invoked if the post content actually contains a shortcode.

In the plugin initialization script, I have the following:

class myPlugin.php:

public function __construct() {
  . . .
  add_filter('the_posts', array(&$this, 'isShortcodeRequest'));
  . . .
}

public function isShortcodeRequest($posts) {
    if (empty($posts)) { return $posts; }
    foreach ($posts as $post) {
      if (stripos($post->post_content, '[PluginShortcode') !== false) {
        $shortcodes = new Shortcodes();
        break;
      }
    }
    return $posts;
  }

My concern is that this filter may be responsible for hijacking the output. . .(?)

Related posts

2 comments

  1. The issue is the shortcode call back, you are “echo” instead of returning this, you should replace shortcodeOne() with this :

    public function shortcodeOne() {
      return "<h1>This is the output of PluginShortcode_1</h1><p>Got here!</p>";
    }
    

    WordPress parses it’s output before printing it, and in your case when it parsed PluginShortcode_1 in order to get it’s content it you printed it and WordPress had null in return.

  2. Meh. In wp-includes function do_shortocode() on lines 199 – 200:

    $pattern = get_shortcode_regex();
        return preg_replace_callback( "/$pattern/s", 'do_shortcode_tag', $content );
    

    the preg_replace is operating on a string. The function is called. The output of said function is interpolated with the content.

    So, output buffering to the rescue!

    public function shortcodeOne() {
      ob_start();
      require_once(__DIR__ . 'views/shortcodeOneView.php');
      $buffer = ob_get_clean();
      return $buffer;
    }
    

    Produces the expeced output! Whew. (Just as a side note, all of my shortcode functions call a render method that requires the file. Saves me from a lot of updates. Thanks @all!
    }

Comments are closed.