Как добавить стили только на страницы с определённым шорткодом?

31 июл. 2013 г., 12:42:21
Просмотры: 14.6K
Голосов: 9

Я запускаю функцию на страницах, где используется шорткод [make-me-a-map]. Она подключает javascript к странице и создаёт карту. Эта часть работает нормально (ура!), но у меня возникли проблемы с добавлением стилей только на эти страницы аналогичным образом.

functions.php (Текущая версия)

add_shortcode("make-me-a-map", "create_new_map");
add_action("wp_head", "style_my_new_map");

function create_new_map () {
    global $new_map_called_for;
    $map_called_for = true;

    wp_register_script('make-a-new-map', get_template_directory_uri() . '/js/new-map.js', array('jquery'), '0.1', true);
    wp_enqueue_script('make-a-new-map');
    }

function style_my_new_map() {
    global $new_map_called_for;
    if ($new_map_called_for == true) {
        $tDir = get_template_directory_uri();

        // Выводим стили напрямую, потому что wp_register_style & wp_enqueue_style сейчас не работают
        // И add_action('wp_enqueue_script', 'style_my_new_maps') с этими функциями добавит стили на все страницы
        // А не только на те, где есть шорткод [make-me-a-map]
        echo "<link rel='stylesheet' href='", $tDir, "/css/new-map.css' />", PHP_EOL;

        // Выводим JavaScript напрямую на страницу (не получилось сделать через wp_enqueue_script) чтобы js-код знал путь к шаблону
        echo '<script type="text/javascript">var templateDir = "', get_template_directory_uri(), '";</script>', PHP_EOL;
        $map_called_for = false;
    }
}

К сожалению, это не работает так, как нужно. Стили добавляются на все страницы.

Я не использовал wp_register_style & wp_enqueue_style, потому что эта ошибка всё ещё добавляет теги <Link /> в подвал через эти функции.

Я мог бы использовать add_action("wp_enqueue_scripts", "style_my_new_map") вместо add_action('wp-head', "style_my_new_map"), но насколько я понимаю и проверял, разницы нет? Стили всё равно добавляются на все страницы.

Так что мой вопрос состоит из двух частей: :)

  1. Почему текущий functions.php не работает и добавляет стили на все страницы? Не уверен, проблема в вызове global или в условии if...
  2. Какой лучший способ добавить стили только в заголовок тех страниц, где используется указанный шорткод, при условии что я не знаю ID страниц и т.д.?

Заранее спасибо! P

1
Комментарии

Лучшее обсуждение здесь: http://wordpress.stackexchange.com/questions/165754/enqueue-scripts-styles-when-shortcode-is-present

JannieT JannieT
9 мар. 2015 г. 13:06:46
Все ответы на вопрос 8
3
11

Динамическая загрузка скриптов и стилей с помощью шорткода

Преимущества

  • Не выполняет поиск по всем записям каждый раз при вызове шорткода.
  • Позволяет динамически добавлять стили и скрипты только когда шорткод присутствует на странице.
  • Не использует регулярные выражения, так как они работают медленнее, чем strstr() или strpos(). Можно переключиться на регулярки, если требуется обработка аргументов.
  • Уменьшает количество обращений к файлам

Объяснение кода

  1. Находит шорткоды на странице с помощью хука save_post только когда запись не является ревизией и соответствует указанному post_type.

  2. Сохраняет найденные ID записей в виде массива с помощью add_option() с автозагрузкой 'yes', если запись еще не существует. В противном случае использует update_option().

  3. Использует хук wp_enqueue_scripts для вызова нашей функции add_scripts_and_styles().

  4. Эта функция вызывает get_option() для получения массива ID страниц. Если текущий $page_id присутствует в массиве $option_id_array, то добавляет скрипты и стили.

Обратите внимание: Я конвертировал код из ООП с использованием пространств имен, поэтому мог что-то упустить. Сообщите в комментариях, если найдете ошибки.

Пример кода: Поиск вхождений шорткода

function find_shortcode_occurences($shortcode, $post_type = 'page')
{
    $found_ids = array();
    $args         = array(
        'post_type'   => $post_type,
        'post_status' => 'publish',
        'posts_per_page' => -1,
    );
    $query_result = new \WP_Query($args);
    foreach ($query_result->posts as $post) {
        if (false !== strpos($post->post_content, $shortcode)) {
            $found_ids[] = $post->ID;
        }
    }
    return $found_ids;
}

function save_option_shortcode_post_id_array( $post_id ) {
    if ( wp_is_post_revision( $post_id ) OR 'page' != get_post_type( $post_id )) {
        return;
    }
    $option_name = 'yourprefix-yourshortcode';
    $id_array = find_shortcode_occurences($option_name);
    $autoload = 'yes';
    if (false == add_option($option_name, $id_array, '', 'yes')) update_option($option_name, $id_array);
}

add_action('save_post', 'save_option_shortcode_id_array' );

Пример кода: Динамическое подключение скриптов и стилей через шорткод

function yourshortcode_add_scripts_and_styles() {
    $page_id = get_the_ID();
    $option_id_array = get_option('yourprefix-yourshortcode');
    if (in_array($page_id, $option_id_array)) {
        wp_enqueue_script( $handle, $src, $deps, $ver, $footer = true );
        wp_enqueue_style( $handle, $src , $deps);
    }
}

add_action('wp_enqueue_scripts', 'yourshortcode_add_scripts_and_styles');
21 февр. 2014 г. 21:10:56
Комментарии

Я еще не тестировал это, но это именно тот ответ, который я искал. Кажется, у этого решения минимальные недостатки.

Jacob Raccuia Jacob Raccuia
21 апр. 2017 г. 16:33:53

@JacobRaccuia Я тестировал это некоторое время назад, и это работало. Не знаю, как это будет работать с новыми версиями WP, но сомневаюсь, что многое изменилось, учитывая природу платформы.

CommandZ CommandZ
4 мая 2017 г. 06:17:22

Я потратил много времени, пытаясь довести это до совершенства. Есть серьезные недостатки, если пользователь вводит шорткод в нетрадиционном для WP месте. Я написал хук для проверки всех пользовательских полей, что потенциально может помочь решить эту проблему.

Jacob Raccuia Jacob Raccuia
4 мая 2017 г. 08:36:53
2

Этот вариант работает у меня:

function register_my_css () {
    wp_register_style('my-style', plugins_url('styles.css', __FILE__));
}

function register_my_scripts () {
    wp_register_script('my-script', plugins_url('scripts.js', __FILE__));
}

// Подключаем скрипты/стили только при вызове шорткода
function do_my_shortcode () {
    wp_enqueue_style('my-style');
    wp_enqueue_script('my-script');

    // выполняем действия шорткода...
}

// Регистрируем CSS
add_action('wp_enqueue_scripts', 'register_my_css');

// Регистрируем JavaScript
add_action('wp_enqueue_scripts', 'register_my_scripts');

// Регистрируем шорткод
add_shortcode('my-shortcode', 'do_my_shortcode');

Подробнее здесь: http://mikejolley.com/2013/12/sensible-script-enqueuing-shortcodes/

16 июл. 2015 г. 13:36:37
Комментарии

Нет, это выведет шорткод поверх контента.

fuxia fuxia
16 июл. 2015 г. 14:23:29

Проблема в том, что стили будут подключены в футере. Это, возможно, сработает. Но это «неправильно» и не гарантирует работоспособность.

Doug Cassidy Doug Cassidy
11 мар. 2016 г. 18:16:17
1

2 вопроса, значит 2 ответа :)

Почему текущий functions.php не работает и добавляет стили на все страницы? Не уверен, проблема в глобальном вызове или в условии if...

Это не работает из-за порядка вызова функций. Ваш шорткод вызывается во время отрисовки контента записи (скорее всего при вызове the_content).

И wp_enqueue_scripts, и wp_head вызываются гораздо раньше: wp_head где-то в файле header.php вашей темы, а wp_enqueue_scripts во время вызова wp_head.

Какой лучший способ добавить таблицы стилей в заголовок только тех страниц, где используется указанный выше шорткод, учитывая что я не буду знать ID страниц и т.д.?

Не думаю, что существует "лучший" способ. Вообще это не очень хорошая идея. Браузеры кэшируют CSS файлы. Поэтому если у вас одинаковый CSS на всех страницах, браузер загрузит его только один раз. Если же будет много CSS файлов для разных страниц, браузеру придется загружать их все. Так что я бы вообще не стал этого делать и включил эти стили в глобальный CSS файл.

Хотя если вам обязательно нужно подключать стили только на страницах с этим шорткодом, тогда (2 решения, выбор за вами; мне кажется второе более изящным)...

  1. Можно добавить эти стили как inline-стили. Главное убедиться, что они не будут добавлены несколько раз. То есть выводить их вместе с шорткодом и гарантировать однократный вывод.
  2. Так как записи уже выбраны, когда вызывается wp_head/wp_enqueue_scripts, можно добавить функцию на этот хук, пройтись по выбранным записям, проверить содержат ли они ваш шорткод и подключить CSS если нужно. (Конечно это не очень эффективно).
31 июл. 2013 г. 13:05:45
Комментарии

Да, вариант #2 может быть менее эффективным, но определённо красивее, чем inline =) Теперь всё работает, спасибо!

Padraic Padraic
3 авг. 2013 г. 11:46:20
0

Вы можете подключиться к действию после выполнения основного запроса и определить, нужно ли загружать ваши стили и скрипты.

add_action('template_include', 'custom_template_include');
function custom_template_include($template) {
    if (is_single() || is_page()) {
          global $post;
          if (has_shortcode($post->post_content, 'your_short_code')) {
              add_action('wp_enqueue_scripts', 'custom_enqueue_scripts');
          }
    } 
    return $template;
}

function custom_enqueue_scripts() {
    // Подключаем здесь необходимые скрипты и стили
}
1 апр. 2015 г. 15:50:55
0
add_action( 'wp_enqueue_scripts', 'enqueue_shortcode_styles', 1 );
function enqueue_shortcode_styles() {

    global $post;

    if ( isset($post->post_content) && is_singular(array( 'post','page' ) ) && ! has_shortcode( $post->post_content, '$tag' ) ) {

    wp_enqueue_style( 'shortcode-styles', get_stylesheet_directory_uri() . '/style.css' );

    }

}

Я бы использовал has_shortcode для проверки содержимого $post и загрузки скриптов с помощью wp_enqueue_scripts, но это зависит от того, где встроены ваши шорткоды.

Замените $tag на ваш тег шорткода в приведенном выше коде.

Добавьте этот код в файл functions.php вашей дочерней темы и при необходимости измените условия.

26 мая 2017 г. 15:16:43
0

Более простое решение, которое сработало у меня - зарегистрировать скрипт вне функции шорткода, а затем подключить его внутри функции. Таким образом, скрипт загружается только на страницах, использующих ваш шорткод.

wp_register_script('make-a-new-map', get_template_directory_uri() . '/js/new-map.js', array('jquery'), '0.1', true);
wp_register_style('make-a-new-map-style', get_template_directory_uri() . '/css/new-map.css');

add_shortcode("make-me-a-map", "create_new_map");
add_action("wp_head", "style_my_new_map");

function create_new_map () {
   wp_enqueue_script('make-a-new-map');
   wp_enqueue_style('make-a-new-map-style');

   global $new_map_called_for;
   $map_called_for = true;
}

Описание этого метода можно найти здесь: http://mikejolley.com/2013/12/sensible-script-enqueuing-shortcodes/

Обратите внимание, что в этом случае CSS загружается в подвале сайта (footer), что может быть нежелательно или не соответствовать стандартам W3C. В моём случае это не было проблемой.

8 нояб. 2014 г. 17:26:44
0

Вы можете сделать это следующим образом:

// хук шорткода
add_shortcode("make-me-a-map", "create_new_map");

// функция обратного вызова шорткода
function style_my_new_map() {
    global $new_map_called_for;
    if ($new_map_called_for == true) {
  wp_register_script('make-a-new-map', get_template_directory_uri() . '/js/new-map.js', array('jquery'), '0.1', true);
  wp_enqueue_script('make-a-new-map');

// остальной ваш код
    }
}

Это также работает и для таблиц стилей. Чтобы загрузить вашу таблицу стилей последней, добавьте цифры к хуку шорткода, вот так:

add_shortcode("make-me-a-map", "create_new_map", 9999);

Я протестировал это, и это работает.

25 февр. 2015 г. 20:03:15
0

Динамическая загрузка скриптов и стилей с использованием шорткода

Это расширенный код для решения, предложенного Commandz выше.

Я обнаружил, что его метод является лучшим и более удобным, так как опция базы данных доступна практически на всех хуках.

Код изменен для поиска вхождений шорткодов только в контенте текущей записи, вместо просмотра всех записей - что может быть медленнее при большом количестве записей.

Изменения внесены в две строки после передачи дополнительной переменной $post_id из действия save_post в функцию find_shortcode_occurences()

if( !empty($post_id) ) {
    $args['posts__in'] = $post_id; 
}

Измененный код для обеих функций

function find_shortcode_occurences($shortcode, $post_id='', $post_type = 'page') {
    $found_ids = array();
    $args         = array(
        'post_type'   => $post_type,
        'post_status' => 'publish',
        'posts_per_page' => -1,
    );

    if( !empty($post_id) ) {
        $args['posts__in'] = $post_id; 
    }

    $query_result = new WP_Query($args);
    foreach ($query_result->posts as $post) {
        if (false !== strpos($post->post_content, $shortcode)) {
            $found_ids[] = $post->ID;
        }
    }
    return $found_ids;
}

add_action('save_post', 'save_option_for_sppro_pages' );
function save_option_for_sppro_pages( $post_id ) {
    if ( wp_is_post_revision( $post_id ) ) {
        return;
    }
    $option_name = 'database-option';
    $shortcode = 'shortcode-name';
    $id_array = find_shortcode_occurences($shortcode, $post_id);
    $autoload = 'yes';
    if (false == add_option($option_name, $id_array, '', 'yes')) {
        $current_value = get_option($option_name);
        $new_value = array_merge($current_value, $id_array);
        update_option($option_name, $id_array);
    }
}

Также добавлена еще одна переменная, чтобы можно было использовать разные имена для опции базы данных и имени шорткода.

26 мая 2017 г. 12:47:02