Loading scripts & styles from a meta box callback function

Case:

I got a set of classes that build form fields based on data from an input array. The class can build the following types of form fields:

  • input (basic, hidden, password)
  • textarea
  • radio
  • checkbox
  • select
  • colorpicker
  • datepicker
  • file upload

EDIT: The class uses wp_register_script/_style & wp_enqueue_script/_style to load the scripts & styles. The functions containing the actions are hooked inside the class like this: add_action( 'admin_enqueue_scripts', array( &$this, 'enqueue' ) );.

Read More

Example:

(Inside functions.php)

// meta box callback function
function test_meta_box_cb()
{   
    $input_args = array(
         'type'         => 'color'
        ,'id'           => 'color-id'
        ,'label'        => 'Input Colorpicker Label'
        ,'opt_name'     => 'abc_xyz'
        ,'value'        => '009ee0'
     );
    new FormClass( $input_args, true );
}
// add the meta box
function add_test_meta_box()
{
    add_meta_box( 'test_box', __('TestBox'), 'test_meta_box_cb', 'post', 'advanced', 'high' );
}
add_action( 'add_meta_boxes', 'add_test_meta_box' );

Problem:

This way, my call for wp_enqueue_script & wp_enqueue_style doesn’t work. I get the form fields rendered, but no scripts or styles.

Situation & Backtracing of the problem:

So far I could track down the problem to the wordpress core architecture:

  • WP doesn’t question what happens inside the callback function until do_action('add_meta_boxes', $post_type, $post) get’s called (inside edit-form-advanced.php).
  • That call happens long after admin-header.php was called (which contains do_action('admin_enqueue_scripts', $hook_suffix);).
  • Therefore the script & style can’t get loaded (if I’m not wrong).

Question:

  1. How could i load styles before the meta box form fields get called?
  2. How could i avoid repeating the same stylesheet over and over again – i want to use wp_enqueue_style & wp_register_style?

I’m open to any answers including those who force me to rewrite my class architecture.

Note: I need to use this class in a lot of different szenarios, so bundling it to close together with the add_meta_box function is not good. I’m close to making an abstraction layer that divides the call for the meta box and the style/script part, but why would I want to add another layer above a core function?

Related posts

Leave a Reply

3 comments

  1. Your problem is adding the scripts, styles inside the class, and because the class instance is created when the hook add_meta_box is fired, at that time the wp_enqueue_script/style are already finished.

    A solution for you is adding the scripts, styles outside the function and the class. And because meta boxes are used only at editing pages, you can do as the following:

    // the editing pages are actually post.php and post-new.php
    add_action('admin_print_styles-post.php', 'custom_js_css');
    add_action('admin_print_styles-post-new.php', 'custom_js_css');
    
    function custom_js_css() {
        wp_enqueue_style('your-meta-box', $base_url . '/meta-box.css');
        wp_enqueue_script('your-meta-box', $base_url . '/meta-box.js', array('jquery'), null, true);
    }
    

    Actually, I wrote a meta box class for WP, that uses another approach. Instead of writing form class for form fields like you did, my class is a wrapper for meta boxes. If you interested in, it’s worth to take a look.

  2. You should really hook you scripts to the wp_enqueue_scripts action and your styles to the wp_print_styles action. Inside your functions, do a check to make sure you’re on the page using your meta boxes before actually using wp_enqueue_script() or wp_enqueue_style().

    For example, in one of my plugins I have:

    public static function enqueue_scripts_and_styles() {
        if( is_admin() ) {
            wp_enqueue_script( 'media-upload' );
            wp_enqueue_script( 'thickbox' );
            wp_enqueue_style( 'thickbox' );
        } else {
            wp_enqueue_style( 'wp-publication-archive-frontend', WP_PUB_ARCH_INC_URL . '/front-end.css', '', '2.0', 'all' );
        }
    }
    

    And I hook that to init (which fires just before all the other scripts and styles are enqueued).

  3. In current form your code dumbs down object to kind of function call (get created, do something, die). Such usage won’t do if you want object to do something long before that object is created and destroyed.

    Instead of creating object inside of metabox content I’d do following:

    1. Create object some time early.
    2. Use object’s method to deal with scripts.
    3. Use another object’s method as meta box callback.