WordPress: Интерактивный тег <!—more—> без перезагрузки страницы

В начале статьи хочу признаться, что я не верстальщик и не владею PHP, JavaScript или CSS на должном уровне, поэтому всё, что написано ниже, используйте на свой страх и риск. Возможно, это неправильно и надо делать не так. Я не знаю, как надо правильно, учусь самостоятельно, поэтому пишу, как умею хрум-хрум-хрум.

Решил привести в порядок свою главную страницу блога. Не нравятся мне длинные посты, которые нужно долго листать, чтобы перейти к следующему. Изначально рассматривал два варианта:

  1. Кнопка [Пропустить пост] для быстрой перемотки к следующему посту и возвращению к предыдущему
  2. Кнопка [Развернуть] для динамической загрузки остальной части поста после тега <!--more-->.

В итоге выбрал третий путь: весь пост загружается сразу, но часть после тега <!--more--> показывается или скрывается по клику на кнопку [развернуть/свернуть].

Я выбрал этот вариант по двум причинам:

  1. Скрытая часть поста должна корректно обрабатываться скриптами по событию onload/onready.
  2. Размер постов у меня небольшой.

Реализация

Для начала нужно выбрать способ обработки поста. Если вызвать get_the_content(), то возвращается только часть до тега. Можно обойти это поведение, используя глобальную переменную $more, но такое решение выглядит как костыль:

function my_the_content() {
    global $more;
    $prev_more = $more;
    $more = 1;
    $content = apply_filters('the_content', get_the_content());
    $more = $prev_more;
}

Я решил брать текст поста из поля post_content объекта $post и делить его с помощью функции get_extended().

В итоге, я заменил вызов the_content() в своей теме на my_the_content($post) такого вида (код нужно добавить в functions.php вашей темы WordPress):

function my_the_content($post) {
    // На странице поста стандартное поведение
    if (is_singular()) {
        the_content();
        return;
    }

    // Получаем текст целиком из поля post_content и применяем фильтры
    $content = apply_filters('the_content', $post->post_content);

    // Разбиваем на несколько частей по тегу <!--more-->
    $parts = get_extended($content);

    // Часть после тега
    $extended = $parts['extended'];

    // После тега ничего нет, заканчиваем работу
    if (empty($extended)) {
        return;
    }

    // Поддержка роботов и тех, кому отключили JavaScript за неуплату
    echo '<noscript>';
    echo '<div>'.$extended.'</div>';
    echo '<style>.post-body {display: none; }</style>';
    echo '</noscript>';

    // Храним всю дополнительную часть в секции post-body,
    // классы expanded/collapsed используются для регулировки видимости элементов
    echo '<div class="post-body">';
    // Прячем кнопки в отдельном контейнере для удобства
    echo '<div class="toggle-buttons">';
    // Две кнопки, одна видна, другая спрятана
    echo '<div class="toggle-post-body expanded">';
    echo '<div class="label expand">развернуть</div>';
    echo '</div>';
    echo '<div class="toggle-post-body collapsed">';
    echo '<div class="label collapse">свернуть</div>';
    echo '</div>';
    echo '</div>';
    // Тело поста спрятано по умолчанию
    echo '<div class="post-body-content collapsed">'.$extended.'</div>';
    echo '</div>';
}

Стилизация

Теперь стили для блока .post-body. Все изменения затрагивают только элементы внутри него:

/* Элементы с классом collapsed внутри post-body скрыты */
.post-body .collapsed {
  display: none;
}

/* Элементы с классом expanded внутри post-body видны */
.post-body .expanded {
  display: block;
}

/* Общие настройки для кнопок-переключателей */
.post-body .toggle-post-body .label {
  color: #cc6633;
  cursor: pointer;
  margin-bottom: 0.5em;
  border-bottom: 1px dashed;
  font-size: 90%;
}

/* Треугольник для кнопки "свернуть" */
.post-body .toggle-post-body .label.collapse:before {
  content: '\25BC';/* ▼ */
  margin-right: 5px;
}

/* Треугольник для кнопки "развернуть" */
.post-body .toggle-post-body .label.expand:before {
  content: '\25B6'; /* ▶ */
  margin-right: 5px;
}

Логика на JavaScript:

И, наконец, скрипт, который переключает видимость:

// Добавляем обработку клику по элементам с классом "toggle-post-body"
jQuery('.toggle-post-body').click(function(event){
  var nextButton = jQuery(this)
    .toggleClass('expanded')
    .toggleClass('collapsed')
    .siblings('.toggle-post-body');

  nextButton
    .toggleClass("expanded")
    .toggleClass("collapsed");

  var contentBlock = nextButton
    .closest(".toggle-buttons")
    .next('.post-body-content');

  contentBlock
    .toggleClass("expanded")
    .toggleClass("collapsed");
});

Заключение

Подводя итог, логика работы выглядит следующим образом:

  1. Расширенная часть поста по умолчанию скрыта (класс .collapsed).
  2. При клике на видимую кнопку (например, «развернуть») запускается скрипт.
  3. Скрипт переключает видимость у нажатой кнопки (скрывая её) и у соседней (показывая её).
  4. Одновременно скрипт меняет видимость у блока с контентом.

Недостатки

  1. Пользователь не может перейти на страницу с самим постом, кроме как кликнув на заголовок.
  2. Пришлось убрать блок кнопки Social Likes с главной страницы для того, чтобы люди могли делиться контентом в социальных сетях. Но они этого и так не делают, так что невелика потеря.
  3. Некоторые мои записи используют канвас для рисования с помощью WebGL или JavaScript. Для них пришлось делать уникальный идентификатор канвасов для каждого поста.
  4. Страница грузит содержимое всех постов, что может быть накладно, если все посты на странице рисуют графику, например.
  5. Пришлось переписать каждый пост с меткой «Интерактив», чтобы каждый скрипт писал в свой уникальный canvas плюс немного исправить вызов requestAnimationFrame. Зато выложил все скрипты на GitHub и добавил каждому демонстрационный index.html.

UPD: Немного упростил логику. Теперь у меня два элемента типа toggle-post-body. По кнопке их видимость меняется местами. Можете посмотреть исходники плагина b2k-tools с актуальной версией на GitHub.

Раз вы дочитали до конца, как считаете: нужно ли добавить кнопку «свернуть» в конец поста для быстрой навигации?

Комментариев нет. Будьте первым!
Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Блог Евгения Жирнова