WidgetCoreمستندات WidgetCore

ویجت جستجوی زنده

راهنمای کامل ویجت جستجوی زنده‌ی WidgetCore؛ کنترل‌های عمومی، طرح‌بندی، کوئری و صفحه‌بندی، ساختار خروجی، رفتار جاوااسکریپت و کار بدون جاوااسکریپت.

ویجت جستجوی زنده یک فیلد جستجوی AJAX است: کاربر تایپ می‌کند و نتایج بدون بارگذاری صفحه زیر فیلد (یا در ناحیه‌ی نتایج همین ویجت) ظاهر می‌شوند. همه‌ی تنظیمات در چهار بخش محتوا و سه بخش استایل قرار دارند.

موردمقدار
شناسه‌ی ویجتwgcr-search
عنوان در پنلجستجوی زنده
آیکون در پنلeicon-search
دستهویجت‌های WidgetCore (wgcr)
استایل / اسکریپتwgcr-search
کلاس ریشه.wgcr-search
واژه‌های کلیدیsearch، live، ajax، «جستجو»، «سرچ»، «دوره»، «مقاله»

بخش «عمومی»

کنترلنوعپیش‌فرضتوضیح
حالت نمایش نتایجانتخابیmodal (حالت لیست)page = حالت نمایش در صفحه
متن راهنمامتنخالیاگر خالی بماند، به‌صورت خودکار پر می‌شود (پایین‌تر توضیح داده شده)
نمایش تصویرکلیدبلهبندانگشتی هر نتیجه
نمایش خلاصهکلیدبله18 کلمه از متن، با نقطه‌چین
متن «نمایش همه»متن«نمایش همه نتایج»پیوندی که کاربر را به صفحه‌ی نتایج کامل می‌برد

منطق متن راهنما: اگر «متن راهنما» را خالی بگذارید، افزونه بر اساس منبع یکی از دو مقدار پیش‌فرض را می‌گذارد — برای منبع course متن «جستجو در دوره‌ها…» و برای بقیه‌ی منابع «جستجو در مقالات…».

حالت‌های نمایش

ویجت جستجوی زنده دو حالت نمایش دارد که با کنترل حالت نمایش نتایج در بخش «عمومی» انتخاب می‌شود. این انتخاب فقط ظاهر را عوض نمی‌کند؛ رفتار پنل، کنترل‌های فعال و حتی کلید Escape را تغییر می‌دهد.

مقایسه‌ی دو حالت

ویژگیحالت لیست (modal)حالت نمایش در صفحه (page)
جای نتایجپنل بازشو زیر فیلدناحیه‌ی همیشه‌باز داخل همان ویجت
وضعیت اولیه‌ی پنلبا hidden بسته استباز است (aria-expanded="true" روی فیلد)
بسته‌شدن با کلیک بیرونبلهخیر (پنل بخشی از صفحه است)
رفتار Escapeبستن پنل؛ اگر بسته بود، پاک‌کردن عبارتپاک‌کردن عبارت جستجو
ستون‌هاهمیشه تک‌ستونی1 تا 6 ستون (واکنش‌گرا)
کاشی و ارتفاع برابرغیرفعالفعال
استایل کانتینر نتایجفقط پس‌زمینه و گردی پنلعرض، ارتفاع کمینه/بیشینه، فاصله، پس‌زمینه، تراز
پیمایش بی‌نهایتداخل پنل (با اسکرول پنل)نسبت به پنجره‌ی مرورگر
پیوند «نمایش همه»بعد از نتایج دیده می‌شودفقط وقتی عبارت معتبر است
کاربری مناسبهدر، نوار کناری، جستجوی سریعصفحه‌ی جستجوی اختصاصی، آرشیو، بخش دوره‌ها

حالت لیست

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

  1. کاربر روی فیلد کلیک می‌کند

    اگر از قبل عبارت معتبری در فیلد باشد و نتیجه‌ای مانده باشد، پنل باز می‌شود.

  2. کاربر تایپ می‌کند

    پس از 250 میلی‌ثانیه درخواست فرستاده می‌شود و پنل باز می‌شود.

  3. با کیبورد یا ماوس یک نتیجه انتخاب می‌شود

    کلیدهای بالا و پایین بین نتایج حرکت می‌کنند و Enter به همان نتیجه می‌رود.

  4. با کلیک بیرون یا Escape پنل بسته می‌شود

    Escape دوم، عبارت داخل فیلد را پاک می‌کند.

کجا استفاده کنیم: هدر سایت، نوار کناری، بالای آرشیو، یا هر جایی که فضا محدود است و کاربر می‌خواهد سریع به یک نتیجه برود.

حالت نمایش در صفحه

در این حالت نتایج در یک ناحیه‌ی دائمی زیر فیلد رندر می‌شوند و پنل هرگز با کلیک بیرون بسته نمی‌شود؛ چون بخشی از محتوای صفحه است.

  1. ناحیه‌ی نتایج از ابتدا روی صفحه است

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

  2. عبارت تایپ می‌شود

    نتایج داخل همان ناحیه، در شبکه‌ی چندستونی قرار می‌گیرند.

  3. ستون‌ها واکنش‌گرا هستند

    مقادیر دسکتاپ/تبلت/موبایل به‌ترتیب پیش‌فرض 3/2/1 است.

  4. صفحه‌بندی داخل همان ناحیه است

    شماره‌ها، قبلی/بعدی یا بارگذاری بیشتر، همه زیر نتایج.

کجا استفاده کنیم: صفحه‌ی «جستجوی پیشرفته»، بخش دوره‌ها یا محصولات، و هر صفحه‌ای که می‌خواهید نتایج مثل یک گرید محتوایی دیده شوند.

ستون‌ها، کاشی و ارتفاع برابر

تنظیماثر
ستون‌هاکلاس wgcr-search--cols-{n} روی ریشه؛ از 3 ستون به بالا شبکه‌ی CSS ساخته می‌شود
کاشیکلاس wgcr-search--masonry؛ آیتم‌ها با ارتفاع طبیعی خودشان چیده می‌شوند
ارتفاع برابرکلاس wgcr-search--equal؛ همه‌ی کارت‌ها به اندازه‌ی بلندترین کارت کشیده می‌شوند

انتخاب قالب در حالت صفحه

وقتی «انتخاب قالب» روی سفارشی باشد، شناسه‌ی قالب به مسیر REST فرستاده می‌شود و هر نتیجه با قالب المنتور شما رندر می‌شود:

  1. قالب را در کتابخانه بسازید

    «قالب‌ها → قالب‌های ذخیره‌شده»؛ قالب باید منتشر شده باشد.

  2. آن را در ویجت انتخاب کنید

    «انتخاب قالب» → سفارشی، سپس قالب موردنظر را از فهرست برگزینید.

  3. خروجی را بررسی کنید

    کلاس wgcr-search--tpl به ریشه اضافه می‌شود و CSS خود قالب یک بار بارگذاری می‌شود.

جزئیات بیشتر در صفحه‌ی قالب‌های المنتور.

تفاوت‌های رفتاری که کمتر دیده می‌شوند

انتخاب با ماوس

  • حالت لیست: حرکت ماوس روی یک نتیجه، آن را «انتخاب‌شده» می‌کند تا با Enter باز شود.
  • هر دو حالت با قالب المنتور: وقتی نتایج با قالب سفارشی رندر می‌شوند (wgcr-search-item--tpl)، حرکت ماوس هیچ نتیجه‌ای را «انتخاب‌شده» نشانه‌گذاری نمی‌کند و استایل انتخاب اعمال نمی‌شود؛ چون قالب خودش لینک و استایل دارد و تداخل، کلیک را خراب می‌کند. اگر نتیجه‌ی قالبی لینک نداشته باشد، کلیک روی خود کارت به آدرس آن نتیجه می‌رود.

فوکوس پس از صفحه‌بندی

وقتی با کیبورد صفحه را عوض می‌کنید، بعد از رندر نتایج فوکوس به همان دکمه‌ای برمی‌گردد که زده‌اید (قبلی، بعدی یا شماره‌ی صفحه‌ی جاری). این کار باعث می‌شود کاربر کیبوردی جای خودش را در نوار صفحه‌بندی گم نکند.

اسکرول بی‌نهایت

در حالت «صفحه»، یک عنصر دیده‌بان (.wgcr-search-sentinel) انتهای نتایج را با IntersectionObserver نسبت به پنجره‌ی مرورگر می‌سنجد؛ یعنی برای بارگذاری بیشتر لازم نیست داخل پنل اسکرول کنید. در حالت لیست، اسکرول خود پنل معیار است.

دسترس‌پذیری در هر دو حالت

ویژگیحالت لیستحالت نمایش در صفحه
role="combobox" روی فیلدبلهبله
aria-expanded و aria-controlsبلهبله
role="listbox" روی پنل نتایجبلهبله
aria-live="polite" برای پیام وضعیتبلهبله
پیمایش نتایج با ArrowDown / ArrowUpبلهبله
بازکردن نتیجه با Enterبلهبله
بستن با Escapeبله— (چیزی برای بستن وجود ندارد)

جزئیات کامل در صفحه‌ی دسترس‌پذیری و کلیدهای کیبورد.

تفاوت‌های استایل

ناحیهحالت لیستحالت نمایش در صفحه
کلاس ریشهwgcr-search--modalwgcr-search--page
پس‌زمینه‌ی نتایجپس‌زمینه‌ی پنل بازشوپس‌زمینه‌ی کانتینر ویجت
بیشینه‌ی ارتفاع70vhنامحدود (تابع کانتینر)
ستون‌های شبکه11 تا 6

چون هر دو حالت کلاس پایه‌ی .wgcr-search را دارند، می‌توانید یک قانون CSS برای بخش‌های مشترک بنویسید و قانون‌های اختصاصی هر حالت را با کلاس‌های تغییردهنده اضافه کنید.

الگوهای پیشنهادی

سناریوتنظیمات
جستجوی سریع در هدرحالت لیست، 5 نتیجه، بدون تصویر، صفحه‌بندی هیچکدام
صفحه‌ی جستجوی اصلیحالت صفحه، 12 نتیجه، 3 ستون، صفحه‌بندی شماره‌ها
گرید دوره‌هاحالت صفحه، منبع course، ستون 3/2/1، کاشی روشن، بارگذاری با اسکرول
نتایج با طراحی اختصاصیحالت صفحه، قالب سفارشی، ستون 2، صفحه‌بندی قبلی/بعدی

قالب‌های المنتور

به‌جای کارت پیش‌فرض افزونه، می‌توانید ظاهر هر نتیجه را با یک قالب ذخیره‌شده در کتابخانه‌ی المنتور بسازید. قالب شما برای هر نتیجه رندر می‌شود و افزونه فقط داده‌های آن نتیجه را در حلقه قرار می‌دهد.

آماده‌سازی قالب

  1. یک قالب جدید در کتابخانه بسازید

    در پیشخوان: «قالب‌ها → افزودن جدید» و نوع «بخش» (Section) یا «قالب حلقه» را انتخاب کنید.

  2. داخل قالب از ویجت‌های حلقه‌ی المنتور استفاده کنید

    ویجت‌هایی مانند «پست حلقه» یا فیلدهای داینامیک عنوان/تصویر/خلاصه، داده‌های همان نتیجه را می‌گیرند.

  3. قالب را منتشر کنید

    فقط قالب‌های با وضعیت publish و نوع elementor_library قابل استفاده‌اند؛ پیش‌نویس در فهرست نمی‌آید.

  4. قالب را در ویجت انتخاب کنید

    در ویجت جستجوی زنده: بخش «طرح‌بندی» → «انتخاب قالب» را روی سفارشی بگذارید و از فهرست «یک قالب انتخاب کنید» همان قالب را انتخاب کنید.

فهرست قالب‌ها با قابلیت جستجو نمایش داده می‌شود و کنار آن یک پیوند ویرایش قالب هست که مستقیم به کتابخانه‌ی المنتور می‌رود.

چه اتفاقی هنگام جستجو می‌افتد

1. درخواست با پارامتر template=<شناسه‌ی قالب> به REST می‌رود
2. سرور برای هر نتیجه، حلقه را روی همان نوشته می‌بندد
3. قالب با get_builder_content_for_display() رندر می‌شود
4. اگر خروجی محتوای قابل‌مشاهده داشته باشد، در فیلد html همان نتیجه برمی‌گردد
5. جاوااسکریپت آن را داخل li.wgcr-search-item--tpl می‌گذارد

بررسی محتوای قابل‌مشاهده

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

بررسیجزئیات
متن قابل‌مشاهدهبرچسب‌های script و style حذف می‌شوند و اگر متن باقی‌مانده خالی نبود، قبول است
رسانهوجود img، svg، picture، video، iframe یا canvas هم کافی است
خطااگر رندر قالب استثنا بدهد، خروجی خالی در نظر گرفته می‌شود

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

CSS قالب چگونه بارگذاری می‌شود

قالب‌های المنتور معمولاً همراه خروجی خود <style> و <link rel="stylesheet"> دارند. افزونه این‌ها را از HTML نتایج بیرون می‌کشد و جدا مدیریت می‌کند:

نوعرفتار
<style>محتوای همه‌ی بلوک‌ها جمع‌آوری، یکسان‌سازی و یک بار داخل <style class="wgcr-search-tpl-style"> در پنل نوشته می‌شود
<link rel="stylesheet">به‌عنوان یک استایل واقعی و یک بار در صفحه به <head> اضافه می‌شود
تکراری‌هابا کلیدِ متن یکسان‌سازی‌شده شناسایی و حذف می‌شوند

نتیجه: حتی با 12 نتیجه، CSS قالب 12 بار تکرار نمی‌شود و <link>ها هم به‌جای درج شدن به‌صورت متن، مانند استایل واقعی رفتار می‌کنند.

انیمیشن‌های ورود و هندلرها

پس از رندر نتایج قالبی، دو کار انجام می‌شود:

  1. کلاس elementor-invisible از عنصرها حذف می‌شود؛ وگرنه عنصرهای دارای انیمیشن ورود نامرئی می‌ماندند.
  2. اگر window.elementorFrontend موجود باشد، هندلرهای سمت کاربر المنتور روی نتایج تازه اجرا می‌شوند تا رفتارهایی مثل تب، آکاردئون یا کاروسل داخل قالب کار کنند.

نتیجه‌های قالبی و تعامل

رفتاردر نتایج قالبی
حرکت ماوس روی نتیجهنتیجه را «انتخاب‌شده» نمی‌کند
استایل انتخاب/هاور افزونهاعمال نمی‌شود (ظاهر کاملاً از قالب شماست)
کیبورد (بالا/پایین و Enter)کار می‌کند و با حلقه‌ی بیرونی مشخص است
کلیک روی کارت بدون لینکبه آدرس همان نتیجه می‌رود
کلیک روی لینک/دکمه/فیلد داخل قالببه همان عنصر واگذار می‌شود

الگوی پیشنهادی قالب

یک قالب نتیجه‌ی خوب معمولاً این عنصرها را دارد:

┌──────────────────────────────────────┐
│ تصویر شاخص (16:9)                     │
│ عنوان (پیوند به نوشته)                 │
│ خلاصه‌ی کوتاه (2 خط)                   │
│ رده · تاریخ · نویسنده                  │
│ دکمه‌ی «ادامه مطلب»                     │
└──────────────────────────────────────┘

نکات عملی:

  • یک لینک اصلی در هر کارت بگذارید؛ لینک‌های تودرتو دسترس‌پذیری را خراب می‌کنند.
  • ارتفاع تصویر را ثابت نگه دارید تا در حالت «کاشی» چیدمان نپرد.
  • اگر از «ارتفاع برابر» استفاده می‌کنید، کارت را با display:flex و flex-direction:column بسازید تا دکمه همیشه پایین بماند.
  • متن‌های طولانی را با line-clamp کوتاه کنید؛ افزونه خلاصه را به 18 کلمه محدود می‌کند ولی قالب شما می‌تواند کمتر نشان دهد.

رفع مشکلات قالب

نشانهعلتراه‌حل
نتایج خالی‌اند و کارت پیش‌فرض می‌آیدقالب محتوای قابل‌مشاهده نساختهدر قالب از فیلدهای داینامیک استفاده کنید، نه متن ثابت خالی
ظاهر قالب بدون استایل استCSS قالب بارگذاری نشدهقالب را یک بار در ویرایشگر باز و ذخیره کنید تا CSS ساخته شود
عنصرها نامرئی می‌مانندکلاس elementor-invisibleافزونه آن را حذف می‌کند؛ اگر ماند، انیمیشن ورود را در قالب خاموش کنید
فقط اولین نتیجه درست استحلقه‌ی قالب به داده‌ی نتیجه وصل نیستاز ویجت‌های حلقه/داینامیک المنتور استفاده کنید
قالب در فهرست نیستوضعیت پیش‌نویسقالب را منتشر کنید

پرس‌وجو و فیلترها

پرس‌وجوی جستجو از دو لایه ساخته می‌شود: کنترل‌های ویجت (یا ویژگی‌های شورت‌کد) که بدون کدنویسی تنظیم می‌شوند، و فیلترهای PHP که اجازه می‌دهند کل کوئری را عوض کنید.

آرگومان‌های پایه‌ی کوئری

هر جستجو به یک WP_Query تبدیل می‌شود که این مقدارهای ثابت را دارد:

آرگومانمقدارچرا
sعبارت کاربرجستجوی اصلی وردپرس
post_typeمنبع انتخابیفقط همان نوع محتوا
post_statuspublishپیش‌نویس‌ها دیده نمی‌شوند
has_passwordfalseنوشته‌های رمزدار دیده نمی‌شوند
posts_per_pagelimit (1 تا 50)سقف نتایج
pagedmax( 1, page )صفحه‌بندی
no_found_rowspage < 1سبک‌تر شدن کوئری وقتی شمارش لازم نیست
ignore_sticky_poststrueترتیب نتایج به هم نریزد

فیلترهای بدون کدنویسی

فیلترپارامترمقدارهااثر روی کوئری
مرتب‌سازیorderbyrelevance, date, title, author, rand, menu_orderrelevance هیچ orderby اضافه نمی‌کند؛ menu_order به menu_order title تبدیل می‌شود
جهتorderASC / DESCفقط وقتی orderby غیر از relevance باشد
بازه‌ی تاریخdateall, week, month, yeardate_query با after و inclusive => true
رده/برچسبterms[taxonomy:]id با ویرگولtax_query با رابطه‌ی OR یا AND
شامل/استثناterms_opinclude / excludeجهت فیلتر رده‌ها
نوشته‌های چسبندهignore_stickyyes / noاگر no باشد، چسبنده‌ها به ابتدای نتایج منتقل می‌شوند
شناسه‌ی کوئریquery_idکلید سادهکلید فیلتر اختصاصی سمت سرور

ساختار tax_query

ترم‌ها بر اساس رده‌بندی گروه می‌شوند و یک tax_query ساخته می‌شود:

php
$tax_query = array( 'relation' => $include ? 'OR' : 'AND' );
foreach ( $grouped_terms as $taxonomy => $ids ) {
	$tax_query[] = array(
		'taxonomy' => $taxonomy,
		'field'    => 'term_id',
		'terms'    => $ids,
		'operator' => $include ? 'IN' : 'NOT IN',
	);
}

یعنی با terms_op="include" کافی است نتیجه در یکی از رده‌های داده‌شده باشد، و با terms_op="exclude" نتیجه باید از همه‌ی رده‌های داده‌شده بیرون باشد.

قالب terms

ورودیتفسیر
12رده‌ی پیش‌فرض (category) با شناسه‌ی 12
category:12همان مورد، صریح
post_tag:57,category:12دو فیلتر از دو رده‌بندی
category:abcنادیده گرفته می‌شود (شناسه باید عدد باشد)
private_tax:5نادیده گرفته می‌شود (فقط رده‌بندی عمومی)

فیلترهای سمت سرور

دو فیلتر روی آرگومان‌های کوئری اعمال می‌شوند، پیش از اجرای WP_Query:

php
$args = apply_filters( 'wgcr_search_query_args', $args, $query_id, $request );
if ( '' !== $query_id ) {
	$args = apply_filters( 'wgcr_search_query_args/' . $query_id, $args, $request );
}
فیلترچه زمانیورودی‌ها
wgcr_search_query_argsهمه‌ی جستجوها$args، $query_id، $request
wgcr_search_query_args/{query_id}فقط ویجت‌هایی با همان شناسه$args، $request

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

کجا بنویسیم

کد نمونه را در یک افزونه‌ی کوچک یا در functions.php پوسته‌ی فرزند بگذارید:

php
add_filter( 'wgcr_search_query_args/courses', function ( $args, $request ) {
	$args['meta_query'] = array(
		array(
			'key'     => 'course_level',
			'value'   => 'beginner',
			'compare' => '=',
		),
	);
	return $args;
}, 10, 2 );

و در ویجت (یا شورت‌کد) همان شناسه را بگذارید:

[wgcr_search source="course" query_id="courses" mode="page" columns="3"]

نمونه‌های کاربردی

محدود کردن به یک نویسنده:

php
add_filter( 'wgcr_search_query_args/team_blog', function ( $args ) {
	$args['author__in'] = array( 4, 17, 22 );
	return $args;
} );

جستجو در عنوان با وزن بیشتر:

php
add_filter( 'wgcr_search_query_args', function ( $args, $query_id, $request ) {
	if ( 'title' === $request->get_param( 'orderby' ) ) {
		$args['orderby'] = 'title';
		$args['order']   = 'ASC';
	}
	return $args;
}, 10, 3 );

حذف یک رده از همه‌ی جستجوها:

php
add_filter( 'wgcr_search_query_args', function ( $args ) {
	$args['tax_query']   = isset( $args['tax_query'] ) ? $args['tax_query'] : array();
	$args['tax_query'][] = array(
		'taxonomy' => 'category',
		'field'    => 'slug',
		'terms'    => array( 'internal' ),
		'operator' => 'NOT IN',
	);
	return $args;
} );

افزودن یک پست‌تایپ دوم:

php
add_filter( 'wgcr_search_query_args/library', function ( $args ) {
	$args['post_type'] = array( 'post', 'document' );
	return $args;
} );

نکات عملکرد

  • orderby="rand" روی محتواهای بزرگ کند است؛ برای فهرست‌های بلند از date استفاده کنید.
  • meta_query بدون ایندکس مناسب، جستجو را سنگین می‌کند؛ اگر تعداد نوشته‌ها زیاد است، کلید متا را ایندکس کنید.
  • date_query با inclusive => true ساخته می‌شود، پس «هفته» یعنی از همین لحظه هفت روز به عقب.
  • اگر به نوار شماره‌ی صفحه نیاز ندارید، page نفرستید تا no_found_rows فعال بماند و کوئری سبک‌تر شود.

صفحه‌بندی

صفحه‌بندی نتایج جستجو در بخش «صفحه‌بندی» ویجت تنظیم می‌شود و فقط وقتی دیده می‌شود که تعداد نتایج از «آیتم در هر برگه» بیشتر باشد.

چهار نوع صفحه‌بندی

نوعمقدار کنترلرفتارمناسب
هیچکدامnoneفقط یک صفحه نتیجههدر، جستجوی سریع
شماره‌هاnumbersنوار کامل با قبلی، بعدی، شماره‌ها و «صفحه X از Y»صفحه‌ی جستجوی اصلی
قبلی / بعدیprev_nextفقط دو دکمهفضاهای باریک
بارگذاری با کلیکload_on_clickدکمه‌ی «بارگذاری بیشتر» نتایج را اضافه می‌کندگرید محتوا
بارگذاری با اسکرولload_on_scrollبا رسیدن به انتها، خودکار اضافه می‌شودفهرست‌های طولانی

ساختار نوار صفحه‌بندی

html
<div class="wgcr-search-foot">
	<nav class="wgcr-search-pagination" aria-label="صفحه‌بندی نتایج">
		<button type="button" class="wgcr-search-page wgcr-search-page--prev">قبلی</button>
		<button type="button" class="wgcr-search-page" data-page="1">1</button>
		<button type="button" class="wgcr-search-page" data-page="2" aria-current="page">2</button>
		<span class="wgcr-search-page wgcr-search-page--gap" aria-hidden="true">…</span>
		<button type="button" class="wgcr-search-page" data-page="9">9</button>
		<button type="button" class="wgcr-search-page wgcr-search-page--next">بعدی</button>
		<span class="wgcr-search-page wgcr-search-page--info">صفحه 2 از 9</span>
	</nav>
	<button type="button" class="wgcr-search-more" aria-controls="wgcr-search-abc123-list" hidden>
		<span class="wgcr-search-more-icon" aria-hidden="true">…</span>
		<span class="wgcr-search-more-text">مشاهده مقالات بیشتر</span>
	</button>
	<div class="wgcr-search-nomore" role="status" hidden>نوشته‌ی بیشتری موجود نیست.</div>
</div>
کلاسنقش
.wgcr-search-paginationناوبری صفحه‌بندی با aria-label
.wgcr-search-page[data-page]دکمه‌ی شماره‌ی صفحه
.wgcr-search-page--prev و --nextدکمه‌های قبلی و بعدی
.wgcr-search-page--gapنقطه‌چین بین شماره‌ها (غیرقابل کلیک)
.wgcr-search-page--infoمتن «صفحه X از Y»
.wgcr-search-moreدکمه‌ی «بارگذاری بیشتر»
.wgcr-search-nomoreپیام پایان نتایج با role="status"

صفحه‌ی جاری با aria-current="page" نشانه‌گذاری می‌شود تا صفحه‌خوان آن را اعلام کند.

کنترل‌های مربوط

کنترلشناسهمقدار پیش‌فرضتوضیح
صفحه‌بندیpagination_typeهیچکدام (none)یکی از چهار نوع بالا
چیدمانpagination_alignوسط (center)واکنش‌گرا؛ فقط وقتی صفحه‌بندی فعال باشد
اسپیسرpagination_spacerبدون (no)کلاس wgcr-search--spacer را به ریشه اضافه می‌کند تا بالای صفحه‌بندی فاصله بگیرد
آیتم در هر برگهposts_per_page12در بخش «طرح‌بندی» (حالت صفحه)؛ 1 تا 50
متن دکمهbutton_text«مشاهده مقالات بیشتر»متن دکمه‌ی «بارگذاری بیشتر»؛ فقط «بارگذاری با کلیک»
آیکنbutton_iconنمایشآیکون شورون کنار متن دکمه
شناسه دکمهbutton_idخالیاگر پر شود، به‌عنوان id دکمه استفاده می‌شود
چیدمان پیامno_posts_alignوسط (center)چیدمان پیام پایان نتایج در هر دو نوع بارگذاری
پیام سفارشیcustom_messageخیربرای فعال‌کردن پیام دلخواه پایان نتایج
متن پیام سفارشیcustom_message_textخالیجایگزین «نوشته‌ی بیشتری موجود نیست.»

چطور تعداد صفحه‌ها محاسبه می‌شود

وقتی درخواست با پارامتر page فرستاده شود، سرور دو هدر برمی‌گرداند:

هدرمحتوا
X-WP-Totalتعداد کل نتایج (found_posts)
X-WP-TotalPagesتعداد کل صفحه‌ها (max_num_pages)

برای اینکه شمارش کل نتایج انجام شود، no_found_rows فقط وقتی page کمتر از 1 باشد روشن می‌شود؛ یعنی در درخواست‌های بدون صفحه‌بندی، کوئری سبک‌تر است و شمارش انجام نمی‌شود.

bash
curl -sI "https://example.com/wp-json/wgcr/v1/search?q=آموزش&limit=12&page=1" | grep -i x-wp
X-WP-Total: 47
X-WP-TotalPages: 4

پیمایش بی‌نهایت

در «بارگذاری با اسکرول»، یک عنصر دیده‌بان به نام .wgcr-search-sentinel بعد از آخرین نتیجه قرار می‌گیرد و با IntersectionObserver دیده می‌شود:

  • در حالت نمایش در صفحه، ملاک دیده‌شدن، پنجره‌ی مرورگر است.
  • در حالت لیست، ملاک، اسکرول داخل پنل نتایج است.
  • اگر IntersectionObserver در مرورگر موجود نباشد، بارگذاری خودکار انجام نمی‌شود ولی «بارگذاری با کلیک» و شماره‌ها کار می‌کنند.

هر بار که صفحه‌ی جدید می‌رسد، تا پایان رندر منتظر می‌ماند و سپس دیده‌بان دوباره فعال می‌شود؛ پس درخواست پشت‌سرهم و تکراری فرستاده نمی‌شود. وقتی صفحه‌ی آخر رسید، پیام پایان نتایج (role="status") نمایش داده می‌شود و دیده‌بان با aria-hidden از دسترس بیرون می‌رود.

رفتار کیبورد

کلیدرفتار
Tabبین فیلد، نتایج و دکمه‌های صفحه‌بندی جابه‌جا می‌شود
Enter روی دکمه‌ی صفحههمان صفحه بارگذاری می‌شود و فوکوس روی همان دکمه می‌ماند
Enter روی «بارگذاری بیشتر»نتایج بعدی اضافه می‌شوند
Escapeدر حالت لیست پنل بسته می‌شود؛ در حالت صفحه عبارت پاک می‌شود

پس از رندر صفحه‌ی جدید، فوکوس به دکمه‌ای برمی‌گردد که زده شده بود: قبلی، بعدی یا دکمه‌ی aria-current="page".

نکات عملکرد

  • آیتم در هر برگه را کوچک نگه دارید: مقدار 12 برای بیشتر سایت‌ها مناسب است؛ مقدار 50 در حالت لیست، پنل را طولانی و رندر را سنگین می‌کند.
  • شمارش کل نتایج هزینه دارد: اگر به نوار شماره‌ها نیاز ندارید، صفحه‌بندی را «هیچکدام» یا «بارگذاری با کلیک» بگذارید تا found_posts شمارش نشود.
  • کش سمت سرور: اگر پروکسی کش هدرهای X-WP-Total را حذف می‌کند، نوار شماره‌ها کامل ساخته نمی‌شود. مسیر /wp-json/ را از کش بیرون بگذارید.

انتخاب نوع صفحه‌بندی

وضعیت شمانوع مناسب
صفحه‌ی جستجو با نتایج زیادشماره‌ها
پنل باریک در سربرگ سایتقبلی/بعدی یا بارگذاری با کلیک
مرور فهرست طولانی بدون کلیکبارگذاری با اسکرول
تعداد کم و ثابت نتایجهیچکدام

استایل‌دهی نتایج

کنترل‌های مخصوص حالت «صفحه» فقط وقتی همان حالت انتخاب شده باشد نمایش داده می‌شوند. راهنمای کامل در صفحه‌ی استایل‌دهی.

ظاهر ویجت جستجو را می‌توانید از سه راه تغییر دهید: کنترل‌های استایل المنتور، متغیرهای CSS و بازنویسی کلاس‌ها. این صفحه هر سه را با نمونه‌کد توضیح می‌دهد.

متغیرهای CSS

افزونه چند متغیر CSS را روی ریشه‌ی هر .wgcr-search تعریف می‌کند. این متغیرها سراسری نیستند؛ مقدارهای پایه‌ی رنگ، کادر، گردی و تعداد ستون‌ها را برای همان ویجت فراهم می‌کنند و می‌توانید آن‌ها را روی ریشه‌ی یک نمونه بازنویسی کنید:

متغیرمقدار پیش‌فرضکاربرد
--wgcr-blue#2E86DEرنگ اصلی: حاشیه‌ی فوکوس، آیکون فعال، اسپینر
--wgcr-navy#1B5EA8حالت‌های تیره‌تر رنگ اصلی
--wgcr-ink#111827رنگ متن عنوان‌ها
--wgcr-slate#64748Bرنگ متن ثانویه (خلاصه، تاریخ، آیکون)
--wgcr-line#E2E8F0رنگ حاشیه‌ها
--wgcr-radius14pxگردی فیلد، پنل و کارت‌ها
--wgcr-search-cols1تعداد ستون‌ها در حالت «صفحه»

تغییر کل ظاهر با یک قطعه‌ی کوچک:

css
.wgcr-search {
	--wgcr-blue: #4f46e5;
	--wgcr-navy: #3730a3;
	--wgcr-ink: #0f172a;
	--wgcr-slate: #64748b;
	--wgcr-line: #e2e8f0;
	--wgcr-radius: 10px;
}

اگر می‌خواهید فقط یک ویجت خاص عوض شود، همان متغیرها را روی پوشش آن ویجت در المنتور بگذارید (کلاس CSS دلخواه در بخش «پیشرفته»).

کنترل‌های استایل المنتور

فیلد جستجو

کنترلانتخابگر هدف
رنگ متن.wgcr-search-input
رنگ متن راهنما.wgcr-search-input::placeholder
پس‌زمینه.wgcr-search-input
رنگ کادر (فوکوس).wgcr-search-input:focus
گردی گوشه‌ها.wgcr-search-input
پدینگ.wgcr-search-input
رنگ و اندازه‌ی آیکون.wgcr-search-icon

کادر نتایج

کنترلهدفشرط
پس‌زمینه.wgcr-search-panelهر دو حالت
گردی و پدینگ پنل.wgcr-search-panelهر دو حالت
عرض کانتینر.wgcr-search--page .wgcr-search-panelفقط حالت صفحه
حداقل / حداکثر ارتفاع.wgcr-search--page .wgcr-search-panelفقط حالت صفحه
فاصله‌ی بیرونی.wgcr-search--page .wgcr-search-panelفقط حالت صفحه
پس‌زمینه‌ی کانتینر.wgcr-search--page .wgcr-search-panelفقط حالت صفحه
تراز افقی.wgcr-search--page .wgcr-search-panelفقط حالت صفحه؛ پیش‌فرض justify

آیتم‌ها

کنترلهدف
رنگ عنوان.wgcr-search-title
پس‌زمینه‌ی آیتم فعال/هاور.wgcr-search-link:hover و .wgcr-search-item[aria-selected="true"] .wgcr-search-link
رنگ خلاصه.wgcr-search-excerpt
رنگ «نمایش همه».wgcr-search-all
رنگ «نمایش همه» (هاور).wgcr-search-all:hover

چیدمان ستونی، کاشی و ارتفاع برابر

کلاس ریشهاثر
.wgcr-search--pageپنل از حالت مطلق به static تغییر می‌کند و فهرست به شبکه‌ی CSS تبدیل می‌شود
.wgcr-search--cols-1 … --cols-6متغیر --wgcr-search-cols را تنظیم می‌کند
.wgcr-search--masonryفهرست از grid به columns تغییر می‌کند و هر آیتم break-inside: avoid می‌گیرد
.wgcr-search--equalalign-items: stretch روی فهرست و height: 100% روی لینک کارت
.wgcr-search--tplنتایج با قالب المنتور رندر شده‌اند
.wgcr-search--spacerفاصله‌ی اضافی پیش از ناحیه‌ی صفحه‌بندی
.wgcr-search.is-loadingاسپینر داخل فیلد دیده می‌شود

ستون‌ها واکنش‌گرا هستند؛ چون المنتور برای هر نقطه‌ی شکست یک مقدار جدا می‌سازد:

css
.wgcr-search--page .wgcr-search-list {
	display: grid;
	grid-template-columns: repeat(var(--wgcr-search-cols, 1), minmax(0, 1fr));
	gap: 4px 10px;
}

نمونه‌کدهای آماده

کارت با سایه‌ی نرم و لبه‌ی رنگی

css
.wgcr-search-item .wgcr-search-link {
	border: 1px solid var(--wgcr-line);
	border-radius: 12px;
	box-shadow: 0 1px 3px rgb(15 23 42 / 6%);
	transition: box-shadow .18s ease, transform .18s ease;
}
.wgcr-search-item .wgcr-search-link:hover {
	box-shadow: 0 10px 24px -8px rgb(15 23 42 / 22%);
	transform: translateY(-2px);
}

پنل تیره

css
.wgcr-search-panel {
	background: #0f172a;
	border-color: #1e293b;
	--wgcr-ink: #f8fafc;
	--wgcr-slate: #94a3b8;
}

پنل هم‌عرض با فیلد در حالت لیست

css
.wgcr-search-panel { inset-inline: 0; }
.wgcr-search--modal .wgcr-search-list { max-height: 60vh; }

حذف تصویر و چیدمان فشرده

css
.wgcr-search-thumb { display: none; }
.wgcr-search-body { gap: 2px; }
.wgcr-search-excerpt { display: none; }

نکات مهم

  • حرکت‌ها با @media (prefers-reduced-motion: reduce) غیرفعال می‌شوند؛ اگر انیمیشن دلخواه اضافه می‌کنید، همین الگو را رعایت کنید.
  • جهت متن از خود سایت می‌آید (inset-inline-start و inset-inline-end)، پس در حالت چپ‌به‌راست هم درست کار می‌کند و نیازی به بازنویسی RTL ندارید.
  • برچسب فیلد (.wgcr-search-label) به‌صورت بصری پنهان است ولی برای صفحه‌خوان خوانده می‌شود؛ آن را display:none نکنید.

ساختار خروجی

html
<div class="wgcr-search wgcr-search--modal" data-wgcr-search
	data-display-mode="modal" data-source="post" data-limit="12"
	data-thumb="yes" data-excerpt="yes" data-all="نمایش همه نتایج"
	data-template="0" data-query="…" data-pagination="none">
	<form class="wgcr-search-form" role="search" method="get" action="https://example.com/">
		<label class="wgcr-search-label" for="wgcr-search-abc123-input">جستجو در مقالات…</label>
		<div class="wgcr-search-field">
			<span class="wgcr-search-icon"><svg viewBox="0 0 24 24" aria-hidden="true">…</svg></span>
			<input type="search" class="wgcr-search-input" id="wgcr-search-abc123-input" name="s"
				placeholder="جستجو در مقالات…" autocomplete="off" role="combobox"
				aria-autocomplete="list" aria-expanded="false"
				aria-controls="wgcr-search-abc123-list" aria-haspopup="listbox">
			<input type="hidden" name="post_type" value="post">
			<span class="wgcr-search-spinner" aria-hidden="true"></span>
		</div>
		<div class="wgcr-search-panel" hidden>
			<ul class="wgcr-search-list" id="wgcr-search-abc123-list" role="listbox" aria-label="نتایج جستجو"></ul>
			<div class="wgcr-search-status" aria-live="polite"></div>
			<a class="wgcr-search-all" href="#" hidden>نمایش همه نتایج</a>
		</div>
	</form>
</div>

هر نتیجه یک li با کلاس wgcr-search-item و role="option" است:

html
<li class="wgcr-search-item" id="wgcr-search-abc123-opt-0" role="option" aria-selected="false">
	<a class="wgcr-search-link" href="https://example.com/?p=42">
		<img class="wgcr-search-thumb" src="…" alt="" width="150" height="150" loading="lazy">
		<span class="wgcr-search-body">
			<span class="wgcr-search-title">عنوان نوشته</span>
			<span class="wgcr-search-excerpt">خلاصه‌ی 18 کلمه‌ای…</span>
			<span class="wgcr-search-date">2026/09/26</span>
		</span>
	</a>
</li>
کلاسنقش
.wgcr-search-labelبرچسب فیلد (برای صفحه‌خوان؛ بصری پنهان است)
.wgcr-search-fieldجعبه‌ی فیلد، آیکون و اسپینر
.wgcr-search-spinnerنشانه‌ی «در حال دریافت»
.wgcr-search-panelپنل نتایج؛ در حالت لیست با hidden شروع می‌شود
.wgcr-search-listفهرست نتایج با role="listbox"
.wgcr-search-statusپیام وضعیت با aria-live="polite" (تعداد نتایج یا خطا)
.wgcr-search-allپیوند «نمایش همه نتایج» به جستجوی خود وردپرس
.wgcr-search-footناحیه‌ی صفحه‌بندی و دکمه‌ی «بارگذاری بیشتر»
.wgcr-search-nomoreپیام «نوشته‌ی بیشتری موجود نیست» با role="status"
.wgcr-search-item--tplنتیجه‌ای که با قالب المنتور رندر شده است
.wgcr-search-thumb--emptyجای خالی تصویر وقتی نوشته تصویر شاخص ندارد

پیکربندی جاوااسکریپت

پیش از فایل search.js، یک آبجکت پیکربندی به‌صورت درون‌خطی در صفحه چاپ می‌شود:

js
window.WGCRSearch = {
	restUrl: 'https://example.com/wp-json/wgcr/v1/search',
	homeUrl: 'https://example.com/',
	minChars: 2,
	maxResults: 50,
	i18n: {
		noResults: 'نتیجه‌ای یافت نشد.',
		found: 'نتیجه',
		error: 'خطا در دریافت نتایج.',
		prev: 'قبلی',
		next: 'بعدی',
		page: 'صفحه',
		pageOf: 'از'
	}
};
کلیدمعنا
restUrlنشانی مسیر جستجو، ساخته‌شده با rest_url()
homeUrlنشانی خانه‌ی سایت، برای فرم واقعی جستجو
minCharsکمترین طول عبارت پیش از ارسال درخواست (2)
maxResultsسقف سخت آیتم‌ها در هر صفحه (50)
i18nمتن‌های رابط، ترجمه‌شده به زبان سایت

رفتار سمت کاربر

رفتارمقدار
حداقل طول عبارت2 نویسه (minChars)
تأخیر پس از تایپ (debounce)250 میلی‌ثانیه
سقف نتایج در هر درخواست50 (WGCR_SEARCH_MAX_RESULTS)
لغو درخواست قبلیبا AbortController هنگام تایپ سریع
نقطه‌ی پایان/wp-json/wgcr/v1/search
پیمایش بی‌نهایتبا IntersectionObserver روی .wgcr-search-sentinel

جریان کار: کاربر تایپ می‌کند → 250 میلی‌ثانیه صبر می‌شود → اگر عبارت کمتر از 2 نویسه بود، پنل خالی و پاک می‌شود → در غیر این صورت درخواست قبلی لغو و درخواست جدید فرستاده می‌شود → نتایج رندر می‌شوند → پیام وضعیت («تعداد نتایج: N») برای صفحه‌خوان خوانده می‌شود.

کار بدون جاوااسکریپت

فرم ویجت یک فرم واقعی GET با action برابر خانه‌ی سایت، فیلد s و فیلد پنهان post_type است. یعنی اگر جاوااسکریپت غیرفعال باشد، ارسال فرم کاربر را به صفحه‌ی نتایج جستجوی خود وردپرس برای همان پست‌تایپ می‌برد. این همان الگویی است که برای دسترس‌پذیری و سئو توصیه می‌شود: پیشرفت تدریجی، نه وابستگی کامل به اسکریپت.

داده‌های روی ریشه‌ی ویجت

جاوااسکریپت تنظیمات را از همان ویژگی‌های data-* روی ریشه می‌خواند؛ پس اگر ویجت را با قالب‌های پویا یا کد PHP می‌سازید، این ویژگی‌ها را کامل بگذارید:

ویژگیمثال
data-wgcr-searchنشانه‌ی راه‌اندازی (بدون مقدار)
data-display-modemodal یا page
data-sourcepost، page، product …
data-limit12
data-thumbyes / no
data-excerptyes / no
data-allمتن پیوند «نمایش همه»
data-templateشناسه‌ی قالب المنتور یا 0
data-queryJSON فشرده‌ی orderby، order، date، terms، terms_op، ignore_sticky، query_id
data-paginationnone، numbers، prev_next، load_on_click، load_on_scroll

فهرست کامل کنترل‌ها

همه‌ی کنترل‌های محتوایی ویجت به ترتیب بخش‌های پنل. کنترل‌های استایل در بخش بالا فهرست شده‌اند.

شناسهبرچسب در پنلنوعپیش‌فرضشرط نمایش
display_modeحالت نمایش نتایجانتخابیmodal (حالت لیست)—
placeholderمتن راهنمامتنخالی (خودکار پر می‌شود)—
thumbنمایش تصویرکلیدبله—
excerptنمایش خلاصهکلیدبله—
all_textمتن «نمایش همه»متن«نمایش همه نتایج»—
template_modeانتخاب قالبانتخابیdefault—
templateیک قالب انتخاب کنیدانتخاب با جستجوخالیtemplate_mode = custom
edit_template_linkویرایش قالبHTML خام (پیوند)—template_mode = custom
columnsستون‌هاعدد واکنش‌گرا3 (تبلت 2، موبایل 1)display_mode = page
posts_per_pageآیتم در هر برگهعدد 1 تا 5012—
masonryکاشیکلیدخیرdisplay_mode = page
equal_heightارتفاع برابرکلیدخیرdisplay_mode = page و masonry خاموش
sourceمنبعانتخابیpost—
custom_typeپست‌تایپ سفارشیمتنخالیsource = custom
include_byشامل توسطانتخابیexclude—
include_termsدسته‌ها و برچسب‌هاانتخاب ترمخالی—
date_filterتاریخانتخابیall—
orderbyترتیب بر اساسانتخابیrelevance—
orderسفارشانتخابیDESCorderby برابر relevance یا rand نباشد
ignore_stickyنادیده گرفتن نوشته‌های چسبندهکلیدبلهsource = post
query_idکوئری IDمتنخالی—
pagination_typeصفحه‌بندیانتخابیnone—
pagination_alignچیدمانانتخابی واکنش‌گراcenterpagination_type برابر none نباشد
pagination_spacerاسپیسرانتخابی (با/بدون)nopagination_type برابر none نباشد
button_headingدکمهعنوان جداکننده—pagination_type = load_on_click
button_textمتن دکمهمتن«مشاهده مقالات بیشتر»pagination_type = load_on_click
button_iconآیکنانتخابی (نمایش/مخفی)yespagination_type = load_on_click
button_idشناسه دکمهمتنخالیpagination_type = load_on_click
no_posts_headingپیام نوشته‌های بیشتر موجود نیستعنوان جداکننده—load_on_click یا load_on_scroll
no_posts_alignچیدمان پیامانتخابی واکنش‌گراcenterload_on_click یا load_on_scroll
custom_messageپیام سفارشیکلیدخیرload_on_click یا load_on_scroll
custom_message_textمتن پیام سفارشیناحیه‌ی متنیخالیشرط بالا و custom_message = yes

رفع مشکلات

نشانهعلت احتمالیراه‌حل
با تایپ چیزی نمی‌آیدعبارت کمتر از 2 نویسهدو نویسه یا بیشتر تایپ کنید
پیام «خطا در دریافت نتایج»REST مسدود یا خطای سرورcurl روی /wp-json/wgcr/v1/search?q=test بزنید
نتایج تکراری می‌آینددو ویجت با «شناسه دکمه» یکسانشناسه‌ی یکتا بگذارید یا خالی بگذارید
تصویر نتایج خالی استنوشته تصویر شاخص نداردکلاس .wgcr-search-thumb--empty جای آن را پر می‌کند؛ یا کنترل «نمایش تصویر» را خاموش کنید
ستون‌ها اثر ندارندحالت نمایش روی لیست استحالت را به «نمایش در صفحه» تغییر دهید
در ویرایشگر کار می‌کند ولی در سایت نهکش صفحه یا بهینه‌ساز JSفایل search.js را از ترکیب/تأخیر خارج کنید