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 : wojnowski.net.pl
*/
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:
Embed a shortcode in one of your WordPress posts or pages
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.
-
query_args - array - arguments for WP_Query class
[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.
Embed [all_posts_list] in one of your WordPress pages.
In functions.php file instantiate and configure sWWWSecondaryQuery class as below:
Configuration options are:
shortcode_tag - string - shortcode tag you embeded in your post
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:
new sWWWSecondaryQuery(
# allowed WP_Query arguments
array(
'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
ob_start();
if ( $data -> have_posts() ):
?>
<ul>
<?php while ( $data->have_posts() ): ?>
<?php $data -> the_post(); ?>
<li>
<h3>
<?php the_title(); ?>
</h3>
<div>
<?php the_content(''); ?>
</div>
</li>
<?php endwhile ?>
<?php wp_reset_postdata(); ?>
</ul>
<?php else: ?>
<p>Nothing found!</p>
<?php endif ?>
<?php
# end output buffering
$html = ob_get_contents();
ob_end_clean();
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
array(
'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
Author, Copyright and citation
Author
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.
Copyrights
©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.
Citation
Cite this article as:
Wojnowski, Sylwester. "Secondary database query and shortcodes in Wordpress." From sWWW - Code For The Web . https://swww.com.pl//main/index/secondary-database-query-and-shortcodes-in-wordpress
Add Comment