kkorsakov-htmx
Плагин для бесшовной интеграции HTMX библиотеки в WordPress с расширенным REST API для обработки фрагментных запросов.
by kkorsakov · github.com/korsakov-kuzjma/kkorsakov-htmx · website
Install
No release zip yet. The repository archive installs, but the folder name will carry the branch suffix and updates will not flow:
wp plugin install https://github.com/korsakov-kuzjma/kkorsakov-htmx/archive/refs/heads/main.zipПлагин для бесшовной интеграции HTMX библиотеки в WordPress с расширенным REST API для обработки фрагментных запросов.
Содержание
- Возможности
- Требования
- Установка
- Быстрый старт
- Использование шорткода [htmx]
- Использование REST API
- Кастомизация шаблонов
- PHP Фильтры
- JavaScript API
- Best Practices
- FAQ
Возможности
- Автоматическая загрузка HTMX библиотеки только на нужных страницах
- REST API endpoint для фрагментных запросов (
/kkorsakov-htmx/v1/fragment) - Поддержка шорткода
[htmx]для быстрого создания HTMX-элементов - Интеграция с WordPress Theme templates
- WP REST API Nonce автоматическая передача
- Фильтры для кастомизации поведения
- Поддержка контекстов
viewиedit - Страница настроек в админке
- Документация в админке WordPress
Требования
- WordPress 6.0 или выше
- PHP 7.4 или выше
- Composer (для разработки)
Установка
Через WordPress Dashboard
- Загрузите файл плагина в
/wp-content/plugins/kkorsakov-htmx - Активируйте плагин через меню 'Плагины' в WordPress
- Готово!
Через Composer
composer require kkorsakov/htmx
Ручная установка
cd /path/to/wordpress/wp-content/plugins/
git clone https://github.com/korsakov-kuzjma/kkorsakov-htmx.git kkorsakov-htmx
Затем активируйте плагин через WordPress Dashboard.
Настройки в админке
После активации плагина в админке WordPress появится новый пункт меню HTMX.
Страница настроек
Перейдите: HTMX → Настройки
Здесь вы можете настроить:
- Использовать CDN — загружать HTMX с внешнего сервера (unpkg.com)
- Принудительная загрузка — загружать HTMX на всех страницах сайта
- Включить историю — поддержка кнопок назад/вперёд в браузере
- Стиль замены — способ подмены контента (innerHTML, outerHTML и др.)
Страница документации
Перейдите: HTMX → Документация
Здесь вы найдёте полную документацию по использованию плагина на русском языке.
Быстрый старт
Пример 1: Простая кнопка с загрузкой фрагмента
[htmx target="#result" trigger="click" url="/wp-json/kkorsakov-htmx/v1/fragment?target=123"]
Загрузить контент
[/htmx]
<div id="result"></div>
Этот пример создаст кнопку, которая при нажатии загрузит контент поста ID 123 в div с id="result".
Пример 2: Форма с AJAX сабмитом
<form hx-post="/wp-json/kkorsakov-htmx/v1/fragment?target=contact-form" hx-target="#form-response">
<input type="email" name="email" placeholder="Ваш email" required>
<button type="submit">Подписаться</button>
</form>
<div id="form-response"></div>
Пример 3: Использование атрибутов напрямую ( Gutenberg block )
В редакторе Gutenberg добавьте HTML блок:
<button
hx-get="/wp-json/kkorsakov-htmx/v1/fragment?target=products"
hx-trigger="click"
hx-target="#products-container">
Загрузить товары
</button>
<div id="products-container"></div>
Использование шорткода [htmx]
Параметры шорткода
| Параметр | Обязательный | Описание | По умолчанию |
|---|---|---|---|
tag |
Нет | HTML тег элемента (span, div, a, button, img и т.д.) | span |
class |
Нет | CSS классы для элемента | (пусто) |
target |
Да | CSS selector целевого элемента, куда загрузить контент | (пусто) |
fragment |
Нет | ID фрагмента для загрузки (пост, термин или кастомный) | значение target |
trigger |
Нет | Событие, которое инициирует запрос | click |
swap |
Нет | Способ замены контента | innerHTML |
url |
Нет | Полный URL для запроса | Автогенерация |
indicator |
Нет | CSS selector элемента-индикатора загрузки | .htmx-indicator |
method |
Нет | HTTP метод запроса | get |
Доступные HTML теги
Вы можете использовать любой из следующих тегов:
span, div, a, button, img, input, form, ul, li, section, article, header, footer, main, aside, nav
Примеры шорткода
Простой линк (по умолчанию создаётся span)
[htmx target="#content" trigger="click"]Нажмите для загрузки[/htmx]
<div id="content"></div>
Использование div вместо span
[htmx tag="div" target="#sidebar" fragment="popular-posts" class="widget"]
<h3>Популярные посты</h3>
<p>Нажмите для загрузки</p>
[/htmx]
<div id="sidebar"></div>
Ссылка с HTMX
[htmx tag="a" target="#main-content" fragment="about" class="btn btn-primary" href="/about"]
О нас
[/htmx]
Результат:
<a hx-get=".../fragment?target=about"
hx-trigger="click"
hx-target="#main-content"
hx-swap="innerHTML"
class="btn btn-primary"
href="/about">
О нас
</a>
Кнопка с HTMX
[htmx tag="button" target="#results" fragment="search" method="post" class="btn btn-load"]
Загрузить результаты
[/htmx]
<div id="results"></div>
Изображение с кликом для загрузки
[htmx tag="img" target="#modal" fragment="123" class="clickable"
src="/wp-content/uploads/placeholder.jpg"
alt="Нажмите для просмотра">
Результат:
<img hx-get=".../fragment?target=123"
hx-trigger="click"
hx-target="#modal"
hx-swap="innerHTML"
class="clickable"
src="/wp-content/uploads/placeholder.jpg"
alt="Нажмите для просмотра">
Форма с AJAX отправкой
[htmx tag="form" target="#form-response" fragment="contact-form" method="post" class="ajax-form"]
<input type="email" name="email" placeholder="Ваш email" required>
<button type="submit">Отправить</button>
[/htmx]
<div id="form-response"></div>
С индикатором загрузки
[htmx target="#posts" trigger="click" indicator=".loader" class="btn"]
Загрузить посты
[/htmx]
<span class="htmx-indicator" style="display:none;">⏳ Загрузка...</span>
<div id="posts"></div>
<style>
.htmx-request .htmx-indicator { display: inline; }
.htmx-request.btn { opacity: 0.5; }
</style>
Ручное указание URL
[htmx target="#widget" url="https://example.com/custom-endpoint/"]
Обновить виджет
[/htmx]
<div id="widget"></div>
С POST запросом
[htmx method="post" target="#status" fragment="mark-read" class="btn-mark"]
Отметить как прочитанное
[/htmx]
<span id="status">Новые</span>
Использование REST API
Endpoint: /kkorsakov-htmx/v1/fragment
Методы: GET, POST
Namespace: kkorsakov-htmx/v1
Параметры запроса
| Параметр | Тип | Обязательный | Описание |
|---|---|---|---|
target |
string | Да | Идентификатор фрагмента (ID поста, слаг, CSS selector) |
context |
string | Нет | Контекст рендеринга: view или edit |
args |
object | Нет | Дополнительные аргументы для шаблона |
Примеры запросов
Запрос через HTMX атрибуты
<div hx-get="/wp-json/kkorsakov-htmx/v1/fragment?target=123" hx-target="#content">
Загрузить пост
</div>
<div id="content"></div>
Запрос через JavaScript
fetch('/wp-json/kkorsakov-htmx/v1/fragment?target=123', {
method: 'GET',
headers: {
'Content-Type': 'application/json',
}
})
.then(response => response.text())
.then(html => {
document.getElementById('content').innerHTML = html;
});
Формат ответа для HTMX запросов
HTTP/1.1 200 OK
Content-Type: text/html; charset=UTF-8
HX-Trigger: afterFragmentLoad
<div class="post-content">
<h1>Название поста</h1>
<p>Контент поста...</p>
</div>
Формат ответа для обычных AJAX запросов
{
"success": true,
"html": "<div class=\"post-content\">...</div>"
}
Поддерживаемые типы target
1. ID поста
?target=123
Загружает контент поста с ID 123.
2. Слаг термина таксономии
?target=category:5
Загружает архивную страницу категории с ID 5.
3. CSS selector
?target=#custom-section
Загружает кастомный фрагмент через хук kkorsakov_htmx_custom_fragment.
4. ID термина таксономии
?target=5
Если термин с ID 5 существует, загружает его архив.
Кастомизация шаблонов
Плагин ищет шаблоны в следующих местах (в порядке приоритета):
Для постов
htmx-fragment-{post_type}-{context}.php
htmx-fragment-{post_type}.php
htmx-fragment-{context}.php
htmx-fragment.php
Пример: Для поста типа product в контексте view будет искаться:
htmx-fragment-product-view.phphtmx-fragment-product.php
Для терминов таксономий
htmx-fragment-{taxonomy}-{context}.php
htmx-fragment-{taxonomy}.php
htmx-fragment-taxonomy-{context}.php
htmx-fragment-taxonomy.php
htmx-fragment-{context}.php
htmx-fragment.php
Пример: Для категории в контексте edit:
htmx-fragment-category-edit.phphtmx-fragment-category.php
Пример шаблона поста
Файл: htmx-fragment-post-view.php
<?php
/**
* Template for rendering post fragment in view context
*
* @package kkorsakov-htmx
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
$post = get_post();
?>
<article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
<header class="entry-header">
<h2 class="entry-title"><?php the_title(); ?></h2>
</header>
<div class="entry-content">
<?php the_content(); ?>
</div>
<footer class="entry-footer">
<span class="posted-on"><?php echo get_the_date(); ?></span>
<span class="byline">by <?php the_author(); ?></span>
</footer>
</article>
Пример шаблона термина
Файл: htmx-fragment-category-view.php
<?php
/**
* Template for rendering category term fragment
*
* @package kkorsakov-htmx
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
$term = get_queried_object();
?>
<section class="term-archive">
<header class="term-header">
<h2 class="term-title"><?php echo esc_html( $term->name ); ?></h2>
<p class="term-description"><?php echo wp_kses_post( term_description() ); ?></p>
</header>
<div class="term-posts">
<?php
$args = array(
'post_type' => 'post',
'posts_per_page' => 5,
'tax_query' => array(
array(
'taxonomy' => $term->taxonomy,
'field' => 'term_id',
'terms' => $term->term_id,
),
),
);
$query = new WP_Query( $args );
if ( $query->have_posts() ) :
while ( $query->have_posts() ) : $query->the_post();
get_template_part( 'template-parts/content', 'excerpt' );
endwhile;
wp_reset_postdata();
endif;
?>
</div>
</section>
PHP Фильтры
kkorsakov_htmx_config
Изменяет конфигурацию HTMX.
add_filter( 'kkorsakov_htmx_config', function( $config ) {
$config['historyEnabled'] = false;
$config['defaultSwapStyle'] = 'outerHTML';
return $config;
} );
kkorsakov_htmx_force_enqueue
Принудительно загружает HTMX на всех страницах.
add_filter( 'kkorsakov_htmx_force_enqueue', '__return_true' );
kkorsakov_htmx_fragment_url
Изменяет URL для фрагментного запроса.
add_filter( 'kkorsakov_htmx_fragment_url', function( $url, $target ) {
if ( $target === 'special' ) {
$url = home_url( '/custom-endpoint/?target=' . $target );
}
return $url;
}, 10, 2 );
kkorsakov_htmx_fragment_output
Изменяет HTML фрагмента перед отправкой.
add_filter( 'kkorsakov_htmx_fragment_output', function( $html, $target, $context ) {
if ( 'special' === $target ) {
$html = '<div class="special">' . $html . '</div>';
}
return $html;
}, 10, 3 );
kkorsakov_htmx_rest_permissions
Управляет правами доступа к REST endpoint.
add_filter( 'kkorsakov_htmx_rest_permissions', function( $allowed, $request ) {
if ( $request->get_param( 'context' ) === 'edit' ) {
return current_user_can( 'edit_posts' );
}
return $allowed;
}, 10, 2 );
kkorsakov_htmx_post_template
Кастомизирует шаблон для поста.
add_filter( 'kkorsakov_htmx_post_template', function( $template, $post, $context ) {
if ( $context === 'edit' ) {
$template = get_template_directory() . '/htmx-edit-post.php';
}
return $template;
}, 10, 3 );
kkorsakov_htmx_term_template
Кастомизирует шаблон для термина.
add_filter( 'kkorsakov_htmx_term_template', function( $template, $term, $context ) {
if ( $term->taxonomy === 'product_cat' ) {
$template = get_template_directory() . '/htmx-product-category.php';
}
return $template;
}, 10, 3 );
kkorsakov_htmx_custom_fragment
Кастомизирует кастомный фрагмент.
add_filter( 'kkorsakov_htmx_custom_fragment', function( $html, $target, $context, $args ) {
if ( $target === '#special-widget' ) {
ob_start();
do_action( 'kkorsakov_htmx_special_widget' );
$html = ob_get_clean();
}
return $html;
}, 10, 4 );
JavaScript API
Плагин регистрирует глобальный объект kkorsakovHtmx.
kkorsakovHtmx.refresh( element )
Обновляет элемент через HTMX.
var element = document.getElementById('content');
kkorsakovHtmx.refresh(element);
kkorsakovHtmx.ajax( method, url, config )
Прямой вызов HTMX ajax.
kkorsakovHtmx.ajax('GET', '/wp-json/kkorsakov-htmx/v1/fragment?target=123', {
target: '#content',
swap: 'innerHTML'
});
kkorsakovHtmx.loadFragment( target, context, args )
Создает URL для загрузки фрагмента.
var url = kkorsakovHtmx.loadFragment('123', 'view', {
format: 'short'
});
// Результат: /wp-json/kkorsakov-htmx/v1/fragment?target=123&context=view&args[format]=short
fetch(url)
.then(response => response.text())
.then(html => {
document.getElementById('content').innerHTML = html;
});
События HTMX
Плагин генерирует собственные события на основе HX-Trigger header.
document.addEventListener('kkorsakovHtmx:afterFragmentLoad', function(event) {
console.log('Fragment loaded!');
console.log('Target:', event.detail.target);
console.log('XHR:', event.detail.xhr);
});
// Или через htmx
htmx.on('#my-element', 'kkorsakovHtmx:afterFragmentLoad', function(evt) {
console.log('Fragment loaded in my-element');
});
События по умолчанию
kkorsakovHtmx:afterFragmentLoad— когда фрагмент загружен
Best Practices
1. Используйте классы вместо ID
<!-- Плохо -->
<button hx-target="#result" ...>Load</button>
<div id="result"></div>
<!-- Хорошо -->
<button hx-target=".result-zone" ...>Load</button>
<div class="result-zone"></div>
2. Обрабатывайте ошибки
<div hx-get="/wp-json/kkorsakov-htmx/v1/fragment?target=123"
hx-target="#content"
hx-swap="innerHTML"
hx-indicator=".loader">
Загрузить
</div>
<div class="loader" style="display:none;">⏳</div>
<style>
.htmx-request .loader { display: block; }
.htmx-request { opacity: 0.5; }
</style>
3. Кэшируйте запросы
[htmx target="#cached-content" trigger="click"
params="'HX-Cache--Control: max-age=300'"]
Обновить кэш
[/htmx]
4. Используйте контекст edit для администраторов
<?php if ( current_user_can( 'edit_posts' ) ) : ?>
<div hx-get="/wp-json/kkorsakov-htmx/v1/fragment?target=123&context=edit"
hx-target="#edit-preview">
Просмотр в режиме редактирования
</div>
<?php endif; ?>
5. Блокируйте повторные клики во время загрузки
document.body.addEventListener('htmx:beforeRequest', function(evt) {
evt.detail.xhr.addEventListener('htmx:abort', function() {
evt.detail.element.disabled = false;
});
});
document.body.addEventListener('htmx:afterRequest', function(evt) {
if (evt.detail.success) {
evt.detail.element.disabled = false;
}
});
FAQ
Почему HTMX не загружается?
Проверьте, что на странице есть шорткод [htmx] или блок kkorsakov/htmx-fragment.
Как отключить CDN?
По умолчанию используется локальный файл. Для использования CDN:
add_filter( 'kkorsakov_htmx_use_cdn', '__return_true' );
Почему 403 Forbidden при запросе?
Убедитесь, что запрос содержит правильный nonce. Плагин автоматически добавляет X-WP-Nonce header.
Как использовать с кастомными эндпоинтами?
add_action( 'rest_api_init', function() {
register_rest_route( 'my-plugin/v1', '/custom', [
'methods' => 'GET',
'callback' => function( $request ) {
return new WP_REST_Response( 'Hello World', 200 );
},
]);
} );
// Использовать в HTMX:
// hx-get="/wp-json/my-plugin/v1/custom"
Можно ли использовать с кэширующими плагинами?
Да, но для кэширования фрагментов используйте header:
add_action( 'rest_api_init', function() {
add_filter( 'kkorsakov_htmx_fragment_output', function( $html ) {
header( 'HX-Push-Url: true' );
header( 'Cache-Control: max-age=300' );
return $html;
});
} );
Лицензия
GPL-2.0-or-later
Участие в разработке
- Форкните репозиторий
- Создайте ветку (
git checkout -b feature/amazing-feature) - Сделайте коммит (
git commit -m 'Add some amazing feature') - Отправьте в ветку (
git push origin feature/amazing-feature) - Создайте Pull Request
Благодарности
- HTMX — замечательная библиотека для создания интерактивных интерфейсов