Question

I would love to defer the loading of the script for a plugin, Simple Locator, which uses Google.maps API.

However it uses wp_localize_script, which prints a wpsl_locator javascript object in the HTML page (to include options), which calls on google-maps API's google object, which isn't loaded yet.

I thought that possibly I could fake it out by hacking the plugin and adding wpsl_locator = new Object() via another (deferred) script, which would include hard-coded options:

wpsl_locator.map_options={[truncated]{style:google.maps.ZoomControlStyle.SMALL,}};

But one problem is that it would break on plugin updating.

It doesn't look like wp_deregister_script( 'simple-locator' ); is removing the i10n output that wp_localize_script is generating.

Is there a recommended way of handling this?

Was it helpful?

Solution

The solution is basically from this SO post:

When wordpress "localizes" a script, what it does is has php print out <script></script> tags with javascript objects in them that are then accessible within the DOM to the scripts you are "sending" the parameters to.

If I understand correctly, the extension of WP_Scripts simple adds a filter, referenced by the (arbitrary) handle, script_l10n, then sends that filtered variable, $110n through to the parent method, localize, which is where WPs array of arrays to "localize" gets sent.

class Filterable_Scripts extends WP_Scripts
{
    function localize( $handle, $object_name, $l10n )
    {
        $l10n = apply_filters( 'script_l10n', $l10n, $handle, $object_name );
        return parent::localize($handle, $object_name, $l10n);
    }
}

Then we replace $GLOBALS['wp_scripts'] with our new filterable one.

function my_filter_script_intlization() {
    $GLOBALS['wp_scripts'] = new Filterable_Scripts;
}
add_action( 'init', 'my_filter_script_intlization');

And now we can hook into the filter to modify the l10n string from the plugin (once we've used print_r() or something to figure out what it is).

function se108362_example_filter($l10n, $handle, $object_name ) {
    if('simple-locator' == $handle && 'wpsl_locator' == $object_name) {

        $phyt_i10n_settings = array(
            'mapTypeId' => 'roadmap',
            'mapTypeControl' => false,
            'zoom' => 8,
            'panControl' => false,
            'zoomControlOptions' => array('style' => '') // was google.maps.ZoomControlStyle.SMALL
            );


        $l10n['l10n_print_after'] = 'wpsl_locator.map_options = ' . json_encode($phyt_i10n_settings);

        return $l10n;
    }
    return $l10n;
}

add_filter('script_l10n', 'se108362_example_filter', 10 , 3);

Then in the js I replace the l10n variables with my hard-coded ones:

wpsl_locator.map_options.zoomControlOptions.style = google.maps.ZoomControlStyle.SMALL;
wpsl_locator.map_options.styles = wpsl_locator.mapstyles;

For some reason the Filterable_Scripts sub-class seems to break the Advanced Custom Fields script loading:

public function my_filter_script_intlization() {
    //These exist here:
    var_dump($GLOBALS['wp_scripts']->registered['acf-field-group']);
    var_dump($GLOBALS['wp_scripts']->registered['acf-input']);
    $GLOBALS['wp_scripts'] = new \PhytJobs\FilterableScripts;
    // But now they are gone
    print_r(isset($GLOBALS['wp_scripts']->registered['acf-field-group']));
}

My workaround is to do this:

public function my_filter_script_intlization() {
    $acf_field_group = $GLOBALS['wp_scripts']->registered['acf-field-group'];
    $acf_input = $GLOBALS['wp_scripts']->registered['acf-input'];
    $GLOBALS['wp_scripts'] = new \PhytJobs\FilterableScripts;
    $GLOBALS['wp_scripts']->registered['acf-field-group'] = $acf_field_group;
    $GLOBALS['wp_scripts']->registered['acf-input'] = $acf_input;
}

But I'm wondering why the sub-classing is breaking it in the first place.

Someone suggested that the issue is caused by hooking the my_filter_script_intlization action too late, after $WP_Scripts has already been partly populated. I'm still a little unclear on how that works or why ACF would be the problem.

UPDATE, ACF only loads its scripts in Admin and the other plugin only l10n in the front end so I just wrapped the action and filter hook in a !is_admin test and ACF has nothing to complain about.

Licensed under: CC-BY-SA with attribution
Not affiliated with wordpress.stackexchange
scroll top