¿Cómo proporcionar una reserva local para Font Awesome si falla CDN?


14

Estoy tratando de desarrollar un tema de Wordpress y descubrir cómo proporcionar un respaldo local para Font Awesome si CDN falla o si desarrollo mi tema en un servidor local sin conexión a Internet.

La solución que tengo en mente es algo como esto (pseudocódigo):

if ( $CDN_IS_AVAILABLE ) { 
        wp_enqueue_style( 'font-awesome', '//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.min.css', false );
    } else {
        wp_enqueue_style('font-awesome', get_template_directory_uri() . '/css/font-awesome/css/font-awesome.min.css', false, '4.0.3' );
    }

¡Gracias!


@Alexan ¿Qué pasa is_readable($cdnPath)?
Mayeenul Islam

Gracias @MayeenulIslam pero parece que devuelve falso incluso el CDN está disponible.
Knott

2
Hay, al menos, un par de formas, sin embargo, la única razón para usar un CDN es el rendimiento, pero estoy bastante seguro de que cualquier forma que encuentre empeorará el rendimiento, por lo que no tiene sentido. Si el tema es para compartir / vender, iría solo por una copia local, asegurándome de dejar a los usuarios una forma fácil de cambiar a la versión CDN, si así lo prefieren. Si el tema es solo para usted, elija uno u otro. Tenga en cuenta que los CDN más famosos tienen un muy bajo% de tiempo de inactividad (y bootstrapcdn es uno de los más confiables, según cdnperf.com ).
gmazzap

¿Tienes una idea genérica de cómo manejar la reserva para empezar? Sé que las fallas de respaldo de JS dependen de las variables de verificación, no estoy seguro de en qué confiar para verificar la carga de CSS.
Rarst

1
Bueno, por supuesto que sí, nunca haría una solicitud adicional de PHP para eso. Ese es el desafío aquí: para empezar, no puedo pensar en una buena manera de verificar la carga de CSS.
Rarst

Respuestas:


15

El problema es que estoy bastante seguro de que es imposible verificar si CSS se agrega efectivamente a una página a través de PHP: CSS es analizado por el navegador, por lo que el lado del cliente, y no tiene ningún efecto en el lado del servidor.

Por supuesto, en PHP es posible verificar si CDN responde o no ...

Opción 1

Envíe una solicitud y si responde con el estado HTTP 200, úsela. Algo como:

function font_awesome_css() {
    $url = 'http://netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.min.css';
    $cdn = wp_remote_get( $url );
    if ( (int) wp_remote_retrieve_response_code( $cdn) !== 200 ) {
        $url = get_template_directory_uri() . '/css/font-awesome/css/font-awesome.min.css';
    }
    wp_enqueue_style( 'font-awesome', $url, false );
}

eso da como resultado 2 solicitudes HTTP, una para la verificación, la segunda para CSS incrustado: realmente malo .

opcion 2

function font_awesome_css() {
    $url = 'http://netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.min.css';
    $cdn = wp_remote_get( $url );
    if ( (int) wp_remote_retrieve_response_code( $cdn ) === 200 ) {
        $css = wp_remote_retrieve_body( $cdn );
        add_action( 'wp_head', function() use( $css ) {
            $absolute = "//netdna.bootstrapcdn.com/font-awesome/4.0.3/fonts/";
            $css = str_replace( "../fonts/", $absolute, $css );
            echo '<style type="text/css">' . $css . '</style>';
        } );
    } else {
        $url = get_template_directory_uri() . '/css/font-awesome/css/font-awesome.min.css';
        wp_enqueue_style( 'font-awesome', $url, false );
    }
}

Esto es aún peor :

  • Arruina el wp_enqueue_styleflujo de trabajo: si un complemento agrega Font Awesome, se agregará 2 veces.
  • El número de solicitudes HTTP es el mismo, sin embargo, normalmente las 2 solicitudes se ejecutan en paralelo , por lo que la generación de la página PHP se ralentiza porque necesita esperar la primera respuesta de la solicitud.
  • Esto también evita que el navegador almacene en caché el CSS, por lo que si usa el mismo estilo en diferentes páginas, fuerza la solicitud de CDN en cada página visitada. Cuando se usa el flujo de trabajo normal, las páginas después del primer CSS se toman del caché.

Entonces, realmente, no hagas esto en casa.

Lo que realmente importa es que usando PHP puedes verificar la solicitud de CDN, pero no verificar CSS, por lo que todos tus esfuerzos terminan en un peor rendimiento, en lugar de mejorar.

Sinceramente, si el suyo es un tema público, le sugiero que use solo la copia local, proporcionando a los usuarios una forma de elegir un CDN:

if ( ! function_exists( 'font_awesome_css' ) ) {
    function font_awesome_css() {
        $_url = get_template_directory_uri() . '/css/font-awesome/css/font-awesome.min.css';
        $url = apply_filters( 'font_awesome_css_url', $_url );
        wp_enqueue_style( 'font-awesome', $url, false );
    }
}

Por lo tanto, los usuarios pueden anular completamente la función usando un tema secundario y también pueden usar el 'font_awesome css_url'filtro para cambiar la URL.

También considere que algunos proveedores de alojamiento de alta gama convierten automáticamente los activos locales a CDN, y hay complementos que permiten CDN todas las cosas; esta es la razón por la cual un tema público no debería usar CDN en absoluto.

Si el tema es para ti, entonces haz una elección. Tenga en cuenta que los CDN más famosos tienen un muy bajo% de tiempo de inactividad (y bootstrapcdn es uno de los más confiables, según cdnperf.com ). Estoy bastante seguro de que su alojamiento tiene un tiempo de inactividad% mayor que bootstrapcdn, por lo que las personas tienen más probabilidades de no ver su sitio en absoluto, que verlo con iconos rotos.

El camino sucio

Como se dijo, PHP no puede verificar CSS, porque la representación de CSS ocurre del lado del cliente, pero puede usar la verificación del lado del cliente: JavaScript.

Primero incrustar CSS usando CDN:

function font_awesome_css() {
    $url =  '//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.min.css';
    wp_enqueue_style( 'font-awesome', $url, false );
} 

Después de eso, agregue algo de JavaScript a su pie de página:

/*
Normally the JS should be properly enqueued and the URL
passed via wp_enqueue_script, but this is a proof of concept,
more than real code.
*/
add_action( 'wp_footer', function() {
    $cssurl = get_template_directory_uri() . '/css/';
    ?>
    <span id="facheck" data-cssuri="<?php echo $cssurl; ?>" class="fa" style="display:none">
    </span>
    <script>
        jQuery(document).ready(function($) {
            var $check = $('#facheck');
            if ( $check.css('fontFamily') !== 'FontAwesome' ) {
                // Font Awesome not loaded!
                // Remove current CSS link
                $('#font-awesome-css').remove;
                // Add the local version
                var local = '<link rel="stylesheet" type="text/css" href="' +
                    $check.data('cssuri') + // This is the theme CSS folder URL
                    'font-awesome/css/font-awesome.min.css" />';
                $('head').append( local );
            }
        });
    </script>
    <?php
});

Este código se ejecuta cuando se carga la página y comprueba si el intervalo invisible agregado al pie de página con la clase 'fa' tiene la propiedad de familia de fuentes establecida en 'FontAwesome'. Esto lo establece Font Awesome, por lo que si no es cierto, significa que CSS no está cargado. Si sucede, el código usa JavaScript para agregar el CSS local al encabezado.

(Para probar este código, puede incrustarlo a través de wp_enqueue_styleuna URL de CDN incorrecta y ver qué sucede)

Por lo tanto, en el raro caso de que un CDN no esté disponible, todos los estilos se mostrarán como se esperaba (para algunos milisegundos, los usuarios verán iconos CSS "rotos", porque CSS se agrega después de que se carga la página).

Ahora, considerando que los CDN son muy confiables, ¿vale la pena hacer este truco para el <1% de las personas que verán iconos rotos? Contestar esta pregunta te queda a ti.


Hace mucho tiempo que no veo un enfoque tan complejo y profundo sobre un tema como este. Eso me despejó por completo. Ahora supongo que usaré CDN solo como una opción de tema, dejando al usuario la libertad de elegir. ¡Gracias!
Knott

Llevo mucho tiempo buscando una solución como esta, así que con respecto a la última oración que pregunta "¿vale la pena hacer este truco para el <1% de las personas que verán iconos rotos?" ¿Quizás agregar un spinner de carga funcionaría?
Carl Alberto

2

Una verificación del lado del servidor tampoco es a prueba de balas. Si su servidor está ubicado en California, su cheque utilizará el Centro de datos de California CDN. Si su usuario se encuentra en China, es probable que esté utilizando un centro de datos completamente diferente. Al menos, así es como creo que funciona.

De todos modos, aquí hay una solución jquery mejorada:

http://jsfiddle.net/skibulk/fp1gqnyc/

<link href="//maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css" rel="stylesheet">
<script>
    (function($){
        var $span = $('<span class="fa" style="display:none"></span>').appendTo('body');
        if ($span.css('fontFamily') !== 'FontAwesome' ) {
            // Fallback Link
            $('head').append('<link href="/wordpress//css/font-awesome.min.css" rel="stylesheet">');
        }
        $span.remove();
    })(jQuery);
</script>

brillante, y un enfoque válido para mucho más que una fuente increíble, gracias por compartir. Debo agregar, también agnóstico a diferencia de las otras soluciones aquí y en otros lugares en SO, por ejemplo.
oucil

1
Como no hay tiempo de espera, esto terminará cargando Font Awesome dos veces si la instancia de CDN termina de cargarse después de la verificación fontFamily.
Dan Dascalescu

1
@DanDascalescu ¿No se cargan los archivos CSS sincrónicamente (bloqueo) de forma predeterminada? ¿Creo que la página no continuará hasta que se cargue el CDN o falle?
skibulk

1
CSS se carga sincrónicamente, pero la fuente en sí se carga solo cuando se procesa el texto que la usa. Aquí hay un JSbin que lo muestra .
Dan Dascalescu
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.