Ответы пользователя по тегу WordPress
  • Как отключить оповещение на е-майл, регистрация нового пользователя?

    HeadOnFire
    @HeadOnFire
    WordPress Evangelist
    Вот список всех ситуаций и писем, которые WP рассылает: https://gist.github.com/johnbillion/0a48021de5510c...
    В описании каждого письма есть инструкция как его отключить. Например, чтобы отключить все письма при регистрации нового пользователя:
    remove_action( 'register_new_user', 'wp_send_new_user_notifications' );

    Впрочем, пользователю желательно отправлять. Давайте отключим только администратору:
    remove_action( 'register_new_user', 'wp_send_new_user_notifications' );
    add_action( 'register_new_user', 'notify_only_user' );
    
    function notify_only_user( $user_id, $notify = 'user' )
    {
        wp_send_new_user_notifications( $user_id, $notify );
    }
    Ответ написан
  • Как автоматически убрать привязку поста к рубрике через определенное время?

    HeadOnFire
    @HeadOnFire
    WordPress Evangelist
    1. Создайте ежедневную cron-задачу, см. wp_schedule_event()
    2. В хуке на этой задаче проверяйте получаете все посты из нужной вам категории, сравниваете их дату с текущей, если пора отключать - отключаете c помощью wp_remove_object_terms()
    Ответ написан
  • Wordpress цикл bootstrap grid?

    HeadOnFire
    @HeadOnFire
    WordPress Evangelist
    Давайте уже закроем этот вопрос. Несколько моментов:

    1. Не нужно запускать цикл несколько раз, все условия проверяются внутри одного цикла.
    2. Свойство $query->current_post проверяем внутри цикла, счетчик начинается с 0.

    <div class="container">
    	<div class="row">
    
    		<?php
    		$args = [
    			'post_status'            => 'publish',
    			'posts_per_page'         => 5,
    			'no_found_rows'          => true,
    			'cache_results'          => true,
    			'update_post_meta_cache' => false,
    			'update_post_term_cache' => false,
    		];
    		$query = new WP_Query( $args );
    
    		while ( $query->have_posts() ) : $query->the_post();
    
    			// 1я запись, целиком в .col-6
    			if ( $query->current_post === 0 )
    			{
    				echo '<div class="col-6">'; // Открыли .col-6
    					echo '<div class="post-card">';
    						the_post_thumbnail( 'custom-size', [ 'class' => 'img-fluid' ] );
    						the_title();
    					echo '</div>';
    				echo '</div>'; // Закрыли .col-6
    			}
    
    			// 2я и 4я записи, только открываем .col-3 и выводим 1 запись
    			if ( $query->current_post === 1 || $query->current_post === 3 )
    			{
    				echo '<div class="col-3">'; // Открыли .col-3
    					echo '<div class="post-card">';
    						the_post_thumbnail( 'custom-size', [ 'class' => 'img-fluid' ] );
    						the_title();
    					echo '</div>';
    			}
    
    			// 3я и 5я записи, выводим запись и закрываем .col-3
    			if ( $query->current_post === 2 || $query->current_post === 4 )
    			{
    					echo '<div class="post-card">';
    						the_post_thumbnail( 'custom-size', [ 'class' => 'img-fluid' ] );
    						the_title();
    					echo '</div>';
    				echo '</div>'; // Закрыли .col-3
    			}
    
    		endwhile; ?>
    
    	</div>
    </div>


    Данный код выведет вот такой HTML:

    <div class="row">
    	<div class="col-6">
    		<div class="post-card">
    			...
    		</div>
    	</div>
    
    	<div class="col-3">
    		<div class="post-card">
    			...
    		</div>
    
    		<div class="post-card">
    			...
    		</div>
    	</div>
    
    	<div class="col-3">
    		<div class="post-card">
    			...
    		</div>
    
    		<div class="post-card">
    			...
    		</div>
    	</div>
    </div>


    Но, важно понимать порядок постов в колонках .col-3 - он будет таким:

    .col-6      .col-3      .col-3
    ------      ------      ------
    post-1      post-2      post-4
                post-3      post-5


    а не вот таким:

    .col-6      .col-3      .col-3
    ------      ------      ------
    post-1      post-2      post-3
                post-4      post-5


    В принципе, еще есть другой путь:

    - Посты получаете через get_posts() в виде массива объектов WP_Post.
    - HTML генерите без цикла, формируете как вам надо.
    - В нужных местах подставляете нужный объект WP_Post по его индексу в массиве.
    Ответ написан
  • Как перевести строку с указанием своего языка в Wordpress?

    HeadOnFire
    @HeadOnFire
    WordPress Evangelist
    Конечно нет. Сигнатура функции __( $sting, $domain ) принимает 2 аргумента, а не 3, и языка там нет. Текущая активная локаль устанавливается отдельно, на раннем этапе загрузки движка. После этого файлы с переводами для установленной локали загружаются в память и все дальнейшие операции по "переводу" строк происходят с этим загруженным массивом строк. Переключение на лету на другой язык означает необходимость догрузки файлов переводов или проактивную их загрузку заранее. Обе идеи - не самые светлые.
    Ответ написан
  • Wp default loop break?

    HeadOnFire
    @HeadOnFire
    WordPress Evangelist
    Во-первых, переменная $i вам не нужна, у объекта WP_Query есть свойство $query->current_post.

    Во-вторых, не нужно делать каждый раз wp_reset_postdata() и продолжать цикл, достаточного одного стандартного цикла while( have_posts() ), а внутри if.

    В третьих, у вас в целом разметка одинаковая, отличаются только классы / стили. Поэтому вашу задачу в принципе можно решить чисто на CSS. Но если все же хотите задействовать PHP, то будет что-то типа такого:

    $arguments = [
        'posts_per_page' => 5
    ]; 
    
    $query = new WP_Query( $arguments ); ?>
    
    <div class="row">
    
    <?php 
    // Обычный WordPress Loop:
    while ( $query->have_posts() ) : $query->the_post();
    
        // Можно ограничиться одним кастомным классом с индексом:
        echo "<div class=\"custom-post-style-{$query->current_post}\">";
    
       ...
    
    endwhile; ?>
    
    </div>
    Ответ написан
  • Как завернуть тег a в span wp menu?

    HeadOnFire
    @HeadOnFire
    WordPress Evangelist
    Регулярками конечно можно, но это молотком ювелирку ровнять. Тем более у вас уже подключен свой вокер:

    'walker' => new My_Walker_Nav_Menu(),

    В нем должен быть метод start_el(). Или скопируйте метод из родительского класса Walker_Nav_Menu и подправьте код ближе к концу метода, вот этот фрагмент:

    $item_output = $args->before;
    $item_output .= '<a'. $attributes .'>';
    $item_output .= $args->link_before . $title . $args->link_after;
    $item_output .= '</a>';
    $item_output .= $args->after;


    измените на:

    $item_output = $args->before;
    $item_output .= '<span>';
    $item_output .= '<a'. $attributes .'>';
    $item_output .= $args->link_before . $title . $args->link_after;
    $item_output .= '</a>';
    $item_output .= '</span>';
    $item_output .= $args->after;


    Но это только в случае если у вас уже есть кастомный вокер. Если нет - все еще проще. Во фрагменте выше обратите внимание на строки:

    $item_output = $args->before;
    ...
    $item_output .= $args->after;


    Документация нам говорит следующее:

    'before'
    (string) Text before the link markup.
    'after'
    (string) Text after the link markup.


    Пусть слово "text" вас не смущает, с помощью этих параметров передается и html-код:

    wp_nav_menu( [
    	'menu'            => '',
    	'container'       => 'nav',
    	'container_class' => 'menu',
    	'echo'            => true,
    	'fallback_cb'     => 'wp_page_menu',
    	'before'          => '<span>',
    	'after'           => '</span>',
    	'items_wrap'      => '<ul>%3$s</ul>',
    	// 'walker'          => new My_Walker_Nav_Menu(),  // Вот это вам не надо, если вы не знаете что делаете.
    ] );


    То есть, стандартный вокер собирает элемент из таких блоков:

    [before] + <a [attributes]> + [link_before] + title + [link_after] + </a> + [after]
    Ответ написан
  • Как присвоить тег?

    HeadOnFire
    @HeadOnFire
    WordPress Evangelist
    Из документации:

    $terms (array/int/string) (required)
    The slug or id of the term (such as category or tag IDs)

    А вот это:

    'до 2019'

    больше похоже на name, а не slug или id. Во-первых, термин (тег) уже должен существовать, во-вторых, передавайте его id. Для slug под капотом делается дополнительный запрос чтобы получить id, собственно на этом запросе и валится ваш код - WP видит string, и воспринимает его как ожидаемый slug, делает запрос термина по этому слагу и получает фигу, потому что термина с таким слагом существовать не может.
    Ответ написан
  • Как хранить таксономии?

    HeadOnFire
    @HeadOnFire
    WordPress Evangelist
    Хранить конфигурацию таксономий в опциях - пожалуй, самое странное решение из возможных. Минусы (предполагается, что autoload=yes, потому как таксономии регистрируем при каждом запросе) могут быть неочевидны на первый взгляд, но с точки зрения производительности они существенны, а иногда критичны. Автозагрузочные опции грузятся одним пакетом в $all_options. И кешируются. Далее, если есть object cache, то все это кешируется одним куском. А тот же memcached имеет определенные лимиты на объем данных. Превысили лимит - получили проблемы. Далее, вы каждый раз десериализуете данные и работаете с массивами. В последних версиях PHP десериализация вполне быстрая (igbinary правда все равно быстрее), но вы это делаете каждый раз, без острой на то необходимости. Тот же массив в виде обычного array в PHP-файле во-первых не десериализуется, во-вторых скомпилен в байткод посредством Opcache.

    Самый главный вопрос - зачем вообще это хранить в опциях? Какую проблему / задачу вы этим пытались решить?
    Ответ написан
  • Как закрыть от поисковиков копию сайта?

    HeadOnFire
    @HeadOnFire
    WordPress Evangelist
    1. В настройках установить "не индексировать" - в robots.txt будет "Disallow /" для всех роботов. Теоретически этого достаточно, но некоторые роботы могут проигнорировать. Впрочем, основные (Google, Yandex и тд) не игнорируют, так что можно считать что это достаточно надежный способ.
    2. Дополнительно, не стоит сильно переживать, так как адреса то разные будут, и по идее как раз вторая копия будет "дубликатом", даже если и проиндексируется. Теоретически, позиции первой, оригинальной копии не должны страдать. Но тоже могут быть нюансы.
    3. Сайты, которые не должны быть публичными (песочницы всякие, staging-сайты) принято закрывать от публичного доступа вообще. Вариантов как это сделать - масса. Навскидку:
    • плагин (или кодом) Maintenance Mode - показывает заглушку всем, кроме авторизованного администратора (или всех авторизованных юзеров - зависит от настроек)
    • установка пароля через http auth
    • разрешение доступа на уровне сервера по IP
    • работа сайта по IP сервера вместо реального домена + локальный резолвинг доменного имени через /etc/hosts (на Win тоже есть)
    Ответ написан
  • Работа с WP-Cron?

    HeadOnFire
    @HeadOnFire
    WordPress Evangelist
    Встроенный WP Cron годится только для самых простых задачек, для более надежного срабатывания четко когда надо используйте крон на уровне ОS. В конфиге выключите встроенный крон:

    define( 'DISABLE_WP_CRON', true );

    И создайте крон-задачу на уровне OS, задав нужный интервал и команду вида:

    wget -q -O - https://example.com/wp-cron.php?doing_wp_cron >/dev/null 2>&1

    Вместо wget можете использовать curl, httpie, или /usr/local/bin/php, тут смотрите по ситуации. Как настраивать крон-задачи из командной строки можете погуглить, как добавить если у вас какая-нибудь CPanel - тоже.

    А еще есть https://github.com/humanmade/Cavalcade

    Ну а для долгих и асинхронных скриптов есть RabbitMQ и вот это все. Посмотрите https://github.com/10up/WP-Minions
    Ответ написан
  • Как получить путь (thumbnail)?

    HeadOnFire
    @HeadOnFire
    WordPress Evangelist
    Функция wp_upload_dir():

    <?php
    $upload_dir = wp_upload_dir();
    var_dump( $upload_dir );
    
    /*
        Array (
            'path' => /path/to/wordpress/wp-content/uploads/2018/12
            'url' => https://example.com/wp-content/uploads/2018/12
            'subdir' => /2018/12
            'basedir' => /path/to/wordpress/wp-content/uploads
            'baseurl' => https://example.com/wp-content/uploads
            'error' =>
        )
    */
    
    echo $upload_dir['url']; // Вот это наверное вам надо
    Ответ написан
  • Как в Wordpress реализовать полноценный поиск через Ajax без тега form?

    HeadOnFire
    @HeadOnFire
    WordPress Evangelist
    $('.my-class').keypress(function(eventObject){
      eventObject.preventDefault();
      ..

    Давно не писал на js, но вроде так.
    Ответ написан
  • Как изменить список выводимых записей в Wordpress?

    HeadOnFire
    @HeadOnFire
    WordPress Evangelist
    1. Хук pre_get_posts.
    2. В нем изолируете с помощью $query->{conditional_check} (is_admin, is_main_query и тд) нужный контекст.
    3. С помощью $query->set( 'параметр', 'значение' ) устанавливаете нужные параметры. Дополнительное поле это будет meta_query.
    Ответ написан
  • Не работает WPML. Как быть?

    HeadOnFire
    @HeadOnFire
    WordPress Evangelist
    <?php _e('Get In Touch', 'Связаться с нами'); ?>

    Это некорректный код. Сигнатура функции:
    _e( 'String in original language', 'textdomain' );
    Где textdomain - это уникальный слаг, по которому подгружается файл переводов. А не сам перевод строки на русский, который вы вставили.
    Ответ написан
  • Как открывать ссылки внутри шаблона Wordpress?

    HeadOnFire
    @HeadOnFire
    WordPress Evangelist
    Вам за школьную парту обратно надо, почитать про routing, а потом про rewrite rules в WordPress. Все запросы WP обрабатывает один и тот же файл /index.php в корне (кроме статики конечно же).
    Ответ написан
  • Почему берется не та относительная ссылка из функции?

    HeadOnFire
    @HeadOnFire
    WordPress Evangelist
    Либо в wp-config.php константа с URL, либо в базе данных в wp_options.
    Ответ написан
  • WordPress: я вписываю весь нужный код в functions.php. Правильно ли это?

    HeadOnFire
    @HeadOnFire
    WordPress Evangelist
    Говнокод, но да.

    Файл functions.php - это просто обычный php-файл, который подключается на определенном этапе работы движка и весь код в нем выполняется. Все кастомизации можно тулить туда. Разумно ли это - другой вопрос, и уже выходит за рамки ответа "да / нет". Если кода много, то стоит задуматься о его организации. По простой логике, функциональность принято делить на отдельные классы, в случае с WP это часто просто отдельные файлы. Я лично предпочитаю в самом functions.php определять только то, что вешается на хук after_setup_theme, а дальше идет просто автолоадер всего остального или инклуды других файлов, которые размещены в theme_dir/inc
    Ответ написан
  • Как добавить такой функционал на WordPress?

    HeadOnFire
    @HeadOnFire
    WordPress Evangelist
    1. WordPress пишется с двумя заглавными буквами, capital_P_dangit()
    2. Git не пишется капсом, это не аббревиатура.
    3. FRONTEND тоже не аббревиатура. Кроме того, корректно писать "front end" (noun), но "front-end developer" (adjective).
    4. Less тоже, кстати, официально пишется не как LESS.
    5. "как мне его добавить в эту панельку" - эта панелька называется Customizer.
    6. WordPress из списка своих навыков можете смело убирать - вы его не знаете.
    7. Что касается добавления своего контрола в панель кастомайзера – читайте доку. Осилите сами – сможете заодно и вернуть тег "WordPress" в свои навыки. Правда, желательно со сноской.
    Ответ написан
  • Как подключить css последним (wordpress)?

    HeadOnFire
    @HeadOnFire
    WordPress Evangelist
    Вот вы странные, чесслово.

    У всех хуков WP есть 3й параметр, который называется priority. Это вот та циферка (опциональная), которая идет после коллбека. По умолчанию, если ее не передать, то значение будет 10. Если несколько коллбеков висит на одном приоритете, то они выполняются в том порядке, в каком были добавлены (условно, считайте что они добавляются в конец массива с помощью array_push). Устанавливайте своему коллбеку более высокий приоритет, и он будет выполнен позже. И есть несколько хитростей, как гарантировать, что ваш коллбек будет самым последним.

    Вариант 1: Устанавливаем приоритет равным значению системной константы PHP_INT_MAX.
    Вариант 2: Получаете список всех подвешенных коллбеков, определяете приоритет последнего, увеличиваете значение на 1 и устанавливаете его своему коллбеку.
    Ответ написан