Escapar comillas en atributos de shortcodes en WordPress
He estado intentando descubrir cómo escapar comillas (simples y dobles) en los atributos de los shortcodes.
Básicamente el contenido es escrito por el usuario y por lo tanto puede potencialmente incluir comillas " y '. El problema es que con comillas dobles " se interrumpe el atributo del shortcode, por ejemplo:
atributo="texto aquí con "comillas" por lo que se detiene el atributo..."
En lugar de obtener la cadena completa, se detiene en el segundo par de comillas.
Sé que sería posible configurarlo con comillas simples, pero eso deja el mismo problema si el usuario usa comillas simples en el texto.
He revisado varias soluciones de PHP/WP pero no logro que ninguna funcione, como esc_html, htmlspecialchars, htmlentities.
Quizás lo he configurado mal o no estoy aplicando la codificación en el lugar correcto.
Actualmente estoy usando esto (sin codificación) como shortcode (simplificado):
function aps_person_schema_shortcode( $atts, $content = null) {
extract( shortcode_atts( array(
'aps_person_description' => ''
), $atts
)
);
$aps_person_return = '<div class="aps_person_container aps_container">';
$aps_person_return .= '<p class="aps_person_description" itemprop="description">' . $aps_person_description . '</p>';
$aps_person_return .= '</div>';
return $aps_person_return;
}
add_shortcode('aps_person', 'aps_person_schema_shortcode');
He intentado agregar después del array extract cosas como:
$aps_person_description = esc_html($atts['aps_person_description']);
pero como el atributo ya está roto (print_r muestra que el texto después de la comilla se separa en ítems del array para cada palabra) escapar la cadena ahí no funciona.
Lo intenté antes del array y tampoco funciona, obtengo un Notice: Undefined index
Entonces, para aclarar, ¿cómo se puede sanitizar la entrada de usuario para datos de atributos en shortcodes?

Resulta que el sistema de shortcodes de WordPress utiliza la función shortcode_parse_atts($text);
para analizar una entrada de shortcode y recuperar los nombres y valores de los atributos, almacenándolos en pares en el array $atts
, que luego se pasa a la función del shortcode. Por lo tanto, en tu caso, agregar acciones de escape en la función del shortcode como esta:
$aps_person_description = esc_html($atts['aps_person_description']);
no funcionará porque shortcode_parse_atts()
ya ha recuperado los nombres y valores de los atributos, y podría haber interpretado incorrectamente las comillas en los valores de los atributos.
Para analizar más de cerca, la función shortcode_parse_atts()
utiliza este patrón de regex:
/(\w+)\s*=\s*"([^"]*)"(?:\s|$)|(\w+)\s*=\s*\'([^\']*)\'(?:\s|$)|(\w+)\s*=\s*([^\s\'"]+)(?:\s|$)|"([^"]*)"(?:\s|$)|(\S+)(?:\s|$)/
para reconocer los nombres y valores de los atributos en los siguientes formatos:
1. attr1="value1"
2. attr2='value2'
3. attr3=value3
4. "value4"
5. value5
Por lo tanto, si un usuario coloca comillas en los valores, puede salir mal fácilmente. Por ejemplo:
[my_shortcode dog='Santa's Little Helper' /]
// $attr es Array ( [0] => dog='Santa's [1] => Little [2] => Helper' )
// debería ser Array ( [dog] => Santa's Little Helper )
Sanear después del análisis es obviamente demasiado tarde, ¿qué hay de sanear antes del análisis? Tendríamos que sanear toda la entrada, ya que aún no tenemos valores de atributos con los que trabajar. Pero esto también causa problemas, por ejemplo:
html_entities("[my_shortcode dog='Santa's Little Helper' /]", ENT_QUOTES);
// ahora la entrada es [my_shortcode dog='Santa's Little Helper' /]
// después del análisis:
Array
(
[dog] => 'Santa's
[0] => Little
[1] => Helper'
)
La paradoja es: para asegurarse de que el motor de análisis analice correctamente, tienes que sanear los valores de los atributos; pero para hacer esto, primero tienes que ejecutar el motor de análisis para obtener los valores.
En conclusión, creo que la forma razonable de asegurarse de que todo funcione correctamente es garantizar que los usuarios ingresen los atributos en formatos adecuados. Una vez que los usuarios publiquen atributos mal formateados, será un gran dolor de cabeza. Para tu información, mi experiencia es hacer uso de $content
. En tu caso, pondría aps_person_description
en el $content
, podría verse así:
[my_shortcode]algún texto aquí con "comillas" para que detenga el atributo....[/my_shortcode]
y las comillas serán menos un problema.

No hay ninguna paradoja, es un error simple pero significativo en shortcode_parse_atts()
. Simplemente no es así como se deberían analizar los atributos entre comillas. Las secuencias de escape son esenciales, no encontrarás un lenguaje de programación que no las tenga. Esto debería haber estado implementado desde el principio. Tu ejemplo podría escribirse fácilmente como [my_shortcode dog='Santa\'s Little Helper' /]
si el analizador tuviera idea de cómo funciona.

Parece que estás trabajando en el extremo equivocado.
Intenta sanear la entrada del usuario, por ejemplo mediante sanitize_text_field
, no la salida del shortcode.

Me encontré con un problema similar al imprimir una variable PHP en un atributo de shortcode. En mi caso, este valor era el nombre de un término de taxonomía, no contenido generado por el usuario, por lo que no había entrada que sanitizar.
Usar htmlentities()
con el flag ENT_QUOTES
permite que cadenas que incluyen '
y "
se puedan usar como atributos de shortcode. Sin embargo, también convierte otros caracteres a entidades HTML, como &
en &
, lo cual no era ideal en mi caso.
Para convertir solo los caracteres '
y "
en entidades HTML, sin convertir otros caracteres como &
:
htmlspecialchars_decode( htmlentities($valor_a_imprimir, ENT_QUOTES), ENT_NOQUOTES )
htmlspecialchars_decode()
revierte todas las entidades HTML convertidas por htmlentities()
. Usar el flag ENT_NOQUOTES
evita que los caracteres '
y "
se conviertan de vuelta.
