Как добавить заголовок «Last Modified» на сайте WordPress + Nginx?

Подробнее о заголовке Last-Modified можно почитать тут. Пожалуй, для SEO добавлю описание:

HTTP заголовок Last-Modified сообщает клиенту (браузеру, поисковому боту) время последнего изменения страницы (объекта). Если клиент получил заголовок Last-Modified, то при следующем обращении к адресу, при условии, что страница (объект) есть в локальном кэше, он добавит заголовок-вопрос If-Modified-Since (не изменилась ли страница после даты, полученной в Last-Modified).

В свою очередь сервер, получив запрос If-Modified-Since должен сверить полученную временную метку с временем последнего изменения страницы и, если страница не изменялась ответить 304 Not Modified.

Как добавить HTTP заголовок Last-Modified на PHP в WordPress?

В целом на официальном сайте уже существует реализация на PHP, которую остаётся немного адаптировать для WP.

Отправка Last-Modified и обработка HTTP_IF_MODIFIED_SINCE на PHP

// время последнего изменения страницы в формате unix time
$lastModified = strtotime('2022-06-18 19:01:58');

// дата последней загрузки, отправляемая клиентом
$ifModified = strtotime(substr($_SERVER['HTTP_IF_MODIFIED_SINCE'] ?? '', 5));

if ($ifModified && $ifModified >= $lastModified) {
    // страница не изменилась, отдача http статуса 304
    header($_SERVER['SERVER_PROTOCOL'] . ' 304 Not Modified');
    exit;
}

header('Last-Modified: ' . gmdate("D, d M Y H:i:s \G\M\T", $lastModified));
// дальнейшая загрузка страницы

Получаем время последнего изменения страницы, проверяем наличие If-Modified-Since, если есть — отдаем 304 Not Modified и останавливаем работу скрипта, иначе генерируем заголовок Last-Modified и отдаем страницу.

Версия для WordPress

Этот готовый код необходимо добавить в functions.php или через плагин. Я рекомендую добавлять этим методом.

/**
 * Last-Modified and If-Modified-Since Headers
*/

add_action('wp', poet_'last_if_modified_headers' );

function poet_last_if_modified_headers() {
    global $post;
        if(isset($post)){
            $LastModified_unix = strtotime($post->post_modified);
            $LastModified = gmdate("D, d M Y H:i:s \G\M\T", $LastModified_unix);
            $IfModifiedSince = false;

            if (isset($_ENV['HTTP_IF_MODIFIED_SINCE'])) {
                $IfModifiedSince = strtotime(substr($_ENV['HTTP_IF_MODIFIED_SINCE'], 5));
            }
            if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
                $IfModifiedSince = strtotime(substr($_SERVER['HTTP_IF_MODIFIED_SINCE'], 5));
            }

            if ($IfModifiedSince && $IfModifiedSince >= $LastModified_unix) {
                header($_SERVER['SERVER_PROTOCOL'] . ' 304 Not Modified');
                exit;
            }

            header('Last-Modified: '. $LastModified);
        }
}

Настройки HTTP-сервера Nginx

Если вы используете в качестве веб-сервера Nginx , то есть вероятность столкнуться с проблемой отдачи заголовка. Всё дело в том, если у вашей конфигурации включена директива ssi

Модуль ngx_http_ssi_module — это фильтр, обрабатывающий команды SSI (Server Side Includes) в проходящих через него ответах.

https://nginx.org/ru/docs/http/ngx_http_ssi_module.html

Пример конфигурации при котором разрешается обработка команд SSI в ответах:

location / {
    ssi on;
    ...
}

Следовательно, прицепом к этой директиве необходимо включить еще одну, которая по умолчанию выключена:

location / {
    ssi on;
    ssi_last_modified on;
}

Позволяет сохранить поле заголовка “Last-Modified” исходного ответа во время обработки SSI для лучшего кэширования ответов.

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

Вот и всё 🙂

Обязательно перезапустите HTTP-сервер Nginx и протестируйте отдачу заголовка.

Вот правильная работа заголовка:

протестируйте отдачу заголовка