• Wordpress отрезает UTM метки. Как исправить?

    HeadOnFire
    @HeadOnFire
    PHP, Laravel & WordPress Evangelist
    Вполне возможно, что происходит редирект (301/302), поэтому теряются метки. Проверить можно в Firebug / Chrome Dev Tools. В RewriteRule что-то подобное этому [NC,QSA,R=301,L] должно помочь (я с Апачем давно не работаю, поэтому нужно пробовать).

    Еще может влиять настройка урл - использование слеша в конце. Если ссылки, генерируемые WP без слеша, то будет происходить редирект на тот же адрес, только со слешем в конце. Вот тут и возникает потеря параметров. Полезная инфа тут и тут.

    И еще есть нюанс - WordPress не очень любит любые _GET параметры, кроме зарегистрированных с помощью add_query_var(). Но не думаю, что проблема в этом - отрезать он их не должен.
    Ответ написан
  • Как вы верстаете Wordpress темы?

    HeadOnFire
    @HeadOnFire
    PHP, Laravel & WordPress Evangelist
    Использование _s - очень правильная идея. Верстка сначала в html - очень неправильная, разве что есть уже свой собственный базовый код, основанный на WordPress. Почему? Потому что WordPress генерит везде кучу своих CSS-классов, и правильно использовать именно их.

    Процесс такой:
    - идея, эскизы на бумаге, продумывание особенностей, модульные сетки, прототип
    - дизайн в фотошопе
    - сборка функциональной части шаблона - подключение нужных плагинов, вывод метаполей, весь кастомный вывод - в общем, необходимо вывести в шаблон (_s) весь реальный контент (или приближенный к реальному), а не верстать с Lorem Ipsum
    - а вот теперь самое интересное - SCSS, mobile first + javascript. В общем, чистый frontend.
    Ответ написан
    4 комментария
  • Как перевести произвольные строчки с помощью Polylang?

    HeadOnFire
    @HeadOnFire
    PHP, Laravel & WordPress Evangelist
    У Polylang есть свои собственные маленькие функции, полезные для таких целей. Конкретно в этом случае, есть 3 варианта:

    1. Локализация строки обычным методом WordPRess - в шаблоне находим где этот текст и оборачиваем его в функцию _e() или __(). После этого делаем перевод строки в POedit, Как обычно.

    2. Локализация строки точно так же, как в п.1, только вместо внешнего POedit ставим плагин Loco Translate и переводим строку прямо в админке.

    3. Вместо функций _e() или __() используем функции pll__(), pll_e() вместе с pll_register_string() и переводим в админке WordPress на странице настроек Polylang. Документация.

    В любом случае, придется ковыряться в коде.
    Ответ написан
    2 комментария
  • Как добавить в кешированную страницу данные авторизованного пользователя?

    HeadOnFire
    @HeadOnFire
    PHP, Laravel & WordPress Evangelist
    Я делаю javascript'ом. Чем не нравится решение? В том месте в шапке сайта, где у нас аватар + имя пользователя и иконка его меню, я вывожу по умолчанию "заглушку" и вращающийся спиннер. Проверяем куку локальную, если авторизован - выводим туда аватар + имя, не авторизован - выводим ссылки на вход и регистрацию. Если это сделать с легкой анимацией, то смотрится вполне отлично. Если куки нет, то эту "заглушку" может быть видно 0.5-3 секунды, зависит от того как долго будет срикпт с сервером общаться, если же кука есть, то чаще всего вообще никто ничего не заметит. Дабы сократить FOUC данный скрипт стоит в самом хтмл прямо в том месте где надо. Чтобы не ждать всех загрузок и т.д. а выполниться максимально быстро.
    Ответ написан
  • Как расставить приоритеты рубрик к записи в wordpress?

    HeadOnFire
    @HeadOnFire
    PHP, Laravel & WordPress Evangelist
    WordPress использует обе ссылки, так как контент должен быть по логике доступен и так, и так. Урл разные, контент дублирующий. С точки зрения SEO решается с использованием rel="canonical", если надо что-то дополнительно делать - есть разные варианты. Тут интересное обсуждение (англ), возможно поможет.

    Не совсем понятно что означает "задать приоритет рубрик". Что конкретно надо сделать?
    Ответ написан
    Комментировать
  • Wordpress 4. Как сделать многоуровневую структуру содержимого?

    HeadOnFire
    @HeadOnFire
    PHP, Laravel & WordPress Evangelist
    Использовать соответствующие шаблоны. Читаем Иерархия шаблонов. Берем archive.php и копируем его в taxonomy-{taxonomy_slugname}.php.
    Ответ написан
    Комментировать
  • Как выполнить функцию после сабмита формы?

    HeadOnFire
    @HeadOnFire
    PHP, Laravel & WordPress Evangelist
    Код и не мог работать на странице формы, WordPress не позволит. Почитай про lifecycle. Хукаться и выполнять другие низкоуровневые действия можно только из functions.php или из плагина. Непосредственно из файла темы (шаблона) работать не будет, если на пальцах - в тот момент, когда инклудится и выполняется файл темы, все основные экшны уже давно выстрелили.
    Ответ написан
    Комментировать
  • Правильно ли организована моя лента для Wordpress?

    HeadOnFire
    @HeadOnFire
    PHP, Laravel & WordPress Evangelist
    Внимательно читайте документацию и best practices в блогах опытных разработчиков. На русском языке действительно качественной информации по WordPress очень мало. Читайте хотя бы Константина Ковшенина (блог на английском, блог на русском).

    1. Никогда не используйте query_posts. Это неэффективно - данная функция заменяет основной запрос (Main Query), но выполняется ПОСЛЕ него. То есть, выполняет запрос к БД повторно, уже с новыми аргументами. Кроме того, практически гарантированно вылезут проблемы с постраничной навигацией. И не забывайте, что все дополнительные данные (виджеты с категориями, последними постами и комментами и т.д.) будут продолжать пытаться использовать данные из основного запроса, а данная функция глобальные переменные заменит, большая часть template tags будет выдавать совершенно неожиданные вещи. Бардак обеспечен. При использовании этой функции нужно не забывать в нужных местах вставлять wp_reset_query(), с чем точно запутаетесь. Данную функцию можно использовать только в одном случае - вызывать ДО основного loop, чтобы изменить параметры запроса. В этом случае WordPress проигнорирует те параметры, которые получит в запросе (GET / ваш урл), и будет использовать те, которые ему передать через query_posts. Но для этих задач есть более правильные решения.

    2. Функция get_posts() предназначена для получения небольших, конкретных списков постов мимо основного Loop. Когда не нужна постраничная навигация и все дополнительное добро. Например, под статьей вывести список 5 последних статей из этого раздела. Или в боковой колонке вывести 10 статей, помеченных тем же тегом, что основная статья.

    3. Если КРОМЕ основного запроса нужно сделать еще один, используйте новый loop:

    $myquery = new WP_Query( $args );
    if( $myquery->have_posts() ) :
        while( $myquery->have_posts() ) : $myquery->the_post();
        ...
        endwhile;
    endif;

    Например, есть раздел "События", и этот раздел - не обычные posts, а custom post type 'event'. И нам в ленте надо вывести не в обычном виде, а 2 блока - первый это ближайшие события (по дате от сегодня и в будущее), второй - прошедшие события (по дате от сегодня и в прошлое). Первый блок выводим модифицированным основным запросом (см. дальше про модификацию основного запроса), второй - нашим новым лупом.

    3. Если нужно модифицировать основной запрос, и все что с ним связано (глобальные переменные и т.д.), единственно правильный способ - через хук pre_get_posts. Использовать надо в файле functions.php

    add_action( 'pre_get_posts', 'my_function' );
    function my_function( $query ) {
        // здесь можно (и нужно) использовать conditional проверки 
        // и модифицировать запросы для разных страниц и исловий, 
        // все в одной фукнции.
        if( $query->is_archive() && $query->is_main_query() ) :
            $query->set(
                'tag_id'                  => '1,10,15,2,30,31,32,35,89,55,120,140,150,4',
    	    'author'                 => '1,2,3,50,150,140,35',
    	    'posts_per_page'   => '10',
    	    'orderby'                => 'date',
            );
        endif;
    }

    Данный способ не плодит дополнительных запросов, модифицирует напрямую основной запрос, при этом остается возможность модифицировать его дополнителньо из других мест (например, из плагинов - тот же WPML или Polylang для мультиязычной подддержки), не вызывает никаких проблем с постраничной навигацией, правильно устанавливает все глобальные переменные, отчего все дополнительные плюшки (виджеты, последние комменты и посты, меню и прочее) работают корректно.
    Ответ написан
  • Как лучше сделать связь записей в CMS WordPress?

    HeadOnFire
    @HeadOnFire
    PHP, Laravel & WordPress Evangelist
    Advanced Custom Fields штука хорошая и удобная, но на больших сайтах со сложным контентом - жутко медленная. Если нужны именно кросс-связи между объектами (post types, users) - есть отличный плагин Posts-to-Posts. Ну и кастомные таксономии.

    Грубо говоря, логика такая:
    - все что похоже на самостоятельный объект со своей моделью -> custom post type
    - любые "поля" / даполнительные данные, по которым нужна агрегация, сортировка, фильтрация и тд -> custom taxonomy
    - любые поля, которые просто дают доп.инфу -> custom meta (postmeta, usermeta и т.д.)
    - у ACF у полей Relationship есть галочка "Загрузить значение основываясь на терминах записи и обновить термины записи при сохранении" - обязательно использовать ее
    - если нужно связать объекты напрямую - Posts-to-Posts.

    Например, есть событие (CPT), есть место/локация (CPT), есть пользователи. Есть таксономии страна/город, тип события. С помощью Posts-to-Posts связываем между собой событие и место, а также к событию привязываем несколько пользователей (например, организаторы события), и у события и у места есть таксономия страна/город. Таксономия тип события релевантна только для событий. Получается стройная и гибкая, расширяемая схема. И главное - это все быстро работает, никаких запросов по meta_key. А место ACF в этой схеме - например, для локации это адрес, карта, контакты, ссылка на сайт/соцсети, фотогалерея и тд. Для события - приглашение, расписание, фотографии и видео, дата и время проведения события и тд.

    Я описал на своем примере, но переложить логику на компании / лица не составит труда.
    Ответ написан
    Комментировать
  • Как отправить id товара через плагин в wordpress?

    HeadOnFire
    @HeadOnFire
    PHP, Laravel & WordPress Evangelist
    Описание весьма запутанное. Ряд товаров на одной странице выводится как? Custom loop? Тогда получить ID товара можно через $post->ID (если это измененный главный запрос/луп, он же main query), или через $myloop->ID, где $myloop - переменная, содержащая кастомный объект WP_Query (автономный луп). Если проблема в том, что шорткод ожидает одно название переменной, а его на момент рендера шорткода не существует, тогда попросту задавайте эту переменную передвызовом, присваивая ей значение, полученное из объекта WP_Query (см. Выше).
    Ответ написан
  • WordPress: Как отсортировать новости по дате из Custom Content?

    HeadOnFire
    @HeadOnFire
    PHP, Laravel & WordPress Evangelist
    Нужно модифицировать запрос. Если это основной Loop - через хук pre_get_posts, если это кастомный Loop, то прямо в нем, естественно:

    /**
     * Custom loop с сортировкой по мета
     */
    $upcoming_args = array (
        'post_type'         => 'event', // тип поста, если стандартный, то 'post'
        'posts_per_page'	=> '20', // сколько записей на страницу
        'order' 		=> 'ASC',
        'orderby' 		=> 'meta_value', // сортировка по значению мета-поля
        'meta_key' 		=> 'date_from', // ключ (название) мета-поля
        'meta_query' 	=> array (
            array (
                'key'     => 'date_from', // ключ (название) мета-поля
                'value'   => date('Ymd'), // текущая дата, в формате хранимого значения, от нее будем проверять
                'compare' => '>=', // сравнение "больше или равно"
            ), 
        ),
    );
    $upcoming = new WP_Query( $upcoming_args );
    if ( $upcoming->have_posts() ) : 
        while ( $upcoming->have_posts() ) : $upcoming->the_post(); 
            // Здесь выводим посты
        endwhile;
    endif;
    wp_reset_postdata();
    ?>
    Ответ написан
    2 комментария
  • Как вывести доп.поля (wordpress) ACF в архивах и таксономии?

    HeadOnFire
    @HeadOnFire
    PHP, Laravel & WordPress Evangelist
    Функция the_field() принимает 2 аргумента, второй из них - это ID поста или значение 'option' если поле нужно забрать со страницы Options (модуля ACF). Если поле вызывается в стандартном loop, то ID передавать не нужно, он его сам подхватывает. Если нужно вывести вне стандартного loop - передавайте принудительно ID поста:

    the_field( 'field_name', $post_id );

    В справке все есть.
    Ответ написан
    Комментировать
  • Как решить MySQL проблему "Failed to read auto-increment value from storage engine" при установке Wordpress?

    HeadOnFire
    @HeadOnFire
    PHP, Laravel & WordPress Evangelist
    Проблема 100% на уровне MySQL, WordPress тут вообще ни при чем. Простая переустановка не факт что поможет. С обычным MySQL давно не работаю, советую сделать то же самое - установить MariaDB 10 (и модуль php-mysqlnd понадобится).

    1. Здесь выбираем свою версию убунты и MariaDB, полученные данные добавляем в список репо
    2. Удаляем MySQL
    3. Устанавливаем MariaDB и php-mysqlnd
    4. Делаем mysql_secure_install
    5. Профит
    Ответ написан
  • Wordpress multisite. Как можно выводить посты со всех поддоменов (мультисайтов)?

    HeadOnFire
    @HeadOnFire
    PHP, Laravel & WordPress Evangelist
    Читаем документацию к функциям switch_to_blog() и restore_current_blog().
    Ответ написан
    Комментировать
  • Как работать с произвольными формами и данными в админке wordpress?

    HeadOnFire
    @HeadOnFire
    PHP, Laravel & WordPress Evangelist
    Список магазинов - это просто несколько полей в таблице Options или это Custom Post Type? Задача описана очень поверхностно, сложно что-то советовать.

    Основных подхода два:
    1. Плагин Advanced Custom Fields Pro (есть бесплатная версия, но девелоперская безлимитная Pro за $100 - это мегаполезный инструмент для разработчиков и просто must have на всех сайтах, если они чуть сложнее яем блог). У него есть модуль создания своих страниц настроек, создания на них любых комбинаций полей, созданиие полей для юзеров, таксономий, постов и та далее. Все, что душе угодно. Есть свои функции для создания форм на frontend, задача добавления формы и ее обработки сводится, по сути, к вызову 2х функций в шаблоне.
    2. Использование своих собственных форм. Создается плагин, он может работать 2мя путями:
    2.1. При активации создаем необходимые страницы, регистрируем и вписываем для каждой свой шорткод, а уже функция шорткода делает все, что нам нужно - обрабатывает данные, выводит форму на странице и так далее.
    2.2. Все обработчики и шаблоны находятся в самом плагине, добавляем кастомные правила и переменные для rewrite, и тогда по нужным нам урлам будет вызываться наш файл-обработчик с разными параметрами. В зависимости от параметра делаем то, что нам нужно. С выводом формы, думаю, все понятно, а вот ее обработка - хукаемся в "init", а дальше как обычно с данными $_POST. Приняв и проверив данные дальше стандартными средствами WP записываем все изменения в базу.

    Документация по все этим моментам есть в Codex.
    Ответ написан
    Комментировать
  • Как подключить JQuery к Wordpress, или проблема все-таки не в нем?

    HeadOnFire
    @HeadOnFire
    PHP, Laravel & WordPress Evangelist
    Никогда не включайте jQuery со сторонних сервисов (хоть jQuery.com, хоть Google CDN), потому что:

    1. В комплекте с WordPress уже идет jQuery, подключается стандартными средствами (wp_enqueue_scripts)
    2. Многие плагины рассчитывают на этот встроенный jQuery, если скрипт плагина требует наличия jQuery, при подключении скрипта всего лишь указывается аргумента dependency - 'jquery'.
    3. Вместе со штатным jQuery подключается jQuery Migrate, который может быть необходим для некоторых плагинов, использующих старые библиотеки скриптов
    4. Зачем ради одного файла добавлять на страницу сторонний запрос, который добавляет 1 лишний DNS Resolving + полный цикл RTT, а это виновники самых больших задержек по времени при загрузке страницы, а учитывая, что CDN Google будет отдавать файл скорее всего из Ирландии, а CDN jQuery - из США, резолвинг DNS будет порядка 100-300мс, RTT - еще столько же, плюс время на получение файла. Итого, железно получаем 200-600мс задержки только из-за одного jQuery, который, к тому же, еще и блокирует рендеринг страницы. Тоесть Time to First Byte будет задержан дополнительно на этот период времени. Если же подключить штатный jQuery, DNS Resolving не делается вообще (уже сделан при запросе страницы), RTT короткий, а если на сервере правильно настроен keep_alive_timeout, то RTT вообще мизерный и файл прилетает значительно быстрее.
    Ответ написан
    1 комментарий
  • Как можно отмониторить нагрузку на сервер через php?

    HeadOnFire
    @HeadOnFire
    PHP, Laravel & WordPress Evangelist
    Внешним PHP никак, только если стучаться на что-то, что эти данные выдает - либо php-скрипт, либо страница статуса веб-сервера (nginx_stub_stats, apache_status), либо еще что-то подобное. Но, если сервер лежит - это вообще не вариант. Munin, Monit, Cacti - этих решений для мониторинга целая туча. Есть еще прекрасный во всех смыслах New Relic.
    Ответ написан
  • Как настроить установку логотипа через админку WordPress?

    HeadOnFire
    @HeadOnFire
    PHP, Laravel & WordPress Evangelist
    Либо ручками в коде - поправить тему либо сделать дочернюю (см. ответ @korobochkin), либо, если все-таки надо чтобы оно было в админке, есть у WordPress для этого родная фишка, называется Customization API. Код можно подсмотреть в штатной теме twentyfourteen, в файле

    /wp-content/themes/twentyfourteen/inc/customizer.php


    Хотя зачем на статичную штуку, которая делается 1 раз, создавать настройку и дергать базу данных - непонятно.
    Ответ написан
    3 комментария
  • Почему FireFox выдает такой бордак в шрифтах?

    HeadOnFire
    @HeadOnFire
    PHP, Laravel & WordPress Evangelist
    В каком формате шрифт подключен?
    Вообще, если не заморачиваться IE меньше 9, можно оставить только один - woff. Его корректно понимают все браузеры. В крайнем случае дополнительно подключать ttf (который сгенерирован через WebFont Generator, а не родной из системы). Все остальные хаки пора уже отправлять на пенсию.
    Ответ написан
    Комментировать
  • Как лучше организовать на Wordpress сайте подмешивание, вывод постов из других вордпресс сайтов?

    HeadOnFire
    @HeadOnFire
    PHP, Laravel & WordPress Evangelist
    Читать посты с других WP сайтов можно по RSS, а еще лучше - установить на всех сайтах JSON REST API. Тогда можно элементарно получать конкретные посты, целые архивы в JSON.

    Что касается подмешивания - тут есть нюансы. Само подмешивание сделать не проблема, в свойстве $posts объекта WP_Query хранятся все полученные из базы посты по текущему запросу. Плюс имеем такой же массив или объект, полученный в JSON с других сайтов. Приводим все к одному формату (объект или массив) и перемешиваем, выводим.

    Но тут всплывает несколько нюансов:

    1. Постраничная навигация будет работать некорректно, либо количество постов на страницах будет всегда больше, чем в настройках (ведь будут родные Х + сторонние У)
    2. Автор поста, метаданные (рубрика, метки и т.д.) постов с другого сайта в текущей БД отсутствуют, поэтому эти вещи лучше не выводить или выводить текстом (не ссылками)
    3. Еще по мелочам вылезет что-то

    Если делать Multisite - это удобнее, комфортнее, приятнее и т.д. Но там эта задача не будет сильно легче. У Multisite общая таблица пользователей, таблицы постов и метаданных - разные, у каждого сайта свои. Да, можно на лету переключаться на другой блог, запрашивать отттуда посты, возвращаться на текущий и перемешивать. Это вместо считывания постов с другого сайта по RSS или JSON. Но дальше те же нюансы. Есть решения по синхронизации метаданных (категорий, меток) между сайтами сети, но это все уже усложнение, не уверен, что это нужно в этом конкретном случае.
    Ответ написан
    Комментировать