I came across an encoding issue when adding inline JavaScript to the footer of a WordPress page via wp_add_inline_script()
.
The following description is a boiled down version of the problem for demonstration purposes.
So, I have a textarea inside a metabox on the post editor which contains the following JavaScript:
var test3 = '3';
var test4 = "4";
Note the use of single AND double quotes for testing. I'm also enqueueing a JavaScript file containing:
console.log("test.js loaded");
The JavaScript from the textarea is added to the page directly after test.js
via wp_add_inline_script().
The issue is that when I inspect the source code the single/double quotes have been encoded:
var test3 = '3';
var test4 = "4";
I couldn't figure out why this was so I did a similar test but storing JavaScript inside a textarea on a plugin settings page.
Here, the textarea contains:
var test1 = '1';
var test2 = "2";
When added to the front end page, this JavaScript outputs perfectly. Here's a screenshot:
It seems as though the data from post meta is encoded while the data from plugin options is not.
Here is the full plugin code:
File: inline-js-test.js
<?php
/*
Plugin Name: Inline JS Test
Version: 0.1
Author: David Gwyer
*/
// ijst_ prefix is derived from [i]nline [js] [t]est
// Enqueue scripts
function ijst_enqueue_scripts() {
$options = get_option( 'ijst_options' );
$js = get_post_meta( '5943', '_ijst-js', true );
wp_enqueue_script( 'ijst-test', plugins_url('test.js', __FILE__), array(), '', true );
$inline_js1 = $options['textarea'];
$inline_js2 = $js;
wp_add_inline_script( 'ijst-test', $inline_js1 );
wp_add_inline_script( 'ijst-test', $inline_js2 );
}
add_action( 'wp_enqueue_scripts', 'ijst_enqueue_scripts' );
// Plugin options page
function ijst_init() {
register_setting( 'ijst_plugin_options', 'ijst_options' );
}
add_action( 'admin_init', 'ijst_init' );
function ijst_add_options_page() {
$page = add_options_page( 'Inline JS Test', 'Inline JS Test', 'manage_options', __FILE__, 'ijst_render_form' );
}
add_action( 'admin_menu', 'ijst_add_options_page' );
function ijst_render_form() {
?>
<div class="wrap">
<h2 style="font-size: 23px;">Inline JS Test</h2>
<form method="post" action="options.php">
<?php
settings_fields( 'ijst_plugin_options' );
$options = get_option( 'ijst_options' );
?>
<table>
<tr>
<td><textarea name="ijst_options[textarea]" rows="7" cols="50" type='textarea'><?php echo $options['textarea']; ?></textarea></td>
</tr>
</table>
<p class="submit"><input type="submit" class="button-primary" value="<?php _e( 'Save Changes' ) ?>"></p>
</form>
</div>
<?php
}
// Post meta box
function ijst_meta_box_init() {
add_meta_box( 'inline-js-test', 'Inline JS Test', 'ijst_render_meta_box', 'post', 'normal', 'high' );
add_action( 'save_post', 'ijst_save_meta_box_data' );
}
add_action( 'admin_init', 'ijst_meta_box_init' );
function ijst_save_meta_box_data( $post_id ) {
if ( isset( $_POST['ijst-js'] ) ) { update_post_meta( $post_id, '_ijst-js', esc_attr( $_POST['ijst-js'] ) ); }
}
function ijst_render_meta_box( $post, $args ) {
$js = get_post_meta( $post->ID, '_ijst-js', true );
?><table><tr><td><textarea id="ijst-js" name="ijst-js"><?php echo esc_attr( $js ); ?></textarea></td></tr></table><?php
}
File: test.js
console.log("test.js loaded");
The code for the whole plugin can also be found on this Gist: https://gist.github.com/dgwyer/0bb2022be0d733cf3bfc4e094ea815f7
Aside from the main issue I also need to understand the correct procedure for escaping/sanitizing JavaScript before adding it to a web page?
I don't think outputting the raw data is a great idea, but obviously don't want to use anything that would break the code.