How to add public shortcodes
tprinty opened this issue ยท 35 comments
Hello,
I am not clear on how to add a public shortcode? Can you provide an example?
Thanks
-Tom
I got this to work.... In class-myplugin-public on the define-hooks()
I added
$this->loader->add_action( 'shortcode', $plugin_public, 'shortcode_function' );
add_shortcode( 'shortcode', array( $plugin_public, 'shortcode_function') );
An alternative (in case you want to add other shortcodes) would be to create a public function that contains all the add_shortcode declarations. Then the separate function for processing the shortcode. Something like:
define_hooks() {
$this->loader->add_action( 'shortcode', $plugin_public, 'register_shortcodes' );
}
public function register_shortcodes() {
add_shortcode( 'shortcode', array( $this, 'shortcode_function') );
add_shortcode( 'anothershortcode', array( $this, 'another_shortcode_function') );
}
@slushman When you used:
define_hooks() {
$this->loader->add_action( 'shortcode', $plugin_public, 'register_shortcodes' );
}
Didn't you mean?:
define_hooks() {
$this->loader->add_action( 'init', $plugin_public, 'register_shortcodes' );
}
There is no hook to 'shortcode'.
Thanks for sharing your method, helped me a lot!
Doh! Yes, Bruno, bad copy/paste. The hook should be init.
@slushman Why do we need a separate function for hooks? Why can't we simply use $this->loader->add_action( 'init', $plugin_public, 'register_shortcodes' );
inside define_public_hooks()
function?
Sorry if I misunderstood this comment - #262 (comment)
Does anyone have or know where i can find a complete shortcode plugin based on this boilerplate and @slushman's recommendation for multiple shortcodes that I could look at? I feel like I am missing some info. I would be happy to share a folder in Dropbox or, get it from here if it's on here.
Thanks in advance.
What I've done recently is add an add_shortcode function to the loader class. That way you can add shortcodes that are admin or public leaning just like you would a filter or action.
I'm on the fence of calling them always one or the other but this way it can be up to you or even both.
In loader:
/**
* Add a new shortcode to the collection to be registered with WordPress
*
* @since 1.0.0
* @param string $tag The name of the new shortcode.
* @param object $component A reference to the instance of the object on which the shortcode is defined.
* @param string $callback The name of the function that defines the shortcode.
*/
public function add_shortcode( $tag, $component, $callback) {
$this->shortcodes = $this->add( $this->shortcodes, $tag, $component, $callback );
}
then change the run function to:
/**
* Register the filters, actions, and shortcodes with WordPress.
*
* @since 1.0.0
*/
public function run() {
foreach ( $this->filters as $hook ) {
add_filter( $hook['hook'], array( $hook['component'], $hook['callback'] ), $hook['priority'], $hook['accepted_args'] );
}
foreach ( $this->actions as $hook ) {
add_action( $hook['hook'], array( $hook['component'], $hook['callback'] ), $hook['priority'], $hook['accepted_args'] );
}
foreach ( $this->shortcodes as $hook ) {
add_shortcode( $hook['hook'], array( $hook['component'], $hook['callback'] ) );
}
}
Hmm looks good but won't this is throwing a bunch of errors for me in the add method regarding missing arguments.
@ gthapar: Sorry for the super-late response! The way I'm describing in #262 is just an abbreviated version of the define_public_hooks method already in the boilerplate. The way the boilerplate is setup, all the hooks are done together in one method. The 'register_shortcodes' method in the public class is where you'd actually register the shortcode and another method in the public class would take care of what happens in that shortcode.
@t1mduma5 also: you can see how all this flows in a plugin I put together called Now Hiring: https://github.com/slushman/now-hiring
I've only defined one shortcode, but adding another one would simply be a matter of adding another register_shortcode() in the 'register_shortcodes' method in the public class and writing the appropriate method to handle whatever that other shortcode does.
@rohan-deshpande You can edit the required arguments so that it doesn't.
@DevinVinson, your suggestions at #262 (comment) worked great for me. I did go ahead and add a $shortcode property and adjusted the add_shortcode() method slightly to include the $priority and $accepted_args arguments which got rid of the errors. It now reads:
public function add_shortcode( $tag, $component, $callback, $priority = 10, $accepted_args = 2 ) {
$this->shortcodes = $this->add( $this->shortcodes, $tag, $component, $callback, $priority, $accepted_args );
}
Thanks for the help.
This should come in plugin boilerplate. Its easy to remove unnecessary code if you dont need shortcodes in your plugin.
Hi, i am creating a custom plugin based on boilerplate plugin, and i use a shortcode to display public data.
$this->loader->add_action( 'test-plugin', $plugin_public, 'display_front_page' );
add_shortcode( 'test-plugin', array( $plugin_public, 'display_front_page') );
The issue is that on every public page, that the shortcode is used, at the end of the page i get the number 1.
I really cannot find where is this number 1 produced from.
Any idea?
Check return vs echo, can you post your whole code?
On 22 Oct 2015, at 10:49, George notifications@github.com wrote:
Hi, i am creating a custom plugin based on boilerplate plugin, and i use a shortcode to display public data.
$this->loader->add_action( 'test-plugin', $plugin_public, 'display_front_page' );
add_shortcode( 'test-plugin', array( $plugin_public, 'display_front_page') );The issue is that on every public page, that the shortcode is used, at the end of the page i get the number 1.
I really cannot find where is this number 1 produced from.Any idea?
โ
Reply to this email directly or view it on GitHub.
I am new to this plugin boilerplate, and I have a lot to learn about it still, but would you please explain to me what are the pros and cons of the two methods:
@slushman's method
#262 (comment)
define_public_hooks() {
$this->loader->add_action( 'init', $plugin_public, 'register_shortcodes' );
}
public function register_shortcodes() {
add_shortcode( 'shortcodename', array( $this, 'shortcode_function') );
add_shortcode( 'anothershortcodename', array( $this, 'another_shortcode_function') );
}
and
@DevinVinson's method
#262 (comment)
/**
* Add a new shortcode to the collection to be registered with WordPress
*
* @since 1.0.0
* @param string $tag The name of the new shortcode.
* @param object $component A reference to the instance of the object on which the shortcode is defined.
* @param string $callback The name of the function that defines the shortcode.
*/
public function add_shortcode( $tag, $component, $callback) {
$this->shortcodes = $this->add( $this->shortcodes, $tag, $component, $callback );
}
/**
* Register the filters, actions, and shortcodes with WordPress.
*
* @since 1.0.0
*/
public function run() {
foreach ( $this->filters as $hook ) {
add_filter( $hook['hook'], array( $hook['component'], $hook['callback'] ), $hook['priority'], $hook['accepted_args'] );
}
foreach ( $this->actions as $hook ) {
add_action( $hook['hook'], array( $hook['component'], $hook['callback'] ), $hook['priority'], $hook['accepted_args'] );
}
foreach ( $this->shortcodes as $hook ) {
add_shortcode( $hook['hook'], array( $hook['component'], $hook['callback'] ) );
}
}
I am looking for - we do it this way or that way because...
I could not think of a good situation when a plugin will need to register multiple shortcodes. If your plugin has more than one you probably need to create new plugins for the extra shortcodes
Hey Radi,
I think either is perfectly fine. The first way is what I started with and I think it matches more closely to the Codex examples.
However, I've started using the latter method recently and now prefer it. I look at shortcodes as a hook, of sorts, and using the loader class to declare which function processes a shortcode seems more efficient than declaring a function that then points to other functions. I'm sure Devin has better reasons. :)
As far as multiple shortcodes, I've run into a few situations recently where the end-user needed a separate shortcode to display different content that wouldn't be easily accomplished using a shortcode attribute. WooCommerce has several examples of this kind of thing. I see it provides the non-technical end-user a method of pseudo-designing a page for their needs without needing to write code. I'm not quite done with the functionality around those additional shortcodes, so I don't believe its up on Github just yet.
There are a lot of reasons why a plugin would be adding multiple shortcodes. So think of that as a given.
With that said, I think either will work though I like adding to the loader since it means the formatting and logic stays the same.
Thank you for replying so fast! I will take your word for it.
Probably this it not the right place to discuss this, but I am curious in what situations would you want/need multiple different shortcodes in your plugin?
For instance, I'm just doing a plugin which is creating multiples shortcodes automatically for a template system where each field becomes a shortcode of type [prefix_my_field]. Usefull instead of writing them down, especially if it's dynamically generated.
I add mine via the loader as well.
OK, so I followed your lead and implemented the add_shortcode method in the loader, but now I get this:
Notice: Undefined property: Pluginname_Loader::$shortcodes in ...\wp-content\plugins\pluginname\includes\class-pluginname-loader.php on line 95
and line 95 is a comment
Did you declared var $shortcodes in the beginning of file "class-pluginname-loader.php" ?
protected $shortcodes;
By the way, your files should be renamed with your plugin name, but that's not an issue I think.
I am sorry, I was working late last night and for some reason I had hardcoded that warning in my shortcode return...
LOL
I am unable to get my shortcode working as described by @DevinVinson andupdated by @jg314
here is my loader file's code
protected $shortcodes;
/**
* Initialize the collections used to maintain the actions and filters.
*
* @since 1.0.0
*/
public function __construct() {
$this->actions = array();
$this->filters = array();
$this->shortcodes = array();
}
public function add_shortcode( $tag, $component, $callback, $priority = 10, $accepted_args = 2 ) {
$this->shortcodes = $this->add( $this->shortcodes, $tag, $component, $callback, $priority, $accepted_args );
}
public function run() {
foreach ( $this->filters as $hook ) {
add_filter( $hook['hook'], array( $hook['component'], $hook['callback'] ), $hook['priority'], $hook['accepted_args'] );
}
foreach ( $this->actions as $hook ) {
add_action( $hook['hook'], array( $hook['component'], $hook['callback'] ), $hook['priority'], $hook['accepted_args'] );
}
foreach ( $this->shortcodes as $hook ) {
add_shortcode( $hook['hook'], array( $hook['component'], $hook['callback'] ), $hook['priority'], $hook['accepted_args'] );
}
}
and code from public class file is
public function define_hooks() {
$this->loader->add_shortcode( "testShortcode", $this->Ec_Authorizenet, "shortcode_function", $priority = 10, $accepted_args = 2 );
}
public function shortcode_function(){
echo 'Test the plugin';
}
Can u place whole public class file, use gist
Sent from my iPhone
On 21 Apr 2016, at 05:09, sftranna notifications@github.com wrote:
I am unable to get my shortcode working as described by @DevinVinson andupdated by @jg314
here is my loader file's code
protected $shortcodes;/**
Initialize the collections used to maintain the actions and filters.
*@SInCE 1.0.0
*/
public function __construct() {$this->actions = array();
$this->filters = array();
$this->shortcodes = array();}
public function add_shortcode( $tag, $component, $callback, $priority = 10, $accepted_args = 2 ) {
$this->shortcodes = $this->add( $this->shortcodes, $tag, $component, $callback, $priority, $accepted_args );
}
public function run() {foreach ( $this->filters as $hook ) { add_filter( $hook['hook'], array( $hook['component'], $hook['callback'] ), $hook['priority'], $hook['accepted_args'] ); } foreach ( $this->actions as $hook ) { add_action( $hook['hook'], array( $hook['component'], $hook['callback'] ), $hook['priority'], $hook['accepted_args'] ); } foreach ( $this->shortcodes as $hook ) { add_shortcode( $hook['hook'], array( $hook['component'], $hook['callback'] ), $hook['priority'], $hook['accepted_args'] ); }
}
and code from public class file is
public function define_hooks() {
$this->loader->add_shortcode( "testShortcode", $this->Ec_Authorizenet, "shortcode_function", $priority = 10, $accepted_args = 2 );
}public function shortcode_function(){ echo 'Test the plugin'; }
โ
You are receiving this because you commented.
Reply to this email directly or view it on GitHub
I have created the gist for both loader and public files, please have a look
https://gist.github.com/sftranna/2dae207cc9912f7b64fec88bacb7066d
2dae207cc9912f7b64fec88bacb7066d-0d3f374ab4d3ef60a8296119da87fb2aed8a8b29.zip
You'll want to put this line:
$this->loader->add_shortcode( "testShortcode", $this->plugin_name, "shortcode_function", $priority = 10, $accepted_args = 2 );
Inside the define_public_hooks() function in the main plugin file. Check out these changes:
$this->loader->add_shortcode( "testShortcode", $public_class, "shortcode_function", 10, 2 );
Change "$this->plugin_name" above to reference the public class and remove the "$priority" and "$accepted_args" variables.
Thanks @slushman and @goranefbl this solved the issue.
@slushman i am now following your plugin https://github.com/slushman/now-hiring as a template for my plugin. Thanks for the working example. Love this ๐ฏ
@sftranna I'm using your example at https://gist.github.com/sftranna/2dae207cc9912f7b64fec88bacb7066d but the shortcodes defined inside the public class on define_hooks are not being added at all.
Shouldn't the define_hooks function be called somewhere?
@sftranna I've added $this->loader->add_action( 'init', $plugin_public, 'define_hooks' );
to the define_public_hooks function on the main class but I'm now getting "Call to a member function add_shortcode() on a non-object" on the define_hooks function maybe because $this is not a Loader class function.
@webdados looking at your gist file I believe the function you are trying to call is 'shortcode_function' so you need to change to $loader->add_action( 'init', $plugin_public, 'shortcode_function' )
You are getting the 'non-object' error because you are trying to call the loader class in a file where it doesn't exist. You don't need to use $this->loader->add_shortcode(...)
unless you are using @DevinVinson method because you are already adding the shortcodes within the 'shortocde_function'.
@webdados Also your define_hooks function is not necessary so you should remove it.
i fix those shortcode script by this line :
public function add_shortcode( $tag, $component, $callback, $priority = 10, $accepted_args = 1) {
$this->shortcodes = $this->add( $this->shortcodes, $tag, $component, $callback, $priority, $accepted_args );
}
@DevinVinson, your suggestions at #262 (comment) worked great for me. I did go ahead and add a $shortcode property and adjusted the add_shortcode() method slightly to include the $priority and $accepted_args arguments which got rid of the errors. It now reads:
public function add_shortcode( $tag, $component, $callback, $priority = 10, $accepted_args = 2 ) { $this->shortcodes = $this->add( $this->shortcodes, $tag, $component, $callback, $priority, $accepted_args ); }
Thanks for the help.
It worked for me
Hello. I have a problem with elementor.
When I create a new Shortcode.
I have defined Protected $shortcode and public function shortcode() in loader, how was written here.
Usually, Shortcode works, but when I insert it with elementor and when I edit this page again, elementor says error: Session expired
https://image.prntscr.com/image/ajXgmN4qS72U0hmfclQdCA.png
how can I solve this problem?
Thanks