Secondary database query and shortcodes in Wordpress

Secondary database query and shortcodes in Wordpress

Created:20 Apr 2017 11:14:15 , in  Web development

Secondary database queries are queries that you do in Wordpress once the main, URL-based query has been performed. Typically, these extra queries are used to fetch data like featured or category post and embed it on in a section of a template file. Alternatively, the data goes in the body of a post or page. For the latter case, WordPress feature called shortcodes becomes invaluable.

On the surface, shortcodes are just WordPress-specific, square-brackets-delimited strings placed in the body of a post. They get saved in the database with the rest of the post contents. However, before a post contents is displayed on the screen, shortcodes embedded in it get replaced with return values of functions registered for them in earlier code.

In this post I present a very minimal PHP class which makes it easy to embed results of a secondary database query in a post content. My primary motivation behind writing it was to separate logic related to database query from HTML code in template files (this mixture is far too frequent in WordPress world). I also took care of simplicity of use and reusability of my code.

sWWWSecondaryQuery class

   Class: sWWWSecondaryQuery - WordPress secondary database query and shortcode
   Author : Sylwester Wojnowski
   WWW :
class sWWWSecondaryQuery{
  private $c = array(
    'query_args' => null,
    'shortcode_tag' => null,
    'callback' => null

  public function __construct($conf){    
    $this -> validate($conf); 
    $this -> c = array_merge($this ->c,$conf);
    add_shortcode($this -> c['shortcode_tag'],array($this, 'toHtml'));
    # do basic input validation
  protected function validate($conf){
    if(!isset($conf['query_args']) || !is_array($conf['query_args'])){
      throw new InvalidArgumentException('WP_Query query configuration arguments should be passed as an array');
    if(!isset($conf['shortcode_tag']) || !is_string($conf['shortcode_tag'])){
      throw new InvalidArgumentException('Shortcode name should be passed as a string');
    if(!isset($conf['callback']) || !is_callable($conf['callback'])){
      $this ->c['callback'] = function($data){
        return '';
  # clean up attributes, run db query 
  protected function query($atts){
    $allowed_atts = shortcode_atts($this -> c['query_args'], $atts);  
    return new WP_Query($allowed_atts);
  # return HTML 
  public function toHtml($atts){
    return $this -> c['callback']($this -> query($atts)); 

In short, sWWWSecondaryQuery does very basic validation on input data, cleans up possible extraneous arguments possibly passed with shortcode to it, carries out database query using instance of WP_Query class and returns a string.

Use example

In order to embed some new contents from the database in the current post with sWWWSecondaryQuery:

  1. Embed a shortcode in one of your WordPress posts or pages

  2. place sWWWSecondaryQuery PHP class in your template functions.php file ( alternatively in a plugin ) and instantiate an object with it passing a PHP array of configuration options.

  3. Configuration options are:

    • query_args - array - arguments for WP_Query class

    • shortcode_tag - string - shortcode tag you embeded in your post

    • [callback] - anonymous function - function that receives WP_Query object as its only argument and your HTML markup as its body. This argument is optional. If it is not given, no data will be displayed.

    Query_args is an array of arguments you pass normally to WP_Query object before making a database query with the object. See WordPress Codex WP_Query related pages for more information on what arguments objects of WP_Query class accept.

    Shortcode_tag is a string you enclose in squere brackets and embed in post contents while editing your post.

    If shortcode in the post contents is [my_shortcode], shortcode_tag will be my_shortcode.

    If shortcode in the post contents is [my_shortcode arg1=val1 arg2=val2], shortcode_tag will be still my_shortcode.

    Callback is the place where you describe a HTML template for the data fetched from the database. You do it the same way, and using the same tools and techniques, you do for primary queries in template files like index.php or page.php. Since functions used with shortcodes have to return a string, callback utilizes output buffering functions ob_start, ob_get_contents and ob_clean. Your HTML markup must be placed between calls to ob_start() and ob_get_contents() to be embedded and displayed correctly and without PHP errors.

    Here is a full example, in which titles and bodies of all posts currently in the database become fetched and embedded in the current page body as an unordered HTML list:

    1. Embed [all_posts_list] in one of your WordPress pages.

    2. In functions.php file instantiate and configure sWWWSecondaryQuery class as below:

    new sWWWSecondaryQuery(
      # allowed WP_Query arguments
        'query_args' => array(
          'post_type' => 'post'
        # name of shortcode
        'shortcode_tag' => 'all_posts_list',
        # HTML template for secondary query code
        'callback' => function($data){
          $html = '';
          # begin output buffering
          if ( $data -> have_posts() ):
    	  <?php while ( $data->have_posts() ): ?>
                <?php $data -> the_post(); ?>
    	        <?php the_title(); ?>
    	        <?php the_content(''); ?>
    	  <?php endwhile ?>
    	  <?php wp_reset_postdata(); ?>
          <?php else: ?>
    	 <p>Nothing found!</p>
          <?php endif ?>  
          # end output buffering
          $html = ob_get_contents();
          return $html;

    Shrinking configuration array

    As it stands, the configuration array, mostly due to fair amount of mixed code the anonymous function carries in it, looks quite clutterd. Probably, it is not a bad idea to move the callback to some dedicated class (let's call it SecondaryQueryCallbacks) now:

    class SecondaryQueryCallbacks{
      public static function theCallback($data){

    The anonymous function is not anonymous anymore, it is called theCallback now.

    After the changes the whole thing can be instantiated as below (works for PHP 5.5+):

    new sWWWSecondaryQuery(
      # allowed WP_Query arguments
        'query_args' => array(
          'post_type' => 'post'
        # name of shortcode
        'shortcode_tag' => 'all_posts_list',
        # HTML template for secondary query code
        'callback' => array(SecondaryQueryCallbacks::class,'theCallback')

    What's left is move SecondaryQueryCallbacks PHP class to some directory where other classes are kept, and possibly register some autoload function for painless utilization. These are just optional step, though.

    Parting thoughts

    I hope sWWWSecondaryQuery PHP class will prove to be a useful tool in your WordPress toolkit. Let me know how it worked for you. Comments are also welcome.

    This post was updated on 27 Apr 2017 15:58:59

    Tags:  php ,  wordpress 

Author, Copyright and citation


Sylwester Wojnowski

Author of the this article - Sylwester Wojnowski - is a sWWW web developer. He has been writing computer code for the websites and web applications since 1998.


©Copyright, 2024 Sylwester Wojnowski. This article may not be reproduced or published as a whole or in parts without permission from the author. If you share it, please give author credit and do not remove embedded links.

Computer code, if present in the article, is excluded from the above and licensed under GPLv3.


Cite this article as:

Wojnowski, Sylwester. "Secondary database query and shortcodes in Wordpress." From sWWW - Code For The Web .

Add Comment

Allowed BB Code - style tags: [b][/b], [i][/i], [code=text][/code],[code=javascript][/code],[code=php][/code],[code=bash][/code],[code=css][/code],[code=html][/code]

I constent to processing my data given through this form for purposes of a reply by the administrator of this website.

Recent Comments

Nobody has commented on this post yet. Be first!