Загрузка скриптов только при наличии определенного шорткода или виджета

28 сент. 2010 г., 08:21:48
Просмотры: 16.1K
Голосов: 17

Мне понадобился способ фильтрации контента страницы/записи перед загрузкой, чтобы добавить скрипты в заголовок, если присутствует определенный шорткод. После долгих поисков я нашел решение на http://wpengineer.com:

function has_my_shortcode($posts) {
    if ( empty($posts) )
        return $posts;

    $found = false;

    foreach ($posts as $post) {
        if ( stripos($post->post_content, '[my_shortcode') )
            $found = true;
            break;
        }

    if ($found){
        $urljs = get_bloginfo( 'template_directory' ).IMP_JS;

    wp_register_script('my_script', $urljs.'myscript.js' );

    wp_print_scripts('my_script');
}
    return $posts;
}
add_action('the_posts', 'has_my_shortcode');

Это решение просто великолепно и полностью соответствует моим потребностям.

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

Проблема в том, что я не могу понять, как получить доступ к содержимому сайдбаров до их загрузки (в рассматриваемой теме используется несколько сайдбаров).

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

Обязательно ли в вашем случае размещать скрипты в шапке? Размещение скриптов в конце страницы проще обрабатывать условно и это рекомендуется для производительности.

Rarst Rarst
28 сент. 2010 г. 08:36:31

Я действительно пробовал сначала разместить их в wp_footer, что изящно устраняет необходимость предварительной фильтрации контента, но хотя скрипты загружались нормально, они не работали. Эти скрипты должны быть в wp_head, чтобы выполнять свою функцию.

Lemon Bacon Lemon Bacon
28 сент. 2010 г. 09:12:31
Все ответы на вопрос 4
9
20

Вы можете использовать функцию is_active_widget. Например:

function check_widget() {
    if( is_active_widget( '', '', 'search' ) ) { // проверяем, используется ли виджет поиска
        wp_enqueue_script('my-script');
    }
}

add_action( 'init', 'check_widget' );

Чтобы загрузить скрипт только на странице, где загружен виджет, вам нужно добавить код is_active_widget() в класс вашего виджета. Например, посмотрите стандартный виджет последних комментариев (wp-includes/default-widgets.php, строка 602):

class WP_Widget_Recent_Comments extends WP_Widget {

    function WP_Widget_Recent_Comments() {
        $widget_ops = array('classname' => 'widget_recent_comments', 'description' => __( 'Последние комментарии' ) );
        $this->WP_Widget('recent-comments', __('Последние комментарии'), $widget_ops);
        $this->alt_option_name = 'widget_recent_comments';

        if ( is_active_widget(false, false, $this->id_base) )
            add_action( 'wp_head', array(&$this, 'recent_comments_style') );

        add_action( 'comment_post', array(&$this, 'flush_widget_cache') );
        add_action( 'transition_comment_status', array(&$this, 'flush_widget_cache') );
    }
28 сент. 2010 г. 09:03:27
Комментарии

Можно ли вызвать это ДО загрузки виджетов. Чтобы было понятно, это должно произойти еще до загрузки страницы. В моем примере кода используется the_posts для фильтрации контента на странице, но это не затрагивает сайдбары/виджеты.

Lemon Bacon Lemon Bacon
28 сент. 2010 г. 09:14:01

Да, смотри пример, который я добавил в свой ответ.

sorich87 sorich87
28 сент. 2010 г. 09:24:42

Твой пример на самом деле не работает. Я что-то упускаю из виду?

Lemon Bacon Lemon Bacon
29 сент. 2010 г. 04:10:18

На самом деле, так и было. wp_enqueue_script, похоже, не работает при применении к wp_head, но wp_print_scripts работает. Однако wp_enqueue_script действительно работает, если применять его к init вот так: add_action( 'init', 'check_widget' );

Lemon Bacon Lemon Bacon
29 сент. 2010 г. 04:25:57

Однако он загружает скрипты на каждой странице сайта, даже если виджет активен только в одной боковой панели. Например, если у меня есть боковая панель для страниц блога и другая боковая панель для остальных страниц. Я добавляю виджет поиска в боковую панель блога, и скрипты загружаются, но они также загружаются на страницах, где нет боковой панели блога. Мне нужно, чтобы скрипт загружался только если виджет присутствует на данной странице.

Lemon Bacon Lemon Bacon
29 сент. 2010 г. 04:49:34

Я отредактировал свой ответ

sorich87 sorich87
29 сент. 2010 г. 06:11:11

Ты просто красавчик! Ура!

Lemon Bacon Lemon Bacon
29 сент. 2010 г. 13:52:53

Очень хорошее решение :)

Anh Tran Anh Tran
25 дек. 2011 г. 06:51:48

Лучше использовать wp_enqueue_scripts вместо wp_head. Отличный ответ, спасибо.

wesamly wesamly
6 мар. 2017 г. 07:38:35
Показать остальные 4 комментариев
0

Хочу поделиться решением, над которым работал, которое позволило сделать мою реализацию более универсальной. Вместо того чтобы заставлять функцию проверять множество шорткодов, я модифицировал её для поиска одного шорткода, который ссылается на функцию скрипта/стиля, требующую подключения. Это будет работать как для методов в других классах (например, плагинов, которые могут не делать этого самостоятельно), так и для функций в текущей области видимости. Просто вставьте приведённый ниже код в functions.php и добавьте следующий синтаксис на любую страницу/запись, где нужны определённые CSS и JS.

Синтаксис для страницы/записи: [loadCSSandJS function="(класс->метод/имя функции)"]

Код для functions.php:

function page_specific_CSSandJS( $posts ) {
  if ( empty( $posts ) )
    return $posts;

  foreach ($posts as $post) {

    $returnValue = preg_match_all('#\[loadCSSandJS function="([A-z\-\>]+)"\]#i', $post->post_content, $types);

    foreach($types[1] as $type) {
      $items = explode("->",$type);
      if (count($items) == 2) {
        global $$items[0];      
        if( method_exists( $$items[0], $items[1] ))
          add_action( 'wp_enqueue_scripts', array(&$$items[0], $items[1]) );
      }
      else if( !empty( $type ) && function_exists( $type ))
        add_action( 'wp_enqueue_scripts', $type );
    }
  }

  return $posts;
}

Это также позволит добавлять любое количество таких вызовов на страницу. Учтите, что у вас должен быть метод/функция для загрузки.

25 сент. 2012 г. 22:14:40
0

В WordPress 4.7 появился еще один способ сделать это в вашем файле functions.php,

add_action( 'wp_enqueue_scripts', 'register_my_script');
function register_my_script(){
  wp_register_script('my-shortcode-js',$src, $dependency, $version, $inFooter);
}

Сначала вы регистрируете свой скрипт, который фактически не выводится на вашей странице, пока вы не подключите его, если вызывается ваш шорткод,

add_filter( 'do_shortcode_tag','enqueue_my_script',10,3);
function enqueue_my_script($output, $tag, $attr){
  if('myShortcode' != $tag){ //убеждаемся, что это правильный шорткод
    return $output;
  }
  if(!isset($attr['id'])){ //можно даже проверить наличие определенных атрибутов
    return $output;
  }
  wp_enqueue_script('my-shortcode-js'); //подключаем ваш скрипт для вывода
  return $output;
}

Фильтр do_shortcode_tag был добавлен в WP 4.7 и его можно найти на новых страницах документации для разработчиков.

31 янв. 2017 г. 05:33:03
0

Спасибо за этот совет! Он доставил мне небольшую головную боль, потому что сначала не работал. Я думаю, что в коде выше has_my_shortcode есть пара ошибок (возможно, опечаток), и я переписал функцию следующим образом:

function has_my_shortcode( $posts ) {

        if ( empty($posts) )
            return $posts;

        $shortcode_found = false;

        foreach ($posts as $post) {

            if ( !( stripos($post->post_content, '[my-shortcode') === false ) ) {
                $shortcode_found = true;
                break;
            }
        }

        if ( $shortcode_found ) {
            $this->add_scripts();
            $this->add_styles();
        }
        return $posts;
    }

Я думаю, было две основные проблемы: break не находился в области видимости оператора if, из-за чего цикл всегда прерывался на первой итерации. Вторая проблема была более тонкой и сложной для обнаружения. Код выше не работает, если шорткод является самым первым элементом в записи. Мне пришлось использовать оператор === чтобы решить это.

В любом случае, большое спасибо за эту технику, она очень помогла.

22 дек. 2011 г. 09:48:39