DevinVinson/WordPress-Plugin-Boilerplate

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.

jg314 commented

@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

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