الدليل المتقدم لتحسين أداء WordPress
نشرت: 2022-03-11اليوم ، يعمل WordPress على تشغيل أكثر من 30٪ من الإنترنت. إنه سهل الاستخدام ، وشعبية بشكل لا يصدق ، ولن يذهب إلى أي مكان في أي وقت قريب.
لكن WordPress يمكن أن يكون بطيئًا. إذن كيف تقوم بتحسينه؟
هناك الكثير من المقالات حول كيفية ضبط وتحسين WordPress. في الواقع ، يوفر WordPress نفسه دليلًا قويًا حول تحسين WordPress.
بالنسبة للجزء الأكبر ، تغطي هذه المقالات والبرامج التعليمية مفاهيم أساسية ومفيدة جدًا ، مثل استخدام المكونات الإضافية لذاكرة التخزين المؤقت ، والتكامل مع شبكات توصيل المحتوى (CDNs) ، وتقليل الطلبات. على الرغم من أن هذه النصائح فعالة للغاية بل وضرورية ، إلا أنها في النهاية لا تعالج المشكلة الأساسية: معظم مواقع WordPress البطيئة ناتجة عن تعليمات برمجية سيئة أو غير فعالة.
لذلك ، تهدف هذه المقالة بشكل أساسي إلى تزويد المطورين وشركات تطوير WordPress ببعض الإرشادات التي يمكن أن تساعدهم في معالجة الأسباب الكامنة وراء العديد من مشكلات أداء WordPress.
يوفر WordPress العديد من الميزات الموجهة نحو الأداء والتي غالبًا ما يغفلها المطورون. يمكن أن تؤدي التعليمات البرمجية التي لا تستفيد من هذه الميزات إلى إبطاء أبسط المهام ، مثل جلب المشاركات. تتناول هذه المقالة بالتفصيل أربعة حلول ممكنة ، والتي تعالج بعض المشكلات الأساسية الكامنة وراء بطء أداء WordPress.
إحضار المشاركات
يوفر WordPress إمكانية جلب أي نوع من المنشورات من قاعدة البيانات. هناك ثلاث طرق أساسية للقيام بذلك:
استخدام
query_posts()
: هذا نهج مباشر للغاية ، ولكن المشكلة أنه يتجاوز الاستعلام الرئيسي ، مما قد يؤدي إلى حدوث بعض المضايقات. على سبيل المثال ، قد تكون هذه مشكلة إذا أردنا تحديد نوع الصفحة التي نتعامل معها في مرحلة ما بعد إحضار المنشورات (مثل داخلfooter.php
). في الواقع ، تحتوي الوثائق الرسمية على ملاحظة توصي بعدم استخدام هذه الوظيفة حيث ستحتاج إلى استدعاء وظيفة إضافية لاستعادة الاستعلام الأصلي. علاوة على ذلك ، فإن استبدال الاستعلام الرئيسي سيؤثر سلبًا على أوقات تحميل الصفحة.استخدام
get_posts()
: تعمل هذه الوظيفة تقريبًا مثلquery_posts()
، ولكنها لا تعدل الاستعلام الرئيسي. من ناحية أخرى ،get_posts()
افتراضيًا بتنفيذ الاستعلام مع تعيين معلمةsuppress_filters
على القيمة "true
". قد يؤدي هذا إلى تناقضات ، خاصةً إذا استخدمنا عوامل تصفية متعلقة بالاستعلام في التعليمات البرمجية الخاصة بنا ، حيث قد يتم إرجاع المشاركات التي لا تتوقعها في الصفحة بواسطة هذه الوظيفة.استخدام فئة
WP_Query
: في رأيي ، هذه هي أفضل طريقة لاسترداد المنشورات من قاعدة البيانات. لا يغير الاستعلام الرئيسي ، ويتم تنفيذه بطريقته القياسية ، تمامًا مثل أي استعلام WordPress آخر.
ولكن أيًا كانت الطريقة التي نستخدمها للتفاعل مع قاعدة البيانات ، فهناك أشياء أخرى نحتاج إلى وضعها في الاعتبار.
تقييد الاستعلام
يجب أن نحدد دائمًا عدد المشاركات التي يجب أن يجلبها استعلامنا.
من أجل تحقيق ذلك ، نستخدم المعامل posts_per_page
.
يتيح لنا WordPress الإشارة إلى -1 كقيمة محتملة لتلك المعلمة ، وفي هذه الحالة سيحاول النظام جلب جميع المشاركات التي تفي بالشروط المحددة.
هذه ليست ممارسة جيدة ، حتى لو كنا متأكدين من أننا سنحصل على نتائج قليلة فقط كاستجابة.
أولاً ، نادرًا ما يمكننا التأكد من استعادة بعض النتائج فقط. وحتى لو استطعنا ، فإن تعيين أي حد سيتطلب من محرك قاعدة البيانات مسح قاعدة البيانات بأكملها بحثًا عن التطابقات.
على العكس من ذلك ، غالبًا ما يؤدي تحديد النتائج إلى تمكين محرك قاعدة البيانات من مسح البيانات جزئيًا فقط ، مما يؤدي إلى تقليل وقت المعالجة والاستجابة الأسرع.
الشيء الآخر الذي يفعله WordPress افتراضيًا ، والذي يمكن أن يؤثر سلبًا على الأداء ، هو أنه يحاول جلب منشورات ثابتة وحساب عدد الصفوف التي تم العثور عليها في الاستعلام.
في كثير من الأحيان ، على الرغم من ذلك ، لا نحتاج حقًا إلى هذه المعلومات. ستؤدي إضافة هاتين المعلمتين إلى تعطيل هذه الميزات وتسريع استعلامنا:
$query = new WP_Query( array( 'ignore_sticky_posts' => true, 'no_found_rows' => true ) );
استبعاد المنشورات من الاستعلام
في بعض الأحيان نريد استبعاد بعض المنشورات من الاستعلام. يقدم WordPress طريقة مباشرة إلى حد ما لتحقيق ذلك: باستخدام المعلمة post__not_in
. علي سبيل المثال:
$posts_to_exclude = array( 1, 2, 3 ); $posts_per_page = 10; $query = new WP_Query( array( 'posts_per_page' => $posts_per_page, 'post__not_in' => $posts_to_exclude ) ); for ( $i = 0; $i < count( $query->posts ); $i++ ) { //do stuff with $query->posts[ $i ] }
ولكن على الرغم من أن هذا بسيط جدًا ، إلا أنه ليس مثاليًا لأنه ينشئ استعلامًا فرعيًا داخليًا. خاصة في التركيبات الكبيرة ، يمكن أن يؤدي ذلك إلى بطء الاستجابة. من الأسرع السماح بإجراء هذه المعالجة بواسطة مترجم PHP مع بعض التعديلات البسيطة:
$posts_to_exclude = array( 1, 2, 3 ); $posts_per_page = 10; $query = new WP_Query( array( 'posts_per_page' => $posts_per_page + count( $posts_to_exclude ) ) ); for ( $i = 0; $i < count( $query->posts ) && $i < $posts_per_page; $i++ ) { if ( ! in_array( $query->posts[ $i ]->ID, $posts_to_exclude ) ) { //do stuff with $query->posts[ $i ] } }
ماذا فعلت هناك؟
في الأساس ، قمت بإنهاء بعض الأعمال من محرك قاعدة البيانات وتركتها بدلاً من ذلك لمحرك PHP ، الذي يقوم بنفس الأشياء ولكن في الذاكرة ، وهو أسرع بكثير.
كيف؟
أولاً ، قمت بإزالة المعامل post__not_in
من الاستعلام.
نظرًا لأن الاستعلام قد يجلب لنا بعض المشاركات التي لا نريدها نتيجة لذلك ، فقد قمت بزيادة posts_per_page
. بهذه الطريقة أضمن أنه ، حتى لو كان لدي بعض المنشورات غير المرغوب فيها في إجابتي ، سيكون لدي على الأقل $posts_per_page
المطلوبة هناك.
بعد ذلك ، عندما أقوم بتكرار المشاركات ، أقوم فقط بمعالجة تلك التي ليست داخل مصفوفة $posts_to_exclude
.
تجنب المعاملات المعقدة
تقدم كل طرق الاستعلام هذه مجموعة متنوعة من الاحتمالات لجلب المنشورات: حسب الفئات ، أو المفاتيح الوصفية أو القيم ، أو التاريخ ، أو المؤلف ، إلخ.
وعلى الرغم من أن هذه المرونة ميزة قوية ، يجب استخدامها بحذر لأن هذه المعلمات يمكن أن تترجم إلى روابط جدول معقدة وعمليات قاعدة بيانات باهظة الثمن.
في القسم التالي ، سنحدد طريقة أنيقة للاستمرار في تحقيق وظائف مماثلة دون المساومة على الأداء.
الضغط على أقصى استفادة من خيارات WordPress
توفر واجهة برمجة تطبيقات WordPress Options سلسلة من الأدوات لتحميل البيانات أو حفظها بسهولة. إنه مفيد للتعامل مع أجزاء صغيرة من المعلومات ، حيث تكون الآليات الأخرى التي يقدمها WordPress (مثل المنشورات أو التصنيفات) معقدة للغاية.

على سبيل المثال ، إذا أردنا تخزين مفتاح مصادقة أو لون خلفية عنوان موقعنا ، فإن الخيارات هي ما نبحث عنه.
لا يمنحنا WordPress الوظائف اللازمة للتعامل معها فحسب ، بل يمكّننا أيضًا من القيام بذلك بأكثر الطرق فعالية.
يتم تحميل بعض الخيارات مباشرةً عند بدء تشغيل النظام ، مما يوفر لنا وصولاً أسرع (عند إنشاء خيار جديد ، نحتاج إلى التفكير فيما إذا كنا نريد تحميله تلقائيًا أم لا).
ضع في اعتبارك ، على سبيل المثال ، موقعًا نمتلك فيه دائرة عرض الأخبار العاجلة المحددة في النهاية الخلفية. ستكون غريزتنا الأولى هي استخدام مفتاح التعريف لذلك على النحو التالي:
// functions.php add_action( 'save_post', function ( $post_id ) { // For simplicity, we do not include all the required validation before saving // the meta key: checking nonces, checking post type and status, checking // it is not a revision or an autosaving, etc. update_post_meta( $post_id, 'is_breaking_news', ! empty ( $_POST['is_breaking_news'] ) ); } ); // front-page.php $query = new WP_Query( array( 'posts_per_page' => 1, 'meta_key' => 'is_breaking_news' ) ); $breaking_news = $query->posts[0] ?: NULL;
كما ترى ، هذا النهج بسيط للغاية ، لكنه ليس الأمثل. سيقوم بإجراء استعلام قاعدة بيانات يحاول العثور على منشور بمفتاح تعريف محدد. يمكننا استخدام خيار لتحقيق نتيجة مماثلة:
// functions.php add_action( 'save_post', function ( $post_id ) { // Same comment for post validation if ( ! empty ( $_POST['is_breaking_news'] ) ) update_option( 'breaking_news_id', $post_id ); } ); // front-page.php if ( $breaking_news_id = get_option( 'breaking_news_id' ) ) $breaking_news = get_post( $breaking_news_id ); else $breaking_news = NULL;
تختلف الوظيفة قليلاً من مثال إلى آخر.
في الجزء الأول من الكود ، سنحصل دائمًا على آخر الأخبار العاجلة ، من حيث تاريخ نشر المنشور.
في المنشور الثاني ، في كل مرة يتم فيها تعيين منشور جديد كأخبار عاجلة ، سيتم استبدال الأخبار العاجلة السابقة.
ولكن نظرًا لأننا ربما نريد منشورًا إخباريًا عاجلاً واحدًا في كل مرة ، فلا ينبغي أن يكون ذلك مشكلة.
وفي النهاية ، قمنا بتغيير استعلام قاعدة بيانات ثقيل (باستخدام WP_Query
مع مفاتيح التعريف) إلى استعلام بسيط ومباشر (استدعاء get_post()
) وهو نهج أفضل وأكثر كفاءة.
يمكننا أيضًا إجراء تغيير بسيط ، واستخدام العابرين بدلاً من الخيارات.
يعمل العابرون بشكل مشابه ولكن يسمحون لنا بتحديد وقت انتهاء الصلاحية.
على سبيل المثال ، بالنسبة للأخبار العاجلة ، فهي مناسبة تمامًا لأننا لا نريد منشورًا قديمًا كأخبار عاجلة ، وإذا تركنا مهمة تغيير هذه الأخبار العاجلة أو حذفها للمسؤول ، فقد ينسى ذلك هو - هي. لذلك ، من خلال تغييرين بسيطين ، نضيف تاريخ انتهاء الصلاحية:
// functions.php add_action( 'save_post', function ( $post_id ) { // Same comment for post validation // Let's say we want that breaking news for one hour // (3600 = # of seconds in an hour). if ( ! empty ( $_POST['is_breaking_news'] ) ) set_transient( 'breaking_news_id', $post_id, 3600 ); } ); // front-page.php if ( $breaking_news_id = get_transient( 'breaking_news_id' ) ) $breaking_news = get_post( $breaking_news_id ); else $breaking_news = NULL;
تمكين التخزين المؤقت المستمر
يحتوي WordPress أصلاً على آلية تخزين مؤقت للكائن.
الخيارات ، على سبيل المثال ، يتم تخزينها مؤقتًا باستخدام تلك الآلية.
ولكن ، افتراضيًا ، لا يكون التخزين المؤقت دائمًا ، مما يعني أنه يستمر لمدة طلب واحد فقط. يتم تخزين جميع البيانات مؤقتًا في الذاكرة ، للوصول بشكل أسرع ، ولكنها متاحة فقط أثناء هذا الطلب.
يتطلب دعم التخزين المؤقت المستمر تثبيت مكون إضافي دائم لذاكرة التخزين المؤقت.
تأتي بعض المكونات الإضافية لذاكرة التخزين المؤقت ذات الصفحة الكاملة مع مكون إضافي دائم لذاكرة التخزين المؤقت (على سبيل المثال W3 Total Cache) ، لكن البعض الآخر لا يفعل ذلك ، ونحن بحاجة إلى تثبيته بشكل منفصل.
سيعتمد ذلك على بنية نظامنا الأساسي ، سواء كنا سنستخدم الملفات أو Memcached أو أي آلية أخرى لتخزين البيانات المخزنة مؤقتًا ، ولكن يجب أن نستفيد من هذه الميزة الرائعة.
قد يتساءل المرء: "إذا كانت هذه ميزة رائعة ، فلماذا لا يقوم WordPress بتمكينها افتراضيًا"؟
السبب الرئيسي هو أنه ، اعتمادًا على بنية النظام الأساسي الخاص بنا ، ستعمل بعض تقنيات ذاكرة التخزين المؤقت والبعض الآخر لن يعمل.
إذا استضفنا موقعنا في خادمنا الموزع ، على سبيل المثال ، يجب أن نستخدم نظام ذاكرة تخزين مؤقت خارجي ، (مثل خادم Memcached) ، ولكن إذا كان موقع الويب الخاص بنا موجودًا على خادم واحد ، فيمكننا توفير بعض المال ببساطة عن طريق استخدام نظام الملفات للتخزين المؤقت.
هناك شيء واحد يجب أن نأخذه في الاعتبار وهو انتهاء صلاحية ذاكرة التخزين المؤقت. هذا هو المأزق الأكثر شيوعًا للعمل مع التخزين المؤقت المستمر.
إذا لم نعالج هذه المشكلة بشكل صحيح ، فسيشتكي المستخدمون من أنهم لن يروا التغييرات التي أجروها أو أن التغييرات التي أجروها استغرقت وقتًا طويلاً لتطبيقها.
في بعض الأحيان سنجد أنفسنا نجري مفاضلات بين الأداء والديناميكية ، ولكن حتى مع هذه العقبات ، فإن التخزين المؤقت المستمر هو شيء يجب أن تستفيد منه كل تثبيتات WordPress تقريبًا.
AJAXing أسرع طريق
إذا احتجنا إلى التواصل عبر AJAX مع موقعنا على الويب ، فإن WordPress يقدم بعض التجريد في وقت معالجة الطلب على جانب الخادم.
على الرغم من أنه يمكن استخدام هذه الأساليب عند برمجة أدوات الواجهة الخلفية أو تقديم عمليات إرسال من الواجهة الأمامية ، إلا أنه يجب تجنبها إذا لم يكن ذلك ضروريًا تمامًا.
والسبب في ذلك هو أنه من أجل استخدام هذه الآليات ، فإننا ملزمون بتقديم طلب نشر لبعض الملفات الموجودة داخل مجلد wp-admin
. غالبية (إن لم يكن كل) إضافات التخزين المؤقت للصفحة الكاملة في WordPress لا تخزن طلبات النشر المؤقت ولا المكالمات إلى ملفات المسؤول.
على سبيل المثال ، إذا قمنا بتحميل المزيد من المنشورات ديناميكيًا عندما يقوم المستخدم بتمرير صفحتنا الرئيسية ، فسيكون من الأفضل الاتصال مباشرة ببعض الصفحات الأمامية الأخرى ، والتي ستحصل على فوائد التخزين المؤقت.
يمكننا بعد ذلك تحليل النتائج عبر JavaScript في المتصفح.
نعم ، نحن نرسل بيانات أكثر مما نحتاج إليه ، لكننا نفوز من حيث سرعة المعالجة ووقت الاستجابة.
تدمير فكرة أن WordPress بطيء فقط
هذه مجرد بعض النصائح التي يجب على المطورين مراعاتها عند البرمجة في WordPress.
في بعض الأحيان ، ننسى أن المكون الإضافي أو السمة الخاصة بنا قد تحتاج إلى التعايش مع المكونات الإضافية الأخرى ، أو أن موقعنا قد يتم تقديمه من قبل شركة استضافة تخدم مئات أو آلاف المواقع الأخرى بقاعدة بيانات مشتركة.
نحن نركز فقط على كيفية عمل المكون الإضافي وليس على كيفية تعامله مع هذه الوظيفة ، أو كيفية القيام بذلك بطريقة فعالة.
مما سبق ، يتضح أن الأسباب الجذرية لضعف الأداء في WordPress هي تعليمات برمجية سيئة وغير فعالة. ومع ذلك ، يوفر WordPress جميع الوظائف الضرورية من خلال واجهات برمجة التطبيقات المختلفة التي يمكن أن تساعدنا في إنشاء مكونات إضافية وسمات أكثر فاعلية دون المساس بسرعة النظام الأساسي ككل.