Dynamic Blocks در وردپرس بلاک‌هایی هستند که خروجی خود را در هر بار بارگذاری صفحه از طریق PHP رندر می‌کنند و رندر سرور به آن‌ها امکان می‌دهد با داده‌های زنده، تنظیمات سایت و context جاری هماهنگ بمانند؛ همین ویژگی آن‌ها را از Static Blocks متمایز می‌کند. در معماری گوتنبرگ، Dynamic Blocks ستون فقرات بلاک‌هایی مانند Latest Posts، Categories، Archives و Calendar هستند و بدون رندر سرور، نمایش محتوای پویا در ویرایشگر بلوک عملاً غیرممکن می‌شد. این مقاله معماری داخلی، نقش رندر سرور، تفاوت با Static Blocks، کاربردهای عملی، اشتباهات رایج و نکات پیشرفته را با مثال‌های واقعی بررسی می‌کند.

Dynamic Blocks در وردپرس بلاک‌هایی هستند که خروجی HTML خود را در هر بار بارگذاری صفحه از طریق PHP تولید می‌کنند و همین وابستگی به رندر سرور، آن‌ها را برای محتوای پویا ضروری می‌سازد.

رندر سرور به Dynamic Blocks اجازه می‌دهد که با آخرین پست‌ها، تنظیمات سایت، نقش کاربر و context جاری هماهنگ بمانند.

بلاک‌های هسته‌ای وردپرس مانند Latest Posts، Archives و Categories همگی Dynamic هستند و بر پایه render_callback کار می‌کنند.

در این مقاله معماری داخلی، نقش رندر سرور، جدول مقایسه، مثال‌های عملی، اشتباهات رایج و نکات پیشرفته Dynamic Blocks را بررسی می‌کنیم.

هدف این است که پس از مطالعه، بتوانید انتخاب درستی میان Static و Dynamic داشته باشید و بلاک‌هایی بسازید که هم پایدار و هم مقیاس‌پذیر باشند.

در نخستین پروژه‌ای که یک بلاک نمایش آخرین محصولات ووکامرس می‌ساختم، آن را به‌صورت Static پیاده کردم و نتیجه این بود که هر بار محصول جدیدی اضافه می‌شد، بلاک همچنان لیست قدیمی را نشان می‌داد. آن تجربه باعث شد که به‌سراغ Dynamic Blocks و رندر سرور بروم و از آن زمان، این رویکرد به یکی از ابزارهای اصلی در ساخت بلاک‌های پویا تبدیل شده است. آنچه در ادامه می‌خوانید حاصل کار عملی با این معماری در پروژه‌های واقعی است.

Dynamic Blocks چیست و چه تفاوتی با Static Blocks دارد؟

Dynamic Blocks بلاک‌هایی هستند که خروجی HTML خود را در زمان ذخیره تولید نمی‌کنند، بلکه در هر بار بارگذاری صفحه، یک تابع PHP مسئول تولید خروجی می‌شود. این تابع که render_callback نام دارد، ویژگی‌های بلاک (Attributes) و context جاری را دریافت کرده و بر اساس آن‌ها، خروجی HTML را می‌سازد. بلاک‌های هسته‌ای وردپرس مانند Latest Posts، Categories، Archives، Calendar و RSS همگی از این الگو پیروی می‌کنند. برای آشنایی با مبانی ساخت بلاک، مقاله آموزش ساخت بلوک سفارشی گوتنبرگ را مطالعه کنید.

در مقابل، Static Blocks خروجی HTML خود را یک بار در تابع save تولید کرده و در پایگاه داده ذخیره می‌کنند. پس از ذخیره، این خروجی ثابت باقی می‌ماند و تا زمانی که کاربر محتوای بلاک را ویرایش نکند، تغییری نمی‌کند. بلاک‌هایی مانند Paragraph، Heading، Image و Quote همگی Static هستند. تفاوت اصلی در این است که Static Blocks خروجی را در پایگاه داده نگه می‌دارند، در حالی که Dynamic Blocks تنها ویژگی‌ها را ذخیره کرده و خروجی را در زمان نمایش تولید می‌کنند.

Dynamic Blocks یک جریان زنده هستند؛ در هر بار بارگذاری از نو ساخته می‌شوند و با داده‌های جاری هماهنگ می‌مانند.

نکته مهمی که در بررسی‌های خود به آن پی بردم این است که تفاوت میان Static و Dynamic تنها در نحوه ذخیره‌سازی نیست؛ این تفاوت بر اعتبارسنجی، عملکرد، امنیت و قابلیت نگهداری نیز تأثیر می‌گذارد. در Static Blocks، مکانیزم اعتبارسنجی دقیقی وجود دارد که خروجی save را با محتوای ذخیره‌شده مقایسه می‌کند. در Dynamic Blocks، این مکانیزم وجود ندارد زیرا تابع save تنها مقدار null بازمی‌گرداند. برای مطالعه بیشتر درباره انتخاب میان این دو، مقاله Static یا Dynamic Blocks در وردپرس؛ کدام انتخاب درست است؟ را ببینید.

چرا رندر سرور برای Dynamic Blocks حیاتی است؟

رندر سرور (Server-Side Rendering) به فرآیندی گفته می‌شود که در آن خروجی HTML در سرور تولید شده و سپس به مرورگر ارسال می‌گردد. در Dynamic Blocks، این فرآیند در هر بار بارگذاری صفحه تکرار می‌شود و همین ویژگی، آن‌ها را از Static Blocks متمایز می‌کند. بدون رندر سرور، Dynamic Blocks نمی‌توانند با داده‌های زنده هماهنگ شوند و در عمل به بلاک‌های ایستا تبدیل می‌شوند.

دلایل متعددی وجود دارد که رندر سرور را برای Dynamic Blocks حیاتی می‌سازد. اولین دلیل، هماهنگی با داده‌های زنده است. فرض کنید یک بلاک نمایش آخرین پست‌ها دارید. اگر این بلاک Static باشد، تنها پست‌هایی که در زمان ذخیره وجود داشته‌اند نمایش داده می‌شوند و پست‌های جدید نادیده می‌مانند. اما با رندر سرور، هر بار بارگذاری، آخرین پست‌ها از پایگاه داده خوانده شده و نمایش داده می‌شوند.

دومین دلیل، هماهنگی با تنظیمات سایت است. فرض کنید یک بلاک نمایش اطلاعات کاربر جاری دارید. این اطلاعات در زمان ذخیره بلاک قابل تعیین نیستند و تنها در زمان نمایش قابل دریافت هستند. رندر سرور امکان دسترسی به این اطلاعات را فراهم می‌کند. برای مطالعه بیشتر درباره مدیریت state، مقاله Data API در وردپرس چیست و چطور state بلاک‌ها را مدیریت می‌کند؟ را ببینید.

سومین دلیل، پشتیبانی از context جاری است. در وردپرس، context جاری شامل پست جاری، دسته‌بندی جاری، کاربر جاری و سایر اطلاعات مرتبط است. Dynamic Blocks با رندر سرور می‌توانند به این context دسترسی پیدا کرده و خروجی خود را بر اساس آن تنظیم کنند. برای مطالعه بیشتر درباره context، مقاله چرا InnerBlocks در وردپرس کلید ساخت بلاک‌های حرفه‌ای است؟ را ببینید.

چهارمین دلیل، امکان ادغام با REST API و سرویس‌های خارجی است. Dynamic Blocks می‌توانند در render_callback خود به REST API یا سرویس‌های خارجی متصل شوند و داده‌های زنده را دریافت کنند. این قابلیت در Static Blocks وجود ندارد زیرا خروجی یک بار برای همیشه ذخیره می‌شود. برای مطالعه بیشتر درباره REST API، مقاله آموزش استفاده از REST API در وردپرس را ببینید.

رندر سرور، پل میان بلاک و دنیای زنده است؛ بدون آن، بلاک تنها یک عکس فوری از گذشته باقی می‌ماند.

پنجمین دلیل، پشتیبانی از SEO است. موتورهای جستجو محتوای HTML اولیه صفحه را ایندکس می‌کنند. اگر یک بلاک به‌صورت سمت کلاینت (Client-Side) رندر شود، موتور جستجو ممکن است آن را نبیند. اما با رندر سرور، خروجی بلاک در HTML اولیه قرار دارد و موتورهای جستجو می‌توانند آن را به‌راحتی ایندکس کنند. برای مطالعه بیشتر درباره سئو، مقاله سئو چیست و چگونه به رشد سایت کمک می‌کند؟ را ببینید.

معماری داخلی Dynamic Blocks

برای درک عمیق Dynamic Blocks، باید معماری داخلی آن‌ها را بررسی کنیم. این معماری بر پایه چند مفهوم بنیادین بنا شده است که درک هر یک برای کار حرفه‌ای ضروری است.

ویژگی‌ها (Attributes)

در Dynamic Blocks، تنها ویژگی‌ها در پایگاه داده ذخیره می‌شوند. این ویژگی‌ها می‌توانند شامل متن، عدد،布尔، آرایه یا شیء باشند. ویژگی‌ها در تابع render_callback دریافت شده و برای تولید خروجی استفاده می‌شوند. برخلاف Static Blocks، در Dynamic Blocks ویژگی‌ها می‌توانند شامل مقادیر پویا باشند که در زمان نمایش محاسبه می‌شوند.

render_callback

هسته اصلی Dynamic Blocks، تابع render_callback است. این تابع در هر بار بارگذاری صفحه اجرا می‌شود و خروجی HTML را تولید می‌کند. این تابع دو پارامتر اصلی دریافت می‌کند: ویژگی‌های بلاک و یک شیء از پارامترهای اضافی که می‌تواند شامل context باشد. خروجی این تابع به‌صورت مستقیم در صفحه قرار می‌گیرد.

Block Registration

در نسخه‌های مدرن وردپرس، Dynamic Blocks با استفاده از فایل block.json ثبت می‌شوند. این فایل شامل تمام اطلاعات لازم درباره بلاک است، از جمله نام، دسته‌بندی، ویژگی‌ها و مسیر فایل render_callback. برای مطالعه بیشتر درباره ساختار استاندارد، مقاله ساختار استاندارد افزونه وردپرس چیست و چطور یک پلاگین حرفه‌ای بسازیم؟ را ببینید.

ServerSideRender

در ویرایشگر، برای نمایش پیش‌نمایش خروجی Dynamic Block، از کامپوننت ServerSideRender استفاده می‌شود. این کامپوننت یک درخواست REST API به سرور ارسال می‌کند و خروجی render_callback را دریافت کرده و نمایش می‌دهد. این رویکرد باعث می‌شود که ویرایشگر بتواند پیش‌نمایش دقیقی از خروجی نهایی نمایش دهد.

render_callback: قلب رندر سرور

تابع render_callback قلب Dynamic Blocks است و تمام منطق تولید خروجی در آن قرار دارد. این تابع در زمان ثبت بلاک تعریف می‌شود و در هر بار بارگذاری صفحه فراخوانی می‌گردد.

function my_plugin_render_latest_posts( $attributes, $content, $block ) {
  $query = new WP_Query( array(
    'posts_per_page' => $attributes[ 'numberOfPosts' ],
    'post_status'    => 'publish',
    'category_name'  => $attributes[ 'categorySlug' ],
  ) );

  if ( ! $query->have_posts() ) {
    return '<p>' . esc_html__( 'پستی یافت نشد.', 'my-plugin' ) . '</p>';
  }

  $output = '<div class="my-latest-posts">';
  while ( $query->have_posts() ) {
    $query->the_post();
    $output .= '<article class="my-latest-posts__item">';
    $output .= '<h3><a href="' . esc_url( get_permalink() ) . '">';
    $output .= esc_html( get_the_title() ) . '</a></h3>';
    if ( $attributes[ 'showDate' ] ) {
      $output .= '<time>' . esc_html( get_the_date() ) . '</time>';
    }
    $output .= '</article>';
  }
  $output .= '</div>';

  wp_reset_postdata();
  return $output;
}

در این کد، تابع my_plugin_render_latest_posts ویژگی‌های بلاک را دریافت کرده و بر اساس آن‌ها، آخرین پست‌ها را از پایگاه داده می‌خواند. توجه کنید که خروجی با توابع پاکسازی مانند esc_html و esc_url رمزگذاری شده است. این رویکرد از بروز آسیب‌پذیری‌هایی مانند XSS جلوگیری می‌کند. برای مطالعه بیشتر درباره امنیت، مقاله چرا HTML API در وردپرس امن‌ترین راه پردازش HTML است؟ را ببینید.

نکته مهم دیگر، استفاده از wp_reset_postdata() پس از پایان حلقه است. این تابع state سراسری وردپرس را به حالت اولیه بازمی‌گرداند و از بروز خطاهای جانبی جلوگیری می‌کند. عدم فراخوانی این تابع یکی از اشتباهات رایج در ساخت Dynamic Blocks است.

تعریف Dynamic Block در block.json

در نسخه‌های مدرن وردپرس، Dynamic Blocks با استفاده از فایل block.json ثبت می‌شوند. این فایل به‌عنوان یک قرارداد استاندارد، تمام اطلاعات لازم درباره بلاک را در خود جای می‌دهد.

{
  "$schema": "https://schemas.wp.org/trunk/block.json",
  "apiVersion": 3,
  "name": "my-plugin/latest-posts",
  "title": "Latest Posts",
  "category": "widgets",
  "icon": "list-view",
  "description": "نمایش آخرین پست‌ها",
  "supports": {
    "html": false,
    "align": true
  },
  "attributes": {
    "numberOfPosts": {
      "type": "number",
      "default": 5
    },
    "categorySlug": {
      "type": "string",
      "default": ""
    },
    "showDate": {
      "type": "boolean",
      "default": true
    }
  },
  "textdomain": "my-plugin",
  "editorScript": "file:./index.js",
  "render": "file:./render.php"
}

در این فایل، ویژگی کلیدی render مسیر فایل PHP حاوی render_callback را مشخص می‌کند. این رویکرد مدرن، کد را تمیزتر و قابل نگهداری‌تر می‌سازد و از ثبت دستی بلاک در PHP جلوگیری می‌کند. برای مطالعه بیشتر درباره ساختار فایل‌های بلاک، مقاله چرا باید بلوک سفارشی گوتنبرگ بسازیم وقتی افزونه‌های آماده وجود دارند؟ را ببینید.

کامپوننت ServerSideRender در ویرایشگر

در ویرایشگر بلوک، برای نمایش پیش‌نمایش Dynamic Block، از کامپوننت ServerSideRender استفاده می‌شود. این کامپوننت یک درخواست REST API به سرور ارسال می‌کند و خروجی render_callback را دریافت کرده و در ویرایشگر نمایش می‌دهد.

import { registerBlockType } from '@wordpress/blocks';
import { useBlockProps, InspectorControls } from '@wordpress/block-editor';
import { PanelBody, RangeControl, ToggleControl } from '@wordpress/components';
import ServerSideRender from '@wordpress/server-side-render';
import { __ } from '@wordpress/i18n';
import metadata from './block.json';

registerBlockType( metadata.name, {
  edit: ( { attributes, setAttributes } ) => {
    const blockProps = useBlockProps();

    return (
      <>
        <InspectorControls>
          <PanelBody title={ __( 'تنظیمات', 'my-plugin' ) }>
            <RangeControl
              label={ __( 'تعداد پست‌ها', 'my-plugin' ) }
              value={ attributes.numberOfPosts }
              onChange={ ( numberOfPosts ) =>
                setAttributes( { numberOfPosts } )
              }
              min={ 1 }
              max={ 20 }
            />
            <ToggleControl
              label={ __( 'نمایش تاریخ', 'my-plugin' ) }
              checked={ attributes.showDate }
              onChange={ ( showDate ) =>
                setAttributes( { showDate } )
              }
            />
          </PanelBody>
        </InspectorControls>
        <div { ...blockProps }>
          <ServerSideRender
            block={ metadata.name }
            attributes={ attributes }
          />
        </div>
      </>
    );
  },
  save: () => null,
} );

در این کد، کامپوننت ServerSideRender پیش‌نمایش خروجی PHP را در ویرایشگر نمایش می‌دهد. توجه کنید که تابع save مقدار null بازمی‌گرداند، زیرا خروجی در زمان ذخیره تولید نمی‌شود. برای مطالعه بیشتر درباره React در بلاک‌ها، مقاله چرا بدون React نمی‌توان بلاک حرفه‌ای در وردپرس ساخت؟ را ببینید.

نکته مهم این است که ServerSideRender تنها برای Dynamic Blocks طراحی شده است و در Static Blocks کاربرد ندارد. همچنین، استفاده از این کامپوننت می‌تواند بر سرعت ویرایشگر تأثیر بگذارد، زیرا در هر تغییر ویژگی‌ها، یک درخواست به سرور ارسال می‌شود.

مقایسه جامع Static و Dynamic

برای درک بهتر تفاوت‌ها، جدول زیر خلاصه‌ای از مقایسه این دو نوع بلاک را نشان می‌دهد:

معیار Static Blocks Dynamic Blocks
نحوه ذخیره‌سازی HTML در پایگاه داده ویژگی‌ها در پایگاه داده
تولید خروجی یک بار در زمان ذخیره هر بار در زمان نمایش
تابع save خروجی HTML بازمی‌گرداند مقدار null بازمی‌گرداند
رندر سرور ندارد الزامی
اعتبارسنجی دقیق و خودکار ندارد
هماهنگی با داده زنده ندارد کامل
سرعت فرانت‌اند بالا متوسط
بار سرور کم زیاد
مناسب برای محتوای ثابت محتوای پویا

همان‌طور که جدول نشان می‌دهد، هر نوع بلاک مزایا و محدودیت‌های خاص خود را دارد. انتخاب میان این دو باید بر اساس ماهیت محتوا و نیازهای پروژه انجام شود. برای مطالعه بیشتر درباره انتخاب درست، مقاله Static یا Dynamic Blocks در وردپرس؛ کدام انتخاب درست است؟ را ببینید.

مثال عملی: ساخت یک Dynamic Block کامل

برای درک عملی Dynamic Blocks، بیایید یک بلاک بسازیم که آخرین محصولات ووکامرس را نمایش می‌دهد. این بلاک شامل ویژگی‌های تعداد محصولات و دسته‌بندی است و از render_callback برای تولید خروجی استفاده می‌کند.

ابتدا فایل block.json را تعریف می‌کنیم:

{
  "$schema": "https://schemas.wp.org/trunk/block.json",
  "apiVersion": 3,
  "name": "my-plugin/latest-products",
  "title": "Latest Products",
  "category": "widgets",
  "icon": "cart",
  "description": "نمایش آخرین محصولات فروشگاه",
  "supports": {
    "html": false
  },
  "attributes": {
    "numberOfProducts": {
      "type": "number",
      "default": 4
    },
    "categoryId": {
      "type": "number",
      "default": 0
    }
  },
  "textdomain": "my-plugin",
  "editorScript": "file:./index.js",
  "render": "file:./render.php"
}

سپس فایل render.php را می‌سازیم:

<?php
$query_args = array(
  'post_type'      => 'product',
  'posts_per_page' => $attributes[ 'numberOfProducts' ],
  'post_status'    => 'publish',
);

if ( ! empty( $attributes[ 'categoryId' ] ) ) {
  $query_args[ 'tax_query' ] = array(
    array(
      'taxonomy' => 'product_cat',
      'field'    => 'term_id',
      'terms'    => $attributes[ 'categoryId' ],
    ),
  );
}

$products = new WP_Query( $query_args );

if ( ! $products->have_posts() ) {
  return '<p>' . esc_html__( 'محصولی یافت نشد.', 'my-plugin' ) . '</p>';
}

$output = '<div class="my-latest-products">';
while ( $products->have_posts() ) {
  $products->the_post();
  $product = wc_get_product( get_the_ID() );

  $output .= '<article class="my-latest-products__item">';
  $output .= '<a href="' . esc_url( get_permalink() ) . '">';
  $output .= woocommerce_get_product_thumbnail();
  $output .= '<h3>' . esc_html( get_the_title() ) . '</h3>';
  $output .= '<span class="price">' . $product->get_price_html() . '</span>';
  $output .= '</a>';
  $output .= '</article>';
}
$output .= '</div>';

wp_reset_postdata();
return $output;

این بلاک با استفاده از WP_Query آخرین محصولات را از پایگاه داده می‌خواند و با استفاده از توابع ووکامرس، اطلاعات هر محصول را استخراج می‌کند. توجه کنید که تمام خروجی با توابع پاکسازی رمزگذاری شده است. برای مطالعه بیشتر درباره توابع ووکامرس، مقاله چگونه از توابع WooCommerce برای توسعه قالب وردپرس استفاده کنیم؟ را ببینید.

استفاده از Block Context در Dynamic Blocks

یکی از قابلیت‌های مهم Dynamic Blocks، دسترسی به Block Context است. Context یک مکانیزم است که به بلاک‌های فرزند اجازه می‌دهد به اطلاعات بلاک والد دسترسی داشته باشند. برای مثال، یک بلاک نمایش محصولات می‌تواند از Context برای دریافت دسته‌بندی جاری استفاده کند.

// در block.json بلاک والد
"providesContext": {
  "my-plugin/categoryId": "categoryId"
}

// در block.json بلاک فرزند
"usesContext": [ "my-plugin/categoryId" ]

سپس در render_callback بلاک فرزند، می‌توانید به Context دسترسی پیدا کنید:

function my_plugin_render_child_block( $attributes, $content, $block ) {
  $category_id = isset( $block->context[ 'my-plugin/categoryId' ] )
    ? $block->context[ 'my-plugin/categoryId' ]
    : 0;

  // استفاده از category_id برای تولید خروجی
}

این مکانیزم به‌ویژه برای بلاک‌هایی که در چندین context مختلف نمایش داده می‌شوند، حیاتی است. برای مطالعه بیشتر درباره مدیریت state، مقاله useSelect و useDispatch در توسعه بلاک وردپرس چطور کار می‌کنند؟ را ببینید.

عملکرد و بهینه‌سازی

عملکرد یکی از چالش‌های اصلی Dynamic Blocks است. از آنجا که خروجی در هر بار بارگذاری تولید می‌شود، بار سرور به‌طور قابل‌توجهی افزایش می‌یابد. در ادامه به بررسی راه‌های بهینه‌سازی می‌پردازیم.

بهینه‌سازی کوئری‌ها

اولین گام در بهینه‌سازی، کاهش تعداد و پیچیدگی کوئری‌های پایگاه داده است. از WP_Query با پارامترهای بهینه استفاده کنید و از کوئری‌های تکراری خودداری نمایید. برای مطالعه بیشتر درباره بهینه‌سازی، مقاله بهینه سازی جاوااسکریپت: قاتلان خاموشی که در پروژه‌ها دیده‌ام را ببینید.

کش کردن خروجی

دومین گام، کش کردن خروجی بلاک است. با استفاده از Transients یا Object Cache، می‌توانید خروجی را برای مدت مشخصی ذخیره کنید و از اجرای مکرر render_callback جلوگیری نمایید. این رویکرد تعادل مناسبی میان عملکرد و تازگی داده‌ها ایجاد می‌کند.

کاهش تعداد بلاک‌ها

سومین گام، کاهش تعداد Dynamic Blocks در یک صفحه است. اگر صفحه‌ای چندین Dynamic Block دارد، هر یک از آن‌ها یک کوئری جداگانه اجرا می‌کند و این می‌تواند بار سرور را افزایش دهد. در صورت امکان، بلاک‌ها را ادغام کنید یا از یک بلاک واحد با چندین بخش استفاده نمایید.

استراتژی کش برای Dynamic Blocks

کش کردن خروجی Dynamic Blocks یکی از مؤثرترین راه‌های بهینه‌سازی است. در ادامه به بررسی چند استراتژی کش می‌پردازیم.

Transients API

Transients API یک مکانیزم کش ساده و مؤثر در وردپرس است. با استفاده از توابع set_transient و get_transient، می‌توانید خروجی بلاک را برای مدت مشخصی ذخیره کنید.

function my_plugin_render_cached_block( $attributes ) {
  $cache_key = 'my_block_' . md5( wp_json_encode( $attributes ) );
  $output = get_transient( $cache_key );

  if ( false === $output ) {
    $output = my_plugin_generate_block_output( $attributes );
    set_transient( $cache_key, $output, HOUR_IN_SECONDS );
  }

  return $output;
}

در این کد، خروجی بلاک در یک transient ذخیره می‌شود و در بارگذاری‌های بعدی، از کش خوانده می‌شود. این رویکرد بار سرور را به‌طور چشمگیری کاهش می‌دهد. برای مطالعه بیشتر درباره Transients، مقاله Synced Patterns در وردپرس چطور محتوا را در چند صفحه هماهنگ می‌کند؟ را ببینید.

Object Cache

اگر سایت شما از Object Cache پشتیبانی می‌کند (مانند Redis یا Memcached)، می‌توانید از این مکانیزم برای کش کردن خروجی استفاده کنید. Object Cache سریع‌تر از Transients عمل می‌کند و برای سایت‌های پربازدید توصیه می‌شود.

Page Cache

اگر خروجی بلاک برای همه کاربران یکسان است، می‌توانید از Page Cache استفاده کنید. این مکانیزم کل صفحه را کش می‌کند و بار سرور را به حداقل می‌رساند. اما اگر خروجی بلاک برای هر کاربر متفاوت باشد، Page Cache مناسب نیست.

امنیت و اعتبارسنجی

امنیت Dynamic Blocks نیازمند توجه ویژه‌ای است زیرا خروجی در هر بار بارگذاری تولید می‌شود و ممکن است شامل داده‌های کاربر باشد. در ادامه به بررسی نکات امنیتی می‌پردازیم.

پاکسازی ورودی‌ها

همیشه ویژگی‌های بلاک را قبل از استفاده پاکسازی کنید. از توابعی مانند absint برای اعداد، sanitize_text_field برای متن و sanitize_key برای شناسه‌ها استفاده نمایید.

رمزگذاری خروجی‌ها

همیشه خروجی را قبل از قرار دادن در HTML رمزگذاری کنید. از توابعی مانند esc_html، esc_attr و esc_url استفاده نمایید. عدم رمزگذاری خروجی یکی از رایج‌ترین دلایل بروز آسیب‌پذیری XSS است.

بررسی دسترسی‌ها

اگر بلاک شما اطلاعات حساسی را نمایش می‌دهد، همیشه دسترسی کاربر را بررسی کنید. از توابعی مانند current_user_can استفاده نمایید تا اطمینان حاصل کنید که کاربر مجاز به مشاهده اطلاعات است.

امنیت در Dynamic Blocks یک انتخاب لوکس نیست؛ یک ضرورت است که هر توسعه‌دهنده باید به آن پایبند باشد.

اشتباهات رایج در پیاده‌سازی

در کار با Dynamic Blocks، توسعه‌دهندگان اغلب مرتکب اشتباهاتی می‌شوند که منجر به کد شکننده یا عملکرد ضعیف می‌شود. در ادامه به برخی از این اشتباهات اشاره می‌کنیم.

عدم استفاده از wp_reset_postdata

یکی از رایج‌ترین اشتباهات، عدم فراخوانی wp_reset_postdata پس از پایان حلقه است. این تابع state سراسری وردپرس را به حالت اولیه بازمی‌گرداند و از بروز خطاهای جانبی جلوگیری می‌کند. عدم استفاده از آن می‌تواند باعث شود که سایر بخش‌های صفحه به‌درستی نمایش داده نشوند.

نادیده گرفتن کش

اشتباه دیگر، نادیده گرفتن کش کردن خروجی است. اگر بلاک شما در هر بار بارگذاری، کوئری‌های سنگینی اجرا کند، سرعت سایت به‌طور چشمگیری کاهش می‌یابد. همیشه از Transients یا Object Cache استفاده کنید.

عدم پاکسازی ورودی‌ها

اگر ویژگی‌های بلاک را قبل از استفاده پاکسازی نکنید، ممکن است به آسیب‌پذیری‌هایی مانند XSS و SQL Injection منجر شود. همیشه ورودی‌ها را پاکسازی و خروجی‌ها را رمزگذاری کنید.

استفاده بیش از حد از ServerSideRender

کامپوننت ServerSideRender در هر تغییر ویژگی‌ها، یک درخواست به سرور ارسال می‌کند. اگر بلاک شما چندین ویژگی دارد، این می‌تواند ویرایشگر را کند کند. برای بهینه‌سازی، از debounce استفاده کنید یا پیش‌نمایش را تنها در صورت درخواست کاربر نمایش دهید.

نادیده گرفتن context

Context یکی از قابلیت‌های قدرتمند Dynamic Blocks است که اغلب نادیده گرفته می‌شود. اگر بلاک شما می‌تواند از Context استفاده کند، این کار را انجام دهید تا کد تمیزتر و قابل نگهداری‌تر شود.

عیب‌یابی مشکلات Dynamic Blocks

عیب‌یابی مسائل مربوط به Dynamic Blocks نیازمند رویکردی سیستماتیک است. در ادامه به بررسی برخی از مشکلات رایج و راه‌حل‌های آن‌ها می‌پردازیم.

خروجی نمایش داده نمی‌شود

اگر خروجی بلاک نمایش داده نمی‌شود، ابتدا بررسی کنید که آیا render_callback به‌درستی تعریف شده است. سپس بررسی کنید که آیا مسیر فایل render.php در block.json صحیح است. در نهایت، بررسی کنید که آیا داده‌های مورد نیاز در پایگاه داده وجود دارند.

خطای 500 در ویرایشگر

اگر در ویرایشگر خطای 500 دریافت می‌کنید، احتمالاً render_callback دارای خطای PHP است. لاگ خطاهای PHP را بررسی کنید و کد را اصلاح نمایید. همچنین، بررسی کنید که آیا تمام وابستگی‌ها (مانند توابع ووکامرس) بارگذاری شده‌اند.

خروجی در ویرایشگر نمایش داده نمی‌شود اما در فرانت‌اند نمایش داده می‌شود

اگر خروجی در ویرایشگر نمایش داده نمی‌شود اما در فرانت‌اند نمایش داده می‌شود، احتمالاً ServerSideRender به‌درستی تنظیم نشده است. بررسی کنید که آیا نام بلاک در ServerSideRender با نام ثبت‌شده در block.json مطابقت دارد.

کندی صفحه

اگر صفحه‌ای که Dynamic Block دارد کند بارگذاری می‌شود، ابتدا کوئری‌های پایگاه داده را بررسی کنید. از ابزارهایی مانند Query Monitor برای شناسایی کوئری‌های سنگین استفاده نمایید. سپس از کش کردن خروجی استفاده کنید.

تحلیل معماری در سطح پیشرفته

از منظر معماری نرم‌افزار، Dynamic Blocks یک پیاده‌سازی از الگوی Separation of Concerns هستند. در این الگو، منطق تولید خروجی از منطق ویرایش جدا می‌شود. تابع edit در JavaScript مسئول رابط کاربری ویرایشگر است و render_callback در PHP مسئول تولید خروجی نهایی. این جداسازی، امکان تست مستقل هر بخش را فراهم می‌کند و کد را قابل نگهداری‌تر می‌سازد.

یکی از جنبه‌های کمتر شناخته‌شده، نحوه مدیریت cache invalidation در Dynamic Blocks است. اگر خروجی بلاک را کش می‌کنید، باید مطمئن شوید که کش در زمان مناسب پاک می‌شود. برای مثال، اگر بلاک آخرین پست‌ها را نمایش می‌دهد، کش باید با انتشار پست جدید پاک شود. وردپرس هوک‌هایی مانند save_post و transition_post_status را فراهم می‌کند که می‌توانید از آن‌ها برای پاک کردن کش استفاده کنید. برای مطالعه بیشتر درباره هوک‌ها، مقاله هوک‌های وردپرس: قلب تپنده توسعه را ببینید.

از منظر عملکرد، Dynamic Blocks یک trade-off میان تازگی داده‌ها و بار سرور ایجاد می‌کنند. هرچه کش کوتاه‌تر باشد، داده‌ها تازه‌تر هستند اما بار سرور بیشتر است. هرچه کش طولانی‌تر باشد، بار سرور کمتر است اما داده‌ها ممکن است قدیمی باشند. انتخاب مدت کش باید بر اساس ماهیت داده‌ها و نیازهای پروژه انجام شود.

از منظر قابلیت مقیاس‌پذیری (Scalability)، Dynamic Blocks در سایت‌های پربازدید چالش‌برانگیز هستند. برای مقیاس‌پذیری، باید از کش چندلایه استفاده کنید: Object Cache برای داده‌های سطح پایین، Transients برای خروجی بلاک و Page Cache برای کل صفحه. این رویکرد به شما امکان می‌دهد که بار سرور را به حداقل برسانید. برای مطالعه بیشتر درباره معماری، می‌توانید صفحه Server-side scripting را در ویکی‌پدیا ببینید.

از منظر قابلیت آزمون‌پذیری (Testability)، Dynamic Blocks امکان تست واحد render_callback را فراهم می‌کنند. از آنجا که این تابع یک تابع خالص است که ویژگی‌ها را دریافت کرده و خروجی بازمی‌گرداند، می‌توان آن را به‌صورت مستقل تست کرد. این ویژگی به‌ویژه در پروژه‌های بزرگ که چندین توسعه‌دهنده دارند، حیاتی است.

آینده Dynamic Blocks

تیم هسته وردپرس در حال کار بر روی بهبود Dynamic Blocks است. از جمله تحولات مورد انتظار می‌توان به پشتیبانی بهتر از Block Context، بهبود عملکرد ServerSideRender و ادغام بهتر با Interactivity API اشاره کرد. این تحولات می‌توانند Dynamic Blocks را به ابزارهای قدرتمندتری برای ساخت بلاک‌های پویا تبدیل کنند. برای مطالعه بیشتر، مقاله آیا WordPress Interactivity API جایگزین React در وردپرس می‌شود؟ را ببینید.

پرسش‌های پرتکرار درباره Dynamic Blocks

Dynamic Blocks چه تفاوتی با Static Blocks دارد؟

Static Blocks خروجی HTML خود را یک بار در پایگاه داده ذخیره می‌کنند، در حالی که Dynamic Blocks خروجی خود را در هر بار بارگذاری از طریق PHP رندر می‌نمایند.

چرا رندر سرور برای Dynamic Blocks ضروری است؟

رندر سرور به Dynamic Blocks اجازه می‌دهد که با داده‌های زنده، تنظیمات سایت، context جاری و سرویس‌های خارجی هماهنگ بمانند. بدون رندر سرور، این بلاک‌ها به بلاک‌های ایستا تبدیل می‌شوند.

آیا Dynamic Blocks سریع‌تر از Static Blocks هستند؟

خیر، Static Blocks سریع‌تر هستند زیرا نیازی به اجرای کد PHP در زمان نمایش ندارند. اما Dynamic Blocks انعطاف‌پذیری بیشتری دارند.

چگونه می‌توانم خروجی Dynamic Block را کش کنم؟

می‌توانید از Transients API یا Object Cache برای کش کردن خروجی استفاده کنید. مقاله Data API در وردپرس چیست و چطور state بلاک‌ها را مدیریت می‌کند؟ به این موضوع می‌پردازد.

آیا Dynamic Blocks از InnerBlocks پشتیبانی می‌کنند؟

بله، InnerBlocks در هر دو نوع بلاک قابل استفاده است. اما در Dynamic Blocks، مدیریت InnerBlocks پیچیده‌تر است زیرا خروجی در زمان نمایش تولید می‌شود.

آیا ServerSideRender بر سرعت ویرایشگر تأثیر می‌گذارد؟

بله، ServerSideRender در هر تغییر ویژگی‌ها یک درخواست به سرور ارسال می‌کند و این می‌تواند ویرایشگر را کند کند. برای بهینه‌سازی، از debounce استفاده کنید.

آیا می‌توانم یک Static Block را به Dynamic تبدیل کنم؟

بله، با تغییر تابع save به بازگشت null و افزودن render_callback، می‌توانید این تبدیل را انجام دهید. اما توجه داشته باشید که این تغییر نیازمند مهاجرت محتوای موجود است.

آیا Dynamic Blocks بر سئو تأثیر می‌گذارند؟

Dynamic Blocks خروجی خود را به‌صورت HTML در فرانت‌اند تولید می‌کنند و موتورهای جستجو می‌توانند آن را ایندکس کنند. اگر خروجی به‌درستی رندر شود، تأثیر منفی بر سئو ندارد.

چگونه می‌توانم خطاهای Dynamic Blocks را عیب‌یابی کنم؟

ابتدا لاگ خطاهای PHP را بررسی کنید. سپس از ابزارهایی مانند Query Monitor برای شناسایی کوئری‌های سنگین استفاده نمایید. در نهایت، بررسی کنید که آیا render_callback به‌درستی تعریف شده است.

آیا می‌توانم از TypeScript در ساخت Dynamic Blocks استفاده کنم؟

بله، استفاده از TypeScript در بخش JavaScript بلاک رایج است و به بهبود کیفیت کد کمک می‌کند. برای مطالعه بیشتر، مقاله چرا TypeScript برای توسعه دهندگان جاوااسکریپت یک تحول بنیادی است؟ را ببینید.

نکات کلیدی

  • Dynamic Blocks خروجی خود را در هر بار بارگذاری از طریق PHP رندر می‌نمایند.
  • رندر سرور به Dynamic Blocks امکان هماهنگی با داده‌های زنده، تنظیمات سایت و context جاری را می‌دهد.
  • بلاک‌های هسته‌ای مانند Latest Posts، Archives و Categories همگی Dynamic هستند.
  • تابع save در Dynamic Blocks مقدار null بازمی‌گرداند و خروجی توسط render_callback تولید می‌شود.
  • کامپوننت ServerSideRender پیش‌نمایش خروجی PHP را در ویرایشگر نمایش می‌دهد.
  • کش کردن خروجی با Transients یا Object Cache بار سرور را به‌طور چشمگیری کاهش می‌دهد.
  • همیشه ورودی‌ها را پاکسازی و خروجی‌ها را رمزگذاری کنید.
  • از wp_reset_postdata پس از پایان حلقه استفاده کنید.
  • Block Context امکان دسترسی بلاک‌های فرزند به اطلاعات بلاک والد را فراهم می‌کند.
  • الگوی ترکیبی Static و Dynamic بهترین رویکرد در پروژه‌های واقعی است.

اگر در پروژه‌ای از Dynamic Blocks استفاده کرده‌اید، برایم جالب است بدانید کدام جنبه آن بیشترین چالش را برای شما ایجاد کرده است؛ به‌ویژه اگر راه‌حل خلاقانه‌ای برای کش کردن خروجی یا بهینه‌سازی کوئری‌ها پیدا کرده‌اید که می‌تواند برای دیگران مفید باشد. تجربه خود را در دیدگاه‌ها بنویسید. 🚀