Poner en secuencia secuencias de comandos / estilos cuando el shortcode está presente

54

¿Cuál es la forma ideal de registrar / poner en cola secuencias de comandos y / o estilos para usar en complementos?

Recientemente hice un complemento simple para agregar al usuario avatar / gravatar con un código corto. Tengo diferentes opciones de estilo para mostrar el avatar (cuadrado, redondo, etc.) y decidí poner el CSS directamente en el código corto.

Sin embargo, ahora me doy cuenta de que este no es un buen enfoque, ya que repetirá el CSS cada vez que se use el shortcode en una página. He visto varios otros enfoques en este sitio y el wx codex incluso tiene dos ejemplos propios, por lo que es difícil saber qué enfoque es más consistente y rápido.

Estos son los métodos que conozco actualmente:

Método 1: Incluir directamente en shortcode: esto es lo que estoy haciendo actualmente en el complemento, pero no parece bueno ya que repite el código.

class My_Shortcode {
function handle_shortcode( $atts, $content="" ) {
/* simply enqueue or print the scripts/styles in the shortcode itself */
?>
<style type="text/css">

</style>
<?php
    return "$content";
     }
}
add_shortcode( 'myshortcode', array( 'My_Shortcode', 'handle_shortcode' ) );

Método 2: utilice la clase para poner en cola secuencias de comandos o estilos condicionalmente

class My_Shortcode {
    static $add_script;
    static function init() {
        add_shortcode('myshortcode', array(__CLASS__, 'handle_shortcode'));
        add_action('init', array(__CLASS__, 'register_script'));
        add_action('wp_footer', array(__CLASS__, 'print_script'));
    }
    static function handle_shortcode($atts) {
        self::$add_script = true;
        // shortcode handling here
    }
    static function register_script() {
        wp_register_script('my-script', plugins_url('my-script.js', __FILE__), array('jquery'), '1.0', true);
    }
    static function print_script() {
        if ( ! self::$add_script )
            return;
        wp_print_scripts('my-script');
    }
}
My_Shortcode::init();

Método 3: usar get_shortcode_regex();

function your_prefix_detect_shortcode() {

    global $wp_query;   
    $posts = $wp_query->posts;
    $pattern = get_shortcode_regex();

    foreach ($posts as $post){
        if (   preg_match_all( '/'. $pattern .'/s', $post->post_content, $matches )
            && array_key_exists( 2, $matches )
            && in_array( 'myshortcode', $matches[2] ) )
        {
            // css/js 
            break;  
        }    
    }
}
add_action( 'wp', 'your_prefix_detect_shortcode' );

Método 4: usar has_shortcode();

function custom_shortcode_scripts() {
    global $post;
    if( is_a( $post, 'WP_Post' ) && has_shortcode( $post->post_content, 'myshortcode') ) {
        wp_enqueue_script( 'my-script');
    }
}
add_action( 'wp_enqueue_scripts', 'custom_shortcode_scripts');
Bryan Willis
fuente
Creo que Method 4: Using has_shortcode();es mejor porque garantizará que las secuencias de comandos y los estilos se carguen una vez si el contenido de la publicación tiene código corto, independientemente de los múltiples usos del código corto. Aunque podría no funcionar para usos de shortcode en widgets o en la barra lateral, no estoy seguro. Si se trata de un complemento, no recomendaría que vincule los scripts con shortcode porque algunos podrían llamar a su función en lugar de shortcode para obtener la salida deseada.
Robert hue

Respuestas:

45

Encontré otra forma que me funciona bien:

Aquí hay un complemento de ejemplo que usa este método que le permite usar get_avatar como shortcode. La hoja de estilo solo se coloca en cola cuando el shortcode está presente.

Uso (el ID predeterminado es el usuario actual):

[get_avatar id="" size="32" default="mystery" alt="Profile Photo" class="round"]

function wpse_165754_avatar_shortcode_wp_enqueue_scripts() {
    wp_register_style( 'get-avatar-style', plugins_url( '/css/style.css', __FILE__ ), array(), '1.0.0', 'all' );
}

add_action( 'wp_enqueue_scripts', 'wpse_165754_avatar_shortcode_wp_enqueue_scripts' );
if ( function_exists( 'get_avatar' ) ) {
    function wpse_165754_user_avatar_shortcode( $attributes ) {

        global $current_user;
        get_currentuserinfo();

        extract( shortcode_atts(
                     array(
                         "id"      => $current_user->ID,
                         "size"    => 32,
                         "default" => 'mystery',
                         "alt"     => '',
                         "class"   => '',
                     ), $attributes, 'get_avatar' ) );

        $get_avatar = get_avatar( $id, $size, $default, $alt );

        wp_enqueue_style( 'get-avatar-style' );

        return '<span class="get_avatar ' . $class . '">' . $get_avatar . '</span>';
    }

    add_shortcode( 'get_avatar', wpse_165754_user_avatar_shortcode' );
}
jblanche
fuente
Olvidé que hice esta pregunta el año pasado, pero en muchos casos también comencé a hacerlo de esta manera. Es como combinar los métodos 1 y 2.
Bryan Willis
44
Este método carga el CSS en el pie de página, que seguramente tiene limitaciones.
Jacob Raccuia
1
Esta es absolutamente la forma correcta de hacer esto. Utilice este método cada vez que necesite cargar condicionalmente una secuencia de comandos o una hoja de estilo cuando el wp_enqueue_scriptsenlace ya haya ocurrido. (Los códigos cortos se analizan durante el the_contentcual es parte del the_postgancho, lo que significa que hacer cola cuando se analiza es demasiado tarde a menos que ya haya registrado el script)
JRad the Bad
26

Antes de comenzar la respuesta, debo decir que con respecto a este tema, css y js no son lo mismo.

La razón es simple: si bien agregar js al cuerpo de la página (en el pie de página) es una forma común y válida de hacerlo, css debe colocarse en la <head>sección de la página: incluso si la mayoría de los navegadores pueden representar correctamente css en la página cuerpo, eso no es un código HTML válido.

Cuando se procesa un código corto, la <head>sección ya se imprimió, significa que se puede agregar js sin ningún problema en el pie de página, pero css se debe agregar antes de que se procese el código corto.

Guiones

Si su shortcode solo necesita js, tiene suerte y solo puede usarlo wp_enqueue_scripten el cuerpo de la devolución de llamada de shortcode:

add_shortcode( 'myshortcode', 'my_handle_shortcode' );

function my_handle_shortcode() {
  wp_enqueue_script( 'myshortcodejs', '/path/to/js/file.js' );
  // rest of code here...
}

Al hacerlo, su script se agrega al pie de página y solo una vez, incluso si el shortcode se usa más de una vez en la página.

Estilos

Si el código necesita estilos, entonces debe actuar antes de que se procese el shortcode.

Hay maneras diferentes de hacer esto:

  1. mire todas las publicaciones en la consulta actual y agregue los estilos de shortcode si es necesario. Esto es lo que haces en el método # 3 y # 4 en OP. De hecho, ambos métodos hacen lo mismo, pero has_shortcodese agregó en WP 3.6, mientras get_shortcode_regexestá disponible desde la versión 2.5, por lo tanto, úselo get_shortcode_regexsolo si desea que su complemento sea compatible con versiones anteriores.

  2. siempre agregue estilo shortcode, en todas las páginas

Cuestiones

El problema con el n. ° 1 es el rendimiento. Las expresiones regulares son operaciones bastante lentas y el lanzamiento de expresiones regulares en un bucle de todas las publicaciones puede ralentizar la página de manera consistente. Además, es una tarea bastante común en los temas mostrar solo el extracto de la publicación en los archivos y mostrar el contenido completo con códigos cortos solo en vistas singulares. Si eso sucede, cuando se muestra un archivo, su complemento lanzará una coincidencia de expresiones regulares en un bucle con el objetivo de agregar un estilo que nunca se utilizará: un impacto innecesario en el doble rendimiento: ralentizar la generación de páginas + solicitud HTTP adicional innecesaria

El problema con el n. ° 2 es el rendimiento, nuevamente. Agregar estilo a todas las páginas significa agregar una solicitud HTTP adicional para todas las páginas, incluso cuando no sea necesario. Incluso si el tiempo de generación de la página del lado del servidor no se ve afectado, el tiempo total de representación de la página lo hará, y para todas las páginas del sitio.

Entonces, ¿qué debe hacer un desarrollador de complementos?

Creo que lo mejor es agregar una página de opciones al complemento, donde los usuarios pueden elegir si el shortcode debe manejarse solo en vista singular o incluso en archivos. En ambos casos, es mejor proporcionar otra opción para elegir qué tipos de publicaciones habilitan shortcode.

De esa manera es posible enganchar "template_redirect"para verificar si la consulta actual satisface los requisitos y, en ese caso, agregar el estilo.

Si el usuario elige usar shortcode solo en vistas de publicaciones singulares, es una buena idea verificar si la publicación tiene shortcode o no: una vez que solo se requiere una expresión regular, no debería ralentizar tanto la página.

Si el usuario elige usar shortcode incluso en archivos, evitaría ejecutar regex para todas las publicaciones si el número de publicaciones es alto y simplemente pondría en cola el estilo si los requisitos de la consulta se ajustaran.

Lo que debe considerarse "alto" a este respecto debe ser utilizar algunas pruebas de rendimiento o, como alternativa, agregar otra opción y dar la opción a los usuarios.

gmazzap
fuente
2
Vale la pena señalar aquí que las <style>etiquetas en el cuerpo del documento ahora son válidas según las especificaciones del W3C. w3.org/TR/html52/document-metadata.html#the-style-element
Isaac Lubow
5

Para mi complemento, descubrí que a veces los usuarios tienen un generador de temas que tiene un código abreviado almacenado en metadatos posteriores . Esto es lo que estoy usando para detectar si mi código abreviado del complemento está presente en la publicación actual o en los metadatos de la publicación :

function abcd_load_my_shorcode_resources() {
       global $post, $wpdb;

       // determine whether this page contains "my_shortcode" shortcode
       $shortcode_found = false;
       if ( has_shortcode($post->post_content, 'my_shortcode') ) {
          $shortcode_found = true;
       } else if ( isset($post->ID) ) {
          $result = $wpdb->get_var( $wpdb->prepare(
            "SELECT count(*) FROM $wpdb->postmeta " .
            "WHERE post_id = %d and meta_value LIKE '%%my_shortcode%%'", $post->ID ) );
          $shortcode_found = ! empty( $result );
       }

       if ( $shortcode_found ) {
          wp_enqueue_script(...);
          wp_enqueue_style(...);
       }
}
add_action( 'wp_enqueue_scripts', 'abcd_load_my_shorcode_resources' );
zdenekca
fuente
2

Lo hago asi:

class My_Shortcode {

    function __construct() {
        do_action('my_start_shortcode'); // call
....

y atrapar hook en otras funciones (u otros complementos):

function wpse_3232_load_script(){
    wp_enqueue_script('js-myjs');
}
add_action('my_start_shortcode','wpse_3232_load_script',10);
Wladimir Druzhaev
fuente
1

Descubrí mi propio complemento, si el shortcode está presente en el widget de texto.

function check_shortcode($text) {

  $pattern = get_shortcode_regex();

   if (   preg_match_all( '/'. $pattern .'/s', $text, $matches )
        && array_key_exists( 2, $matches )
        && in_array( 'myshortcode', $matches[2] ) )
    {
        // myshortcode is being used

        // enque my css and js
        /****** Enqueu RFNB  ******/
        wp_enqueue_style('css-mycss');
        wp_enqueue_script('js-myjs');

        // OPTIONAL ALLOW SHORTCODE TO WORK IN TEXT WIDGET
        add_filter( 'widget_text', 'shortcode_unautop');
        add_filter( 'widget_text', 'do_shortcode'); 

    }

  return $text;

}
add_filter('widget_text', 'check_shortcode');
Gino
fuente
1

WordPress tiene una función incorporada para hacer algo basado en un estado de presentación Shortcode específico. El nombre de la función es has_shortcode(). Puedes usar el siguiente código para poner en cola tu estilo y tus scripts.

Aquí usé is_a( $post, 'WP_Post' )para verificar si el $postobjeto es de la WP_Postclase y solía $post->post_contentverificar el contenido de la publicación.

if ( is_a( $post, 'WP_Post' ) && has_shortcode( $post->post_content, 'shortcode_tag') ) {
    wp_enqueue_style( 'handle', get_template_directory_uri() . '/your_file_filename.css' );
}
Arif Rahman
fuente
0

Hice una combinación del código de ejemplo de la página de Wordpress para has_shortcode () y la respuesta que dio zndencka . Me di cuenta de que la función has_shortcode se agrega en Wordpress 3.6, por eso primero compruebo si la función existe. Tal vez esa verificación es un poco obsoleta, ya que ya no hay muchos usuarios por debajo de wordpress 3.6 según wordpress sus propias estadísticas.

// This makes sure the styling is already enqueued in the header, so before the shortcode loads in the page/post
function enqueue_shortcode_header_script() {
    global $post;
    if ( function_exists( 'has_shortcode' ) ){  // is added in wordpress 3.6
        // Source: https://codex.wordpress.org/Function_Reference/has_shortcode
        if( is_a( $post, 'WP_Post' ) && has_shortcode( $post->post_content, 'my_shortcode') ) {
            wp_enqueue_style( 'shortcode-css' );
        }
    }
    else if ( isset($post->ID) ) { // Small percentage wordpress users are below 3.6 https://wordpress.org/about/stats/
        global $wpdb;
        $result = $wpdb->get_var(
          $wpdb->prepare(
              "SELECT count(*) FROM $wpdb->postmeta " .
              "WHERE post_id = %d and meta_value LIKE '%%my_shortcode%%'",
               $post->ID )
        );
        if (!empty( $result )) { wp_enqueue_style( 'shortcode-css' ); }
    }
}
add_action( 'wp_enqueue_scripts', 'enqueue_shortcode_header_script');
Vasco
fuente
0

De hecho, podemos cargar condicionalmente archivos CSS y JS a través de shortcode sin usar ninguna función demasiado elaborada :

Primero, supongamos que registramos todos nuestros archivos CSS / JS anteriormente (tal vez cuando se wp_enqueue_scriptsejecutó)

function prep_css_and_js() {
     wp_register_style('my-css', $_css_url);
     wp_register_script('my-js', $_js_url);
}
add_action( 'wp_enqueue_scripts', 'prep_css_and_js', 5 );

A continuación, examinemos nuestra función de shortcode:

function my_shortcode_func( $atts, $content = null ) {
  if( ! wp_style_is( "my-css", $list = 'enqueued' ) ) { wp_enqueue_style('my-css'); }
  if( ! wp_script_is( "my-js", $list = 'enqueued' ) ) { wp_enqueue_script('my-js'); }
  ...
}

Sencillo. Hecho. Ergo: podemos "cargar condicionalmente" archivos css / js (solo cuando se ejecuta [shortcode]).

Consideremos la siguiente ideología:

  • Queremos cargar ciertos archivos CSS / JS (pero solo cuando se activa shortcode)
  • Tal vez no queremos que esos archivos se carguen en cada página, o en absoluto si el shortcode no se usa en una página / publicación. (peso ligero)
  • Podemos lograr esto asegurándonos de que WP registre TODOS los archivos css / js antes de llamar al shortcode y antes de la cola.
  • IE: Tal vez durante mi prep_css_and_js()función cargue TODOS los archivos .css / .js que están en ciertas carpetas ...

Ahora que WP los ve como scripts registrados, podemos llamarlos, condicionalmente, en función de una serie de situaciones, que incluyen pero no se limitan a my_shortcode_func()

Beneficios: (sin MySQL, sin funciones avanzadas y sin filtros necesarios)

  • esto es "WP orthodix", elegante, carga rápida, fácil y simple
  • permite a los compiladores / minificadores detectar tales scripts
  • utiliza las funciones de WP (wp_register_style / wp_register_script)
  • compatible con más temas / complementos que deseen cancelar el registro de esos scripts por una gran cantidad de razones.
  • no se disparará varias veces
  • implica muy poco procesamiento o código

Referencias

Christian Žagarskas
fuente