Je suis tombé sur un problème d’encodage lors de l’ajout de JavaScript inline au pied de page d’une page WordPress via wp_add_inline_script()
.
La description suivante est une version abrégée du problème à des fins de démonstration.
Donc, j'ai un textarea à l'intérieur d'un metabox sur l'éditeur de publication qui contient le code JavaScript suivant:
var test3 = '3';
var test4 = "4";
Notez l'utilisation de guillemets simples ET doubles pour les tests. Je suis également en train de mettre en file d'attente un fichier JavaScript contenant:
console.log("test.js loaded");
Le code JavaScript de la zone de texte est ajouté à la page directement après le test.js
via wp_add_inline_script ().
Le problème est que lorsque j'inspecte le code source, les guillemets simples/doubles ont été codés:
var test3 = '3';
var test4 = "4";
Je ne pouvais pas comprendre pourquoi c'était ainsi j'ai fait un test similaire mais en stockant JavaScript dans une zone de texte sur une page de paramètres de plugin.
Ici, la zone de texte contient:
var test1 = '1';
var test2 = "2";
Lorsqu'il est ajouté à la page d'accueil, ce JavaScript est parfaitement généré. Voici une capture d'écran:
Il semble que les données de post meta soient codées alors que les données de plug-in ne le sont pas.
Voici le code complet du plugin:
Fichier: 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
}
Fichier: test.js
console.log("test.js loaded");
Le code pour le plugin complet peut également être trouvé sur cette Gist: https://Gist.github.com/dgwyer/0bb2022be0d733cf3bfc4e094ea815f7
Outre le problème principal, j'ai également besoin de comprendre la procédure correcte pour échapper/assainir JavaScript avant de l'ajouter à une page Web?
Je ne pense pas que la sortie des données brutes soit une bonne idée, mais je ne souhaite évidemment pas utiliser quoi que ce soit qui casserait le code.
1) Pour échapper au contenu de textarea, vous devez utiliser esc_textarea
et non esc_attr
.
2) Vous ne devez pas échapper des objets lorsque vous les stockez dans la base de données. Ils doivent être échappés uniquement au moment de la sortie. (Je suppose que vous pouvez trouver un cas Edge dans lequel cela pourrait être nécessaire, mais en règle générale, ne le faites pas).
3) Demander aux utilisateurs d'insérer du code JS est très hostile à l'utilisateur. En plus du problème de sécurité évident qui pourrait survenir, un type général de casse est presque inévitable ... pensez à quelqu'un qui fait $ = 'dollar';
. Cela n'aide pas que si vous allez dans cette direction, vous n'avez aucun moyen d'assainir quoi que ce soit et vous devez le servir cru.