Ak ste niekedy pridali na stránku „len malé tlačidlo“ WordPressPotom, keď skončíte s 200 KB JavaScriptu, závislosťou od frameworku a vyrovnávacou pamäťou, ktorá sa nikdy nevyprázdni, narazíte na skutočný problém: interaktivita na strane klienta sa rýchlo prejaví na úkor zložitosti.
WordPress už niekoľko verzií ponúka prístup „priateľskejší k jadru“: Interactivity API. Myšlienka je na papieri jednoduchá: deklarovať správanie na strane klienta priamo vo vašom značkovaní (prostredníctvom data-wp-*), s responzívnym obchodom spravovaným systémom WordPress, bez React/Vue/Svelte vo vašej šablóne.
Problém / Potreba
Konkrétna potreba: vytvoriť front-endový komponent (napr. „páči sa mi to“, „počítadlo“, „filter“, „akordeón“, „kopírovať do schránky“nakladanie progresívny“) interaktívny bez vloženia frameworku, pričom zostáva kompatibilný s ekosystémom WordPressu (vyrovnávacia pamäť, témy, blokové témy, tvorcovia stránok, zabezpečenie).
Nakoniec budete vedieť:
- Vytvorte malý plugin, ktorý sprístupní blok (alebo HTML vykreslenie použiteľné všade) pomocou rozhrania Interactivity API.
- Spravujte stav (úložisko) a akcie (obslužné rutiny) na strane klienta bez externých závislostí.
- Pridať koncový bod AJAX/REST zabezpečí pretrvávanie stavu (napr. ako počítadlo).
- Ladenie reálnych prípadov: zlé zaradenie do frontu, agresívne ukladanie do vyrovnávacej pamäte, zle zvolené hooky, konflikty pri builderoch.
Rýchle zhrnutie
- Napísali sme plugin „Páči sa mi to“ (počítadlo + prepínač) založený na Interactivity API, kompatibilný s WordPress 6.9.4+ a PHP 8.1+.
- Značenie používa
data-wp-interactive,data-wp-on--click,data-wp-text,data-wp-class--*. - JS úložisko spravuje lokálny stav (optimistické používateľské rozhranie) a potom sa synchronizuje cez REST API.
- Na strane PHP: REST endpoint
/wp-json/bpcab/v1/like, REST nonce, oprávnenia, sanitizácia/escaping. - Ponúkame variant shortcode + integrácie Divi 5 / Elementor / Avada.
Kedy použiť toto riešenie
- Chcete ľahkú interaktivitu (prepínač, počítadlo, stav používateľského rozhrania) bez balíka React.
- Dodávate tému alebo plugin určený pre rôzne stránky (buildery, vyrovnávacia pamäť, CDN) a chcete znížiť riziko konfliktov JS.
- Potrebujete SSR vykresľovanie (HTML generované pomocou PHP), ktoré zostane použiteľné bez JS a potom sa pomocou JS „vylepší“ (progresívne vylepšovanie).
- Chcete sa držať vzorov WordPressu (zaradenie do frontu, REST, nonces) a vyhnúť sa „mini-SPA“ v kúte.
Kedy toto riešenie NEPOUŽÍVAŤ
- Vytvárate bohatú jednostránkovú aplikáciu (SPA) so smerovaním, komplexnými formulármi a rozsiahlym globálnym reportingom. Vhodnejší by bol framework (alebo aspoň robustnejšia architektúra).
- Musíte podporovať veľmi staré prehliadače (Interactivity API sa riadi modernými štandardmi; skontrolujte si obmedzenia).
- Vašu interaktivitu už riadne zabezpečuje plugin (napr. bloky WooCommerce, špecializované fazety). Údržba „vynájdenia kolesa“ je drahá.
- Máte požiadavku na prácu v reálnom čase (WebSocket, prítomnosť, spolupráca). Interactivity API nie je náhradou za vrstvu v reálnom čase.
Predpoklady / pred začatím
- WordPress minimálne 6.9.4 (apríl 2026), PHP 8.1+.
- Testovacie prostredie (lokálne alebo v prostredí staging). Vyhnite sa testovaniu tohto typu kódu priamo v produkčnom prostredí: Videl som, ako sa zle chránený REST endpoint zastavil v priebehu niekoľkých minút.
- Prístup k permalinkom (nastaveniam) na kontrolu REST API a jeho regeneráciu v prípade potreby.
- Užitočné nástroje:
- Monitor dotazov na kontrolu hookov/REST/výkonu.
- Prehliadač DevTools (sieť + konzola).
Oficiálne zdroje, ktoré by ste mali mať poruke:
- Interaktivné API (Príručka editora blokov)
- Príručka REST API
- register_rest_route()
- wp_enqueue_script ()
- Filter/validácia PHP (php.net)
Pre monitorovanie jadra: keď narazíte na nezvyčajné správanie (najmä pri interakcii s vyrovnávacou pamäťou alebo editorom), skontrolujte tikety na core.trac.wordpress.org a PR na github.com/WordPress/gutenberg.
Naivný prístup (a prečo sa mu vyhnúť)
Verzia, ktorú stále často vídavam: tlačidlo s onclick vložený, a fetch na admin-ajax.php, žiadny nikde inde a skript načítaný všade na stránke.
<?php
// Exemple à NE PAS copier : inline JS, pas de nonce, pas de contrôle de permission.
echo '<button onclick="likePost(' . get_the_ID() . ')">Like</button>';
?>
<script>
function likePost(postId){
fetch('/wp-admin/admin-ajax.php?action=like&post_id=' + postId)
.then(r => r.json())
.then(console.log);
}
</script>
Čo sa deje v zákulisí:
- Bezpečnosť: Koncový bod bez nonce = triviálne CSRF. A ak neoveríte
post_id, otváraš dvere svojvoľným spisom. - Výkon: skript vložený všade, nemožné ho presne ovládať a ťažké ho správne ukladať do vyrovnávacej pamäte.
- Údržba: v deň, keď potrebujete sprístupniť komponent (ARIA), spraviť ho testovateľným alebo kompatibilným s tvorcom, začínate od nuly.
- DX: Vložené obslužné programy sa stanú nezvládnuteľnými hneď, ako máte 2 varianty komponentov.
Správny prístup – podrobný návod
Vytvoríme minimalistický, čistý plugin s funkčným komponentom „Páči sa mi to“:
- Bez JS: tlačidlo sa zobrazí (a môžete si zvoliť záložnú možnosť).
- S JS: okamžité prepínanie + aktualizované počítadlo, potom REST synchronizácia.
Krok 1 – Vytvorenie doplnku
Vytvoriť priečinok wp-content/plugins/bpcab-interactivity-like/ s:
bpcab-interactivity-like.phpassets/like.js
Krok 2 – Definujte „interaktívne“ vykresľovanie HTML
Interactivity API sa spolieha na atribúty data-wp-* v označení. Najdôležitejšie je: data-wp-interactive ktorý „pripája“ menný priestor úložiska k podstromu DOM.
Vytvoríme tlačidlo a počítadlo. Tlačidlo:
- spúšťa akciu prostredníctvom
data-wp-on--click - zobrazuje dynamický text prostredníctvom
data-wp-text - prepnúť triedu CSS pomocou
data-wp-class--is-liked
Krok 3 – Správne načítanie skriptu (cielené zaradenie do frontu)
Klasická chyba: načítanie JS kódu na každej stránke. Tu načítame skript iba v prípade, že obsah obsahuje náš shortcode (alebo ak je náš blok vykreslený). Aby sme to zjednodušili a spoľahlivo udržali, budeme:
- zadajte krátky kód
[bpcab_like] - zistiť jeho prítomnosť prostredníctvom
has_shortcode()v pravý okamih
Poznámka: Na stránkach s výrazným využitím funkcií (Elementor/Divi) sa môže obsah generovať odlišne. Nižšie uvediem niekoľko variácií.
Krok 4 – Zverejnite zabezpečený koncový bod REST
Vyhýbame sa admin-ajax.php V tomto prípade je REST API čistejšie, optimalizované pre vyrovnávaciu pamäť a lepšie vybavené (HTTP kód, JSON, autentifikácia). Vytvoríme trasu:
POST /wp-json/bpcab/v1/likespost_idetdelta(+1 alebo -1)
Chránime pomocou:
- REST jednorazový kód (
wp_create_nonce( 'wp_rest' )) - Prísna validácia parametrov
- Povolenia: Tu sú povolení anonymní návštevníci, ale vplyv je obmedzený (delta ±1, existujúci príspevok, verejný typ). Pre skutočnú perzistenciu „na používateľa“ by bol potrebný model identity (ID používateľa, podpísaný súbor cookie alebo prísnejšie ukladanie na serveri).
Krok 5 – Interaktivita obchodu (optimistické používateľské rozhranie + vrátenie zmien)
Vzor, ktorý často používam:
- Okamžite aktualizujeme používateľské rozhranie (optimisticky).
- Posielame REST požiadavku
- Ak to zlyhá, vrátime stav späť a správne sa zaprotokolujeme.
Úplný kód
Súbor 1: PHP plugin
vytvoriť wp-content/plugins/bpcab-interactivity-like/bpcab-interactivity-like.php.
<?php
/**
* Plugin Name: BPCAB Interactivity Like
* Description: Exemple avancé Interactivity API : bouton Like sans framework, avec synchronisation REST.
* Version: 1.0.0
* Requires at least: 6.9
* Requires PHP: 8.1
* Author: BPCAB
*/
declare(strict_types=1);
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
final class BPCAB_Interactivity_Like_Plugin {
private const SCRIPT_HANDLE = 'bpcab-like-interactivity';
private const REST_NAMESPACE = 'bpcab/v1';
private const REST_ROUTE = '/like';
public function hooks(): void {
add_action( 'init', [ $this, 'register_shortcode' ] );
add_action( 'wp_enqueue_scripts', [ $this, 'maybe_enqueue_assets' ] );
add_action( 'rest_api_init', [ $this, 'register_rest_routes' ] );
}
public function register_shortcode(): void {
add_shortcode( 'bpcab_like', [ $this, 'render_shortcode' ] );
}
/**
* Rend le composant Like.
* Utilisable dans un article, une page, un widget texte, ou via do_shortcode().
*/
public function render_shortcode( array $atts = [] ): string {
$atts = shortcode_atts(
[
'post_id' => 0,
'label_like' => 'J’aime',
'label_unlike' => 'Je n’aime plus',
],
$atts,
'bpcab_like'
);
$post_id = (int) $atts['post_id'];
if ( $post_id <= 0 ) {
$post_id = get_the_ID() ? (int) get_the_ID() : 0;
}
if ( $post_id <= 0 ) {
return '';
}
$post = get_post( $post_id );
if ( ! $post || 'publish' !== $post->post_status ) {
return '';
}
// Compteur stocké en post meta. Pour un site à fort trafic, préférez une table dédiée ou un agrégat asynchrone.
$likes = (int) get_post_meta( $post_id, '_bpcab_likes', true );
if ( $likes < 0 ) {
$likes = 0;
}
// État initial "liked" : ici, on ne persiste pas par utilisateur.
// On part sur false. Pour une vraie UX, vous pouvez lire un cookie signé ou une table user/post.
$initial_liked = false;
// Données initiales injectées dans le DOM (JSON) pour hydrater le store côté client.
$initial_state = [
'postId' => $post_id,
'likes' => $likes,
'liked' => $initial_liked,
'labels' => [
'like' => (string) $atts['label_like'],
'unlike' => (string) $atts['label_unlike'],
],
];
// Escaping : on encode en JSON, puis on échappe pour attribut HTML.
$initial_state_json = wp_json_encode( $initial_state, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES );
if ( false === $initial_state_json ) {
return '';
}
// Markup Interactivity API.
// data-wp-interactive="bpcab/like" : namespace du store côté client.
// data-wp-context : contexte initial (state) accessible via le store.
$html = '<div class="bpcab-like"';
$html .= ' data-wp-interactive="bpcab/like"';
$html .= ' data-wp-context="' . esc_attr( $initial_state_json ) . '"';
$html .= '>';
$html .= '<button type="button" class="bpcab-like__button"';
$html .= ' data-wp-on--click="actions.toggle"';
$html .= ' data-wp-class--is-liked="state.liked"';
$html .= '>';
$html .= '<span class="bpcab-like__label" data-wp-text="state.liked ? state.labels.unlike : state.labels.like"></span>';
$html .= '</button>';
$html .= '<span class="bpcab-like__count" aria-live="polite">';
$html .= '<strong data-wp-text="state.likes">' . esc_html( (string) $likes ) . '</strong>';
$html .= '</span>';
$html .= '</div>';
return $html;
}
/**
* Enqueue conditionnel : on charge le JS seulement si le shortcode est présent.
* Attention : sur certaines pages builder, le contenu n'est pas dans post_content.
*/
public function maybe_enqueue_assets(): void {
if ( is_admin() ) {
return;
}
$post = get_post();
if ( ! $post ) {
return;
}
// Détection simple : shortcode présent dans post_content.
// Variante builder plus bas.
if ( ! has_shortcode( (string) $post->post_content, 'bpcab_like' ) ) {
return;
}
$asset_url = plugin_dir_url( __FILE__ ) . 'assets/like.js';
$asset_path = plugin_dir_path( __FILE__ ) . 'assets/like.js';
$ver = file_exists( $asset_path ) ? (string) filemtime( $asset_path ) : '1.0.0';
// Dépendances : le runtime Interactivity est fourni par WordPress (paquet @wordpress/interactivity).
// Le handle exact peut évoluer selon les versions ; en pratique WP expose les scripts nécessaires
// quand vous utilisez l'Interactivity API dans les blocs.
//
// Ici, on reste robuste : pas de dépendance forcée, mais on s'appuie sur le fait que WP charge
// le runtime interactivity quand le markup data-wp-interactive est présent.
wp_enqueue_script(
self::SCRIPT_HANDLE,
$asset_url,
[],
$ver,
[
'in_footer' => true,
'strategy' => 'defer',
]
);
// Données globales minimales : endpoint REST + nonce.
// Le nonce 'wp_rest' est le standard pour REST API.
wp_add_inline_script(
self::SCRIPT_HANDLE,
'window.BPCAB_LIKE = ' . wp_json_encode(
[
'restUrl' => esc_url_raw( rest_url( self::REST_NAMESPACE . self::REST_ROUTE ) ),
'nonce' => wp_create_nonce( 'wp_rest' ),
],
JSON_UNESCAPED_SLASHES
) . ';',
'before'
);
// Un peu de CSS minimal via inline (vous pouvez le sortir dans un fichier).
$css = '.bpcab-like{display:flex;gap:.6rem;align-items:center}.bpcab-like__button.is-liked{font-weight:700}.bpcab-like__count{opacity:.85}';
wp_register_style( 'bpcab-like-inline', false, [], $ver );
wp_enqueue_style( 'bpcab-like-inline' );
wp_add_inline_style( 'bpcab-like-inline', $css );
}
public function register_rest_routes(): void {
register_rest_route(
self::REST_NAMESPACE,
self::REST_ROUTE,
[
'methods' => 'POST',
'callback' => [ $this, 'rest_like' ],
'permission_callback' => [ $this, 'rest_permission' ],
'args' => [
'post_id' => [
'type' => 'integer',
'required' => true,
'sanitize_callback' => 'absint',
'validate_callback' => function ( $value ) {
return is_numeric( $value ) && (int) $value > 0;
},
],
'delta' => [
'type' => 'integer',
'required' => true,
'sanitize_callback' => function ( $value ) {
$value = (int) $value;
if ( 1 === $value ) {
return 1;
}
if ( -1 === $value ) {
return -1;
}
return 0;
},
'validate_callback' => function ( $value ) {
$value = (int) $value;
return 1 === $value || -1 === $value;
},
],
],
]
);
}
/**
* Permission : on accepte les visiteurs anonymes, mais on exige un nonce REST valide.
* Si vous voulez limiter aux utilisateurs connectés : return is_user_logged_in();
*/
public function rest_permission( WP_REST_Request $request ): bool|WP_Error {
$nonce = $request->get_header( 'X-WP-Nonce' );
if ( ! $nonce ) {
return new WP_Error( 'bpcab_like_missing_nonce', 'Nonce manquant.', [ 'status' => 403 ] );
}
if ( ! wp_verify_nonce( $nonce, 'wp_rest' ) ) {
return new WP_Error( 'bpcab_like_invalid_nonce', 'Nonce invalide.', [ 'status' => 403 ] );
}
return true;
}
public function rest_like( WP_REST_Request $request ): WP_REST_Response|WP_Error {
$post_id = (int) $request->get_param( 'post_id' );
$delta = (int) $request->get_param( 'delta' );
$post = get_post( $post_id );
if ( ! $post || 'publish' !== $post->post_status ) {
return new WP_Error( 'bpcab_like_invalid_post', 'Article introuvable.', [ 'status' => 404 ] );
}
// Optionnel : limiter aux post types publics.
$post_type_obj = get_post_type_object( (string) $post->post_type );
if ( ! $post_type_obj || ! $post_type_obj->public ) {
return new WP_Error( 'bpcab_like_forbidden_type', 'Type de contenu non autorisé.', [ 'status' => 403 ] );
}
// Mise à jour robuste.
// Note : update_post_meta n'est pas atomique. Sur très fort trafic, vous pouvez avoir des collisions.
// Pour un compteur critique, utilisez une table custom + requête SQL atomique, ou un système de queue.
$current = (int) get_post_meta( $post_id, '_bpcab_likes', true );
$new = $current + $delta;
if ( $new < 0 ) {
$new = 0;
}
update_post_meta( $post_id, '_bpcab_likes', $new );
return new WP_REST_Response(
[
'postId' => $post_id,
'likes' => $new,
],
200
);
}
}
add_action(
'plugins_loaded',
static function (): void {
( new BPCAB_Interactivity_Like_Plugin() )->hooks();
}
);
Súbor 2: Interaktívny skript
vytvoriť wp-content/plugins/bpcab-interactivity-like/assets/like.js.
/* global BPCAB_LIKE */
(function () {
'use strict';
/**
* Interactivity API :
* On enregistre un store "bpcab/like" qui expose state/actions.
* Le state initial provient de data-wp-context (injecté côté PHP).
*
* Référence : https://developer.wordpress.org/block-editor/reference-guides/interactivity-api/
*/
const { store, getContext } = window.wp && window.wp.interactivity ? window.wp.interactivity : {};
if (!store || !getContext) {
// Cas réel : le runtime interactivity n'est pas chargé (mauvais enqueue, optimisation agressive, plugin cache).
// On évite de casser la page.
return;
}
async function postLike({ postId, delta }) {
const res = await fetch(BPCAB_LIKE.restUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-WP-Nonce': BPCAB_LIKE.nonce
},
body: JSON.stringify({ post_id: postId, delta })
});
if (!res.ok) {
const text = await res.text().catch(() => '');
const err = new Error('REST error ' + res.status + ' ' + res.statusText);
err.details = text;
throw err;
}
return await res.json();
}
store('bpcab/like', {
state: {
get postId() {
return getContext().postId;
},
get likes() {
return getContext().likes;
},
get liked() {
return getContext().liked;
},
get labels() {
return getContext().labels || { like: 'J’aime', unlike: 'Je n’aime plus' };
}
},
actions: {
/**
* Toggle optimiste :
* - on inverse liked
* - on ajuste likes (+1/-1)
* - on synchronise REST
* - rollback en cas d'erreur
*/
async toggle() {
const ctx = getContext();
const previousLiked = !!ctx.liked;
const previousLikes = Number.isFinite(ctx.likes) ? ctx.likes : 0;
const nextLiked = !previousLiked;
const delta = nextLiked ? 1 : -1;
// Mise à jour optimiste.
ctx.liked = nextLiked;
ctx.likes = Math.max(0, previousLikes + delta);
try {
const data = await postLike({ postId: ctx.postId, delta });
// On resynchronise avec la vérité serveur.
if (data && typeof data.likes === 'number') {
ctx.likes = data.likes;
}
} catch (e) {
// Rollback.
ctx.liked = previousLiked;
ctx.likes = previousLikes;
// Log discret. En prod, vous pouvez envoyer vers un logger.
// Ne faites pas d'alert() agressif.
console.error('[bpcab/like] Échec synchronisation', e);
}
}
}
});
})();
Vysvetlenie kódu
Všeobecná (jednoduchá) logika
PHP vykreslí „normálny“ HTML súbor (tlačidlo + počítadlo) a pridá nasledujúce:
data-wp-interactive="bpcab/like"povedať WordPressu: „tento podstrom používa úložisko bpcab/like“.data-wp-context="...json..."vložiť počiatočný stav (postId, likes, liked, lajky).data-wp-on--click="actions.toggle"prepojiť kliknutie s akciou JS.data-wp-text="..."zobraziť hodnotu vypočítanú zo stavu.
JS ukladá úložisko typu „bpcab/like“. Keď používateľ klikne, kontext sa zmení (reaktívne) a potom sa zavolá REST API na uchovanie počítadla.
Technické detaily (hooky, zabezpečenie, integrácia WP 6.9.4)
add_shortcode()Toto je praktické pre prenosný príklad. V produkčnom prostredí budete často používať dynamický blok (render_callback) pre presnejšiu kontrolu v editore.wp_enqueue_scriptsVyšetrujeme spredu. Citlivým bodom je detekcia prítomnosti. Ak váš tvorca nevloží shortcodepost_contentSkript sa nenačítaNižšie uvádzam variácie.- REST API :
register_rest_route()odhaľuje cestu.permission_callbackskontroluj jednorazové čísloX-WP-Nonce(CSRF).- Prísne overovanie
deltav rámci ±1. Bez toho uvidíte ľudí, ktorí uverejňujú príspevkydelta=999999hneď ako je koncový bod verejne dostupný.
- Podmienky pretekov Počítadlo post-meta nie je atomické. Pri vysokej návštevnosti môžu dva súčasné dopyty prepísať hodnotu. Pre typický blog je to prijateľné; pre mediálny kanál s vysokým objemom záujmu používam vlastnú tabuľku a atomické dopyty (alebo buffer/front).
Pourquoi data-wp-context skôr než wp_localize_script podľa príkladu
wp_localize_script je globálny (prostredníctvom handle), čo sa stáva ťažkopádnym s 10 komponentmi na tej istej stránke. Tu každá inštancia nesie svoj vlastný JSON. Toto je oveľa škálovateľnejšie, keď máte slučku článkov (napr. stránka kategórie s 20 „lajkmi“).
Varianty a prípady použitia
Variant 1 — Viacero tlačidiel na stránke (slučka) bez zložitého globálneho JS
Môžete dať [bpcab_like post_id="123"] v slučke alebo vygenerovať HTML pomocou PHP. Každý komponent má svoj vlastný data-wp-contextObchod je zdieľaný, ale kontext je individuálny: presne o to ide.
Variant 2 – Ukladanie „lajkov“ pre každého (prihláseného) používateľa namiesto jednoduchého počítadla
Vzor, ktorý používam:
- Ak je používateľ prihlásený: uložte do meta údajov používateľa zoznam (alebo relačnú tabuľku) príspevkov, ktoré sa vám páčia.
- Kontroly koncového bodu REST
is_user_logged_in()a používaget_current_user_id(). - Agregované počítadlo zostáva v meta údajoch príspevku (alebo tabuľke), ale stav „páči sa mi to“ sa stáva spoľahlivým.
Upozornenie: zoznam v meta údajoch používateľa môže narásť. Na veľkých stránkach sa odporúča vyhradená relačná tabuľka (user_id, post_id, created_at) + index.
Variant 3 – „Netrvalý“ režim (iba používateľské rozhranie) pre akordeóny/tabulátory
Ak potrebujete čisto používateľské rozhranie (akordeón, karty), odstráňte koncový bod REST a ponechajte iba:
data-wp-on--clickzmeniť boolovskú hodnotu v kontextedata-wp-class--is-open/data-wp-textodrážať štát
Podľa mojich skúseností je toto najlepší vstupný bod: nulový backend, nulová bezpečnosť a overíte si kompatibilitu vášho kanála zaradenia do frontu/vyrovnávacej pamäte.
Kompatibilita s Divi 5 / Elementor / Avada
Bod, ktorý sa najčastejšie láme: Skript sa nepodarilo načítať pretože váš konečný obsah neobsahuje skrátený kód v post_content.
Divi 5
Divi dokáže ukladať rozloženia do meta tagov a konečné vykreslenie nie je vždy detekovateľné prostredníctvom has_shortcode( $post->post_content )Dve robustné možnosti:
- „Veľký“ dopyt iba na stránkach, kde viete, že sa modul nachádza (napr. prostredníctvom podmienenej šablóny).
- Alebo zistiť prítomnosť vykreslených značiek v čase vykresľovania (vyrovnávacia pamäť) – krehkejšie.
Pragmatický prístup, ktorý som často používal: pridanie malého nastavenia „vynúteného zaradenia do frontu“ pomocou filtra.
<?php
// À mettre dans votre plugin (ou un mu-plugin) si Divi ne déclenche pas has_shortcode().
add_filter( 'bpcab_like_force_enqueue', function( bool $force ): bool {
if ( function_exists( 'et_theme_builder_get_template_layouts' ) ) {
// Indice que Divi est actif. À affiner selon votre contexte.
return true;
}
return $force;
}, 10, 1 );
Potom sa prispôsobte maybe_enqueue_assets() Ak chcete použiť tento filter (ak chcete túto variantu, urobte to správne). Predvolene som ho nezahrnul, aby bol plugin minimalistický.
Elementor
V Elementore sa obsah často vykresľuje z meta tagov. Dve prehľadné riešenia:
- Vytvorte špecializovaný widget Elementoru, ktorý vykresľuje značky (a registruje závislosť skriptu prostredníctvom rozhrania Elementor API).
- Alebo dotazovať stránky Elementoru pomocou podmienky (detekcia pluginov + meta).
Ak sa rozhodnete pre jednoduchú detekciu:
<?php
// Exemple : détecter une page construite avec Elementor.
$is_elementor = (bool) get_post_meta( get_the_ID(), '_elementor_edit_mode', true );
Avada (výrobca fúzií)
Avada má vlastné shortcode a renderovací kanál. Najspoľahlivejšie: použite shortcode [bpcab_like] priamo do bloku/prvku „Kód“ alebo „Skrátený kód“.
Ak Avada vykonáva agresívnu minifikáciu/zreťazovanie, skontrolujte, či:
- skript sa nepresunie do
headsansdefer - Interaktivita runtime nie je optimalizáciou „odstránená“
Kontroly po inštalácii
- Na stránke obsahujúcej
[bpcab_like]Otvorte DevTools > Sieť:- skontrolujte to
assets/like.jsje plne nabitá (stav 200) - skontrolujte to
POST /wp-json/bpcab/v1/likevráti 200 po kliknutí
- skontrolujte to
- Nástroje pre vývojárov > Konzola:
- žiadna chyba
window.wp.interactivitynedefinované
- žiadna chyba
- Na strane WordPressu:
- meta
_bpcab_likesaktualizuje sa sám (môžete si to skontrolovať cez WP-CLI alebo meta plugin).
- meta
Rýchla diagnostická tabuľka
| symptóm | Príčina pravdepodobná | overenie | Riešenie |
|---|---|---|---|
| Tlačidlo sa zobrazí, ale nereaguje. | Interaktivita za behu nie je načítaná alebo JS nie je načítaný | Konzola: window.wp.interactivity Existuje? Sieť: like.js poplatok? |
Opraviť Zaradenie do frontu, vypnutie optimalizácie JS, kontrola buildera |
| Chyba 403 na trase REST | Chýbajúci/neplatný nonce | Sieť: hlavička X-WP-Nonce tu? |
skontrolovať wp_add_inline_script, HTML vyrovnávacia pamäť, CDN, ktorá odstraňuje hlavičky |
| Počítadlo „skáče“ dozadu | Vrátenie zmien po chybe REST | Konzola: protokol [bpcab/like] Échec synchronisation |
Skontrolujte REST URL adresy, permalinks, WAF, CORS a bezpečnostné pluginy. |
| Meradlo je pri zaťažení nekonzistentné | Podmienka pretekania v metadátach príspevku | Simulujte simultánne kliknutia (k6/ab) a porovnajte ich | Vlastná tabuľka + atomická aktualizácia alebo asynchrónna agregácia |
Ak to nefunguje
- Skontrolujte, kam ste vložili kód Tento plugin musí byť v
wp-content/plugins/...a aktivované. Už som videl, ako sa súbor PHP vloží do témy a potom „funguje na jednej stránke a na druhej nie“. - Skontrolujte PHP Vo verziách PHP starších ako 8.1 sa môžete stretnúť s typovými chybami. Pozrite si
wp-content/debug.logsiWP_DEBUGje aktivovaný. - Skontrolujte trvalé odkazy Ak REST API vráti chybu 404, prejdite do časti Nastavenia > Trvalé odkazy a uložte zmeny (bez akejkoľvek zmeny). Toto je bežný problém počas migrácií.
- Dočasne zakázať optimalizáciu JS (cache/minify): Často som sa stretol s interaktivitou za behu, ktorá bola „prerušená“ zreťazením, ktoré zmenilo poradie načítavania.
- Otestujte koncový bod REST pomocou funkcie Curl :
curl -i -X POST "https://example.com/wp-json/bpcab/v1/like"
-H "Content-Type: application/json"
-H "X-WP-Nonce: VOTRE_NONCE"
--data '{"post_id":123,"delta":1}'
Ak nemáte k dispozícii žiadny nonce, aspoň otestujte, či trasa existuje (malo by vrátiť chybu 403 „Chýbajúci nonce“, čo je dobré znamenie).
Časté úskalia a chyby
| Chyba | Spôsobiť | Riešenie |
|---|---|---|
Uncaught TypeError: Cannot destructure property 'store' ... |
window.wp.interactivity chýba (runtime nie je načítané) |
Skontrolujte zaradenie do frontu, vypnite minifikáciu a uistite sa, že WP načíta interaktívne skripty. |
| Skript sa nikdy nenačíta | has_shortcode() nedetekuje (tvorca, vykreslené cez meta) |
Pridajte nástroj na tvorbu podmienok (Elementor/Divi/Avada) alebo zaraďte do frontu pomocou vyhradeného widgetu/modulu |
403 Nonce invalide |
HTML uložené vo vyrovnávacej pamäti s vypršaným nonce alebo stránka zobrazená prostredníctvom vyrovnávacej pamäte celej stránky | Vylúčte stránku z vyrovnávacej pamäte, vygenerujte nonce prostredníctvom verejného koncového bodu alebo ho obmedzte na prihlásených používateľov. |
SyntaxError: Unexpected token v data-wp-context |
Nesprávne kódovaný/escapovaný JSON, prerušené úvodzovky | Vždy prejdite wp_json_encode potom esc_attr |
| Závažná chyba po kopírovaní a vkladaní | Chýbajúca zátvorka/bodkočiarka alebo súbor je umiestnený v nesprávnom priečinku | Overiť pomocou linteru, povoliť WP_DEBUG pri staging, opraviť syntax |
| Počítadlo sa stane záporným | Delta nie je overená alebo rýchle dvojité kliknutie | Overiť delta ±1, upevnenie na 0 na strane servera aj klienta |
| Konflikt s doplnkom zabezpečenia/WAF | Blokovanie požiadaviek alebo hlavičiek REST POST | Pridať trasu na bielu listinu /wp-json/bpcab/v1/likeskontrolovať protokoly WAF |
| Používate starý úryvok kódu z roku 2023 | Zmenené API/handlery, zastarané postupy | Zacielenie na WP 6.9.4+, na základe aktuálnej dokumentácie k interaktivite |
Tipy na bezpečnosť, výkon a údržbu
Zabezpečenie
- Vyžaduje sa REST nonce Ak váš koncový bod upraví dáta. Bez jednorazového kódu, CSRF.
- Potvrďte nastavenia tu
deltaje striktne ±1. Je to jednoduchá, ale účinná bariéra. - Premýšľajte o zneužívaní Verejné počítadlo je možné manipulovať. Ak má metrika obchodnú hodnotu, pridajte:
- obmedzenie rýchlosti (na úrovni reverznej proxy/WAF)
- úložisko na používateľa (prihláseného) alebo podpísaný súbor cookie
- detekcia botov
výkon
- Podmienený dopyt: vyhnúť sa načítaniu
like.jsvšade. - Vyhnite sa zbytočným REST požiadavkám: môžete pridať debounce, ak povolíte viacnásobné kliknutia (tu prepíname, aby bola stabilita).
- Vysoká návštevnosť: post meta + neatomická aktualizácia. Ak máte nárasty, prejdite na vlastnú tabuľku a atomickú aktualizáciu SQL (alebo odloženú agregáciu).
údržba
- Uchovávajte obchod v prehľadnom mennom priestore (
bpcab/like), vyhýbajte sa generickým názvom (app). - Vyhnite sa prepojeniu logiky s nástrojom na tvorbu kódu. V prípade potreby vytvorte integračnú vrstvu (widget/modul).
- Monitorujte vývoj Interactivity API prostredníctvom Gutenbergu (PR) a príručky. Zmeny sa najskôr objavia na strane Gutenbergu a potom sa zlúčia do jadra.
zdroje
- Interaktívne API (developer.wordpress.org)
- Príručka REST API
- register_rest_route() (referencia)
- wp_create_nonce() (odkaz)
- wp_verify_nonce() (referencia)
- WordPress Core Trac (sledovanie chýb)
- Gutenbergov repozitár (PR Interactivity)
- filter_var() (php.net)
- Fóra podpory WordPress.org (prípady zo skutočného života)
Často kladené otázky
Nahrádza Interactivity API React v Gutenbergu?
Nie. Gutenberg stále používa React ako editor. Interactivity API je primárne zamerané na interaktivitu blokov/komponentov na strane front-endu s ľahším a deklaratívnejším modelom.
Prečo môj window.wp.interactivity je nedefinované?
V praxi ide buď o problém s radením (skript sa načíta príliš skoro/vôbec sa nenačíta), optimalizáciu JavaScriptu, ktorá naruší poradie, alebo nástroj na tvorbu obsahu bez spustenia vašich podmienok. Dočasne vypnite agresívne operácie minifikácie/odloženia a skontrolujte nastavenia siete.
Je to kompatibilné s celostránkovou vyrovnávacou pamäťou?
Áno, pre zobrazenie. Pre perzistenciu buďte opatrní s nonce: ak je HTML stránka zobrazená z vyrovnávacej pamäte a obsahuje expirovaný nonce, vaše požiadavky REST POST zlyhajú (403). Na stránkach s vysokou cache uprednostňujem generovanie nonce prostredníctvom verejného koncového bodu (iba na čítanie) alebo obmedzenie funkčnosti na prihlásených používateľov.
Prečo používať REST namiesto admin-ajax?
REST poskytuje čistejšiu sémantiku HTTP, štandardné odpovede JSON a lepšie sa integruje s modernými nástrojmi. admin-ajax zostáva platný, ale rýchlo sa stáva univerzálnym nástrojom, ktorý je ťažké zabezpečiť a profilovať.
Môžeme použiť Gutenbergov blok namiesto shortcode?
Áno, a to je často výhodnejšie. Jadro vzoru zostáva rovnaké: vykresľovanie SSR + atribúty data-wp-* + obchod. Používam tu shortcode, takže si ho môžete otestovať za 5 minút, a to aj v builderoch.
Ako spravovať niekoľko rôznych počítadiel (lajky, záložky, hlasy)?
Použite samostatné menné priestory (bpcab/like, bpcab/bookmark) alebo jeden úložný priestor konfigurovaný kontextom. Vyhnite sa „monolitickej“ položke, ak sú vaše komponenty nezávislé.
Je počítadlo v post-meta spoľahlivé?
Pre typický blog: áno. Pre vysokú návštevnosť: nie, budete mať kolízie. Prepnite na vlastnú tabuľku a atomické aktualizácie alebo použite stratégiu asynchrónnej agregácie.
Ako môžem tento kód správne otestovať?
Zvyčajne robím:
- Staging + protokol WP_DEBUG
- Manuálny test: rýchle kliknutia, navigácia, vyrovnávacia pamäť prehliadača
- REST test: curl (očakáva sa 403 bez nonce, 200 s nonce)
- Test kompatibility vyrovnávacej pamäte: povolenie vyrovnávacej pamäte, kontrola expirácie nonce
Prečo nedosadiť nuncia? data-wp-context ?
Môžete, ale v každom prípade budete duplikovať citlivú hodnotu. Uprednostňujem minimálny globálny objekt a potom kontext pre každý komponent pre stav používateľského rozhrania. Ak máte veľmi dlhé stránky, zmenší sa tým veľkosť HTML.
Funguje to v klasickej (nie FSE) téme?
Áno. Interactivity API nie je obmedzené len na blokové témy. Kľúčom je správne načítať prvky a vykresliť značky s atribútmi. data-wp-*.
Čo mám robiť, ak plugin pre úryvky kódu poškodí kód?
Vyhnite sa vkladaniu tohto pluginu do úryvku kódu. Vytvorte si vhodný plugin (ako je tento). Úryvky kódu sú pohodlné, ale videl som príliš veľa stránok, ktoré zlyhali kvôli úryvku kódu aktivovanému v inej verzii PHP alebo kvôli úlohe kopírovania a vkladania s chýbajúcou zloženou zátvorkou.