Skip to content
  1. Blog

Stop Using wp_localize_script to Pass Data

Ben Word Ben Word

If you’re using wp_localize_script() to pass data from PHP to JavaScript, you’re using the wrong tool. Despite what countless tutorials suggest, it was built for making JavaScript strings translatable and not for data passing. WordPress gave us wp_add_inline_script() nearly a decade ago specifically for this purpose, and it’s time we started using it.

The problem with wp_localize_script

wp_localize_script() was originally designed for making JavaScript strings translatable. Using it to pass data to JavaScript works, but it’s a hack that comes with limitations:

  • Misuse of purpose: It was built for translations, not data passing, which is why the function name includes “localize”
  • Always creates globals: Your data is always attached to the global window object
  • Forces object structure: Data must be an associative array/object, you can’t pass simple values, arrays, or other JavaScript primitives directly
  • Inefficient output: Generates unnecessary var declarations and wraps everything in an object, even when you don’t need that structure
  • Limited to one script: You can only localize a script once, calling it multiple times for the same handle just overwrites previous data

Here’s what wp_localize_script() generates:

wp_localize_script('my-script', 'myData', [
    'apiUrl' => rest_url('app/v1'),
    'nonce' => wp_create_nonce('wp_rest')
]);

Output:

<script id="my-script-js-extra">
var myData = {"apiUrl":"https://example.com/wp-json/app/v1","nonce":"abc123"};
</script>

Using wp_add_inline_script

wp_add_inline_script() gives you complete control over what JavaScript you output. Here’s how to pass the same data:

wp_enqueue_script('my-script', get_template_directory_uri() . '/js/script.js', [], '1.0', true);

$data = [
    'apiUrl' => rest_url('app/v1'),
    'nonce' => wp_create_nonce('wp_rest')
];

wp_add_inline_script('my-script', 
    'const myData = ' . wp_json_encode($data) . ';',
    'before'
);

Output:

<script>
const myData = {"apiUrl":"https://example.com/wp-json/app/v1","nonce":"abc123"};
</script>
<script src="https://example.com/wp-content/themes/my-theme/js/script.js" id="my-script-js"></script>

Why wp_add_inline_script is better

Flexibility: You control the exact JavaScript output: use const, let, or even wrapping your data in an IIFE to avoid globals.

Semantic clarity: The function name actually describes what it does: adds inline script rather than implying it’s for localization.

Better scoping: You can use modern JavaScript scoping (const, let) and avoid polluting the global namespace if desired.

More than just data: Pass any valid JavaScript, not just data objects. This includes function calls, conditionals, or initialization code.

Multiple additions: You can call wp_add_inline_script() multiple times for the same handle, and all scripts will be output.

Advanced examples

Adding inline scripts without dependencies

Sometimes you need to add global configuration data or initialization code without attaching it to a specific script file. Since WordPress 5.0, you can register a script with an empty source and use it as a handle for inline scripts:

add_action('wp_enqueue_scripts', function() {
    // Register a dummy handle with no source file
    wp_register_script('global', '');
    wp_enqueue_script('global');
    
    // Add your inline script
    $config = [
        'apiUrl' => rest_url('app/v1'),
        'nonce' => wp_create_nonce('wp_rest'),
        'userId' => get_current_user_id()
    ];
    
    wp_add_inline_script('global', 
        'window.APP_CONFIG = ' . wp_json_encode($config) . ';'
    );
});

This outputs pure inline JavaScript without loading an external file, perfect for configuration data that needs to be available globally before your other scripts run.

Avoiding global scope entirely

wp_add_inline_script('my-script', 
    '(function() {
        const config = ' . wp_json_encode($config) . ';
        window.myApp = window.myApp || {};
        window.myApp.config = config;
    })();',
    'before'
);

Passing multiple data sets

wp_add_inline_script('my-script', 
    'const API_CONFIG = ' . wp_json_encode($api_config) . ';',
    'before'
);

wp_add_inline_script('my-script', 
    'const USER_DATA = ' . wp_json_encode($user_data) . ';',
    'before'
);

Conditional initialization

$init_code = 'if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", initMyApp);
} else {
    initMyApp();
}';

wp_add_inline_script('my-script', $init_code, 'after');

When to use each

wp_add_inline_script: Everything. New projects, new features, any time you need to pass data or code to JavaScript.

wp_localize_script: Only for actual localization/i18n of JavaScript strings, or when maintaining legacy code where refactoring isn’t justified.

Making the switch

wp_add_inline_script() has been available since WordPress 4.5 (released in 2016). The switch is straightforward:

// Old way
wp_localize_script('my-script', 'myData', $data);

// New way
wp_add_inline_script('my-script', 
    'const myData = ' . wp_json_encode($data) . ';',
    'before'
);

For a comprehensive guide on script handling in WordPress, check out the official WordPress documentation on wp_add_inline_script().

Discuss this post on Roots Discourse

About the author

Ben Word

Ben Word has been creating WordPress sites since 2004. He loves dogs, climbing, and yoga, and is passionate about helping people build awesome things on the web.

Subscribe for updates

Join over 8,000 subscribers on our newsletter to get the latest Roots updates and tips on building better WordPress sites

Looking for WordPress plugin recommendations, the newest modern WordPress projects, and general web development tips and articles?

One last step! Check your email for a verification link.