Умовно завантаження JavaScript / CSS для коротких кодів


37

Я випустив плагін, який створює короткий код і вимагає файлу JavaScript та CSS-файлу для завантаження на будь-яку сторінку, що містить цей короткий код. Я міг би просто зробити сценарій / стиль завантаження на всі сторінки, але це не найкраща практика. Я хочу лише завантажувати файли на сторінки, які викликають короткий код. Я знайшов два методи цього, але в обох є проблеми.

Спосіб 1 встановлює прапор істинним у функції обробника короткого коду, а потім перевіряє це значення всередині wp_footerзворотного дзвінка. Якщо це правда, він використовує wp_print_scripts()для завантаження JavaScript. Проблема в цьому полягає в тому, що він працює лише для JavaScript, а не для CSS, тому що CSS повинен бути оголошений всередині <head>, що ви можете робити лише під час раннього гака, як initабо wp_head.

Спосіб 2 запускається рано та "зазирає вперед", щоб побачити, чи існує короткий код у поточному вмісті сторінки. Мені цей метод подобається набагато краще, ніж перший, але проблема з ним він не виявить, якщо шаблон викликає do_shortcode().

Отже, я схиляюся до використання другого методу, а потім намагаюся виявити, чи призначений шаблон, і якщо так, розбери його на шорт-код. Перш ніж я це зробив, хотів перевірити, чи хтось знає кращий метод.

Оновлення: я інтегрував рішення у свій плагін. Якщо комусь цікаво побачити, як воно з'явилося в прямому ефірі, ви можете завантажити його або переглянути його .

Оновлення 2: Станом на WordPress 3.3, тепер можна зателефонувати wp_enqueue_script()безпосередньо у зворотний дзвінок із коротким кодом, а файл JavaScript буде викликаний у нижньому колонтитулі документа. Це технічно можливо і для CSS-файлів, але це слід вважати поганою практикою, оскільки виведення CSS за межі <head>порушує специфікації W3C, може спричинити FOUC і може змусити браузер повторно відобразити сторінку.


Раніше я використовував варіацію методу 1. Завантажте JS для короткого коду в нижньому колонтитулі, завантажте CSS для короткого коду в рядку. Це працює, але хакі. Чекаємо кращого рішення.
EAMann

Основні проблеми вбудованого CSS полягають у тому, що важко перекрити інші стилі, і він не використовує метод wp_enqueue_styles ().
Ян Данн

Скільки у вас css?
mfields

Скільки рядків javascript?
mfields

2
Javascript - це легка частина. Найкраще це зробити під " Джедаєм
mfields

Відповіді:


11

Виходячи з власного досвіду, я використовував комбінацію методу 1 і 2 - сценарії архітектури та нижнього колонтитула 1 та техніку "погляд вперед" 2.

Для огляду наперед я використовую регулярний вираз замість stripos; особистісні переваги, швидше, і вони можуть перевірити наявність "неправильного" короткого коду;

preg_match( '#\[ *shortcode([^\]])*\]#i', $content );

Якщо ви стурбовані авторами, які використовують do_shortcodeвручну, я б вирішив доручити їм використовувати виклик дій, який передасть ваш попередньо зареєстрований стиль вручну.

ОНОВЛЕННЯ : Для ледачого автора, який ніколи не RTFM, виведіть повідомлення, щоб виділити помилку їх шляхів;)

function my_shortcode()
{
    static $enqueued;
    if ( ! isset( $enqueued ) )
        $enqueued = wp_style_is( 'my_style', 'done' ); // cache it so we don't repeat if called over and over

    // do shortcode
    $output = '';

    if ( ! $enqueued )
        // you can output the message on first occurence only by wrapping it in the previous if
        $output .= <<<HTML
<p>Attention! You must enqueue the shortcode stylesheet yourself if calling <code>do_shortcode()</code> directly!</p>
<p>Use <code>wp_enqueue_style( 'my_style' );</code> before your <code>get_header()</code> call inside your template.</p>
HTML;

    return $output;
}

Це хороший момент. В ідеалі я хотів би, щоб це працювало без того, щоб вони нічого зайвого не робили - тому що половину часу вони, ймовірно, спочатку не прочитають FAQ, тому вони просто припускають, що це зламано - але я можу в кінцевому підсумку це зробити. Я можу зареєструвати сценарії на кожній сторінці, але запускати їх лише за умови виявлення короткого коду. Тоді користувачі можуть підключитися до init та викликати функції enqueue у певних шаблонах, де це необхідно, припускаючи, що у цьому пункті вже не пізно у виконанні. Також WP має вбудований get_shortcode_regex ().
Ян Данн

3
Якщо користувачі вміють реалізовувати do_shortcode(), чи не є розумним вважати, що вони також вміють виконувати наступні вказівки щодо стилю короткого коду?
Чіп Беннетт

1
Щоправда, але він отримає регулярний вираз для всіх шорт-кодів, а не тільки вашого;) "Я міг би зареєструвати сценарії на кожній сторінці" Напевно, і кращий метод! Зверніть увагу, що вони не потребують підключення init, як ніде раніше wp_head. Для ледачого розробника перевірте wp_style_is( 'my_style_handle', 'done' )свій короткий код. Якщо це неправда, роздрукуйте видиму помилку, яка вказує їм, що робити.
TheDeadMedic

@Chip - Я не переживаю, що вони не здатні виконувати вказівки, просто не знають, що їм належить, оскільки 99% часу не потрібно робити нічого зайвого.
Ян Данн

1
@Ian я міркував про те, що додавання do_shortcode()до шаблону вже є "робити [щось] щось зайве" - і користувачі, які роблять це щось зайве, або вже знають про необхідність завоювати стиль, інакше будуть більш охочі / ймовірно слідувати спеціальним інструкціям.
Чіп Беннетт

8

Я спізнююсь відповісти на це запитання, але, оскільки Іан запустив цю тему у список wp-хакерів сьогодні, я змусив її подумати, особливо враховуючи, що я планував додати таку функцію до деяких плагінів, над якими я працював.

Підхід, який слід врахувати, полягає у тому, щоб перевірити завантаження на першій сторінці, щоб перевірити, чи дійсно використовується короткий код, а потім зберегти стан використання короткого коду до мета-ключа пост. Ось як:

Крок за кроком Як робити

  1. Встановіть $shortcode_usedпрапор на 'no'.
  2. У самій функції короткого коду встановіть $shortcode_usedпрапор 'yes'.
  3. Встановіть 'the_content'пріоритет гака, 12який буде після того, як WordPress обробив шорт-коди, і перевірте мета meta за ''допомогою ключа "_has_{$shortcode_name}_shortcode". (Повертається значення '', коли мета-ключ повідомлення не існує для ідентифікатора публікації.)
  4. Використовуйте 'save_post'гачок, щоб видалити мета-повідомлення, очищаючи стійкий прапор для цієї публікації, якщо користувач змінить використання короткого коду.
  5. Також у 'save_post'гачку використовують wp_remote_request()для надсилання неблокуючого HTTP GET на власну постійну посилання, щоб викликати завантаження першої сторінки та встановлення постійного прапора.
  6. Нарешті встановити 'wp_print_styles'і перевірити пост мета для значення 'yes', 'no'або з ''допомогою ключа "_has_{$shortcode_name}_shortcode". Якщо значення 'no'не служить зовнішньому. Якщо значення є 'yes'або ''йдіть вперед і обслуговуйте зовнішнє.

І це має робити. Я написав і протестував приклад плагіна, щоб показати, як це все працює.

Приклад коду плагіна

Плагін прокидається на [trigger-css]короткому коді, який встановлює <h2>елементи сторінки на білий-червоний, щоб ви могли легко побачити, як він працює. Він передбачає cssпідкаталог, що містить style.cssфайл із цим CSS у ньому:

/*
 * Filename: css/style.css
 */
h2 {
  color: white;
  background: red;
}

А нижче - код у робочому плагіні:

<?php
/**
 * Plugin Name: CSS on Shortcode
 * Description: Shows how to conditionally load a shortcode
 * Author: Mike Schinkel <mike@newclarity.net>
 */
class CSS_On_Shortcode {

  /**
   * @var CSS_On_Shortcode
   */
  private static $_this;

  /**
   * @var string 'yes'/'no' vs. true/false as get_post_meta() returns '' for false and not found.
   */
  var $shortcode_used = 'no';

  /**
   * @var string
   */
  var $HAS_SHORTCODE_KEY = '_has_trigger-css_shortcode';
  /**
   *
   */
  function __construct() {
    self::$_this = $this;
    add_shortcode( 'trigger-css', array( $this, 'do_shortcode' ) );
    add_filter( 'the_content', array( $this, 'the_content' ), 12 ); // AFTER WordPress' do_shortcode()
    add_action( 'save_post', array( $this, 'save_post' ) );
    add_action( 'wp_print_styles', array( $this, 'wp_print_styles' ) );
  }

  /**
   * @return CSS_On_Shortcode
   */
  function this() {
    return self::$_this;
  }

  /**
   * @param array $arguments
   * @param string $content
   * @return string
   */
  function do_shortcode( $arguments, $content ) {
    /**
     * If this shortcode is being used, capture the value so we can save to post_meta in the 'the_content' filter.
     */
    $this->shortcode_used = 'yes';
    return '<h2>THIS POST WILL ADD CSS TO MAKE H2 TAGS WHITE ON RED</h2>';
  }

  /**
   * Delete the 'has_shortcode' meta value so that it can be regenerated
   * on first page load in case shortcode use has changed.
   *
   * @param int $post_id
   */
  function save_post( $post_id ) {
    delete_post_meta( $post_id, $this->HAS_SHORTCODE_KEY );
    /**
     * Now load the post asynchronously via HTTP to pre-set the meta value for $this->HAS_SHORTCODE_KEY.
     */
    wp_remote_request( get_permalink( $post_id ), array( 'blocking' => false ) );
  }

  /**
   * @param array $args
   *
   * @return array
   */
  function wp_print_styles( $args ) {
    global $post;
    if ( 'no' != get_post_meta( $post->ID, $this->HAS_SHORTCODE_KEY, true ) ) {
      /**
       * Only bypass if set to 'no' as '' is unknown.
       */
      wp_enqueue_style( 'css-on-shortcode', plugins_url( 'css/style.css', __FILE__ ) );
    }
   }

  /**
   * @param string $content
   * @return string
   */
  function the_content( $content ) {
    global $post;
    if ( '' === get_post_meta( $post->ID, $this->HAS_SHORTCODE_KEY, true ) ) {
      /**
       * This is the first time the shortcode has ever been seen for this post.
       * Save a post_meta key so that next time we'll know this post uses this shortcode
       */
      update_post_meta( $post->ID, $this->HAS_SHORTCODE_KEY, $this->shortcode_used );
    }
    /**
     * Remove this filter now. We don't need it for this post again.
     */
    remove_filter( 'the_content', array( $this, 'the_content' ), 12 );
    return $content;
  }

}
new CSS_On_Shortcode();

Приклад скріншотів

Ось серія скріншотів

Основний редактор публікацій, без вмісту

Повідомлення, відсутність вмісту

Основний редактор [trigger-css]пошти з коротким кодом

Повідомлення з [trigger-css]коротким кодом

Не впевнений, якщо це 100%

Я вважаю, що вищезазначене має працювати майже у всіх випадках, але, як тільки я писав цей код, я не можу бути на 100% впевнений. Якщо ви можете знайти ситуації, коли це не працює, я дуже хотів би знати, щоб я міг виправити код у деяких плагінах, до яких я тільки що додав. Заздалегідь спасибі.


Отже, п'ять плагінів із використанням вашого підходу викликатимуть п'ять віддалених запитів кожного разу, коли повідомлення буде збережено? Я вважаю за краще використовувати регулярний вираз post_content. А як щодо шорт-кодів у віджетах?
fuxia

@toscho Запуск завантаження після фактично необов’язковий; це лише для того, щоб користувач не повинен бачити завантаження першої сторінки із завантаженими зовнішніми сторонами. Це також не блокуючий виклик, тому теоретично ви не повинні цього помічати. Для нашого коду ми працюємо в базовому класі, тому базовий клас може обробляти це лише один раз. Ми можемо підключити 'pre_http_request'гак і відключити кілька дзвінків до однієї і тієї ж URL-адреси, поки 'save_post'гак активний, але я хотів би почекати, поки справді не з’явиться потреба в цьому, ні? Що стосується віджетів, то їх можна вдосконалити для обробки, але це ще не корисний випадок, який я ще розглядав.
MikeSchinkel

1
@toscho - Також ви не можете бути впевнені, що короткий код є, оскільки інший гак може очистити його. Єдиний спосіб, в якому ви можете бути впевнені, полягає в тому, що функція короткого коду насправді працює. Тож підхід регулярного вираження не є 100% надійним.
MikeSchinkel

Я знаю. Там немає НЕ куленепробивного способу надати CSS для коротких номерів ( за винятком використання <style>).
фуксія

Я працюю з реалізацією, що базується на цьому рішенні, і я просто хотів зазначити, що цей метод не загрожує перегляду публікації / сторінки.
mor7ifer

5

Гуглінг знайшов мені потенційну відповідь . Я кажу, що "потенціал", як це виглядає добре, повинен працювати, але я не переконаний на 100%, що це найкращий спосіб зробити це:

add_action( 'wp_print_styles', 'yourplugin_include_css' );
function yourplugin_include_css() {
    // Check if shortcode exists in page or post content
    global $post;

    // I removed the end ' ] '... so it can accept args.
    if ( strstr( $post->post_content, '[yourshortcode ' ) ) {
        echo $csslink;
    }
}

Це повинно бути в змозі перевірити, чи використовує поточний пост короткий код, і додати <head>елемент стилю до елемента належним чином. Але я не думаю, що це буде працювати на сторінці з індексом (тобто декількома публікаціями у циклі) ... Це також із 2-річної старої публікації в блозі, тому я навіть не впевнений, що вона буде працювати з WP 3.1.X .


Це не спрацює, якщо у шорт-коду є аргументи. Якщо ви дійсно хочете піти цим шляхом, який повільно, використовуйте WP get_shortcode_regex()для пошуку.
onetrickpony

Як я вже сказав, "потенційна" відповідь, яку я ще не перевіряв ... :-)
EAMann

Це в основному те саме, що метод 2, але він все ще не перевіряє шаблон для викликів do_shortcode ().
Ян Данн

Чому це потрібно робити? Якщо ви зателефонуєте do_shortcode()вручну в шаблон, тоді ви вже знаєте, що будете використовувати короткий код
onetrickpony

Я не той, хто називає короткий код, користувач. Це для розповсюдженого плагіна, а не для приватного.
Ян Данн

2

Використовуючи комбінацію відповіді TheDeadMedic і в get_shortcode_regex () документациях (яка на самому ділі не знайшли мої шорткоди), я створив просту функцію , яка використовується для блокування сценарії для декількох коротких номерів . Оскільки wp_enqueue_script () у коротких кодах додається лише до нижнього колонтитулу, це може бути корисним, оскільки може обробляти як сценарій заголовка, так і колонтитула.


function add_shortcode_scripts() {
    global $wp_query;   
    $posts = $wp_query->posts;
    $scripts = array(
        array(
            'handle' => 'map',
            'src' => 'http://maps.googleapis.com/maps/api/js?sensor=false',
            'deps' => '',
            'ver' => '3.0',
            'footer' => false
        ),
        array(
            'handle' => 'contact-form',
            'src' => get_template_directory_uri() . '/library/js/jquery.validate.min.js',
            'deps' => array( 'jquery' ),
            'ver' => '1.11.1',
            'footer' => true
        )   
    );

    foreach ( $posts as $post ) {
        foreach ( $scripts as $script ) {
            if ( preg_match( '#\[ *' . $script['handle'] . '([^\]])*\]#i', $post->post_content ) ) {
                // enqueue css and/or js
                if ( wp_script_is( $script['handle'], 'registered' ) ) {
                    return;
                } else {
                    wp_register_script( $script['handle'], $script['src'], $script['deps'], $script['ver'], $script['footer'] );
                    wp_enqueue_script( $script['handle'] );
                }
            }
        }
    }
}
add_action( 'wp', 'add_shortcode_scripts' );

1

Нарешті, я також знайшов рішення для умовного завантаження css, яке працює для мого плагіна www.mapsmarker.com, і я хотів би поділитися з вами. Він перевіряє, чи використовується мій короткий код у поточному файлі шаблону та header / footer.php, і якщо так, в заголовку запускається необхідний таблиця стилів:

  function prefix_template_check_shortcode( $template ) {
    $searchterm = '[mapsmarker';
    $files = array( $template, get_stylesheet_directory() . DIRECTORY_SEPARATOR . 'header.php', get_stylesheet_directory() . DIRECTORY_SEPARATOR . 'footer.php' );
    foreach( $files as $file ) {
        if( file_exists($file) ) {
            $contents = file_get_contents($file);
            if( strpos( $contents, $searchterm )  ) {
                wp_enqueue_style('
leafletmapsmarker', LEAFLET_PLUGIN_URL . 'leaflet-dist/leaflet.css');
                  break; 
            }
        }
    }
  return $template;
  }  
  add_action('template_include','prefix_template_check_shortcode' );

трохи вбік, але це не передбачає, що люди використовують header.php і footer.php. Що щодо методів обгортання тем, таких як описаний scribu.net/wordpress/theme-wrappers.html ? чи такі теми, як коріння, які зберігають частини шаблону в іншому місці?
orionrush

1

Для мого плагіна я виявив, що інколи користувачі мають конструктор тем, який містить короткий код, який зберігається у метаданих пост . Ось що я використовую, щоб визначити, чи присутній мій короткий код плагіна в поточних або публікаціях метаданих :

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' );

0

тому що CSS повинен бути оголошений всередині <head>

Для CSS-файлів ви можете завантажити їх у межах свого короткого коду:

<style type="text/css">
  @import "path/to/your.css"; 
</style>

Встановіть константу або щось після цього, наприклад MY_CSS_LOADED(включайте CSS лише якщо константа не встановлена).

Обидва ваші методи проходять повільніше, ніж йти цим шляхом.

Для файлів JS ви можете зробити те ж саме, якщо сценарій, який ви завантажуєте, унікальний і не має зовнішніх залежностей. Якщо це не так, завантажте його всередині колонтитула, але використовуйте константу, щоб визначити, чи потрібно його завантажувати чи ні ...


3
Завантаження CSS за межами <head>елемента не є належною розміткою. Правда, перевірка - це лише керівництво, але якщо ми намагаємося дотримуватися цього керівництва, це робить завантаження таблиці стилів в межах короткого коду поганою ідеєю.
EAMann

Вбудовані CSS-блоки є дійсною розміткою навіть у XHTML з того, що я пам'ятаю. Немає причин не використовувати їх, коли у вас немає іншої прийнятної альтернативи
onetrickpony

1
Згідно інструмент перевірки W3C: <style type="text/css"> The element named above was found in a context where it is not allowed. This could mean that you have incorrectly nested elements -- such as a "style" element in the "body" section instead of inside "head". Отже стилі inline ( <element style="..."></element>) є дійсними, але <style>елементи вбудованого тексту не є.
EAMann

1
зробіть його фільтрувальним і будь-який інший плагін або тему можуть робити так, як їм подобається. Якщо вони налаштують фільтр для повернення порожнього рядка - нічого не буде надруковано.
mfields

1
Ви не згадали жодних об'єктивних причин проти цієї практики. У будь-якому випадку це не має значення; Тут я бачу лише два варіанти: Завжди завантажуйте CSS / скрипти (оптимізуйте їх за розміром), або умовні стилі вбудованих програм
onetrickpony

0

Script Logic - це плагін WordPress, який дає вам повний контроль над усіма файлами JavaScript та CSS. За допомогою цього плагіна ви можете умовно завантажувати файл CSS та JS лише на потрібні сторінки.

http://wordpress.org/plugins/script-logic/


Це насправді не має відношення до цього питання, яке стосується контролю за запитаннями всередині самого плагіна. Ваш підхід вимагає попросити користувача встановити інший плагін, а потім зрозуміти, як правильно його налаштувати.
Іван Данн
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.