متد wpdb::get_results() یکی از پرکاربردترین ابزارهای وردپرس برای دریافت آرایه‌ای از ردیف‌های حاصل از یک کوئری SQL است. این متد در کنار get_var()، get_row() و get_col() یک خانواده کامل از توابع خواندن دیتابیس را تشکیل می‌دهد و در هر پروژه‌ای که به گزارش‌گیری یا خواندن داده اختصاصی نیاز دارد، پای ثابت کد است.

متد wpdb::get_results یکی از پرکاربردترین متدهای وردپرس برای دریافت آرایه نتایج کوئری است. این متد امکان تعیین شکل خروجی، استفاده از objects سفارشی و ترکیب با prepare را فراهم می‌کند و پایه گزارش‌گیری حرفه‌ای محسوب می‌شود. در این راهنما ساختار کامل، پارامترها، نمونه‌های واقعی، اشتباهات رایج و نکات امنیتی و عملکردی این متد بررسی می‌شود. همچنین تفاوت آن با get_row و get_var توضیح داده می‌شود. در پایان پرسش‌های پرتکرار و منظر مهندسی سطح بالای این متد مرور خواهد شد.

در خیلی از پروژه‌های واقعی، ابتدا یک کوئری با prepare ساخته می‌شود و بعد با get_results اجرا می‌شود. همین دو مرحله ساده، بیشترین حجم کدهای گزارش‌گیری، داشبوردهای مدیریتی و خروجی‌های سفارشی را تشکیل می‌دهند. اما همین الگوی ساده، ظرافت‌های مهمی دارد که بی‌توجهی به آن‌ها می‌تواند به باگ‌های پنهان یا افت کارایی منجر شود.

چرا wpdb::get_results اهمیت دارد

وردپرس ذاتاً یک CMS است و برای گزارش‌های پیچیده SQL در آن از پیش ساخته نشده است. با این حال، تعداد زیادی از افزونه‌های تحلیلی، سیستم‌های اعلان، پنل‌های مدیریتی و ابزارهای داده محور روی همین متد بنا شده‌اند. اگر شما هم به‌عنوان توسعه‌دهنده به جمع‌آوری داده از جدول‌های سفارشی نیاز دارید، این متد ابزار اصلی شما خواهد بود.

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

برای درک بهتر ساختار کوئری سفارشی، مطلب کدنویسی کوئری‌های سفارشی در وردپرس را از دست ندهید.

ساختار و امضای متد get_results

امضای این متد به شکل زیر است:

$wpdb->get_results( string $query = null, string $output = OBJECT ): array|object|null

پارامتر اول کوئری نهایی است که باید از قبل با prepare آماده شده باشد. پارامتر دوم شکل خروجی را مشخص می‌کند. مقدار پیش‌فرض OBJECT است و خروجی یک آرایه از اشیای stdClass خواهد بود. اگر کوئری نتیجه‌ای نداشته باشد، مقدار null یا آرایه خالی برگردانده می‌شود.

یک نکته مهم: اگر به هر دلیلی query string اشتباه باشد یا در حین اجرا خطایی رخ دهد، این متد مقدار null برمی‌گرداند. بنابراین همیشه نتیجه را بررسی کنید تا از خطاهای بعدی جلوگیری شود.

پارامتر output و انواع آن

پارامتر output یکی از مهم‌ترین قابلیت‌های این متد است. در حال حاضر چند مقدار معتبر دارد:

OBJECT

مقدار پیش‌فرض. یک آرایه از اشیای stdClass برمی‌گرداند. استفاده رایج و ساده‌ترین حالت:

$rows = $wpdb->get_results( $query, OBJECT );
foreach ( $rows as $row ) {
    echo esc_html( $row->user_email );
}

ARRAY_A

خروجی به‌صورت آرایه‌ای از آرایه‌های انجمنی برگردانده می‌شود. این حالت وقتی مفید است که بخواهید با توابع آرایه‌ای PHP مثل array_map کار کنید:

$rows = $wpdb->get_results( $query, ARRAY_A );
$emails = array_column( $rows, 'user_email' );

ARRAY_N

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

$rows = $wpdb->get_results( $query, ARRAY_N );

objects سفارشی

از نسخه‌های جدید وردپرس می‌توانید نام یک کلاس سفارشی را به‌عنوان output بدهید تا هر ردیف به یک instance از آن کلاس تبدیل شود:

class My_Order {
    public $id;
    public $total;
}
$rows = $wpdb->get_results( $query, 'My_Order' );

این قابلیت در پروژه‌های DDD (Domain Driven Design) بسیار کاربرد دارد، چون بلافاصله داده دیتابیس را به Domain Object تبدیل می‌کند.

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

نمونه‌های عملی در پروژه واقعی

در ادامه چند الگو که در پروژه‌های واقعی بارها به آن‌ها برخورده‌ام را مرور می‌کنیم:

گزارش سفارش‌های یک بازه زمانی

$from = '2025-01-01';
$to   = '2025-12-31';
$query = $wpdb->prepare(
    "SELECT ID, total, status
     FROM {$wpdb->prefix}orders
     WHERE created_at BETWEEN %s AND %s",
    $from, $to
);
$orders = $wpdb->get_results( $query );

استفاده از BETWEEN در کوئری بازه‌ای کارایی بهتری از ترکیب >= و <= دارد چون به بهینه‌ساز اجازه می‌دهد از ایندکس بازه‌ای استفاده کند.

دریافت بالاترین خریداران

$query = "
    SELECT user_id, SUM(total) AS spend
    FROM {$wpdb->prefix}orders
    GROUP BY user_id
    ORDER BY spend DESC
    LIMIT 10
";
$top = $wpdb->get_results( $query );

در این نوع کوئری‌ها حتماً روی ستون user_id ایندکس داشته باشید، وگرنه روی دیتابیس‌های بزرگ با اسکن کامل جدول مواجه می‌شوید.

گزارش کاربران با نقش خاص

اگر می‌خواهید کاربران را از جدول wp_users و wp_usermeta با JOIN دریافت کنید، به‌جای کوئری مستقیم شاید بهتر باشد از get_users() استفاده کنید. مطلب تابع get_users در وردپرس گزینه‌های سریع‌تر را معرفی می‌کند.

درج داده و سپس دریافت آن

پس از درج داده، گاهی نیاز دارید ردیف درج‌شده را دریافت کنید. استفاده ترکیبی از متد wpdb::insert و سپس get_results الگوی استانداردی است، اما توجه داشته باشید که $wpdb->insert_id سریع‌ترین راه برای دسترسی به ID رکورد جدید است.

به‌روزرسانی و بررسی نتیجه

در سناریوهایی که پس از به‌روزرسانی باید داده را بخوانید، می‌توانید از متد wpdb::update استفاده کنید و سپس با get_results نتیجه را تأیید کنید. برای حذف نیز الگوی مشابه با متد wpdb::delete پیاده می‌شود.

ترکیب با prepare

هیچ‌گاه کوئری حاوی متغیر کاربر را بدون prepare اجرا نکنید. مطلب متد wpdb::prepare در وردپرس جزئیات کامل این مرحله را پوشش می‌دهد.

تفاوت get_results با get_row و get_var و get_col

این چهار متد اغلب با هم اشتباه گرفته می‌شوند، درحالی‌که هرکدام کاربرد مشخصی دارند:

متدخروجیکاربرد
get_resultsآرایه ردیف‌هاگزارش‌های چندردیفی
get_rowیک شیء یا آرایهخواندن یک رکورد خاص
get_varیک مقدار سادهشمارش یا خواندن تک مقدار
get_colآرایه یک‌ستونیاستخراج یک ستون مشخص

در پروژه‌های واقعی، انتخاب درست بین این چهار متد می‌تواند تفاوت محسوسی در مصرف حافظه داشته باشد. برای کوئری‌ای که فقط یک مقدار شمارش می‌خواهد، استفاده از get_results هدررفت منابع است.

اشتباهات رایج در استفاده از get_results

در بررسی کدهای افزونه‌های مختلف این اشتباهات را زیاد دیده‌ام:

نبود prepare پیش از get_results

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

نبود بررسی خطا و خروجی null

اگر کوئری اشتباه باشد، get_results مقدار null برمی‌گرداند. اگر کد بعدی روی نتیجه foreach بزند، خطای PHP رخ می‌دهد. همیشه ابتدا با is_array() بررسی کنید.

نبود escape در خروجی HTML

داده‌ای که از دیتابیس می‌آید، ممکن است حاوی HTML یا JavaScript مخرب باشد. همیشه هنگام چاپ در HTML از esc_html() و در attribute از esc_attr() استفاده کنید.

نبود محدودیت در نتایج بزرگ

کوئری بدون LIMIT روی جدولی با میلیون‌ها ردیف، حافظه PHP را پر می‌کند. همیشه بازه نتیجه را محدود کنید یا از صفحه‌بندی استفاده کنید.

نبود تست روی حالت‌های مرزی

تست‌هایی مثل «جدول خالی»، «ردیف با مقادیر NULL» و «کوئری با یک ردیف» را حتماً بنویسید، چون این سناریوها همیشه در محیط تولید رخ می‌دهند.

امنیت و عملکرد در get_results

این متد به‌تنهایی هیچ امنیتی اضافه نمی‌کند و فقط داده را برمی‌گرداند. مسئولیت امنیت کاملاً به شما برمی‌گردد:

  • ورودی‌ها را با prepare امن کنید
  • خروجی‌ها را با esc_* escape کنید
  • سطح دسترسی کاربر را با current_user_can بررسی کنید
  • در endpoint‌های عمومی، نتایج حساس را فیلتر کنید

در مورد امنیت کوئری‌ها، مطلب SQL Injection Prevention در وردپرس مرجع اصلی محسوب می‌شود.

از نظر عملکرد، چند نکته کلیدی:

  1. حتماً روی ستون‌هایی که در WHERE و ORDER BY استفاده می‌کنید ایندکس بسازید
  2. نتایج را در Object Cache یا Transient ذخیره کنید
  3. در سایت‌های بزرگ از کش لایه‌ای استفاده کنید
  4. حجم نتایج را با LIMIT کنترل کنید
  5. برای الگوهای بهینه در اسنیپت‌های کوئری، مطلب قطعه کد بهینه‌سازی کوئری را ببینید.

    پرسش‌های پرتکرار درباره wpdb::get_results

    تفاوت get_results با get_row چیست؟

    get_row() فقط اولین ردیف نتیجه را برمی‌گرداند و برای خواندن یک رکورد خاص مناسب است. get_results() تمام ردیف‌ها را برمی‌گرداند.

    آیا می‌توان از get_results برای شمارش استفاده کرد؟

    از نظر فنی بله، اما بهینه نیست. برای شمارش از get_var() با کوئری SELECT COUNT(*) استفاده کنید.

    آیا می‌توان خروجی را با کلاس سفارشی دریافت کرد؟

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

    چرا get_results گاهی null برمی‌گرداند؟

    سه دلیل رایج: کوئری اشتباه، جدول ناموجود یا خطای اتصال. با $wpdb->last_error می‌توانید علت دقیق را ببینید.

    آیا می‌توان نتایج را کش کرد؟

    بله، بهترین روش ذخیره در Transient یا Object Cache با یک کلید مبتنی بر hash کوئری است. این الگو در پروژه‌های پربازدید تفاوت چشمگیری ایجاد می‌کند.

    منظر یک مهندس ارشد

    در سطح معماری، get_results() را نباید یک ابزار همه‌کاره در نظر گرفت. این متد در واقع یک wrapper نازک روی mysqli_query است و تمام هزینه‌های آماده‌سازی داده و ساخت اشیا در PHP پرداخت می‌شود. در گزارش‌های بسیار بزرگ، این هزینه به یک گلوگاه واقعی تبدیل می‌شود.

    راهکار استاندارد در سطح Enterprise این است که این کوئری‌ها به یک سرویس داده جداگانه منتقل شوند. حتی در پروژه‌های وردپرسی متوسط، اگر چند گزارش سنگین دارید، بهتر است نتایج را در یک جدول cache اختصاصی نگهداری کنید و در بازه‌های زمانی مشخص بازسازی کنید.

    نکته دوم در مورد استفاده از این متد در endpoint‌های REST است. هر بار که یک درخواست REST می‌آید، اجرای یک کوئری سنگین و serialize کردن نتیجه به JSON می‌تواند زمان پاسخ را از چند میلی‌ثانیه به چند صد میلی‌ثانیه برساند. در این حالت، کش سطح HTTP با هدرهای مناسب بسیار مؤثرتر از بهینه‌سازی خود کوئری است.

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

    اگر در پروژه‌ای با مشکل کندی یک گزارش بزرگ دست‌وپنجه نرم کرده‌اید و توانسته‌اید آن را حل کنید، برای من جالب است بدانید کدام راهکار (ایندکس، کش، بازطراحی کوئری) واقعاً اثرگذار بوده است. تجربه خود را در دیدگاه‌ها بنویسید تا برای توسعه‌دهندگان دیگر هم مفید باشد.