Los estilos en línea para los bloques de Gutenberg no se representan cuando el contenido se obtiene con una solicitud AJAX

5 minutos de lectura

necesito agarrar the_content() a través de una solicitud AJAX y represente todos los bloques de Gutenberg con su estilo en línea en la página.

El problema es que las clases de bloque únicas se agregan al pie de página en las plantillas de temas.

.wp-container-5 {
  display: flex;
  gap: 2em;
  flex-wrap: nowrap;
  align-items: center;
}

Cuando get_the_content() se usa a través de una solicitud AJAX, ese estilo de bloque único no se representa. Supongo que esto se debe a que el estilo de bloque en línea se basa en un gancho de algún tipo que no se dispara con una solicitud AJAX. do_blocks() no representa el estilo en línea.

Busqué en la base de datos y revisé los archivos fuente de WordPress y no puedo encontrar clases como .wp-container-5 vienen de Pensé que si podía encontrar la ubicación del estilo en línea, simplemente podría consultarlo y mostrarlo en la página.

¿Alguien sabe dónde se almacenan los estilos de bloque únicos y/o cómo consultarlos e incluirlos a través de una solicitud AJAX?

  • este es un nuevo comportamiento en wp (supongo que desde v6). no estoy seguro, cómo resolver esto fácilmente ya que tengo los mismos problemas ahora con el resto de la API. ¿De dónde obtengo el estilo, si no de la propia API?

    – bocina31

    6 de julio a las 15:34

Logré resolver esto después de muchas horas de frustración.

En wp-includes/block-supports/layout.php hay una funcion llamada wp_render_layout_support_flag(). Esta función toma el contenido de un bloque y un objeto de bloque y asigna la clase única wp-container- con una identificación única al final. Luego representa el estilo en línea con la función wp_get_layout_style() y encola ese estilo con wp_enqueue_block_support_styles().

El problema es, wp_render_layout_support_flag() no devuelve el estilo. Devuelve el contenido del bloque con clases de CSS e inserta el estilo en el pie de página con las clases de CSS que coinciden. Entonces, no es tan simple como simplemente llamar wp_get_layout_style() porque se asigna una identificación única en wp_render_layout_support_flag() que solo coincide cuando wp_get_layout_style() se llama dentro del wp_render_layout_support_flag() función.

La solución fue copiar y pegar (no es lo ideal pero funciona) el wp_render_layout_support_flag() función y modificarla ligeramente.

function my_render_layout_support_flag( $block_content, $block ) {
    $block_type     = WP_Block_Type_Registry::get_instance()->get_registered( $block['blockName'] );
    $support_layout = block_has_support( $block_type, array( '__experimentalLayout' ), false );

    if ( ! $support_layout ) {
        return $block_content;
    }

    $block_gap             = wp_get_global_settings( array( 'spacing', 'blockGap' ) );
    $default_layout        = wp_get_global_settings( array( 'layout' ) );
    $has_block_gap_support = isset( $block_gap ) ? null !== $block_gap : false;
    $default_block_layout  = _wp_array_get( $block_type->supports, array( '__experimentalLayout', 'default' ), array() );
    $used_layout           = isset( $block['attrs']['layout'] ) ? $block['attrs']['layout'] : $default_block_layout;
    if ( isset( $used_layout['inherit'] ) && $used_layout['inherit'] ) {
        if ( ! $default_layout ) {
            return $block_content;
        }
        $used_layout = $default_layout;
    }

    $class_name = wp_unique_id( 'wp-container-' );
    $gap_value  = _wp_array_get( $block, array( 'attrs', 'style', 'spacing', 'blockGap' ) );
    // Skip if gap value contains unsupported characters.
    // Regex for CSS value borrowed from `safecss_filter_attr`, and used here
    // because we only want to match against the value, not the CSS attribute.
    if ( is_array( $gap_value ) ) {
        foreach ( $gap_value as $key => $value ) {
            $gap_value[ $key ] = $value && preg_match( '%[\\\(&=}]|/\*%', $value ) ? null : $value;
        }
    } else {
        $gap_value = $gap_value && preg_match( '%[\\\(&=}]|/\*%', $gap_value ) ? null : $gap_value;
    }

    $fallback_gap_value = _wp_array_get( $block_type->supports, array( 'spacing', 'blockGap', '__experimentalDefault' ), '0.5em' );

    // If a block's block.json skips serialization for spacing or spacing.blockGap,
    // don't apply the user-defined value to the styles.
    $should_skip_gap_serialization = wp_should_skip_block_supports_serialization( $block_type, 'spacing', 'blockGap' );
    $style                         = wp_get_layout_style( ".$class_name", $used_layout, $has_block_gap_support, $gap_value, $should_skip_gap_serialization, $fallback_gap_value );
    // This assumes the hook only applies to blocks with a single wrapper.
    // I think this is a reasonable limitation for that particular hook.
    $content = preg_replace(
        "https://stackoverflow.com/" . preg_quote( 'class="', "https://stackoverflow.com/" ) . "https://stackoverflow.com/",
        'class="' . esc_attr( $class_name ) . ' ',
        $block_content,
        1
    );

    // This is where the changes happen

    return '<style>' . $style . '</style>' . $content;
}

El único cambio está cerca del final donde wp_enqueue_block_support_styles() se eliminó y ahora se devuelven el estilo y el contenido.

¡Ahora, los bloques de Gutenberg se pueden representar y tener el estilo adecuado cuando se usa una llamada AJAX!

$content = get_the_content(null, true, $post_id);
$blocks = parse_blocks( $content );

foreach ($blocks as $block) {
    echo my_render_layout_support_flag( render_block($block), $block );
}

Esta solución parece un poco ridícula, pero funciona… WordPress realmente debería admitir la representación de bloques de forma asíncrona.

  • Gracias. Esto ayudó Pero necesitaba quitar el filtro original. remove_filter( 'render_block', 'wp_render_layout_support_flag' ) y agrega el personalizado add_filter( 'render_block', 'my_render_layout_support_flag', 10, 2 ) y simplemente llama render_block( $block ). De lo contrario, los conteos de los contenedores estaban desordenados.

    – xsonic

    7 de julio a las 9:09

Avatar de usuario de Justin
justin

No he probado esto dentro de la respuesta de una solicitud AJAX usando el antiguo admin-ajax.php método, sin embargo, había estado tratando de lograr lo mismo dentro de una respuesta de la API REST.

Habiendo encontrado este hilo y leyendo la solución provista por Myles, gracias por sus detalles, por cierto, y buscando en el wp_render_layout_support_flag funcionar un poco más, se me ocurrió una posible alternativa.

Genéricamente, con la API REST, podría agregar algo como esto:

register_rest_field('post', 'styles', [
    'get_callback' => function ($post) {
        ob_start();

        do_action('wp_footer');

        $content = ob_get_clean();

        // perform any needed manipulation

        return $content;
    },
    'schema' => [
        'description' => __('Styles'),
        'type' => 'string',
    ],
]);

Probablemente desee eliminar el contenido sin estilo en el resultado, en caso de que tenga otras funciones que envíen contenido que aparecería dentro wp_footer.

Tal vez algo como esto te daría lo que estás buscando:

ob_start();

the_content();

do_action('wp_footer');

$content = ob_get_clean();

¿Ha sido útil esta solución?