1

I have a plugin that is using Class style programming. I'm completely stumped - scripts are being loaded on every single page, even if the plugin is not being used on that page.

Since the plugin should only run when one of its shortcodes are called, I don't understand why they are always being enqueued. The code is:

<?php
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly

add_action( 'plugins_loaded', array ( 'Lipstick_Consultation', 'init' ));

if (!class_exists('Lipstick_Consultation')){

//used for the script loader, to load custom jquery at the footer
$plugin_script = "";

class Lipstick_Consultation{

    public static function init() {
        $class = __CLASS__;
        new $class;
    }

    /**
     * @since 1.0
     */
    public function __construct() {

        //get contstants
        $this->setup_constants();

        //get file includes
        $this->includes();

        //register plugin shortcodes
        $this->register_shortcodes();

        //Register Styles
        add_action( 'wp_enqueue_scripts', array( $this, 'register_styles' ) );

        //Register Scripts
        add_action( 'wp_enqueue_scripts', array( $this, 'register_scripts' ) );

        $this->page_scripts();

        return $this;
    }

    /**
     * Include our Class files
     *
     * @access private
     * @since 1.0.0
     * @return void
     */
    private function includes() {

        /****SHORTCODES****/
        //[slider_person]
        require_once LC_DIR . 'inc/shortcodes/slider.php';

        //[suggested_colors]
        require_once LC_DIR . 'inc/templates/tmpl-suggestedcolors.php';
    }

    /**
     * Setup plugin constants
     *
     * @access private
     * @since 1.0.0
     * @return void
     */
    private function setup_constants() {

        // Plugin information
        define( 'LC_VERSION',       '1.0.0' ); // Current plugin version
        define( 'LC_URL',           plugin_dir_url( __FILE__ ) );
        define( 'LC_DIR',           plugin_dir_path( __FILE__ ) );

    }

    /**
     * Register Styles
     *
     * @access private
     * @since 1.0.0
     * @return void
     */
    public function register_styles() {

        //main style file
        wp_register_style( 'consultation_style', LC_URL . "assets/css/style.css", array(), time(), 'all' );
        wp_enqueue_style( 'consultation_style' );

        //styles for full page plugin
        wp_register_style( 'lc_full_page_style', LC_URL . "assets/css/jquery.fullPage.css", array(), time(), 'all' );
        wp_enqueue_style( 'lc_full_page_style' );

    }

    /**
     * Register Scripts
     *
     * @access private
     * @since 1.0.0
     * @return void
     */
    public function register_scripts() {
        //Script that makes div have a scrollbar
        wp_register_script( 'lc_slim_scroll', LC_URL . "assets/js/jquery.slimscroll". SUFFIX . ".js", array( 'jquery' ), time() );
        wp_enqueue_script( 'lc_slim_scroll' );


        //Script that makes full width/height/page divs
        wp_register_script( 'lc_full_page', LC_URL . "assets/js/jquery.fullPage". SUFFIX . ".js", array( 'jquery' ), time() );
        wp_enqueue_script( 'lc_full_page' );

    }

    private function register_shortcodes(){
        //slider for "Choose You" Slider
        add_shortcode("lipstick_person", array('Lipstick_Consultation', "shortcode_person_slider"));

        //Template for lipstick color suggestions
        add_shortcode("suggested_colors", array($this, "suggested_colors_template"));
    }

    private function page_scripts(){

        //load fullPage jquery code
        $this->add_full_page_script();

    }

    /*
    *function to echo the script that triggers the plugin
    */
    public function add_script_footer(){
        echo $this->plugin_script;
    } 

    /**********************************************************************/
    /**********************************************************************/
    /*************MAY BE BETTER TO INCLUDE THIS IN ITS OWN FILE************/
    /**********************************************************************/
    /**********************************************************************/

    /*
    * Add script to get the full page effect on all page elements (this is for the page content)
    */
    private function add_full_page_script(){
        ob_start();
    ?>
        <!--jQuery Function to Trigger the plugin for this page-->
        <script type="text/javascript">
        //on document ready
        jQuery(document).ready(function($){
            $('#fullpage').fullpage({
                anchors:['instructions', 'choose-you', 'consultation-suggested-colors', 'all-colors'],
                scrollOverflow: true

                //look into the menu option https://github.com/alvarotrigo/fullPage.js

            });
        });


        </script>

    <?php
        //get jQuery script, set it as global script variable and call the WP callback
        $script = ob_get_contents();
        ob_end_clean();

        //set variable to the script above
        $this->plugin_script = $script;

        //call hook to add script to footer.
        add_action('wp_footer', array($this,'add_script_footer'),20); 

    }
}
}
?>

If I understand what is happening, on the plugins_loaded hook the plugin is being instantiated. When the construct method is being called it is enqueing the scripts. That all makes sense.

When looking at other plugins it looks as though they use a similar structure, yet - their script files are only loaded when their plugin is being invoked on that page.

What am I doing wrong? Thanks!

UPDATE #1

Guys, I just cannot figure out how to do this. I made the following edits to the code:

    public function __construct() {

        //get contstants
        $this->setup_constants();

        //get file includes
        $this->includes();

        //register plugin shortcodes
        $this->register_shortcodes();

        return $this;
    }

    /**
     * Registers the styles and scripts for the shortcodes
     */
    private function register_shortcode_requirements() {

        //Register Styles
        add_action( 'wp_enqueue_scripts', array( $this, 'register_styles' ) );

        //Register Scripts
        add_action( 'wp_enqueue_scripts', array( $this, 'register_scripts' ) );

    }

    /**
     * Register Styles
     */
    public function register_styles() {

        //main style file
        wp_register_script( 'consultation_style', LC_URL . "assets/css/style.css", array(), time(), 'all' );
        wp_enqueue_script( 'consultation_style' );

        //styles for full page plugin
        wp_register_script( 'lc_full_page_style', LC_URL . "assets/css/jquery.fullPage.css", array(), time(), 'all' );
        wp_enqueue_script( 'lc_full_page_style' );

    }

    /**
     * Register Scripts
     */
    public function register_scripts() {
        //Script that makes div have a scrollbar
        wp_register_script( 'lc_slim_scroll', LC_URL . "assets/js/jquery.slimscroll". SUFFIX . ".js", array( 'jquery' ), time() );
        wp_enqueue_script( 'lc_slim_scroll' );


        //Script that makes full width/height/page divs
        wp_register_script( 'lc_full_page', LC_URL . "assets/js/jquery.fullPage". SUFFIX . ".js", array( 'jquery' ), time() );
        wp_enqueue_script( 'lc_full_page' );

    }

    private function register_shortcodes(){
        //slider for "Choose You" Slider
        add_shortcode("lipstick_person", array($this,"shortcode_person_slider_caller"));

    }
    /*
    * Calling Function to include scripts and then fire the actual shortcode function contained in separate .php file
     */
    public function shortcode_person_slider_caller($atts, $content){

        //register styles/scripts
        $this->register_shortcode_requirements();

        //run actual function for rendering
        $content = shortcode_person_slider($atts);
        return $content;
    }

Then in the caller function the shortcode_person_slider is a function included in one of the require_once loaded files.

The function is firing (tested with a var_dump) in that function and it displays. Yet, the content is not displaying on the page (even though $content has all of the html markup).

Further, the script/style files are not being enqueued.

When testing, the register_shortcode_requirements() is firing, but each of the wp_enqueue_script hooks are not.

Any advice? Thank you!

2 Answers 2

2

As Rarst already noted, you answered your question. You are telling the software to load those scripts all the time. You need to control that process. Software is stupid. It can't decide when a good time is to load the code. SO...

Since the plugin should only run when one of its shortcodes are called, ...

Since you say the script should load only when a shortcode is used, go ahead and register your scripts but enqueue then in the shortcode handler, like this from another question:

function my_shortcode( $atts, $content = null ) {
    extract(shortcode_atts(array(
            'title'  => '',
           ), $atts));
    static $counter = 0;
    echo $counter++;
    wp_enqueue_script('wp-mediaelement'); 

}
add_shortcode('enq','my_shortcode');

Your script will load in the footer of the page, so make sure the Javascript can manage that.

As for your stylesheet,

  1. You can load those in the footer of the page similarly to the scripts. This is invalid markup but tends to work.
  2. You can load the styles inline in the shortcode, which is a decent option, maybe the best one.
  3. You can have the javascript insert the styles dynamically
  4. You can "pre-process" the shortcode, similarly to this (which is a resource intensive solution): https://wordpress.stackexchange.com/a/101515/21376
4
  • thanks for the code sample and stylesheet options. What about the processing time of enqueing the same script multiple times if the shortcode is used multiple times on the same page? Jun 12, 2015 at 16:04
  • That is kinda what the enqueue system is meant for... that and handling dependencies. If the script is enqueued correctly, the system will handle it. You will only the load the file once. Processing time shouldn't be an issue.
    – s_ha_dum
    Jun 12, 2015 at 16:07
  • 1
    Okay, that's great to know! See update - still can't get it to conditionally enqueue. Must be doing something wrong. Jun 12, 2015 at 23:41
  • @W00tW00t111: could you solve at the end?
    – Revious
    Nov 7, 2018 at 20:20
0

You are answering your own question — scripts are being enqueued because that's what plugin does every load unconditionally.

There is no logic that controls when should it happen or not happen, it simply happens always.

If you take a closer look at a plugin that does it more intelligently you will usually notice one of these things:

  • there are conditional check for hooking methods or inside methods themselves
  • the hooks being used are specific to certain context
  • the enqueue is being called from code with related function, for example scripts needed by shortcode might be queued when from inside shortcode's handler
2
  • 1
    Thanks Rarst - that's what I was able to determine, but didn't know the best practice to conditionally load scripts. Should the plugin always be instantiated with plugins_loaded and then have a generic shortcode handler function to handle all shortcode calls (as they all need the same scripts). I was afraid since some pages will call multiple shortcodes that there would be multiple script enqueue calls wasting processing time. Any links of a best practice or example plugin that intelligently handles this? Jun 12, 2015 at 16:00
  • Added a code update with conditional functionality. Some items are firing (correctly and conditionally based on shortcode calling) but the enqueued scripts are not. Posted an update. Jun 12, 2015 at 23:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.