Soporte » Guías – Resolución de problemas » «noopener» and «noreferrer» en WP 5.1

  • Moderador almendron

    (@almendron)


    Hasta la versión 5.1, disponíamos de un filtro que nos permitía desactivar la adición de «noopener» and «noreferrer» a los enlaces con target=»_blank». Dicho filtro es el siguiente:

    add_filter('tiny_mce_before_init','tinymce_allow_unsafe_link_target');
    function tinymce_allow_unsafe_link_target( $mceInit ) {
    	$mceInit['allow_unsafe_link_target']=true;
    	return $mceInit;
    }

    Esta función funcionaba hasta ahora siempre y cuando se hubiera desactivado el editor Gutenberg y se estuviera trabajando con el clásico. Sin embargo, el filtro ha dejado de funcionar al llegar la versión 5.1 de WordPress.

    Por lo que he podido comprobar, hay dos nuevas funciones implicadas en el error.
    Archivo wp-includes/formatting.php. Línea 3036:

    /**
     * Adds rel noreferrer and noopener to all HTML A elements that have a target.
     *
     * @param string $text Content that may contain HTML A elements.
     * @return string Converted content.
     */
    function wp_targeted_link_rel( $text ) {
    	// Don't run (more expensive) regex if no links with targets.
    	if ( stripos( $text, 'target' ) !== false && stripos( $text, '<a ' ) !== false ) {
    		$text = preg_replace_callback( '|<a\s([^>]*target\s*=[^>]*)>|i', 'wp_targeted_link_rel_callback', $text );
    	}
    
    	return $text;
    }

    Archivo wp-includes/formatting.php. Línea 3054:

    /**
     * Callback to add rel="noreferrer noopener" string to HTML A element.
     *
     * Will not duplicate existing noreferrer and noopener values
     * to prevent from invalidating the HTML.
     *
     * @param array $matches Single Match
     * @return string HTML A Element with rel noreferrer noopener in addition to any existing values
     */
    function wp_targeted_link_rel_callback( $matches ) {
    	$link_html = $matches[1];
    	$rel_match = array();
    
    	/**
    	 * Filters the rel values that are added to links with <code>target</code> attribute.
    	 *
    	 * @since 5.1.0
    	 *
    	 * @param string The rel values.
    	 * @param string $link_html The matched content of the link tag including all HTML attributes.
    	 */
    	$rel = apply_filters( 'wp_targeted_link_rel', 'noopener noreferrer', $link_html );
    
    	// Avoid additional regex if the filter removes rel values.
    	if ( ! $rel ) {
    		return "<a $link_html>";
    	}
    
    	// Value with delimiters, spaces around are optional.
    	$attr_regex = '|rel\s*=\s*?(\\\\{0,1}["\'])(.*?)\\1|i';
    	preg_match( $attr_regex, $link_html, $rel_match );
    
    	if ( empty( $rel_match[0] ) ) {
    		// No delimiters, try with a single value and spaces, because <code>rel =  va&quot;lue</code> is totally fine...
    		$attr_regex = '|rel\s*=(\s*)([^\s]*)|i';
    		preg_match( $attr_regex, $link_html, $rel_match );
    	}
    
    	if ( ! empty( $rel_match[0] ) ) {
    		$parts     = preg_split( '|\s+|', strtolower( $rel_match[2] ) );
    		$parts     = array_map( 'esc_attr', $parts );
    		$needed    = explode( ' ', $rel );
    		$parts     = array_unique( array_merge( $parts, $needed ) );
    		$delimiter = trim( $rel_match[1] ) ? $rel_match[1] : '"';
    		$rel       = 'rel=' . $delimiter . trim( implode( ' ', $parts ) ) . $delimiter;
    		$link_html = str_replace( $rel_match[0], $rel, $link_html );
    	} else {
    		$link_html .= " rel=\"$rel\"";
    	}
    
    	return "<a $link_html>";
    }

    Mi pregunta es: ¿cuál sería la mejor forma de deshabilitar estas funciones?

Viendo 9 respuestas - de la 1 a la 9 (de un total de 9)
  • Moderador LGrusin

    (@lgrusin)

    No he tenido tiempo para comprobarlo pero supongo que puedes jugar con el filtro
    wp_targeted_link_rel

    Moderador almendron

    (@almendron)

    Ni aún eliminando esas dos funciones se corrige el problema.

    Solo lo he conseguido comentando «add_filter» en la siguiente función.

    function wp_init_targeted_link_rel_filters() {
    	$filters = array(
    		'title_save_pre',
    		'content_save_pre',
    		'excerpt_save_pre',
    		'content_filtered_save_pre',
    		'pre_comment_content',
    		'pre_term_description',
    		'pre_link_description',
    		'pre_link_notes',
    		'pre_user_description',
    	);
    
    	foreach ( $filters as $filter ) {
    		add_filter( $filter, 'wp_targeted_link_rel' );
    	};
    }

    Ahora bien, justo debajo hay otra función nueva que se supone desactiva la anterior:

    function wp_remove_targeted_link_rel_filters() {
    	$filters = array(
    		'title_save_pre',
    		'content_save_pre',
    		'excerpt_save_pre',
    		'content_filtered_save_pre',
    		'pre_comment_content',
    		'pre_term_description',
    		'pre_link_description',
    		'pre_link_notes',
    		'pre_user_description',
    	);
    
    	foreach ( $filters as $filter ) {
    		remove_filter( $filter, 'wp_targeted_link_rel' );
    	};
    }

    El problema es como añado en mi plugin de funciones tal desactivación y así no tener que tocar el archivo del core.

    Moderador almendron

    (@almendron)

    He conseguido corregir el error añadiendo en mi archivo de plugin lo siguiente

    do_action( ‘wp_remove_targeted_link_rel_filters’ );

    ¿Hay alguna otra forma de hacerlo de forma más conveniente?

    • Esta respuesta fue modificada hace 5 años por almendron.
    • Esta respuesta fue modificada hace 5 años por almendron.
    • Esta respuesta fue modificada hace 5 años por almendron.
    Moderador almendron

    (@almendron)

    No he dicho nada. Lo de «do_action» tampoco funciona.

    Moderador kallookoo

    (@kallookoo)

    @almendron
    has probado usando el filtro wp_targeted_link_rel devolviendo un valor vacio.

    
    add_filter( 'wp_targeted_link_rel', '__return_false', 9999 );
    

    La prioridad la puse alta para que asi fuese el ultimo.
    Con eso no se deberia modificar el html link.

    Revisando el core hay un action init que inicia todos los filtros, tambien podrias probar asi.

    
    add_action( 'wp_loaded', 'wp_remove_targeted_link_rel_filters' );
    

    No he probado ninguna de las dos maneras, pero ahora mismo es lo unico que se me ocurre.

    Moderador almendron

    (@almendron)

    Comprobado. Las dos opciones funcionan.

    En resumen. Si estamos usando el editor clásico y la versión 5.1, es necesario añadir lo siguiente en el archivo functions.php o en nuestro plugin de funciones:

    Primero (o no funcionará), cualquiera de las dos instrucciones indicadas por @kallookoo

    add_filter( 'wp_targeted_link_rel', '__return_false', 9999 ); o bien add_action( 'wp_loaded', 'wp_remove_targeted_link_rel_filters' );

    Y después hay que poner lo siguiente:

    add_filter('tiny_mce_before_init','tinymce_allow_unsafe_link_target');
    function tinymce_allow_unsafe_link_target( $mceInit ) {
    	$mceInit['allow_unsafe_link_target']=true;
    	return $mceInit;
    }
    Moderador almendron

    (@almendron)

    El problema lo tenemos ahora con el editor Gutenberg. No hay forma de deshabilitar esa función.

    Moderador kallookoo

    (@kallookoo)

    Revisando el codigo el problema es que el gutenberg cuando seleccionas abrir en otra ventana añade el codigo usando javascript y el html se guarda en la DB.

    Solo se me ocurre esto:

    1.- crear algun plugin que sobreescriba el contendido del bloque cuando se añada un link eliminando asi el rel.
    2.- crear una function de php para eliminar el html antes de guardarlo en la DB, usando por ejemplo el filtro content_save_pre
    3.- crear una function de php para eliminar el html antes de imprimirlo, usando por ejemplo el filtro the_content.

    Me declino por la primera por rendimiento, la 2 y 3 podrian consumir muchos recursos al tener un contenido grande.

    Añado que revisando el github del gutenberg lo añadieron por razones de seguridad. Vease: https://github.com/WordPress/gutenberg/pull/6316
    Y por lo visto tambien esta dando problemas a los links de afiliados que necesitan del referer, asi que creo que lo modificaran.

    De momento se puede editar manualmente el link (vista html) y eliminar el rel o simplemente no usar el gutenberg.

    • Esta respuesta fue modificada hace 5 años por kallookoo. Razón: Añado link referencia "javascript"
    Moderador almendron

    (@almendron)

    Muchas gracias @kallookoo

    Dejo el hilo el abierto para poder añadir aquí la solución si en el futuro apareciera alguna novedad.

Viendo 9 respuestas - de la 1 a la 9 (de un total de 9)
  • El debate ‘«noopener» and «noreferrer» en WP 5.1’ está cerrado a nuevas respuestas.