আপনি যদি কখনও কোনো পৃষ্ঠায় “শুধু একটি ছোট বোতাম” যোগ করে থাকেন ওয়ার্ডপ্রেসএরপরে, ২০০ কিলোবাইট জাভাস্ক্রিপ্ট, একটি ফ্রেমওয়ার্কের উপর নির্ভরতা এবং এমন একটি ক্যাশ যা কখনও খালি হয় না—এই সবকিছু মিলিয়ে আপনি আসল সমস্যাটির সম্মুখীন হন: ক্লায়েন্ট-সাইড ইন্টারঅ্যাক্টিভিটি দ্রুতই জটিলতা বাড়িয়ে তোলে।
বেশ কয়েকটি সংস্করণ ধরে ওয়ার্ডপ্রেস একটি আরও "কোর-ফ্রেন্ডলি" পদ্ধতি দিয়ে আসছে: ইন্টারঅ্যাকটিভিটি এপিআই। ধারণাটি কাগজে-কলমে সহজ: আপনার মার্কআপে সরাসরি ক্লায়েন্ট-সাইড আচরণগুলো ঘোষণা করা (এর মাধ্যমে data-wp-*), ওয়ার্ডপ্রেস দ্বারা পরিচালিত একটি রেসপন্সিভ স্টোরের সাথে, আপনার থিমে React/Vue/Svelte ছাড়াই।
সমস্যাটি / প্রয়োজন
নির্দিষ্ট প্রয়োজন: একটি ফ্রন্ট-এন্ড কম্পোনেন্ট তৈরি করা (যেমন, “লাইক”, “কাউন্টার”, “ফিল্টার”, “অ্যাকর্ডিয়ন”, “ক্লিপবোর্ডে কপি”, “বোঝাই কোনো ফ্রেমওয়ার্ক এমবেড না করেই ইন্টারেক্টিভ ("প্রগতিশীল") এবং একই সাথে ওয়ার্ডপ্রেস ইকোসিস্টেমের (ক্যাশ, থিম, ব্লক থিম, পেজ বিল্ডার, নিরাপত্তা) সাথে সামঞ্জস্যপূর্ণ।
অবশেষে, আপনি জানতে পারবেন:
- একটি ছোট প্লাগইন তৈরি করুন যা ইন্টারঅ্যাকটিভিটি এপিআই ব্যবহার করে একটি ব্লক (অথবা সর্বত্র ব্যবহারযোগ্য একটি এইচটিএমএল রেন্ডারিং) প্রকাশ করে।
- কোনো বাহ্যিক নির্ভরতা ছাড়াই ক্লায়েন্ট-সাইড স্টেট (স্টোর) এবং অ্যাকশন (হ্যান্ডলার) পরিচালনা করুন।
- একটি এন্ডপয়েন্ট যোগ করুন AJAX এরস্টেট (যেমন, কাউন্টার) ধরে রাখার জন্য REST সুরক্ষিত।
- বাস্তব ক্ষেত্রে ডিবাগিং: ত্রুটিপূর্ণ এনকিউ, অতিরিক্ত ক্যাশিং, ভুলভাবে নির্বাচিত হুক, বিল্ডার কনফ্লিক্ট।
দ্রুত সারসংক্ষেপ
- আমরা ইন্টারঅ্যাকটিভিটি এপিআই (Interactivity API) ব্যবহার করে একটি “লাইক বাটন” প্লাগইন (কাউন্টার + টগল) কোড করেছি, যা ওয়ার্ডপ্রেস ৬.৯.৪+ এবং পিএইচপি ৮.১+ এর সাথে সামঞ্জস্যপূর্ণ।
- মার্কআপ ব্যবহার করে
data-wp-interactive,data-wp-on--click,data-wp-text,data-wp-class--*. - JS স্টোরটি লোকাল স্টেট (অপটিমিস্টিক UI) পরিচালনা করে, তারপর REST API-এর মাধ্যমে সিঙ্ক্রোনাইজ করে।
- PHP-এর দিকে: REST এন্ডপয়েন্ট
/wp-json/bpcab/v1/likeREST ননস, অনুমতি, স্যানিটাইজেশন/এসকেপিং। - আমরা একটি শর্টকোড সংস্করণ ও ডিভি ৫ ইন্টিগ্রেশন প্রদান করি। Elementor আভাদা।
কখন এই সমাধানটি ব্যবহার করবেন
- আপনি রিয়্যাক্ট বান্ডেল ছাড়াই হালকা ইন্টারঅ্যাক্টিভিটি (টগল, কাউন্টার, UI স্টেট) চান।
- আপনি বিভিন্ন সাইটের (বিল্ডার, ক্যাশে, সিডিএন) জন্য একটি থিম বা প্লাগইন সরবরাহ করেন এবং আপনি জেএস কনফ্লিক্টের ঝুঁকি কমাতে চান।
- আপনার এমন একটি SSR রেন্ডারিং (PHP দ্বারা তৈরি HTML) প্রয়োজন, যা JS ছাড়াই ব্যবহারযোগ্য থাকে এবং পরে JS-এর সাথে "উন্নত" হয় (প্রগতিশীল বর্ধন)।
- আপনি ওয়ার্ডপ্রেসের নিয়মকানুন (এনকিউ, রেস্ট, ননস) মেনে চলতে চাইবেন এবং এক কোণে একটি “মিনি-এসপিএ” তৈরি করা এড়াতে চাইবেন।
কখন এই সমাধানটি ব্যবহার করা উচিত নয়
- আপনি রাউটিং, জটিল ফর্ম এবং ব্যাপক গ্লোবাল রিপোর্টিং সহ একটি সমৃদ্ধ সিঙ্গেল-পেজ অ্যাপ্লিকেশন (SPA) তৈরি করছেন। এর জন্য একটি ফ্রেমওয়ার্ক (অথবা অন্তত একটি আরও শক্তিশালী আর্কিটেকচার) বেশি উপযুক্ত হবে।
- আপনাকে খুব পুরোনো ব্রাউজারগুলো সমর্থন করতে হবে (ইন্টারঅ্যাকটিভিটি এপিআই আধুনিক মান অনুসরণ করে; আপনার সীমাবদ্ধতাগুলো যাচাই করে নিন)।
- আপনার ইন্টারঅ্যাক্টিভিটি ইতিমধ্যেই একটি প্লাগইনের মাধ্যমে সঠিকভাবে প্রদান করা হয়েছে (যেমন, WooCommerce ব্লক, ডেডিকেটেড ফেসেট)। নতুন করে চাকা আবিষ্কার করা এবং তার রক্ষণাবেক্ষণ ব্যয়বহুল।
- আপনার একটি রিয়েল-টাইম প্রয়োজন (ওয়েবসকেট, উপস্থিতি, সহযোগিতা)। ইন্টারঅ্যাকটিভিটি এপিআই কোনো রিয়েল-টাইম লেয়ারের বিকল্প নয়।
শুরু করার আগে পূর্বশর্তসমূহ /
- ন্যূনতম ওয়ার্ডপ্রেস ৬.৯.৪ (এপ্রিল ২০২৬), পিএইচপি ৮.১+।
- একটি পরীক্ষামূলক পরিবেশ (লোকাল বা স্টেজিং)। এই ধরনের কোড সরাসরি প্রোডাকশনে পরীক্ষা করা থেকে বিরত থাকুন: আমি দেখেছি, দুর্বলভাবে সুরক্ষিত একটি REST এন্ডপয়েন্ট কয়েক মিনিটের মধ্যেই মারাত্মকভাবে ক্ষতিগ্রস্ত হয়েছে।
- REST API পরীক্ষা করতে এবং প্রয়োজনে পুনরায় তৈরি করতে পারমালিঙ্ক (সেটিংস)-এ প্রবেশাধিকার।
- দরকারী সরঞ্জাম:
- হুক/রেস্ট/পারফরম্যান্স নিরীক্ষণের জন্য কোয়েরি মনিটর।
- ডেভটুলস ব্রাউজার (নেটওয়ার্ক + কনসোল)।
হাতের কাছে রাখার জন্য সরকারি সূত্র:
- ইন্টারঅ্যাক্টিভিটি এপিআই (ব্লক এডিটর হ্যান্ডবুক)
- REST API হ্যান্ডবুক
- register_rest_route()
- wp_enqueue_script ()
- পিএইচপি ফিল্টার/ভ্যালিডেশন (পিএইচপি.নেট)
মূল পর্যবেক্ষণের জন্য: যখন আপনি কোনো অস্বাভাবিক আচরণের সম্মুখীন হন (বিশেষ করে ক্যাশে বা এডিটরের সাথে কাজ করার সময়), তখন টিকেটগুলো দেখুন। core.trac.wordpress.org এবং জনসংযোগের উপর github.com/WordPress/gutenberg.
সরল পন্থা (এবং কেন তা পরিহার করা উচিত)
যে সংস্করণটি আমি এখনও প্রায়শই দেখি: একটি বোতাম যার সাথে একটি onclick ইনলাইন, একটি fetch Vers admin-ajax.phpকোনো ননস নেই, এবং সাইটের সর্বত্র একটি স্ক্রিপ্ট লোড করা আছে।
<?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>
নেপথ্যে যা ঘটছে:
- নিরাপত্তা: ননস (nonce) ছাড়া এন্ডপয়েন্ট = সামান্য CSRF। এবং যদি আপনি যাচাই না করেন
post_idতুমি যথেচ্ছ লেখার দরজা খুলে দাও। - পারফরম্যান্স: স্ক্রিপ্ট সর্বত্র প্রবেশ করানো হয়, সূক্ষ্মভাবে নিয়ন্ত্রণ করা অসম্ভব এবং সঠিকভাবে ক্যাশ করা কঠিন।
- রক্ষণাবেক্ষণ: যেদিন আপনাকে কম্পোনেন্টটিকে অ্যাক্সেসিবল (ARIA), টেস্টেবল বা বিল্ডার কম্প্যাটিবল করতে হবে, সেদিন আপনাকে একেবারে গোড়া থেকে শুরু করতে হবে।
- DX: দুটি কম্পোনেন্ট ভ্যারিয়েন্ট থাকলেই ইনলাইন হ্যান্ডলারগুলো নিয়ন্ত্রণ করা কঠিন হয়ে পড়ে।
সঠিক পদ্ধতি — ধাপে ধাপে নির্দেশিকা
আমরা একটি কার্যকরী 'লাইক' কম্পোনেন্ট সহ একটি ন্যূনতম ও পরিচ্ছন্ন প্লাগইন তৈরি করতে যাচ্ছি:
- JS ছাড়া: বাটনটি প্রদর্শিত হয় (এবং আপনি একটি ফলব্যাক বেছে নিতে পারেন)।
- JS-এর মাধ্যমে: তাৎক্ষণিক টগল ও আপডেট হওয়া কাউন্টার, তারপর REST সিঙ্ক্রোনাইজেশন।
ধাপ ১ — প্লাগইনটি তৈরি করুন
একটি ফোল্ডার তৈরি করুন wp-content/plugins/bpcab-interactivity-like/ সঙ্গে
bpcab-interactivity-like.phpassets/like.js
ধাপ ২ — “ইন্টারেক্টিভ” এইচটিএমএল রেন্ডারিং সংজ্ঞায়িত করুন
ইন্টারঅ্যাক্টিভিটি এপিআই অ্যাট্রিবিউটের উপর নির্ভর করে। data-wp-* মার্কআপে। সবচেয়ে গুরুত্বপূর্ণ বিষয় হলো: data-wp-interactive যা একটি স্টোর নেমস্পেসকে একটি DOM সাবট্রি-র সাথে “সংযুক্ত” করে।
আমরা একটি বাটন এবং একটি কাউন্টার তৈরি করব। বাটনটি হলো:
- এর মাধ্যমে একটি ক্রিয়া শুরু করে
data-wp-on--click - এর মাধ্যমে গতিশীল পাঠ্য প্রদর্শন করে
data-wp-text - CSS ক্লাস টগল করুন
data-wp-class--is-liked
ধাপ ৩ — স্ক্রিপ্টটি সঠিকভাবে লোড করুন (টার্গেটেড এনকিউ)
একটি চিরাচরিত ভুল হলো: প্রতিটি পেজে JS লোড করা। এখানে, আমরা স্ক্রিপ্টটি কেবল তখনই লোড করি যখন কন্টেন্টে আমাদের শর্টকোড থাকে (অথবা যখন আমাদের ব্লকটি রেন্ডার করা হয়)। বিষয়টিকে সহজ এবং নির্ভরযোগ্য রাখতে, আমরা যা করব তা হলো:
- একটি শর্টকোড প্রদান করুন
[bpcab_like] - এর উপস্থিতি সনাক্ত করুন
has_shortcode()উপযুক্ত মুহূর্তে
দ্রষ্টব্য: যেসব সাইটে প্রচুর বিল্ট-ইন টুল (যেমন এলিমেন্টর/ডিভি) ব্যবহৃত হয়, সেখানে কন্টেন্ট ভিন্নভাবে তৈরি হতে পারে। নিচে আমি এর কিছু ভিন্নতা তুলে ধরব।
ধাপ ৪ — একটি সুরক্ষিত REST এন্ডপয়েন্ট উন্মুক্ত করুন
আমরা এড়িয়ে চলি admin-ajax.php এই ক্ষেত্রে, REST API আরও পরিচ্ছন্ন, ক্যাশ-বান্ধব এবং উন্নততর সরঞ্জামযুক্ত (HTTP কোড, JSON, প্রমাণীকরণ)। আমরা একটি রাউট তৈরি করি:
POST /wp-json/bpcab/v1/likeসঙ্গেpost_idetdelta(+১ অথবা -১)
আমরা সুরক্ষা দিই:
- বিশ্রাম ননস (
wp_create_nonce( 'wp_rest' )) - প্যারামিটারগুলির কঠোর যাচাইকরণ
- অনুমতি: এখানে, বেনামী দর্শকদের অনুমতি দেওয়া হয়, কিন্তু এর প্রভাব সীমিত (ডেল্টা ±১, বিদ্যমান পোস্ট, পাবলিক টাইপ)। সত্যিকারের 'ব্যবহারকারী-ভিত্তিক' স্থায়িত্বের জন্য একটি পরিচয় মডেলের প্রয়োজন হবে (ইউজার আইডি, স্বাক্ষরিত কুকি, অথবা আরও কঠোর সার্ভার স্টোরেজ)।
ধাপ ৫ — স্টোরের ইন্টারঅ্যাক্টিভিটি (অপটিমিস্টিক UI + রোলব্যাক)
যে ধরণটি আমি প্রায়শই ব্যবহার করি:
- আমরা অবিলম্বে UI আপডেট করব (আশাবাদী)।
- আমরা REST অনুরোধ পাঠাই
- যদি সেটি ব্যর্থ হয়, আমরা অবস্থাটি পূর্বাবস্থায় ফিরিয়ে আনি এবং যথাযথভাবে লগ করি।
সম্পূর্ণ কোড
ফাইল ১: পিএইচপি প্লাগইন
তৈরি করুন 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();
}
);
ফাইল ২: ইন্টারঅ্যাক্টিভিটি স্ক্রিপ্ট
তৈরি করুন 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);
}
}
}
});
})();
কোডের ব্যাখ্যা
সাধারণ (সরল) যুক্তি
PHP একটি 'সাধারণ' HTML ফাইল (একটি বাটন ও একটি কাউন্টার) রেন্ডার করে এবং নিম্নলিখিত বিষয়গুলো যোগ করে:
data-wp-interactive="bpcab/like"ওয়ার্ডপ্রেসকে জানাতে: “এই সাবট্রিটি bpcab/like স্টোর ব্যবহার করে”।data-wp-context="...json..."প্রাথমিক অবস্থা (postId, likes, liked, labels) ইনজেক্ট করতে।data-wp-on--click="actions.toggle"ক্লিকটিকে একটি JS অ্যাকশনের সাথে সংযুক্ত করতে।data-wp-text="..."অবস্থা থেকে গণনা করা একটি মান প্রদর্শন করতে।
JS একটি “bpcab/like” স্টোর সংরক্ষণ করে। যখন ব্যবহারকারী ক্লিক করেন, তখন কনটেক্সটটি পরিবর্তিত হয় (রিঅ্যাক্টিভ), এবং এরপর কাউন্টারটি স্থায়ীভাবে সংরক্ষণের জন্য REST API কল করা হয়।
প্রযুক্তিগত বিবরণ (হুক, নিরাপত্তা, WP 6.9.4 ইন্টিগ্রেশন)
add_shortcode()একটি পোর্টেবল উদাহরণের জন্য এটি কার্যকরী। প্রোডাকশনে, এডিটরের মধ্যে আরও সূক্ষ্ম নিয়ন্ত্রণের জন্য আপনি প্রায়শই একটি ডাইনামিক ব্লক (render_callback) ব্যবহার করবেন।wp_enqueue_scriptsআমরা সম্মুখ থেকে তদন্ত করছি। সংবেদনশীল বিষয়টি হলো উপস্থিতি শনাক্তকরণ। যদি আপনার বিল্ডার শর্টকোডটি না দেয়post_contentস্ক্রিপ্টটি লোড হবে না।আমি নিচে বিভিন্ন প্রকারভেদগুলো আলোচনা করেছি।- বিশ্রাম এপিআই :
register_rest_route()রাস্তাটি উন্মুক্ত করে।permission_callbackননসটি পরীক্ষা করুনX-WP-Nonce(সিএসআরএফ)।- কঠোর বৈধতা
delta±১ এর মধ্যে। তা না হলে, আপনি দেখবেন লোকেরা পোস্ট করছেdelta=999999এন্ডপয়েন্টটি পাবলিক হওয়ার সাথে সাথেই
- রেসের শর্ত একটি পোস্ট-মেটা কাউন্টার অ্যাটমিক নয়। বেশি ট্র্যাফিকের সময়, একই সাথে দুটি কোয়েরি একটি ভ্যালুকে ওভাররাইট করে দিতে পারে। একটি সাধারণ ব্লগের জন্য এটি গ্রহণযোগ্য; কিন্তু বেশি লেনদেনকারী মিডিয়া আউটলেটের জন্য আমি একটি কাস্টম টেবিল এবং অ্যাটমিক কোয়েরি (অথবা একটি বাফার/কিউ) ব্যবহার করি।
Pourquoi data-wp-context বরং wp_localize_script উদাহরণস্বরূপ
wp_localize_script এটি গ্লোবাল (হ্যান্ডেলের মাধ্যমে), যা একই পেজে ১০টি কম্পোনেন্ট থাকলে অসুবিধাজনক হয়ে ওঠে। এখানে, প্রতিটি ইনস্ট্যান্স তার নিজস্ব JSON বহন করে। যখন আপনার আর্টিকেলের একটি লুপ থাকে (যেমন, ২০টি 'লাইক' সহ একটি ক্যাটাগরি পেজ), তখন এটি অনেক বেশি স্কেলেবল।
বিভিন্ন রূপ এবং ব্যবহারের ক্ষেত্র
পদ্ধতি ১ — জটিল গ্লোবাল JS ছাড়াই একটি পৃষ্ঠায় একাধিক বাটন (লুপ)
আপনি রাখতে পারেন [bpcab_like post_id="123"] একটি লুপের মধ্যে, অথবা PHP-এর মাধ্যমে HTML তৈরি করুন। প্রতিটি উপাদানের নিজস্ব data-wp-contextস্টোরটি শেয়ার করা হলেও, কনটেক্সটটি প্রতিটি ইনস্ট্যান্সের জন্য আলাদা: ঠিক এটাই মূল বিষয়।
বিকল্প ২ — সাধারণ কাউন্টারের পরিবর্তে প্রতিটি (লগ-ইন করা) ব্যবহারকারীর জন্য “লাইক” সংরক্ষণ করুন।
আমি যে প্যাটার্নটি ব্যবহার করি:
- যদি ব্যবহারকারী লগ ইন করা থাকেন, তাহলে ব্যবহারকারীর মেটাতে পছন্দ করা পোস্টগুলির একটি তালিকা (বা রিলেশনাল টেবিল) সংরক্ষণ করুন।
- REST এন্ডপয়েন্ট চেকগুলি
is_user_logged_in()এবং ব্যবহারget_current_user_id(). - সামগ্রিক কাউন্টারটি পোস্ট মেটা (বা টেবিলে) থেকে যায়, কিন্তু “লাইকড” অবস্থাটি নির্ভরযোগ্য হয়ে ওঠে।
সতর্কীকরণ: ইউজার মেটা-তে থাকা তালিকাটি বড় হতে পারে। বড় সাইটগুলির জন্য, একটি ডেডিকেটেড রিলেশনাল টেবিল (user_id, post_id, created_at) ও ইনডেক্স ব্যবহার করার পরামর্শ দেওয়া হয়।
ভ্যারিয়েন্ট ৩ — অ্যাকর্ডিয়ন/ট্যাবের জন্য “অস্থায়ী” মোড (শুধুমাত্র UI)
আপনার প্রয়োজন যদি শুধুমাত্র UI (অ্যাকর্ডিয়ন, ট্যাব) হয়, তাহলে REST এন্ডপয়েন্টটি সরিয়ে দিন এবং শুধু নিম্নলিখিতগুলি রাখুন:
data-wp-on--clickকনটেক্সটে একটি বুলিয়ান পরিবর্তন করতেdata-wp-class--is-open/data-wp-textঅবস্থা প্রতিফলিত করতে
আমার অভিজ্ঞতায়, এটাই সেরা সূচনা বিন্দু: কোনো ব্যাকএন্ড নেই, কোনো নিরাপত্তা নেই, এবং আপনি আপনার এনকিউ/ক্যাশ সামঞ্জস্যতা পাইপলাইন যাচাই করে নিতে পারেন।
Divi 5 / Elementor / Avada-এর সাথে সামঞ্জস্যপূর্ণ
যে পয়েন্টটি সবচেয়ে বেশি ভাঙে: স্ক্রিপ্টটি লোড হতে ব্যর্থ হয় কারণ আপনার চূড়ান্ত কন্টেন্টে শর্টকোডটি নেই post_content.
দিভি ৫
ডিভি মেটা ট্যাগে লেআউট সংরক্ষণ করতে পারে, এবং চূড়ান্ত রেন্ডারিং সবসময় এর মাধ্যমে শনাক্ত করা যায় না। has_shortcode( $post->post_content )দুটি শক্তিশালী বিকল্প:
- "বৃহৎ" কোয়েরি শুধুমাত্র সেইসব পেজেই ব্যবহার করুন যেখানে মডিউলটি উপস্থিত আছে বলে আপনি জানেন (যেমন, শর্তসাপেক্ষ টেমপ্লেটের মাধ্যমে)।
- অথবা রেন্ডারিংয়ের সময় রেন্ডার করা মার্কআপের (বাফার) উপস্থিতি শনাক্ত করা — যা আরও ভঙ্গুর।
একটি বাস্তবসম্মত পদ্ধতি যা আমি প্রায়শই ব্যবহার করি: ফিল্টারের মাধ্যমে একটি ছোট “ফোর্স এনকিউ” সেটিং যোগ করা।
<?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 );
তারপর মানিয়ে নিন maybe_enqueue_assets() এই ফিল্টারটি প্রয়োগ করতে (যদি আপনি এই সংস্করণটি চান, তবে তা সঠিকভাবে করুন)। প্লাগইনটিকে সংক্ষিপ্ত রাখার জন্য আমি এটি ডিফল্টভাবে অন্তর্ভুক্ত করিনি।
Elementor
এলিমেন্টরে প্রায়শই মেটা ট্যাগ থেকে কন্টেন্ট রেন্ডার করা হয়। দুটি পরিচ্ছন্ন সমাধান:
- একটি ডেডিকেটেড এলিমেন্টর উইজেট তৈরি করুন যা মার্কআপ রেন্ডার করবে (এবং এলিমেন্টর এপিআই-এর মাধ্যমে একটি স্ক্রিপ্ট ডিপেন্ডেন্সি রেজিস্টার করবে)।
- অথবা একটি শর্তের মাধ্যমে এলিমেন্টর পেজগুলিতে অনুসন্ধান করুন (প্লাগইন সনাক্তকরণ + মেটা)।
আপনি যদি সহজ সনাক্তকরণ বেছে নেন:
<?php
// Exemple : détecter une page construite avec Elementor.
$is_elementor = (bool) get_post_meta( get_the_ID(), '_elementor_edit_mode', true );
আভাদা (ফিউশন বিল্ডার)
Avada-র নিজস্ব শর্টকোড এবং রেন্ডারিং পাইপলাইন রয়েছে। সবচেয়ে নির্ভরযোগ্য উপায় হলো শর্টকোড ব্যবহার করা। [bpcab_like] সরাসরি একটি “কোড” বা “শর্টকোড” ব্লক/এলিমেন্টের মধ্যে।
যদি Avada অতিরিক্ত পরিমাণে মিনিফাই বা কনক্যাটিনেট করে, তবে যাচাই করুন যে:
- স্ক্রিপ্টটি সরানো হয়নি
headব্যতীতdefer - অপ্টিমাইজেশনের মাধ্যমে ইন্টারঅ্যাক্টিভিটি রানটাইম "অপসারণ" করা হয় না।
ইনস্টলেশন-পরবর্তী পরীক্ষা
- একটি পৃষ্ঠায় যা ধারণ করে
[bpcab_like]ডেভটুলস খুলুন > নেটওয়ার্ক:- যাচাই করুন যে
assets/like.jsসম্পূর্ণ চার্জ হয়েছে (স্ট্যাটাস ২০০) - যাচাই করুন যে
POST /wp-json/bpcab/v1/likeক্লিক করলে ২০০ ফেরত দেয়
- যাচাই করুন যে
- ডেভটুলস > কনসোল:
- কোন ত্রুটি নেই
window.wp.interactivityঅনির্দিষ্ট
- কোন ত্রুটি নেই
- ওয়ার্ডপ্রেসের দিক থেকে:
- মেটা
_bpcab_likesএটি স্বয়ংক্রিয়ভাবে আপডেট হয় (আপনি WP-CLI বা একটি মেটা প্লাগইনের মাধ্যমে তা পরীক্ষা করতে পারেন)।
- মেটা
দ্রুত রোগ নির্ণয় চার্ট
| লক্ষণ | সম্ভাব্য কারণ | প্রতিপাদন | সমাধান |
|---|---|---|---|
| বাটনটি দেখা যায় কিন্তু কাজ করে না। | রানটাইম ইন্টারঅ্যাক্টিভিটি লোড হয়নি অথবা JS লোড হয়নি | কনসোল: window.wp.interactivity এর কি অস্তিত্ব আছে? নেটওয়ার্ক: like.js চার্জ? |
সংশোধন করতে এনকিউ, জেএস অপ্টিমাইজেশন নিষ্ক্রিয় করুন, বিল্ডার পরীক্ষা করুন |
| REST রুটে ত্রুটি ৪০৩ | অনুপস্থিত/অবৈধ ননস | নেটওয়ার্ক: হেডার X-WP-Nonce এখানে? |
চেক wp_add_inline_scriptএইচটিএমএল ক্যাশে, সিডিএন যা হেডার বাদ দেয় |
| কাউন্টারটি পিছনের দিকে "লাফিয়ে" যায়। | REST ত্রুটির পরে রোলব্যাক | কনসোল: লগ [bpcab/like] Échec synchronisation |
REST URL, পারমালিঙ্ক, WAF, CORS এবং নিরাপত্তা প্লাগইনগুলো যাচাই করুন। |
| লোডের অধীনে মিটারটি অসামঞ্জস্যপূর্ণ আচরণ করে। | পোস্ট মেটা-তে রেস কন্ডিশন | একই সাথে ক্লিক (k6/ab) অনুকরণ করুন এবং তুলনা করুন | কাস্টম টেবিল + অ্যাটমিক আপডেট, অথবা অ্যাসিঙ্ক্রোনাস অ্যাগ্রিগেশন |
যদি সেটা কাজ না করে
- আপনি কোডটি কোথায় পেস্ট করেছেন তা পরীক্ষা করুন। এই প্লাগইনটি অবশ্যই থাকতে হবে
wp-content/plugins/...এবং সক্রিয় করা হয়েছে। আমি ইতিমধ্যেই থিমে পিএইচপি ফাইলটি পেস্ট করা দেখেছি, তারপর "এটি একটি পৃষ্ঠায় কাজ করে এবং অন্যটিতে করে না"। - পিএইচপি পরীক্ষা করুন PHP 8.1-এর পূর্ববর্তী সংস্করণগুলিতে আপনি টাইপ এররের সম্মুখীন হতে পারেন। দেখুন
wp-content/debug.logsiWP_DEBUGসক্রিয় করা হয়েছে। - স্থায়ী লিঙ্কগুলি পরীক্ষা করুন যদি REST API একটি 404 ত্রুটি দেখায়, তাহলে সেটিংস > পারমালিঙ্কস-এ যান এবং (কোনো কিছু পরিবর্তন না করে) সংরক্ষণ করুন। মাইগ্রেশনের সময় এটি একটি সাধারণ সমস্যা।
- সাময়িকভাবে JS অপ্টিমাইজেশন নিষ্ক্রিয় করুন (ক্যাশ/মিনিফাই): আমি প্রায়শই দেখেছি যে, কোনো কনক্যাটেনেশনের কারণে লোডিং অর্ডার বদলে যাওয়ায় রানটাইম ইন্টারঅ্যাক্টিভিটি "ভেঙে" যায়।
- curl দিয়ে REST এন্ডপয়েন্টটি পরীক্ষা করুন :
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}'
আপনার কাছে যদি ননস (nonce) না থাকে, তাহলে অন্তত রুটটি বিদ্যমান কিনা তা পরীক্ষা করুন (এটির 403 “Nonce missing” রিটার্ন করা উচিত, যা একটি ভালো লক্ষণ)।
সাধারণ ফাঁদ এবং ভুলগুলি
| এরর | কারণ | সমাধান |
|---|---|---|
Uncaught TypeError: Cannot destructure property 'store' ... |
window.wp.interactivity অনুপস্থিত (রানটাইম লোড হয়নি) |
এনকিউ (enqueue) পরীক্ষা করুন, মিনিফাই (minify) নিষ্ক্রিয় করুন, এবং নিশ্চিত করুন যে WP ইন্টারঅ্যাকটিভিটি স্ক্রিপ্টগুলো লোড করছে। |
| স্ক্রিপ্টটি কখনোই লোড হয় না। | has_shortcode() সনাক্ত করা যায় না (বিল্ডার, মেটার মাধ্যমে রেন্ডার করা) |
একটি কন্ডিশন বিল্ডার (এলিমেন্টর/ডিভি/আভাডা) যোগ করুন অথবা একটি ডেডিকেটেড উইজেট/মডিউলের মাধ্যমে এনকিউ করুন। |
403 Nonce invalide |
মেয়াদোত্তীর্ণ ননস দিয়ে ক্যাশ করা এইচটিএমএল, অথবা সম্পূর্ণ-পৃষ্ঠা ক্যাশের মাধ্যমে পরিবেশিত পৃষ্ঠা। | পৃষ্ঠাটিকে ক্যাশে থেকে বাদ দিন, অথবা একটি পাবলিক এন্ডপয়েন্টের মাধ্যমে ননস (nonce) তৈরি করুন, অথবা এটিকে শুধুমাত্র লগ-ইন করা ব্যবহারকারীদের জন্য সীমাবদ্ধ করুন। |
SyntaxError: Unexpected token মধ্যে data-wp-context |
JSON ভুলভাবে এনকোড/এস্কেপ করা হয়েছে, উদ্ধৃতি চিহ্ন ভাঙা | সর্বদা মধ্য দিয়ে যান wp_json_encode তারপর esc_attr |
| কপি-পেস্ট করার পর মারাত্মক ত্রুটি | বন্ধনী/সেমিকোলন অনুপস্থিত, অথবা ফাইলটি ভুল ফোল্ডারে রাখা হয়েছে। | লিন্টার দিয়ে যাচাই করুন, স্টেজিং-এ WP_DEBUG চালু করুন, সিনট্যাক্স সংশোধন করুন। |
| কাউন্টারটি ঋণাত্মক হয়ে যায়। | ডেল্টা যাচাই করা হয়নি অথবা দ্রুত ডাবল-ক্লিক | সত্যতা সমর্থন করা delta ±১, সার্ভার এবং ক্লায়েন্ট উভয় দিকে ০-তে ক্ল্যাম্প। |
| একটি নিরাপত্তা/WAF প্লাগইনের সাথে দ্বন্দ্ব | REST POST অনুরোধ বা হেডার ব্লক করা | রুটটি হোয়াইটলিস্ট করুন /wp-json/bpcab/v1/likeWAF লগ চেক করুন |
| আপনি ২০২৩ সালের একটি পুরোনো স্নিপেট ব্যবহার করছেন। | এপিআই/হ্যান্ডেল পরিবর্তিত হয়েছে, প্রচলিত পদ্ধতি সেকেলে হয়ে গেছে | বর্তমান ইন্টারঅ্যাক্টিভিটি ডকুমেন্টেশনের উপর ভিত্তি করে WP 6.9.4+ কে লক্ষ্য করে তৈরি। |
নিরাপত্তা, কর্মক্ষমতা এবং রক্ষণাবেক্ষণের পরামর্শ
নিরাপত্তা
- REST ননস প্রয়োজন আপনার এন্ডপয়েন্ট যদি ননস (nonce) ছাড়া ডেটা পরিবর্তন করে, তাহলে তা সিএসআরএফ (CSRF)।
- সেটিংস নিশ্চিত করুন এখানে
deltaএর সীমা কঠোরভাবে ±১। এটি একটি সরল কিন্তু কার্যকর প্রতিবন্ধকতা। - নির্যাতনের কথা ভাবুন একটি পাবলিক কাউন্টারকে ম্যানিপুলেট করা যেতে পারে। যদি মেট্রিকটির কোনো ব্যবসায়িক মূল্য থাকে, তাহলে যোগ করুন:
- রেট লিমিটিং (রিভার্স প্রক্সি/WAF পর্যায়ে)
- প্রতি ব্যবহারকারীর (লগ ইন করা) বা স্বাক্ষরিত কুকির জন্য স্টোরেজ
- বট সনাক্তকরণ
সম্পাদন
- শর্তসাপেক্ষ জরিপ: লোডিং এড়িয়ে চলুন
like.jsসর্বত্র। - অপ্রয়োজনীয় REST অনুরোধ পরিহার করুন: একাধিক ক্লিকের অনুমতি দিলে আপনি একটি ডিবান্স যোগ করতে পারেন (এখানে আমরা টগল করি, তাই এটি স্থিতিশীল)।
- উচ্চ ট্র্যাফিক: পোস্ট মেটা + নন-অ্যাটোমিক আপডেট। যদি ট্র্যাফিকের পরিমাণে আকস্মিক বৃদ্ধি ঘটে, তবে একটি কাস্টম টেবিল এবং একটি অ্যাটোমিক SQL আপডেট (অথবা একটি ডিফার্ড অ্যাগ্রিগেট) ব্যবহার করুন।
রক্ষণাবেক্ষণ
- স্টোরটিকে একটি স্পষ্ট নেমস্পেসে রাখুন (
bpcab/like), সাধারণ নাম পরিহার করুন (app). - আপনার লজিককে কোনো বিল্ডারের সাথে যুক্ত করা থেকে বিরত থাকুন। প্রয়োজনে একটি ইন্টিগ্রেশন লেয়ার (উইজেট/মডিউল) তৈরি করুন।
- গুটেনবার্গ (পিআর) এবং হ্যান্ডবুকের মাধ্যমে ইন্টারঅ্যাকটিভিটি এপিআই-এর অগ্রগতি পর্যবেক্ষণ করুন। পরিবর্তনগুলো প্রথমে গুটেনবার্গের দিকে আসে, তারপর কোরে একীভূত করা হয়।
সম্পদ
- ইন্টারঅ্যাক্টিভিটি এপিআই (developer.wordpress.org)
- REST API হ্যান্ডবুক
- register_rest_route() (রেফারেন্স)
- wp_create_nonce() (রেফারেন্স)
- wp_verify_nonce() (রেফারেন্স)
- ওয়ার্ডপ্রেস কোর ট্র্যাক (বাগ ট্র্যাকিং)
- গুটেনবার্গ রিপোজিটরি (পিআর ইন্টারঅ্যাক্টিভিটি)
- filter_var() (php.net)
- WordPress.org সাপোর্ট ফোরাম (বাস্তব জীবনের ঘটনা)
FAQ
গুটেনবার্গে কি ইন্টারঅ্যাকটিভিটি এপিআই রিয়্যাক্টকে প্রতিস্থাপন করে?
না। গুটেনবার্গ এখনও এডিটরের জন্য রিয়্যাক্ট ব্যবহার করে। ইন্টারঅ্যাকটিভিটি এপিআই মূলত ব্লক/কম্পোনেন্টের ফ্রন্ট-এন্ড ইন্টারঅ্যাকটিভিটির জন্য তৈরি, যা একটি হালকা এবং অধিক ডিক্লারেটিভ মডেল অনুসরণ করে।
কেন আমার window.wp.interactivity অসংজ্ঞায়িত?
বাস্তবে, এটি হয় একটি এনকিউ (enqueue) সমস্যা (স্ক্রিপ্ট খুব তাড়াতাড়ি লোড হওয়া বা একেবারেই লোড না হওয়া), অথবা জাভাস্ক্রিপ্ট অপটিমাইজেশন যা ক্রমটি নষ্ট করে দেয়, কিংবা এমন কোনো বিল্ডার যা আপনার শর্তগুলো পূরণ না করেই কন্টেন্ট তৈরি করে। সাময়িকভাবে অতিরিক্ত মিনিফাই/ডিফার অপারেশনগুলো নিষ্ক্রিয় করুন এবং নেটওয়ার্ক সেটিংস পরীক্ষা করুন।
এটি কি পূর্ণ-পৃষ্ঠা ক্যাশের সাথে সামঞ্জস্যপূর্ণ?
হ্যাঁ, প্রদর্শনের জন্য। স্থায়িত্বের জন্য, ননস (nonce) ব্যবহারের ক্ষেত্রে সতর্ক থাকুন: যদি এইচটিএমএল (HTML) পৃষ্ঠাটি ক্যাশে থেকে পরিবেশন করা হয় এবং এতে একটি মেয়াদোত্তীর্ণ ননস থাকে, তাহলে আপনার REST POST অনুরোধগুলি ব্যর্থ হবে (403)। যেসব সাইটে প্রচুর পরিমাণে ক্যাশে ব্যবহৃত হয়, সেখানে আমি একটি পাবলিক এন্ডপয়েন্টের (শুধুমাত্র পঠনযোগ্য) মাধ্যমে ননস তৈরি করতে অথবা এই কার্যকারিতাটি শুধুমাত্র লগ-ইন করা ব্যবহারকারীদের মধ্যে সীমাবদ্ধ রাখতে পছন্দ করি।
অ্যাডমিন-এজ্যাক্স এর পরিবর্তে REST কেন ব্যবহার করা হয়?
REST আরও পরিচ্ছন্ন HTTP সিম্যান্টিকস, স্ট্যান্ডার্ড JSON রেসপন্স প্রদান করে এবং আধুনিক টুলগুলোর সাথে আরও ভালোভাবে ইন্টিগ্রেট করে। অ্যাডমিন-এজ্যাক্স এখনও কার্যকর, কিন্তু এটি দ্রুত এমন একটি সর্বগ্রাহী ব্যবস্থায় পরিণত হয় যাকে সুরক্ষিত করা এবং যার প্রোফাইল তৈরি করা কঠিন।
আমরা কি শর্টকোডের পরিবর্তে গুটেনবার্গ ব্লক ব্যবহার করতে পারি?
হ্যাঁ, এবং সেটাই প্রায়শই শ্রেয়। প্যাটার্নটির মূল অংশ একই থাকে: SSR রেন্ডারিং + অ্যাট্রিবিউট। data-wp-* + স্টোর। আমি এখানে একটি শর্টকোড ব্যবহার করছি যাতে আপনি এটি ৫ মিনিটের মধ্যে পরীক্ষা করতে পারেন, বিল্ডার সহ।
বিভিন্ন কাউন্টার (লাইক, বুকমার্ক, ভোট) কীভাবে পরিচালনা করবেন?
আলাদা নেমস্পেস ব্যবহার করুন (bpcab/like, bpcab/bookmarkঅথবা কনটেক্সট দ্বারা কনফিগার করা একটি একক স্টোর। আপনার কম্পোনেন্টগুলো স্বাধীন হলে "মনোলিথিক" স্টোর পরিহার করুন।
পোস্ট-মেটার কাউন্টারটি কি নির্ভরযোগ্য?
একটি সাধারণ ব্লগের জন্য: হ্যাঁ। কিন্তু বেশি ট্র্যাফিকের ক্ষেত্রে: না, এতে ডেটা সংঘর্ষ (collision) হবে। একটি কাস্টম টেবিল এবং অ্যাটমিক আপডেট ব্যবহার করুন, অথবা একটি অ্যাসিঙ্ক্রোনাস অ্যাগ্রিগেশন কৌশল অবলম্বন করুন।
আমি কীভাবে এই কোডটি সঠিকভাবে পরীক্ষা করতে পারি?
আমি সাধারণত যা করি:
- স্টেজিং + WP_DEBUG লগ
- ম্যানুয়াল পরীক্ষা: দ্রুত ক্লিক, নেভিগেশন, ব্রাউজার ক্যাশে
- REST পরীক্ষা: curl (ননস ছাড়া প্রত্যাশিত ৪০৩, ননস সহ ২০০)
- ক্যাশ সামঞ্জস্যতা পরীক্ষা: ক্যাশ সক্রিয় করুন, ননস মেয়াদ শেষ হওয়া পরীক্ষা করুন
কেন নুনসিওকে রাখা হচ্ছে না? data-wp-context ?
আপনি তা করতে পারেন, কিন্তু এতে প্রতিটি ক্ষেত্রে একটি সংবেদনশীল মান নকল হয়ে যাবে। আমি একটি ন্যূনতম গ্লোবাল অবজেক্ট এবং UI অবস্থার জন্য প্রতিটি কম্পোনেন্টের জন্য একটি কনটেক্সট ব্যবহার করা পছন্দ করি। আপনার পৃষ্ঠাগুলো খুব দীর্ঘ হলে, এটি HTML-এর আকার কমিয়ে দেয়।
এটি কি ক্লাসিক (নন-এফএসই) থিমে কাজ করে?
হ্যাঁ। ইন্টারঅ্যাকটিভিটি এপিআই শুধু ব্লক থিমের মধ্যেই সীমাবদ্ধ নয়। মূল বিষয় হলো অ্যাসেটগুলো সঠিকভাবে লোড করা এবং অ্যাট্রিবিউটসহ মার্কআপ রেন্ডার করা। data-wp-*.
যদি কোনো স্নিপেটস প্লাগইন কোড নষ্ট করে দেয়, তাহলে আমার কী করা উচিত?
এই প্লাগইনটি কোনো স্নিপেটে পেস্ট করা থেকে বিরত থাকুন। একটি যথাযথ প্লাগইন তৈরি করুন (যেমন এটি)। স্নিপেট সুবিধাজনক হলেও, আমি দেখেছি ভিন্ন পিএইচপি সংস্করণে সক্রিয় করা স্নিপেটের কারণে, অথবা একটি কার্লি ব্রেস বাদ পড়া কপি-পেস্টের ফলে বহু সাইট ক্র্যাশ করেছে।