How to pass data from WordPress to JavaScript

Jul 31, 2019

The title of this article could be somewhat misleading for some advanced users because of WP-REST, WPGraphQL etc. so let me clarify first: this article is about passing data from the PHP side of WordPress (eg. functions.php or a template file) to a JavaScript file.

These are your options

The “wp_localize_script()” option

As the name suggest, wp_localize_script() function was originally intended to be used for passing string translations from PHP to JavaScript. It, however, can be used for passing all kinds of data to JavaScript. In most cases you probably should use it.

Just note that it’s intended to use in functions.php and it’s a bit tricky to use in page templates (more info here). If you’d wish to generate your JSON in page template, see “The “script tag and querySelector” option”.

wp_localize_script() function works like this:

<?php

function wpa_enqueue_scripts() {
 wp_enqueue_script( 'wpa-main-js', get_template_directory_uri() . '/dist/scripts/main.js', [], null, true );

 $wpa_main_js_vars = [
  'title' => __('Text title', 'textdomain'),
  'content' => __('Some content', 'textdomain'),
 ];

 wp_localize_script('wpa-main-js', 'wpa_main_js_vars', $wpa_main_js_vars);
}

add_action( 'wp_enqueue_scripts', 'wpa_enqueue_scripts', 100 );

This outputs the data between tags before the enqueued file like this:

<script type='text/javascript'>
/* <![CDATA[ */
var wpa_main_js_vars = {"title":"Text title","content":"Some content"};
/* ]]> */
</script>
<script type='text/javascript' src='https://www.example.com/wp-content/themes/yourtheme/dist/scripts/main.js'></script>

So you can use the data in your main.js like this:

var data = window.wpa_main_js_vars;

console.log( data.title );
// Outputs: Text title

The “script tag and querySelector” option

This is the method if you wish to generate your JSON within your page templates. Usually it would be best to separate your data and your views (and to use wp_localize_script() option in functions.php) but this blog is not about how to be a programmer purist. Sometimes life happens and depending on your setup it might be really convenient to wrap some data in a JSON string in your page template, grab it with querySelector and call it a day.

Having only one HTML element of this kind per page

You can use this method if you’re going to have a maximum of a single instance of this kind of element per page.

In your PHP you add the data into a script tag with an unique class like this:

<?php 

// page.php

$data = [
	'title' => 'Second element',
	'content' => 'Some content',
];
?>

<div id="my-element-class"></div>
<script id="my-element-class-data" type="application/json">
		<?php echo json_encode( $data ); ?>
</script>

and in your JavaScript file you grab the data like this:

var el = document.querySelector("#my-element-class");
var dataEl = document.querySelector("#my-element-class-data");

if( el.length > 0 && dataEl.length > 0 ) {
	data = JSON.parse(dataEl.innerHTML);

	el.innerHTML = 
	'<h2>' + data.title + '</h2>' + 
	'<p>' + data.content + '</p>';
}

Having multiple similar HTML elements per page with a different set of data

This is a great way to do this if you need (or might need in the future) a multiple instances of that same element with a different set of data on the same page.

In your PHP you add the data into a script tag with a class and unique data-id attribute like this:

<?php 

// page.php

$data_array = [
	[
		'title' => 'First element',
		'content' => 'Some content',
	],
	[
		'title' => 'Second element',
		'content' => 'Some content',
	],
];

$i = 0;

?>

<?php foreach ($data_array as $data) ?>
	<div class="my-element-class" data-id="<?php echo $i; ?>"></div>

	<script class="my-element-class-data" data-id="<?php echo $i; ?>" type="application/json">
		<?php echo json_encode( $data ); ?>
	</script>

	<?php $i++; ?>
<?php endforeach; ?>

and in your JavaScript file you grab the data like this:

var elements = document.querySelectorAll(".my-element-class");

if( elements.length > 0 ) {
	for (var el of elements) {
		var dataId = el.dataset.id;
		const dataEl = document.querySelector(
		`.my-element-class-data[data-id="${dataId}"]`,
		;

		el.innerHTML =
		'<h2>' + data.title + '</h2>' + 
		'<p>' + data.content + '</p>';
	}
}