-
المساهمات
1406 -
تاريخ الانضمام
-
تاريخ آخر زيارة
-
عدد الأيام التي تصدر بها
63
نوع المحتوى
ريادة الأعمال
البرمجة
التصميم
DevOps
التسويق والمبيعات
العمل الحر
البرامج والتطبيقات
آخر التحديثات
قصص نجاح
أسئلة وأجوبة
كتب
دورات
كل منشورات العضو عبد اللطيف ايمش
-
من الطبيعي أن نرتكب نحن البشر أخطاءً، لكننا نصحح تلك الأخطاء بنفسنا، أي أننا نميل إلى التعلم من أخطائنا ولا نرتكب الخطأ نفسه مرتين؛ أغلبية الأخطاء التي أقع فيها عند تطوير مواقع ووردبريس تأتي من محاولتي لتقليل الوقت اللازم لإنشاء الميزات، لكن ينتهي المطاف بمَن يعتمد هذه الطريقة بألمٍ في الرأس وندمٍ على أخطائه؛ لكن التعلم من هفوات الآخرين أفضل من الوقوع بكثير من الأخطاء وتضييع الوقت. الخطأ الشائع الأول: عدم تفعيل ميزة التنقيح في ووردبريس لماذا علينا تفعيل ميزة التنقيح (debugging) عندما تعمل الشيفرة كما يجب؟ ميزة التنقيح هي ميزةٌ مدمجة في ووردبريس التي ستؤدي إلى إظهار الأخطاء والتحذيرات والملاحظات (عن الدوال المهملة [deprecated functions] …إلخ.). عندما تكون ميزة التنقيح معطلةً فقد لا تظهر التحذيرات أو الملاحظات المهمة، مما قد يؤدي إلى حدوث مشاكل مستقبلًا إن لم تتعامل مع تلك التحذيرات مباشرةً. ونريد أن تتوافق الشيفرات الجديدة مع بقية عناصر الموقع، لذا عند إضافتها إلى ووردبريس يجب فعل ذلك في بيئة تطويرية مُفعَّلةٌ فيها ميزة التنقيح (لكن احرص على تعطيل هذه الميزة قبل نشر الموقع وتحويله إلى بيئةٍ إنتاجيةٍ). عليك تعديل ملف wp-config.php الموجود في المجلد الرئيسي لووردبريس لتفعيل هذه الميزة، هذا جزءٌ من الملف: // Enable debugging define('WP_DEBUG', true); // Log all errors to a text file located at /wp-content/debug.log define('WP_DEBUG_LOG', true); // Don’t display error messages write them to the log file /wp-content/debug.log define('WP_DEBUG_DISPLAY', false); // Ensure all PHP errors are written to the log file and not displayed on screen @ini_set('display_errors', 0); لا تضم الشيفرة السابقة جميع خيارات الضبط التي يمكن تفعيلها، لكن الضبط السابق كافٍ عادةً لأغلبية الاحتياجات. الخطأ الشائع الثاني: إضافة السكربتات وأنماط CSS عبر wp_head أين الخطأ في إضافة السكربتات إلى قالب header؟ تتضمن ووردبريس مسبقًا عددًا كبيرًا من السكربتات المشهورة، ومع ذلك يأتي المطورون ويضيفون سكربتاتٍ جديدة باستخدام الخطّاف (hook) ذو الاسم wp_head. وهذا قد يؤدي إلى تحميل نفس السكربت عدِّة مرات لكن بإصدارات مختلفة. أتت عملية طلب تحميل السكربتات (enqueuing) لحل هذه الإشكالية، وهذه العملية تمثِّل الطريقة المثُلى لإضافة السكربتات وأنماط CSS إلى موقع ووردبريس. علينا استخدام هذه الطريقة لمنع التضاربات بين السكربتات التي تتطلّب الإضافات استخدامها، وللتعامل مع (ومن ثم تضمين) المكتبات المطلوبة من أحد السكربتات. يمكن استخدام هذه التقنية عبر الدالتين الموجودتين في ووردبريس wp_enqueue_script و wp_enqueue_style لطلب تحميل السكربتات وصفحات الأنماط (على التوالي وبالترتيب). الفرق الأساسي بين الدالتين السابقتين يمكن في أنَّ الدالة wp_enqueue_script تقبل معاملًا (parameter) إضافيًا الذي يسمح لنا بنقل مكان إضافة السكربت إلى أسفل الصفحة. wp_register_script( $handle, $src, $deps = array(), $ver = false, $in_footer = false ) wp_enqueue_script( $handle, $src = false, $deps = array(), $ver = false, $in_footer = false ) wp_register_style( $handle, $src, $deps = array(), $ver = false, $media = 'all' ) wp_enqueue_style( $handle, $src = false, $deps = array(), $ver = false, $media = 'all' ) إذا لم يكن السكربت ضروريًا لعرض محتوى الصفحة، فيمكننا نقله إلى أسفلها لكي تُحمَّل محتويات الصفحة بسرعة؛ يجدر بالذكر أنَّه من المستحسن تسجيل (register) السكربت أولًا قبل طلب تحميله، لأنَّ ذلك يسمح للمطورين الآخرين بإلغاء تسجيل السكربت عبر المرجعية (أي $handle) وذلك ضمن الإضافات التي يكتبونها، دون الحاجة إلى تعديل الشيفرات البرمجية لإضافتك. وعند تسجيل السكربت فيمكن ذكره ضمن مصفوفة الاعتماديات (أي $deps) عبر مرجعيته إن وَجَبَ تحميله قبل تضمين أحد السكربتات الأخرى التي طُلِبَ تحميلها، فعندئذٍ سيُحمَّل السكربت تلقائيًا قبل تحميل السكربت الآخر. الخطأ الشائع الثالث: تفادي استخدام القوالب الأبناء وتعديل ملفات ووردبريس الأساسية أنشِئ قالب ابن (child theme) دومًا إذا أدرتَ تعديل أحد القوالب، فبعض المطورين يجرون تعديلات على ملفات القالب الأب ثم يكتشفون أنَّ جميع تعديلاتهم قد ذهبت أدراج الرياح ولن يستطيعوا استعادتها بعد تحديث القالب. لإنشاء قالب ابن عليك وضع ملف style.css في مجلدٍ فرعي تابعٍ للقالب الابن الخاص بك، وبه المحتويات الآتية: /* Theme Name: Twenty Sixteen Child Theme URI: http://example.com/twenty-fifteen-child/ Description: Twenty Fifteen Child Theme Author: John Doe Author URI: http://example.com Template: twentysixteen Version: 1.0.0 License: GNU General Public License v2 or later License URI: http://www.gnu.org/licenses/gpl-2.0.html Tags: light, dark, two-columns, right-sidebar, responsive-layout, accessibility-ready Text Domain: twenty-sixteen-child */ الملف السابق هو مثالٌ عن إنشاء قالب ابن يعتمد على أحد قوالب ووردبريس المُضمَّنة فيها وهو Twenty Sixteen. أهم سطر في الشيفرة السابقة هو السطر الذي يحتوي على كلمة Template والتي يجب أن يُطابِق محتواه اسمَ مجلد القالب الأب. ينطبق نفس المبدأ على ملفات ووردبريس الأساسية: لا تختر الطريق السهل وتُعدِّل الملفات الأساسية. وإنما ابذل جهدًا قليلًا وأعد تعريف الدوال القابلة للتعديل فقط (تسمى Pluggable functions) واستعمل مرشِّحات ووردبريس لمنع الكتابة فوق تعديلاتك بعد تحديث نسخة ووردبريس. تسمح لك إعادة تعريف الدوال باستخدام شيفرات خاصة بك بدلًا من الدوال الأساسية، لكن خفَّ استعمال هذه الطريقة وأصبحنا نستخدم المُرشِّحات (filters) بدلًا منها. حيث يؤدي استخدام المرشحات إلى نفس الناتج، وستُضاف التعليمات البرمجية في نهاية دوال ووردبريس للسماح بتعديل مخرجاتها. إحدى الأشياء التي عليك الانتباه إليها هي إعادة تعريف الدوال ضمن عبارة شرطية if ( !function_exists() ) لاحتمال تعديل أكثر من إضافة لنفس الدالة، فبدون تلك العبارة الشرطية فسيحدث خطأٌ من النوع fetal. الخطأ الشائع الرابع: ضبط بعض القيم ضبطًا ثابتًا نستسهل عادةً إضافة قيمٍ ثابتةٍ (مثل روابط URL) في مكانٍ ما في الشيفرات التي نكتبها، لكن الوقت الذي سننفقه لمعرفة سبب حدوث المشاكل ناتجة عن القيم الثابتة ولتصحيح تلك المشاكل سيكون أكبر. وإذا استعملنا الدالة المناسبة لتوليد المسار المطلوب ديناميكيًا، فسنُبسِّط عملية صيانة وتنقيح الشيفرة. فمثلًا لو نقلتَ موقعك من بيئةٍ تطويريةٍ إلى بيئةٍ إنتاجيةٍ لكنك استخدمتَ روابط URL ثابتة في الشيفرات؛ فعندئذٍ ستُفاجَأ أنَّ موقعك لا يعمل. وهذا هو السبب وراء وجوب استخدامنا للدوال –كتلك المذكورة أدناه– لتوليد مسارات وروابط URL توليدًا ديناميكيًا: // الحصول على رابط القالب الابن الحالي stylesheet_directory_uri(); // الحصول على رابط القالب الأب get_template_directory_uri(); // الحصول على رابط الموقع الحالي site_url(); مثالٌ آخر عن مساوئ ضبط القيم ضبطًا ثابتًا يظهر جليًا عند كتابة طلبيات SQL مخصصة. فنحن نغيّر عادةً «السابقة» (prefix) التي تأتي قبل أسماء الجداول في قاعدة بيانات ووردبريس من wp_ إلى شيءٍ آخر مختلف مثل wp743_، فلو وضعنا اسم الجدول كقيمة ثابتة فلن تُنفَّذ الطلبيات إذا نقلنا ووردبريس إلى قاعدة بيانات أخرى، لأنَّ السابقة قد تختلف حينها. ولمنع حدوث هذه الإشكالية فيمكننا استعمال خاصيات الصنف wpdb: global $wpdb; $user_count = $wpdb->get_var( "SELECT COUNT(*) FROM $wpdb->users" ); لاحظ أنَّنا لم نستعمل القيمة wp_users مكان اسم الجدول، وإنما تركنا الأمر بيد ووردبريس. سيساعدنا استعمال هذه الخاصيات لتوليد أسماء صحيحة للجداول. الخطأ الشائع الخامس: عدم منع فهرسة موقعك من محركات البحث لماذا قد أرغب منع فهرسة محركات البحث لموقعي؟ أليس ذلك أمرًا جيدًا؟ حسنًا، عندما تطوِّر موقع ويب فلن ترغب بالسماح لمحركات البحث بفهرسة الموقع إلى أن تنتهي من بنائه وتختار بنية «الروابط الدائمة» (permalinks) المناسبة. إضافةً إلى أنَّك إذا كنتَ تطوِّر الموقع على خادوم آخر فلن ترغب بفهرسة محركات البحث لصفحات الموقع كي لا تمسي صفحات الموقع الإنتاجي وكأنها منسوخة من هذا الموقع! وعندما تتواجد أكثر من نسخة لنفس المحتوى، فسيصعب على محركات البحث تحديد ما هو المصدر الملائم أكثر لمطابقة عبارة البحث، وستعاقب محركات البحث عادةً المواقع ذات المحتوى المتماثل مما يؤدي إلى تقليل تقييم صفحتك في نتائج البحث. وكما هو ظاهر في الصورة الآتية، هنالك خيارٌ في صفحة «Reading Settings» (إعدادات القراءة) المُعَنوَن «Discourage search engines from indexing this site» (منع محركات البحث من أرشفة هذا الموقع) لكن لا تغفل عن الملاحظة الظاهر أسفل ذاك الخيار التي تقول أنَّ الأمر متروكٌ لمحركات البحث لكي تستجيب لطلبك بعدم فهرسة الموقع. ابقِ ببالك أنَّ محركات البحث لا تستجيب عادةً لهذا الطلب، ولذا إذا أردتَ منعًا حقيقيًا لمحركات البحث من فهرسة الموقع، فعدِّل ملف .htaccess وأضف السطر الآتي: Header set X-Robots-Tag "noindex, nofollow" الخطأ الشائع السادس: عدم التحقق من تفعيل إحدى الإضافات لماذا نتحقق أنَّ دالةً مرتبطةً بإحدى الإضافات موجودةٌ إذا كانت الإضافة مفعلةً دومًا؟ لكن ماذا لو كانت الإضافة مفعلةً بنسبة 99%، ماذا عن احتمال 1% أنَّ الإضافة معطلة؟ إذا حدث ذلك فمن المرجح أن يعرض موقعك رسائل خطأ، ولمنع ذلك يجب علينا أن نتأكَّد إن كانت الإضافة مفعلة قبل استدعاء إحدى دوالها. إذا كانت تلك الدالة مستدعاةً في «الواجهة الأمامية» (front-end)، فسنحتاج إلى تضمين ملف plugin.php لكي نستطيع استخدام الدالة is_plugin_active(): include_once( ABSPATH . 'wp-admin/includes/plugin.php' ); if ( is_plugin_active( 'plugin-folder/plugin-main-file.php' ) ) { // تنفيذ الشيفرات هنا } هذه الطريقة ناجعة وعملية، لكن هنالك بعض الحالات التي يغيّر فيها المطوِّر اسم مجلد الإضافة الرئيسي، لذا من الأفضل التحقق من وجود أحد الأصناف المُعرَّفة في الإضافة: if( class_exists( ‘WooCommerce’ ) ) { // إضافة WooCommerce مفعلة } من غير المرجح أن يُعدِّل المطورون أسماء الأصناف، لذا أفضِّلُ استخدام الطريقة الثانية. الخطأ الشائع السابع: تحميل الكثير من الموارد لماذا يجب أن ننتقي ما هي الموارد التي يجب تحميلها لصفحات الموقع؟ لا يوجد سببٌ منطقيٌ لتحميل السكربتات أو صفحات أنماط CSS التابعة لإضافةٍ معينةٍ إن لم تكن تلك الإضافة مستعملةً في الصفحة التي انتقل إليها المستخدم. يمكننا تقليل وقت تحميل الصفحة إذا حمّلنا الموارد الضرورية فقط، وبالتالي سيُحسِّن ذلك من تجربة المستخدم. خذ على سبيل المثال موقعًا يستعمل WooCommerce، حيث نحتاج إلى تحميل الإضافة في صفحات التسوق فقط، وفي هذه الحالة يمكننا حذف أيّة موارد غير ضرورية في صفحات الموقع الأخرى لتحسين الأداء. يمكننا إضافة الشيفرة الآتية إلى ملف functions.php للقالب أو للإضافة: function load_woo_scripts_styles(){ if( function_exists( 'is_woocommerce' ) ){ if(! is_woocommerce() && ! is_cart() && ! is_checkout() ) { // Dequeue scripts. wp_dequeue_script('woocommerce'); wp_dequeue_script('wc-add-to-cart'); wp_dequeue_script('wc-cart-fragments'); // Dequeue styles. wp_dequeue_style('woocommerce-general'); wp_dequeue_style('woocommerce-layout'); wp_dequeue_style('woocommerce-smallscreen'); } } } add_action( 'wp_enqueue_scripts', 'load_woo_scripts_styles'); يمكن حذف السكربتات عبر الدالة wp_dequeue_script($handle) باستخدام المرجعية التي سُجِّلَت فيها. وبشكلٍ شبيه، تمنع الدالة wp_dequeue_style($handle) تحميل صفحات الأنماط. لكن إن رأيتَ أنَّ ما سبق معقدٌ جدًا ولا تستطيع تنفيذه لبقية الإضافات، فأنصحك بتثبيت إضافة Plugin Organizer التي توفر لك القدرة على اختيار الإضافات التي ستُحمَّل مواردها بناءً على معايير معيّنة، مثل نوع المنشور أو اسمه. من الأفضل أيضًا تعطيل أيّة إضافات للتخزين المؤقت مثل W3Cache والتي فعّلتَها مسبقًا لإظهار التعديلات التي أجريتها. الخطأ الشائع الثامن: الإبقاء على شريط الإدارة لماذا لا أترك شريط الإدارة الموجود أعلى الصفحات ظاهرًا لجميع المستخدمين؟ حسنًا، يمكنك السماح لمستخدميك بالوصول إلى الصفحات الإدارية، لكن ذاك الشريط لن يندمج بشكلٍ جميل مع القالب المختار. إذا أردتَ أن يبدو موقعك احترافيًا، فعليك تعطيل شريط الإدارة وتوفير صفحة مخصصة لإدارة الحساب: add_action('after_setup_theme', 'remove_admin_bar'); function remove_admin_bar() { if (!current_user_can('administrator') && !is_admin()) { show_admin_bar(false); } } ستؤدي الشيفرة السابقة عند إضافتها إلى ملف functions.php (التابع للقالب الذي تستعمله) إلى إظهار شريط الإدارة لمدراء الموقع فقط. يمكنك إضافة أيّة أنواع من المستخدمين إلى دالة current_user_can($capability) في الشيفرة السابقة لعدم إخفاء الشريط لهم. الخطأ الشائع التاسع: عدم استخدام المرشِّح GetText أستطيع استخدام CSS أو JavaScript لتغيير لافتة أحد الأزرار، ما المانع؟ حسنًا، أنت تضيف شيفرات عجيبة وتضيع وقتك سدى لتغيير تلك اللافتة، في حين يمكنك استعمال أحد أجمل المرشِّحات في ووردبريس المدعو gettext. وعند استخدامه مع textdomain التابع للإضافة (وهو مُعرِّف فريد الذي يضمن أن تستطيع ووردبريس التفريق بين جميع الترجمات المتوافرة)، فيمكننا حينها استعمال المرشح gettext لتعديل النص قبل توليد الصفحة. إذا بحثت في الشيفرة المصدرية عن الدالة load_plugin_textdomain($domain)فستجد اسم المجال (domain name) الذي ستحتاج له لتعديل النص. جميع الإضافات الاحترافية تضبط textdomain أثناء تهيئة الإضافة. أما إذا كان لديك نصٌ ما ضمن قالب وكنت تريد تغييره، فابحث عن load_theme_textdomain($domain). سنستعمل هنا إضافة WooCommerce مرةً أخرى كمثال، يمكننا تغيير النص الظاهر لترويسة «Related Products» بإضافة الشيفرة الآتية في ملف functions.php في قالبك: function translate_string( $translated_text, $untranslated_text, $domain ) { if ( $translated_text == 'Related Products') { $translated_text = __( 'Other Great Products', 'woocommerce' ); } return $translated_text; } add_filter( 'gettext', 'translate_string', 15, 3 ); سيُطبَّق المرشِّح السابق على النص المُترجَم عبر دوال __() و _e()، لطالما كان مجال النص (textdomain) مضبوطٌ ضبطًا صحيحًا أثناء استخدام تلك الدوال: _e( 'Related Products', 'woocommerce' ); ابحث في إضافتك عن دوال ترجمة النص لمعرفة ما هي السلاسل النصية التي يمكنك تخصيصها. الخطأ الشائع العاشر: الإبقاء على بنية الروابط الدائمة الافتراضية تستخدم ووردبريس افتراضيًا بنية روابط دائمة (permalinks) تتضمن مُعرِّف (ID) المنشور لإظهار محتوى معيّن، لكن هذه البنية ليست جميلة ومستحيلة القراءة، وقد يحذف الزوار أجزاءً مهمةً من روابط URL أثناء نسخها. وأهم ما في الأمر أنَّ الروابط الدائمة الافتراضية ليست «صديقةً» لمحركات البحث. وتفعيل ما ندعوه «الروابط الدائمة الجميلة» سيؤدي إلى تضمين كلمات مفتاحية واسم المنشور في روابط URL مما يُحسِّن من تقييم محركات البحث لموقعنا. يمكن أن يكون تغيير بنية الروابط مهمةً شاقةً خصوصًا إذا كان موقعك يعمل منذ فترةٍ طويلةٍ ولديك مئات المنشورات التي تمت فهرستها من محركات البحث. لذا بعد أن تثبِّت ووردبريس فاحرص على تعديل بنية الروابط الدائمة ليستطيع الزائر معرفة محتوى الصفحة من رابطها بدلًا من عرض معرِّف المنشور فقط. عمومًا أستخدمُ اسم المنشور في الروابط الدائمة لأغلبية المواقع التي أبنيها، لكن يمكننا تخصيص الروابط الدائمة كيفما شئت، انظر إلى مقالة «الدليل الشامل للروابط الدائمة في ووردبريس». الخلاصة لم تضم هذه المقالة جميع الأخطاء التي يرتكبها مطورو ووردبريس (حتى الخبراء منهم)، الفكرة الأساسية التي عليك أن تفهمها من هذه المقالة هي أنَّك عليك ألّا تأخذ الطرق المختصرة (وهذه القاعدة تنطبق أيضًا على جميع منصات التطوير، ولا أقصد بها ووردبريس بعينها). الوقت الذي توفره باتباعك للأساليب البرمجية الضعيفة ستنفق أضعافه وأنت تحاول إصلاح المشاكل التي ستواجهك مستقبلًا. شاركنا بعض الأخطاء التي كنت تقع فيها وأخبرنا ما هي الدروس التي تعلمتها منها في التعليقات. ترجمة –وبتصرّف– للمقال The 10 Most Common Mistakes That WordPress Developers Make لصاحبه Andrew Schultz
-
سنشرح في هذه الدرس كيفية تقليل عدد السجلات المُعادة من طلبية SELECT، وطريقة ترتيب الناتج بناءً على شرطٍ معيّن. إضافةً إلى ما سبق، سنتعلم كيفية تجميع السجلات وإجراء عمليات حسابية أساسية على الحقول الرقمية، وكل ما سبق سيساعدنا على إنشاء سكربت SQL الذي سنستخدمه لإنشاء تقارير مفيدة. إذا لم تكن لديك خلفية جيّدة حول قواعد بيانات MySQL فأنصحك بقراءة هذا الدّرس أوّلا المتطلبات المسبقة عليك اتباع الخطوات الآتية قبل المتابعة: نزِّل قاعدة بيانات employees، التي تحتوي على ستة جداول تتضمن حوالي 4 ملايين سجل إجماليًا: # wget https://launchpad.net/test-db/employees-db-1/1.0.6/+download/employees_db-full-1.0.6.tar.bz2 # tar xjf employees_db-full-1.0.6.tar.bz2 # cd employees_db ادخل إلى مِحَث MariaDB وأنشِئ قاعدة بيانات باسم employees: # mysql -u root -p Enter password: Welcome to the MariaDB monitor. Commands end with ; or \g. Your MariaDB connection id is 2 Server version: 10.1.14-MariaDB MariaDB Server Copyright (c) 2000, 2016, Oracle, MariaDB Corporation Ab and others. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. MariaDB [(none)]> CREATE DATABASE employees; Query OK, 1 row affected (0.00 sec) استورد قاعدة البيانات إلى خادوم MairaDB كالآتي: MariaDB [(none)]> source employees.sql انتظر دقيقةً أو دقيقتين إلى أن ينتهي استيراد قاعدة البيانات (أبقِ في بالك أننا نتحدث هنا عن أربعة ملايين سجل!). تأكد من أنَّ استيراد قاعدة البيانات قد تمَّ بشكلٍ صحيح بعرض جداولها: MariaDB [employees]> USE employees; Database changed MariaDB [employees]> SHOW TABLES; +---------------------+ | Tables_in_employees | +---------------------+ | departments | | dept_emp | | dept_manager | | employees | | salaries | | titles | +---------------------+ 6 rows in set (0.02 sec) أنشِئ حسابًا مخصصًا لاستخدام قاعدة بيانات employees (اختر اسمًا وكلمة مرور): MariaDB [employees]> CREATE USER empadmin@localhost IDENTIFIED BY 'empadminpass'; Query OK, 0 rows affected (0.03 sec) MariaDB [employees]> GRANT ALL PRIVILEGES ON employees.* to empadmin@localhost; Query OK, 0 rows affected (0.02 sec) MariaDB [employees]> FLUSH PRIVILEGES; Query OK, 0 rows affected (0.00 sec) MariaDB [employees]> exit Bye سجِّل دخولك الآن إلى مِحَث MariaDB بالمستخدم empadmin: # mysql -u empadmin -p Enter password: Welcome to the MariaDB monitor. Commands end with ; or \g. Your MariaDB connection id is 4 Server version: 10.1.14-MariaDB MariaDB Server Copyright (c) 2000, 2016, Oracle, MariaDB Corporation Ab and others. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. MariaDB [(none)]> USE employees; Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A Database changed احرص على تنفيذ جميع الخطوات الست السابقة قبل إكمالك لقراءة هذا الدرس. ترتيب وتقليل عدد السجلات المعروضة جدول الرواتب salaries يحتوي على جميع واردات كل موظف مع تاريخ البداية والنهاية. ربما تود أن تعرض رواتب الموظف emp_no=10001 خلال فترةٍ من الزمن. وهذا سيساعدك على الإجابة عن التساؤلات الآتية: هل حصل على زيادة في راتبه؟ إذا حدث ذلك، فمتى؟ نفِّذ الأمر الآتي لمعرفة ذلك: MariaDB [employees]> SELECT * FROM salaries WHERE emp_no=10001 ORDER BY from_date; +--------+--------+------------+------------+ | emp_no | salary | from_date | to_date | +--------+--------+------------+------------+ | 10001 | 60117 | 1986-06-26 | 1987-06-26 | | 10001 | 62102 | 1987-06-26 | 1988-06-25 | | 10001 | 66074 | 1988-06-25 | 1989-06-25 | | 10001 | 66596 | 1989-06-25 | 1990-06-25 | | 10001 | 66961 | 1990-06-25 | 1991-06-25 | | 10001 | 71046 | 1991-06-25 | 1992-06-24 | | 10001 | 74333 | 1992-06-24 | 1993-06-24 | | 10001 | 75286 | 1993-06-24 | 1994-06-24 | | 10001 | 75994 | 1994-06-24 | 1995-06-24 | | 10001 | 76884 | 1995-06-24 | 1996-06-23 | | 10001 | 80013 | 1996-06-23 | 1997-06-23 | | 10001 | 81025 | 1997-06-23 | 1998-06-23 | | 10001 | 81097 | 1998-06-23 | 1999-06-23 | | 10001 | 84917 | 1999-06-23 | 2000-06-22 | | 10001 | 85112 | 2000-06-22 | 2001-06-22 | | 10001 | 85097 | 2001-06-22 | 2002-06-22 | | 10001 | 88958 | 2002-06-22 | 9999-01-01 | +--------+--------+------------+------------+ 17 rows in set (0.03 sec) لكن ماذا لو أردنا معرفة آخر خمس زيادات؟ يمكننا أن نستخدم ORDER BY form_date DESC. تُشير الكلمة المحجوزة DESC إلى أنَّ الترتيب الذي نريد اتباعه هو الترتيب التنازلي. إضافةً إلى ما سبق، يسمح لنا التعبير LIMIT 5 بإعادة أوّل خمسة سجلات: MariaDB [employees]> SELECT * FROM salaries WHERE emp_no=10001 ORDER BY from_date DESC LIMIT 5; +--------+--------+------------+------------+ | emp_no | salary | from_date | to_date | +--------+--------+------------+------------+ | 10001 | 88958 | 2002-06-22 | 9999-01-01 | | 10001 | 85097 | 2001-06-22 | 2002-06-22 | | 10001 | 85112 | 2000-06-22 | 2001-06-22 | | 10001 | 84917 | 1999-06-23 | 2000-06-22 | | 10001 | 81097 | 1998-06-23 | 1999-06-23 | +--------+--------+------------+------------+ 5 rows in set (0.00 sec) يمكنك أيضًا استخدام ORDER BY على عدِّة حقول، فمثلًا ستُرتِّب الطلبية الآتية النتائج اعتمادًا على تاريخ ولادة الموظف تصاعديًا (وهو الترتيب الافتراضي) ثم عبر اسم الموظف الأخير بترتيبٍ هجائيٍ تنازلي: MariaDB [employees]> SELECT CONCAT(last_name, ', ', first_name) AS Name, gender AS Gender, hire_date AS "Hire date" FROM employees ORDER BY birth_date, last_name DESC LIMIT 10; +--------------------+--------+------------+ | Name | Gender | Hire date | +--------------------+--------+------------+ | Whitcomb, Kiyokazu | M | 1988-07-26 | | Schaad, Ronghao | M | 1988-07-10 | | Remmele, Supot | M | 1989-01-27 | | Pocchiola, Jouni | M | 1985-03-10 | | Kuzuoka, Eishiro | M | 1992-02-12 | | Decaestecker, Moni | M | 1986-10-06 | | Wiegley, Mircea | M | 1985-07-18 | | Vendrig, Sachar | M | 1985-11-04 | | Tsukuda, Cedric | F | 1993-12-12 | | Tischendorf, Percy | M | 1986-11-10 | +--------------------+--------+------------+ 10 rows in set (0.31 sec) يمكنك معرفة المزيد من المعلومات عن LIMIT في الدليل الرسمي. تجميع السجلات، واستخدام MAX و MIN و AVG و ROUND كما ذكرنا سابقًا، الجدول salaries يحتوي على رواتب الموظفين خلال فترات زمنية، وبجانب استخدام LIMIT، يمكننا استخدام الكلمتين المحجوزتين MAX و MIN لتحديد متى كان أعلى راتب وأدنى راتب لموظفين معينين: MariaDB [employees]> SELECT CONCAT(last_name, ', ', first_name) AS Name, MAX(B.salary) AS "Max. salary" FROM employees A JOIN salaries B ON A.emp_no = B.emp_no WHERE A.emp_no IN (10001, 10002, 10003) GROUP BY A.emp_no; +-----------------+-------------+ | Name | Max. salary | +-----------------+-------------+ | Facello, Georgi | 88958 | | Simmel, Bezalel | 72527 | | Bamford, Parto | 43699 | +-----------------+-------------+ 3 rows in set (0.02 sec) MariaDB [employees]> SELECT CONCAT(last_name, ', ', first_name) AS Name, MIN(B.salary) AS "Min. salary" FROM employees A JOIN salaries B ON A.emp_no = B.emp_no WHERE A.emp_no IN (10001, 10002, 10003) GROUP BY A.emp_no; +-----------------+-------------+ | Name | Min. salary | +-----------------+-------------+ | Facello, Georgi | 60117 | | Simmel, Bezalel | 65828 | | Bamford, Parto | 40006 | +-----------------+-------------+ 3 rows in set (0.00 sec) وبناءً على النتائج السابقة، هل تستطيع أن تعرف ماهو ناتج الطلبية الآتية: MariaDB [employees]> SELECT CONCAT(last_name, ', ', first_name) AS Name, ROUND(AVG(B.salary), 2) AS "Avg. salary" FROM employees A JOIN salaries B ON A.emp_no = B.emp_no WHERE A.emp_no IN (10001, 10002, 10003) GROUP BY A.emp_no; +-----------------+-------------+ | Name | Avg. salary | +-----------------+-------------+ | Facello, Georgi | 75388.94 | | Simmel, Bezalel | 68854.50 | | Bamford, Parto | 43030.29 | +-----------------+-------------+ 3 rows in set (0.01 sec) إذا توقعتَ أنَّ الناتج هو المتوسط الحسابي (عبر AVG) للراتب مقرّبًا إلى منزلتين عشريتين (عبر ROUND)، فأنت مصيب. إذا أردنا أن نعرف مجموع رواتب الموظفين وإعادة أوّل خمسة، فيمكننا حينها استعمال الطلبية الآتية: MariaDB [employees]> SELECT emp_no, SUM(salary) AS Salary FROM salaries GROUP BY emp_no ORDER BY Salary DESC LIMIT 5; +--------+---------+ | emp_no | Salary | +--------+---------+ | 109334 | 2553036 | | 43624 | 2492873 | | 66793 | 2383923 | | 237542 | 2381119 | | 47978 | 2374024 | +--------+---------+ 5 rows in set (2.22 sec) جمّعنا الرواتب في الطلبية السابقة عبر الموظف، ثم أجرينا عليها عملية SUM. تجميع المعلومات السابقة في سكربت لحسن الحظ، لا نحتاج إلى تشغيل طلبية تلو أخرى لإنشاء تقرير، وإنما نستطيع إنشاء سكربت فيه سلسلة من تعليمات SQL التي تُعيد جميع النتائج المطلوبة. بعد تنفيذ السكربت، فستظهر جميع النتائج دون تدخل منا، ولنسمِّ الملف باسم maxminavg.sql في مجلد العمل الحالي وفيه المحتويات الآتية: --Select database USE employees; --Calculate maximum salaries SELECT CONCAT(last_name, ', ', first_name) AS Name, MAX(B.salary) AS "Max. salary" FROM employees A JOIN salaries B ON A.emp_no = B.emp_no WHERE A.emp_no IN (10001, 10002, 10003) GROUP BY A.emp_no; --Calculate minimum salaries SELECT CONCAT(last_name, ', ', first_name) AS Name, MIN(B.salary) AS "Min. salary" FROM employees A JOIN salaries B ON A.emp_no = B.emp_no WHERE A.emp_no IN (10001, 10002, 10003) GROUP BY A.emp_no; --Calculate averages, round to 2 decimal places SELECT CONCAT(last_name, ', ', first_name) AS Name, ROUND(AVG(B.salary), 2) AS "Avg. salary" FROM employees A JOIN salaries B ON A.emp_no = B.emp_no WHERE A.emp_no IN (10001, 10002, 10003) GROUP BY A.emp_no; الأسطر التي تبدأ بشرطتين -- هي تعليقات وسيتم تجاهلها. وستُنفَّذ الطلبيات تلو بعضها. ويمكننا تنفيذ هذا السكربت إما من سطر أوامر لينكس: # mysql -u empadmin -p < maxminavg.sql Enter password: Name Max. salary Facello, Georgi 88958 Simmel, Bezalel 72527 Bamford, Parto 43699 Name Min. salary Facello, Georgi 60117 Simmel, Bezalel 65828 Bamford, Parto 40006 Name Avg. salary Facello, Georgi 75388.94 Simmel, Bezalel 68854.50 Bamford, Parto 43030.29 أو من مِحث MariaDB: # mysql -u empadmin -p Enter password: Welcome to the MariaDB monitor. Commands end with ; or \g. Your MariaDB connection id is 4 Server version: 10.1.14-MariaDB MariaDB Server Copyright (c) 2000, 2016, Oracle, MariaDB Corporation Ab and others. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. MariaDB [(none)]> source maxminavg.sql Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A Database changed الخلاصة شرحنا في هذه المقالة كيفية استخدام عدِّة دوال في MariaDB لتحسين النتائج التي يُخرجها الاستعلام SELECT. وبعد أن تكتب الاستعلامات لأول مرة، فيمكنك بكل بساطة وضعها داخل سكربت وتنفيذها بسهولة مما سيُقلِّل من الخطأ البشري عند كتابتها. ترجمة -وبتصرّف- للمقال Learn How to Use Several Functions of MySQL and MariaDB – Part 2 لصاحبه Gabriel Cánepa.
-
تُحدِّد خصائص مصفوفات RAID بطريقة الضبط والعلاقة بين الأقراص، وهذا يُسمى «مستوى RAID» (RAID level). أكثر مستويات RAID شيوعًا هي: RAID 0 يدمج مستوى RAID 0 بين جهازين أو أكثر عبر توزيع البيانات عليها، وكما ذكرنا في الدرس السابق (مقدمة إلى اصطلاحات ومفاهيم RAID ) ، التوزيع (striping) هو الآلية التي تُقسِّم البيانات إلى أجزاء (chunks) ثم تكتب تلك الأجزاء بشكلٍ تناوبي على كل قرص في المصفوفة. الفائدة من اتباع هذه الطريقة هي أنَّ البيانات موزَّعة، ويمكن الاستفادة من كل قرص لإجراء عمليات القراءة والكتابة؛ وبالتالي سيكون الأداء النظري لمصفوفة RAID 0 هو حاصل ضرب أداء أحد الأقراص بالعدد الكلي لها (الأداء العملي والحقيقي سيكون أقل من ذلك). ميزة أخرى هي أنَّ المساحة القابلة للاستخدام من المصفوفة هي مجموع مساحات الأقراص المُشكِّلة لها. صحيحٌ أنَّ هذا المستوى يوفِّر أداءً رائعًا، إلا أنَّه يعاني من سلبيات ذات أهمية كبيرة. فلمّا كانت البيانات ستُقسَّم بين عدد من الأقراص في المصفوفة، فإن فشل أحد الأجهزة سيؤدي إلى توقف كامل المصفوفة عن العمل وستفقد جميع البيانات. وعلى النقيض من معظم مستويات RAID الأخرى، لا نستطيع إعادة بناء مصفوفات RAID 0، إذ لا توجد مجموعة من الأقراص التي تحتوي معلومات كافية عن محتوى المصفوفة للمساعدة في إعادة بنائها. إذا كنتَ ستستخدم مصفوفات RAID 0، فسيصبح أخذ نسخ احتياطية أمرًا شديد الأهمية، حيث ستفشل المصفوفة في حال فشل أحد الأقراص المكوِّنة لها. RAID 1 مستوى RAID 1 هو المستوى الذي يُنشِئ نسخةً انعكاسيةً بين جهازَين أو أكثر. أي أنَّ كل المعلومات التي تُكتَب على المصفوفة ستُكتَب بدورها مرتين في كلا القرصين المشكلَين للمجموعة. وهذا يعني أنَّ كل قرص سيحتوي على كامل البيانات الموجودة في المصفوفة، وهذا يوفِّر قدرةً تعويضيةً (redundancy) في حال فشل أحد الأقراص. ستتمكن من الوصول إلى بياناتك في مصفوفات RAID 1 في حال بقي قرصٌ وحيدٌ في المصفوفة سليمًا ويعمل دون مشاكل، ويمكن إعادة بناء المصفوفة باستبدال الأقراص التالفة، ومن ثم ستُستخدَم بقية الأقراص السليمة لنسخ البيانات إلى القرص الجديد. هنالك بعض المساوئ لهذا الضبط، فسرعة القراءة النظرية –كما في مستوى RAID 0– يمكن أن تُحسَب بضرب سرعة القراءة لأحد الأقراص بعددها. لكن سرعة الكتابة النظرية القصوى هي سرعة أبطأ قرص في المصفوفة، وذلك لأنَّ كل البيانات يجب أن تُكتَب على كل قرص في المصفوفة. إضافةً إلى ما سبق، المساحة التخزينية الكلية للمصفوفة ستكون مساويةً لمساحة أصغر قرص، لذا إذا كانت لدينا مصفوفة RAID 1 فيها قرصين لهما نفس القدرة التخزينية، فستكون القدرة التخزينية الإجمالية للمصفوفة مساوية لمساحة أحدهما. وإضافة أقراص أخرى سيزيد من عدد النسخ التعويضية للبيانات، ولن يزيد في المساحة المتوافرة. RAID 5 يملك RAID 5 بعض ميزات مستويي RAID السابقَين، لكن له أداءٌ مختلفٌ وسلبياتٌ مختلفة. ففي مستوى RAID 5، ستوزَّع البيانات على الأقراص بنفس الطريقة التي يتبعها المستوى RAID 0، لكن لكل جزء من البيانات التي تُكتَب على المصفوفة فستُكتَب معلومات parity على أحد الأقراص، والتي هي قيمةٌ محسوبةٌ رياضيًا التي تُستخدَم لتصحيح الأخطاء وإعادة بناء معلومات المصفوفة. سيتم تغيير القرص الذي سيستلم معلومات parity المحسوبة (بدلًا من البيانات الحقيقية) بعد كتابة كل جزء من البيانات. لهذا المستوى بعض المزيات المهمة. فمثل بقية المستويات التي توزِّع البيانات على أكثر من قرص، فإن أداء القراءة سيزداد نتيجةً للقدرة على القراءة من عدِّة أقراص معًا. ويمكن لمصفوفات RAID 5 أن تعمل حتى لو فشل أحد الأقراص في المصفوفة. حيث ستسمح معلومات parity بإكمال إعادة بناء البيانات إن حدث ذلك؛ وذلك لأنَّ معلومات parity موزعة (بعض مستويات RAID الأقل شيوعًا تستخدم قرصًا مخصصًا لمعلومات parity)، حيث يملك كل قرصٍ قدرًا متساويًا من معلومات parity. وصحيحٌ أنَّ المساحة التخزينية القابلة للاستخدام في مصفوفات RAID 1 مساوية لمساحة أحد الأقراص (وذلك لأنَّ جميع الأقراص فيها نسخ متماثلة من البيانات)، لكن في RAID 5، يمكن تحقيق القدرة التعويضية بالاستغناء عن المساحة التخزينية لقرصٍ وحيد، فمثلًا إذا كان لدينا أربعة أقراص 100G في مصفوفة RAID 5 فسينتج عنها مساحة تخزينية تساوي 300G (أما 100G الضائعة فستُستَخدم لتخزين معلومات parity). وكما في المستويات الأخرى، هنالك سلبياتٌ لمصفوفات RAID 5 التي يجب أخذها بعين الاعتبار. فقد تؤدي إلى تقليل أداء النظام نتيجةً لحساب معلومات parity ديناميكيًا طوال الوقت، وهذا قد يؤثر على الأداء عند كل عملية كتابة على المصفوفة. وإذا فشل أحد الأقراص في المصفوفة وأصبحت المصفوفة ذات حالة منخفضة، فسيؤدي ذلك أيضًا إلى بطئ شديد عند القراءة منها (لأنَّ البيانات الناقصة ستُحسَب من بقية الأقراص). بالإضافة إلى ذلك، عند محاولة إصلاح المصفوفة بعد استبدال القرص التالف، فيجب قراءة كل قرص بأكمله واستخدام المعالج لحساب البيانات الناقصة لإعادة بناء المصفوفة. وهذا قد يُجهِد بقية الأقراص، مما يؤدي أحيانًا إلى فشلٍ إضافيٍ في أحد الأقراص، مما يؤدي في النهاية إلى فقدان البيانات. RAID 6 يَستخدم مستوى RAID 6 بنيةً قريبةً من مستوى RAID 5، لكن مع مضاعفة كمية معلومات parity. هذا يعني أنَّ المصفوفة ستصمد حتى لو حدث عطب بقرصين. وهذه ميزة مهمة جدًا لزيادة احتمال حدوث عطب آخر أثناء عملية إعادة بناء المصفوفة عند حدوث خطأ. وفي هذا المستوى –كغيره من المستويات التي تستخدم التوزيع– سيكون أداء القراءة جيد إجمالًا. وجميع ميزات RAID 5 تنطبق أيضًا على RAID 6. أما مساوئ هذا المستوى، فهي استخدام مساحة تخزينية أكبر لمعلومات parity، وهذا يعني أنَّ المساحة الإجمالية للمصفوفة هي مجموع مساحات جميع الأقراص المكوِّنة لها منقوصًا منها مساحة قرصين. إضافةً إلى أنَّ العمليات الحسابية اللازمة لإنشاء معلومات parity لمستوى RAID 6 أكثر تعقيدًا من RAID 5، مما يعني أداءً أسوأ للكتابة مقارنةً مع RAID 5. يعاني مستوى RAID 6 من نفس المشاكل التي تحدث في RAID 5 عندما تصبح المصفوفة بحالة منخفضة، لكن وجود قرص إضافي للتعويض سيقل احتمال حدوث مشاكل إضافية تؤدي إلى حذف جميع البيانات عند عمليات إعادة البناء. RAID 10 يمكن تطبيق مستوى RAID 10 بعدِّة طرائق، والتي ستؤثِّر على خصائصه: مستويا 1 و 0 متشعبان تقليديًا، يُشير مستوى RAID 10 إلى مستوى متشعب، والذي يُنشَأ بضبط مصفوفتَي RAID 1 أو أكثر أولًا، ثم استخدام تلك المصفوفات كمكونات لإنشاء مصفوفة RAID 0 موزّعة. ويدعى هذا المستوى حاليًا أحيانًا باسم RAID 1+0 للإشارة إلى هذه العلاقة. وبسبب تصميم هذا المستوى، فإن العدد الأدنى للأقراص هو أربعة وذلك لإنشاء مصفوفة RAID 1+0 (أي مستوى RAID 0 يستعمل مصفوفتَي RAID 1 تتألف كلٌ منهما على قرصين). تملك مصفوفات RAID 1+0 أداءً عاليًا شبيهًا بمصفوفات RAID 0، لكن بدلًا من الاعتماد على أقراص مفردة لتوزيع البيانات، فسيتم استخدام مصفوفة منسوخة نسخًا انعكاسيًا (mirrored array)، مما يعني توفير قدرة تعويضية. يمكن أن يتحمل هذا النوع من الضبط أيّة أخطاء ومشاكل في الأقراص لطالما بقي قرصٌ وحيدٌ يعمل في كل مصفوفة RAID 1 مُشكِّلة للمصفوفة النهائية. يمكن أن يتحمل هذا المستوى عددًا مختلفًا من المشاكل اعتمادًا على مكان وقوعها. ولأنَّ مصفوفات RAID 1+0 توفِّر أداءً عاليًا وقدرةً تعويضيةً، فهي خيارٌ ممتازٌ إن لم تكن مقيدًا بعددٍ معيّنٍ من الأقراص. RAID 10 عبر mdadm لدى برمجية mdadm في لينكس نسخةٌ خاصةٌ بها من RAID 10، والتي تحمل نفس فوائد RAID 1+0 لكن تُغيّر في طريقة تنفيذها لكي تكون مرنةً أكثر وتوفِّر ميزاتٍ إضافيةٍ. وكما في مستوى RAID 1+0، مستوى RAID 10 في mdadm يسمح بتوزيع البيانات ونسخها أكثر من مرة. لكن الأقراص لن تُرتَّب كمجموعتَين منسوختين نسخًا انعكاسيًا، وإنما سيقرِّر مدير النظام عدد النسخ التي ستُكتَب على المصفوفة. ستُجزَّأ البيانات وتُكتَب على المصفوفة بأكثر من نسخة، مع الحرص على أن تُكتَب كل نسخة من البيانات على قرصٍ فيزيائيٍ منفصل. والنتيجة النهائية هو وجود نفس العدد من النسخ، لكن طريقة بناء المصفوفة تختلف (أي لن يكون فيها «تشعب»). هذا الضبط لمستوى RAID 10 له ميزات تجعله متفوقًا عن RAID 1+0، فلأنه لا يعتمد على تشعّب المصفوفات فذلك يعني أننا نستطيع استخدام رقم فردي من الأقراص ويمكن أيضًا تقليل عدد الأقراص الأدنى (ليصبح 3 فقط). يمكن أيضًا ضبط عدد النسخ. وستصبح الإدارة أبسط لأنك ستحتاج إلى إدارة مصفوفة وحيدة، ويمكنك استخدام أقراص بديلة (كقطع غيار) لكامل المصفوفة، بدلًا من إمكانية استخدامها لمصفوفة متشعبة وحيدة. الخلاصة أكثر مستوى من مستويات RAID يناسب خادومك يعتمد تمامًا على حالات استخدامك له وعلى هدفك من المصفوفة. التكلفة والقيود التي يضعها العتاد سيؤثران أيضًا على عملية تقرير مستوى RAID المناسب. ترجمة -وبتصرّف- للمقال An Introduction to RAID Terminology and Concepts لصاحبه Justin Ellingwood
-
سنشرح في هذا الدرس كيفية إنشاء قاعدة بيانات، وجداول (مع تبيان أنواع بيانات حقولها)، وسنفصّل طريقة إجراء عمليات على البيانات على خادوم MySQL أو MariaDB. سنفترض أنَّك قد ثبّتَ الحزم اللازمة على نظامك، ونفّذتَ الأمر mysql_secure_installation لتحسين حماية خادوم قواعد البيانات. وإلا فانظر إلى درسنا عن كيفية تثبيت خادوم MySQL/MariaDB . للاختصار، سنشير إلى قواعد البيانات باسم «MariaDB» في هذا الدرس، لكن نفس الاصطلاحات والتعليمات المشروحة هنا ستنطبق تمامًا على MySQL. إنشاء قواعد البيانات والجداول والمستخدمين كما تعلم، يمكن تعريف قواعد البيانات بأبسط الكلمات على أنها مجموعة منظمة من المعلومات؛ وندعو قواعد MariaDB تحديدًا أنَّها نظام إدارة قواعد بيانات علائقية (relational database management system اختصارًا RDBMS) التي تستخدم لغة الاستعلام البنيوية (Structure Query Language أي SQL) لإجراء العمليات على قواعد البيانات. أبقِ في بالك أنَّ MariaDB تستعمل الاصطلاحين «database» (قاعدة بيانات) و «schema» (مخطط) لنفس المعنى تمامًا. نستعمل الجداول (tables) لتخزين المعلومات الدائمة في قواعد البيانات التي تُخزَّن فيها «سجلاتٌ» (rows) من البيانات. وعادةً يرتبط جدولان أو أكثر مع بعضها بطريقةٍ ما. وهذا هو جزءٌ مهمٌ من عملية التنظيم التي تُميّز قواعد البيانات العلائقية. إنشاء قاعدة بيانات جديدة علينا أن ندخل أولًا إلى مِحَث (prompt) قواعد بيانات MariaDB بإدخال الأمر الآتي، وذلك لإنشاء قاعدة بيانات جديدة (سيُطلَب منك إدخال كلمة مرور المستخدم root لقواعد البيانات): [root@TecMint ~]# mysql -u root -p Enter password: Welcome to the MariaDB monitor. Commands end with ; or \g. Your MariaDB connection id is 2 Server version: 10.1.14-MariaDB MariaDB Server Copyright (c) 2000, 2016, Oracle, MariaDB Corporation Ab and others. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. MariaDB [(none)]> CREATE DATABASE BookstoreDB; Query OK, 1 row affected (0.00 sec) MariaDB [(none)]> بعد إنشاء قاعدة البيانات، فسنحتاج إلى إنشاء جدولين على الأقل فيها، لكن دعنا أولًا نلقي نظرةً على مفهوم أنواع البيانات في الجداول. لمحة عن أنواع البيانات في قواعد MariaDB كما ذكرنا سابقًا، الجداول هي الكائن الرئيسية في قواعد البيانات والتي ستُخزَّن فيها المعلومات الدائمة. يتألف كل جدول من حقلين أو أكثر (تُعرَف أيضًا بالأعمدة [columns]) لها نوع بيانات معيّن (أي نوع المعلومات التي ستُخزَّن فيها) التي يستطيع كل حقلٍ (أو عمودٍ) تخزينها. سأستعرض أشهر أنواع البيانات في MariaDB (يمكنك الرجوع إلى الدليل الرسمي لتحصل على قائمةٍ كاملةٍ): أنواع البيانات الرقمية BOOLEAN: قيمٌ منطقيةٌ، وتعتبَر فيها القيم المساوية للصفر (0) على أنَّها false، وبقية القيم true. TINYINT: إذا استخدمَت مع الكلمة المحجوزة SIGNED فستُمثِّل المجال من -128 إلى 127، بينما مجالها إن كانت UNSIGNED فهو من 0 إلى 255. SMALLINT: إذا استخدمت مع SIGNED فهي تمثِّل المجال من -32768 إلى 32767. بينما مجال UNSIGNED فهو من 0 إلى 65535. INT: إذا استخدمت مع SIGNED فهي تغطي المجال من 0 إلى 4294967295، ومن -2147483648 إلى 2147483647 فيما عدا ذلك. ملاحظة: في أنواع البيانات TINYINT و SMAILLINT و INT، القيمة الافتراضية المرتبطة معها هي SIGNED. DOUBLE(M, D): يُمثِّل هذا النوع الأعداد العشرية ذات الفاصلة، حيث M هو العدد الكلي للأرقام و D هو عدد الأرقام بعد الفاصلة العشرية. إذا اُستعمِلَت الكلمة UNSIGND فلن يُسمَح بإدراج قيم سالبة في هذا الحقل. أنواع البيانات النصية VARCHAR(M): يُمثِّل هذا النوع السلاسل النصية ذات الطول المتغير حيث M هو عدد الأحرف المسموح الأقصى للسلسلة النصية مقدرًا بالبايت (يمكن أن يبلغ نظريًا 65535 بايت). في حال كانت السلاسل النصية المُدخَلة بالإنكليزية، فسيأخذ كل محرف بايتًا واحدًا، لكن هنالك استثناءٌ لبعض المحارف التي قد تأخذ 3 بايت لكي تُمثَّل، فمثلًا، الحرف الإسباني ñ لا يأخذ بايتًا واحدًا وإنما ثلاثة بايتات. TEXT(M): يُمثِّل هذا النوع الأعمدة ذات الطول الأقصى المقدّر 65535 محرفًا، لكن كما في نوع البيانات VARCHAR(M) سينقص طول التخزين الأقصى إذا استعملنا محارف تأخذ أكثر من بايت لتُمثَّل في الحاسوب. إذا حُدِّدَ M فسيُنشأ العمود بأصغر نوع بيانات التي يستطيع تخزين هذا العدد من المحارف. MEDIUMTEXT(M) و LONGTEXT(M) شبيهة بنوع البيانات TEXT(M) لكن الطول الأقصى المسموح هو 16777215 و 4294967295 محرفًا على التوالي وبالترتيب. الوقت والتاريخ DATE: تمثيل التاريخ بصيغة YYYY-MM-DD. TIME: تمثيل الوقت بصيغة HH:MM:SS.sss (أي الساعة والدقيقة والثانية والملي ثانية). DATETIME: جمعٌ بين DATE و TIME بالصيغة YYYY-MM-DD HH:MM:SS. TIMESTAMP: تُستعمَل بصمة الوقت لتعريف اللحظة التي أضيف أو حُدِّث فيها سجلٌ (row) ما. بعد اطلاعك على أنواع البيانات السابقة، فيمكن أن تستطيع الآن تحديد ما هو نوع البيانات الذي ستحتاج له لإسناده إلى عمودٍ معيّن في الجدول. على سبيل المثال، يمكن أن يتسع اسم المستخدم بسهولة في عمودٍ بنوع البيانات VARCHAR(50)، لكن محتوى تدوينة سيحتاج إلى نوع TEXT (اختر قيمة M بما يلبي احتياجاتك). إنشاء جداول فيها مفاتيح أساسية وأجنبية قبل أن نشرع في إنشاء جداول، فمن الضروري استيعاب مفهومين أساسيين عن قواعد البيانات العلائقية: المفتاح الأساسي (primary key) والمفتاح الأجنبي (foreign key). يحتوي المفتاح الأساسي قيمةً تُمثِّلُ مُعرِّفًا فريدًا لكل سطرٍ أو سجلٍ (row أو record) في الجدول، لكن في المقابل يستعمل المفتاح الأجنبي للربط بين البيانات في جدولين، وللتحكم في البيانات التي يمكن تخزينها في الجدول الذي يحتوي على المفتاح الأجنبي. يُعتَبَر المفتاحان الأساسي والأجنبي قيمًا رقميةً (INT) عادةً. لشرح هذا المفهوم عمليًا، فلنستخدم قاعدة بيانات BookstoreDB ونُنشِئ جدولين باسم AuthorsTBL و BooksTBL. تُشير NOT NULL إلى أنَّ الحقل المرتبط بها يتطلب قيمةً تختلف عن NULL. يمكن أيضًا استعمال AUTO_INCREMENT لزيادة قيمة عمود المفتاح الرئيسي الرقمي بمقدار 1 عند إضافة سجل جديد إلى الجدول. MariaDB [(none)]> USE BookstoreDB; Database changed MariaDB [BookstoreDB]> CREATE TABLE AuthorsTBL ( -> AuthorID INT NOT NULL AUTO_INCREMENT, -> AuthorName VARCHAR(100), -> PRIMARY KEY(AuthorID) -> ); Query OK, 0 rows affected (0.05 sec) MariaDB [BookstoreDB]> CREATE TABLE BooksTBL ( -> BookID INT NOT NULL AUTO_INCREMENT, -> BookName VARCHAR(100) NOT NULL, -> AuthorID INT NOT NULL, -> BookPrice DECIMAL(6,2) NOT NULL, -> BookLastUpdated TIMESTAMP, -> BookIsAvailable BOOLEAN, -> PRIMARY KEY(BookID), -> FOREIGN KEY (AuthorID) REFERENCES AuthorsTBL(AuthorID) -> ); Query OK, 0 rows affected (0.05 sec) MariaDB [BookstoreDB]> يمكننا الآن المتابعة وإضافة السجلات إلى جدولَي AuthorsTBL و BooksTBL. تحديد السجلات وإضافتها وتحديثها وحذفها علينا أولًا ملء الجدول AuthorsTBL، لكن لماذا؟ لأننا سنحتاج إلى وجود قيم في العمود AuthorID قبل إضافة سجلات إلى جدول BooksTBL. نفِّذ الأمر الآتي من مِحَث MariaDB: MariaDB [BookstoreDB]> INSERT INTO AuthorsTBL (AuthorName) VALUES ('Agatha Christie'), ('Stephen King'), ('Paulo Coelho'); بعدئذٍ سنُحدِّد جميع السجلات من جدول AuthorsTBL. تذكّر أننا نحتاج إلى AuthorID لكل سجل لإنشاء استعلام INSERT في جدول BooksTBL. إذا أردتَ الحصول على سجلٍ وحيدٍ فقط، فاستعمل عبارة WHERE لكتابة شرط الذي يجب أن تُحقِّقه السجلات المُعادة. على سبيل المثال: MariaDB [BookstoreDB]> SELECT * FROM AuthorsTBL WHERE AuthorName='Agatha Christie'; يمكنك عوضًا عن ذلك أن تحصل على جميع السجلات معًا: MariaDB [BookstoreDB]> SELECT * FROM AuthorsTBL; ناتج تنفيذ الطلبيتين السابقتين: MariaDB [BookstoreDB]> SELECT * FROM AuthorsTBL WHERE AuthorName='Agatha Christie'; +----------+-----------------+ | AuthorID | AuthorName | +----------+-----------------+ | 1 | Agatha Christie | +----------+-----------------+ 1 row in set (0.00 sec) MariaDB [BookstoreDB]> SELECT * FROM AuthorsTBL; +----------+-----------------+ | AuthorID | AuthorName | +----------+-----------------+ | 1 | Agatha Christie | | 2 | Stephen King | | 3 | Paulo Coelho | +----------+-----------------+ 3 rows in set (0.00 sec) MariaDB [BookstoreDB]> لنُنشِئ الآن استعلام INSERT لجدول BooksTBL، وذلك عبر استخدام حقل AuthorID المناسب لمُطابقة مؤلف كل كتاب. القيمة 1 في حقل BookIsAvaiable تعني توافر الكتاب، بينما 0 تعني عكس ذلك: MariaDB [BookstoreDB]> INSERT INTO BooksTBL (BookName, AuthorID, BookPrice, BookIsAvailable) -> VALUES ('And Then There Were None', 1, 14.95, 1), -> ('The Man in the Brown Suit', 1, 23.99, 1), -> ('The Stand', 2, 35.99, 1), -> ('Pet Sematary', 2, 17.95, 0), -> ('The Green Mile', 2, 29.99, 1), -> ('The Alchemist', 3, 25, 1), -> ('By the River Piedra I Sat Down and Wept', 3, 18.95, 0); Query OK, 7 rows affected (0.03 sec) Records: 7 Duplicates: 0 Warnings: 0 سنستخدم الآن SELECT لرؤية السجلات في جدول BooksTBL ثم سنُحدِّث عبر UPDATE سعر كتاب «The Alchemist» لمؤلفه Paulo Coelho ثم سنعرض السجلات (عبر SELECT) مرةً أخرى. لاحظ كيف يعرض الحقل BookLastUpdated قيمةً مختلفةً، وكما شرحنا سابقًا، الحقل TIMESTAMP يُخزِّن الوقت الذي أُنشِئ أو حُدِّث فيه السجل. MariaDB [BookstoreDB]> SELECT * FROM BooksTBL; +--------+-----------------------------------------+----------+-----------+---------------------+-----------------+ | BookID | BookName | AuthorID | BookPrice | BookLastUpdated | BookIsAvailable | +--------+-----------------------------------------+----------+-----------+---------------------+-----------------+ | 1 | And Then There Were None | 1 | 14.95 | 2016-10-01 23:31:41 | 1 | | 2 | The Man in the Brown Suit | 1 | 23.99 | 2016-10-01 23:31:41 | 1 | | 3 | The Stand | 2 | 35.99 | 2016-10-01 23:31:41 | 1 | | 4 | Pet Sematary | 2 | 17.95 | 2016-10-01 23:31:41 | 0 | | 5 | The Green Mile | 2 | 29.99 | 2016-10-01 23:31:41 | 1 | | 6 | The Alchemist | 3 | 25.00 | 2016-10-01 23:31:41 | 1 | | 7 | By the River Piedra I Sat Down and Wept | 3 | 18.95 | 2016-10-01 23:31:41 | 0 | +--------+-----------------------------------------+----------+-----------+---------------------+-----------------+ 7 rows in set (0.00 sec) MariaDB [BookstoreDB]> UPDATE BooksTBL SET BookPrice=22.75 WHERE BookID=6; Query OK, 1 row affected (0.04 sec) Rows matched: 1 Changed: 1 Warnings: 0 MariaDB [BookstoreDB]> SELECT * FROM BooksTBL WHERE BookID=6; +--------+---------------+----------+-----------+---------------------+-----------------+ | BookID | BookName | AuthorID | BookPrice | BookLastUpdated | BookIsAvailable | +--------+---------------+----------+-----------+---------------------+-----------------+ | 6 | The Alchemist | 3 | 22.75 | 2016-10-01 23:35:00 | 1 | +--------+---------------+----------+-----------+---------------------+-----------------+ 1 row in set (0.00 sec) MariaDB [BookstoreDB]> لنفترض أننا نريد حذف أحد السجلات الذي لم يعد مفيدًا، فمثلًا سنحذف كتاب «The Alchemist» من جدول BooksTBL. يمكنك استخدام عبارة DELETE لفعل ذلك كما يلي: MariaDB [BookstoreDB]> DELETE FROM BooksTBL WHERE BookID=6; وكما في عبارة UPDATE، من المستحسن إجراء عملية SELECT أولًا لرؤية الحقول التي ستؤثر فيها عملية الحذف. لا تنسَ أن تُضيف عبارة WHERE وشرطًا(BookID=6) لتحديد سجل مُعيّن لحذفه. وإلا فقد تصبح جميع سجلات جدولك معرضةً للحذف. إذا أردتَ دمج حقلين (أو أكثر) معًا، فيمكنك استخدام عبارة CONCAT، فلنقل على سبيل المثال أننا نريد عرض ناتج يحتوي على عمودٍ فيه اسم الكتاب والمؤلف على الشكل الآتي «The Alchemist (Paulo Coelho)» ثم يليه عمودٌ فيه سعره. هذا سيتطلب إجراء عملية JOIN بين جدولَي AuthorsTBL و BooksTBL في الحقل المشترك بينهما (ألا وهو AuthorID): MariaDB [BookstoreDB]> SELECT CONCAT(BooksTBL.BookName, ' (', AuthorsTBL.AuthorName, ')') AS Description, BooksTBL.BookPrice FROM AuthorsTBL JOIN BooksTBL ON AuthorsTBL.AuthorID = BooksTBL.AuthorID; وكما نرى، تسمح لنا عبارة CONCAT بدمج عدِّة تعبيرات نصية المفصول بينها بفاصلة. ستلاحظ أيضًا أننا استخدمنا اسمًا بديلًا وهو Description لعرض ناتج عملية دمج الحقلين. هذا هو ناتج تنفيذ الاستعلام السابقة: MariaDB [BookstoreDB]> SELECT CONCAT(BooksTBL.BookName, ' (', AuthorsTBL.AuthorName, ')') AS Description, BooksTBL.BookPrice FROM AuthorsTBL JOIN BooksTBL ON AuthorsTBL.AuthorID = BooksTBL.AuthorID; +--------------------------------------------------------+-----------+ | Description | BookPrice | +--------------------------------------------------------+-----------+ | And Then There Were None (Agatha Christie) | 14.95 | | The Man in the Brown Suit (Agatha Christie) | 23.99 | | The Stand (Stephen King) | 35.99 | | Pet Sematary (Stephen King) | 17.95 | | The Green Mile (Stephen King) | 29.99 | | The Alchemist (Paulo Coelho) | 25.00 | | By the River Piedra I Sat Down and Wept (Paulo Coelho) | 18.95 | +--------------------------------------------------------+-----------+ 7 rows in set (0.00 sec) إنشاء مستخدم للوصول إلى قاعدة بيانات BookstoreDB لا أنصحك باستخدام المستخدم root لإجراء جميع عمليات معالجة البيانات، ولتجنب ذلك سنُنِشئ حساب مستخدم جديد (سنسميه bookstoreuser) ونُسنِد إليه جميع الامتيازات اللازمة لإدارة قاعدة البيانات BookstoreDB: MariaDB [BookstoreDB]> CREATE USER bookstoreuser@localhost IDENTIFIED BY 'tecmint'; Query OK, 0 rows affected (0.00 sec) MariaDB [BookstoreDB]> GRANT ALL PRIVILEGES ON BookstoreDB.* to bookstoreuser@localhost; Query OK, 0 rows affected (0.00 sec) MariaDB [BookstoreDB]> FLUSH PRIVILEGES; Query OK, 0 rows affected (0.00 sec) وجود حساب مستخدم منفصل ومخصص لكل قاعدة بيانات سيحمي كامل الخادوم إن حدث اختراقٌ لأحد الحسابات. نصائح إضافية في قواعد MySQL لمسح الشاشة وإظهار مِحَث MariaDB فيها فقط، فأدخِل الأمر الآتي ثم اضغط على Enter: MariaDB [BookstoreDB]> \! clear نفِّذ الأمر الآتي لرؤية بنية أحد الجداول: MariaDB [BookstoreDB]> SHOW COLUMNS IN [TABLE NAME HERE ]; لعرض الأعمدة الموجودة في جدول BooksTBL في قاعدة بياناتنا: MariaDB [BookstoreDB]> SHOW COLUMNS IN BooksTBL; +-----------------+--------------+------+-----+-------------------+-----------------------------+ | Field | Type | Null | Key | Default | Extra | +-----------------+--------------+------+-----+-------------------+-----------------------------+ | BookID | int(11) | NO | PRI | NULL | auto_increment | | BookName | varchar(100) | NO | | NULL | | | AuthorID | int(11) | NO | MUL | NULL | | | BookPrice | decimal(6,2) | NO | | NULL | | | BookLastUpdated | timestamp | NO | | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP | | BookIsAvailable | tinyint(1) | YES | | NULL | | +-----------------+--------------+------+-----+-------------------+-----------------------------+ 6 rows in set (0.02 sec) تفحص سريع لبنية الجدول سيكشف أنَّ الحقل BookIsAvailable يقبل القيم NULL. ولعدم رغبتنا في ذلك، فسنُعدِّل (ALTER) الجدول كالآتي: MariaDB [BookstoreDB]> ALTER TABLE BooksTBL MODIFY BookIsAvailable BOOLEAN NOT NULL; (تستطيع الآن عرض بنية الجدول مرةً أخرى، وستجد أنَّ كلمة YES الموجودة في عمود Null أصبحت NO). أخيرًا، لعرض جميع قواعد البيانات في خادومك، تستطيع تنفيذ الأمر: MariaDB [BookstoreDB]> SHOW DATABASES; أو MariaDB [BookstoreDB]> SHOW SCHEMAS; الناتج الآتي يعرض مخرجات الأمر السابق بعد الدخول إلى مِحَث MariaDB عبر المستخدم bookstoreuser (لاحظ أنَّ هذا الحساب لا يستطيع «رؤية» أيّة قواعد بيانات ما عدا BookstoreDB و information_schema [المتوافرة لجميع المستخدمين]): [root@TecMint ~]# mysql -u bookstoreuser -p Enter password: Welcome to the MariaDB monitor. Commands end with ; or \g. Your MariaDB connection id is 3 Server version: 10.1.14-MariaDB MariaDB Server Copyright (c) 2000, 2016, Oracle, MariaDB Corporation Ab and others. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. MariaDB [BookstoreDB]> SHOW DATABASES; +--------------------+ | Database | +--------------------+ | BookstoreDB | | information_schema | +--------------------+ 2 rows in set (0.00 sec) MariaDB [BookstoreDB]> SHOW SCHEMAS; +--------------------+ | Database | +--------------------+ | BookstoreDB | | information_schema | +--------------------+ 2 rows in set (0.00 sec) الخلاصة شرحنا في هذا الدرس كيفية إجراء عمليات على البيانات، إضافةً إلى إنشاء قاعدة بيانات، وجداولها، وتخصيص مستخدم لقاعدة البيانات، ثم رأينا فائدة بعض التلميحات التي تساعد في تسهيل إدارة قواعد البيانات عليك. ترجمة -وبتصرّف- للمقال Learn MySQL / MariaDB for Beginners – Part 1 لصاحبه Gabriel Cánepa.
-
تمهيد من المهم أن تأخذ طريقة التخزين بعين الاعتبار عندما تضبط خادومًا، إذ أنَّ أغلبية المعلومات المهمة التي تهتمُ أنت ومستخدموك بها ستُكتَب في مرحلةً ما إلى وسيط تخزين للحصول عليها لاحقًا. ستستفيد من الأقراص المستقلة إذا كانت احتياجاتك بسيطة، لكن إن أردتَ الحصول على أداءٍ عالٍ أو ضمانٍ لعدم فقدان بياناتك، فعندئذٍ ستستفيد من تقنيات مثل RAID. سنتحدث في هذا الدرس عن اصطلاحات RAID ومفاهيمها الشائعة، وسنناقش بعض ميزات (ومساوئ) استخدام مصفوفات RAID، وسنتحدث عن الاختلافات بين طرائق تنفيذ تقنية RAID. ما هي مصفوفة RAID؟ ترمز الكلمة RAID إلى «Redundant Arrays of Independent Disks» وهي تعني «مصفوفة الأقراص التعويضية المستقلة»، أي استخدام عدِّة أقراص بأنماط مختلفة مما يمنح مدراء الأنظمة أداءً أفضل أو قدرةً تعويضيةً (ضد فشل الأقراص) مقارنةً بمجموعةٍ من الأقراص التي تعمل بمفردها. يمكن تطبيق RAID على الأقراص الخام أو على الأقسام الموجودة في قرصٍ ما. متى يُفضَّل استخدام RAID؟ الفائدة الأساسية من مصفوفات RAID هي القدرة على تعويض فقدان البيانات والزيادة في الأداء. القدرة التعويضية تعني زيادةً في إتاحية (availability) البيانات المخزنة، وهذا يعني أننا سنتمكن من الوصول إلى المعلومات المخزنة عند حدوث بعض الحالات مثل فشل أحد أقراص التخزين، وسيتمكن النظام من إكمال عمله إلى أن يُستبَدل القرص المعطوب. لكن هذا لا يعني أنَّ هذه هي آلية نسخ احتياطي (يجب أخذ نسخ احتياطية لمصفوفات RAID كغيرها من أنواع التخزين)، وإنما الغرض من هذه الآلية هو تقليل الانقطاعات عند حدوث مشكلة. فائدةٌ أخرى رئيسيةٌ توفرها مصفوفات RAID في بعض الحالات هي الزيادة في الأداء، فعادةً ستكون سرعة الكتابة أو القراءة على وسائط التخزين محدودة (ومرتبطة) بسرعة الكتابة على قرصٍ وحيد، أما البيانات في مصفوفات RAID فهي إما موجودة نفسها في أكثر من قرص (redundant) أو موزعة على أكثر من قرص (distributed)، وهذا يعني أننا نستطيع استخدام عدِّة أقراص لكل عملية قراءة مما يزيد من كمية البيانات التي يمكن قراءتها في الثانية؛ ويمكن أيضًا تحسين سرعة عمليات الكتابة في بعض حالات الضبط التي يمكن فيها كتابة قسم من البيانات على كل قرص. بعض الجوانب السلبية في مصفوفات RAID تتضمن زيادةً في تعقيد عملية الإدارة وعادةً تؤدي إلى إنقاص المساحة التخزينية المتوافرة. وهذا يعني تكاليف إضافية يجب دفعها للحصول على نفس مقدار المساحة التخزينية القابلة للاستخدام. هنالك مصاريف أخرى تتضمن استخدام قطع عتاديّة خاصة عندما لا تريد إدارة المصفوفة عبر أدواتٍ برمجيةٍ فقط. إحدى السلبيات الأخرى للمصفوفات المضبوطة للحصول على أداءٍ عالٍ دون قدرة تعويضية هي الزيادة في احتمال فقدات البيانات، حيث تعتمد البيانات المخزنة على الأقراص في تلك الحالات على أكثر من وسيط تخزين وحيد، مما يزيد من احتمال فقدان البيانات نتيجة عطب في أحد الأقراص. مصفوفات RAID التي تعتمد على العتاد، والتي تعتمد على البرمجيات، والتي تعتمد على البرمجيات بمساعدة العتاد يمكن إنشاء وإدارة مصفوفات RAID بمختلف التقنيات. وهي: مصفوفات RAID التي تعتمد على العتاد هنالك قطعٌ عتاديةٌ مخصصة تسمى «متحكمات RAID» (RAID controllers) أو «بطاقات RAID» (RAID cards) يمكن أن تستعمل لإعداد وإدارة مصفوفات RAID بمعزل عن نظام التشغيل، وهذا معروفٌ بالمصطلح «hardware RAID». تملك متحكمات RAID العتادية معالجًا منفصلًا لإدارة أجهزة RAID. لمصفوفات RAID التي تعتمد على العتاد عدِّة ميزات، نذكر منها: الأداء: متحكمات RAID العتادية (الحقيقة) لا تأخذ من وقت المعالج لإدارة الأقراص الموجودة ضمن المصفوفة. وهذا يعني أنَّك لن تُسبِّب تقليل أداء الخادوم لإدارة أجهزة التخزين. توفِّر المتحكمات ذات الجودة العالية تخزينًا مؤقتًا كبيرًا وله أثرٌ كبيرٌ على الأداء. إخفاء تعقيدات المصفوفة: ميزة أخرى لاستخدام متحكمات RAID هي أنَّها تخفي طريقة ترتيب الأقراص وإدارتها عن نظام التشغيل، حيث ستُمثِّل متحكماتُ RAID المصفوفةَ على أنها وحدة تخزينٍ منطقيةٍ وحيدةٍ. وليس من الضروري أن يفهم نظام التشغيل طريقة ترتيب مصفوفة RAID؛ إذ أنَّه سيتعامل مع كامل المصفوفة على أنها قرصٌ وحيدٌ. سيُتاح استخدام المصفوفة عند الإقلاع: بسبب أنَّ المصفوفة مدارة بشكلٍ كامل عتاديًا دون تدخل البرمجيات، فهذا يعني أنها متاحة الاستخدام عند الإقلاع، مما يسمح بإنشاء نظام الملفات الرئيسي (الذي سيُثبَّت داخله نظام التشغيل) داخل مصفوفة RAID. لكن هنالك بعض السلبيات لمصفوفات RAID التي تعتمد على العتاد: احتكار الشركات: لأن مصفوفات RAID العتادية مدارةٌ من برمجيات تجارية موجودة داخل العتاد، فهذا يعني أنَّنا يجب أن نستعمل المصفوفة مع نوع العتاد الذي أنشأها فقط؛ فلو تعطل متحكم RAID، ففي أغلب الحالات يجب أن نضع شريحة مماثلة أو شريحة متوافقة مع الشريحة القديمة بدلًا عنه. يَنصح بعض مدراء الأنظمة بشراء أكثر من متحكم RAID من نفس النوع كاحتياطٍ في حال حدثت مشكلة. الكلفة العالية: متحكمات RAID ذات الجودة العالية تكون ذات سعر مرتفع عادةً. مصفوفات RAID التي تعتمد على البرمجيات يمكن أيضًا ضبط RAID داخل نظام التشغيل نفسه. ولأنَّ العلاقة بين الأقراص ستُعرَّف وتُضبَط داخل نظام التشغيل عوضًا عن استخدام جهاز عتادية منفصل، فستسمى تلك المصفوفات بمصفوفات «software RAID». بعض ميزات مصفوفات RAID البرمجية: المرونة: لمّا كانت مصفوفات RAID التي تعتمد على البرمجيات تُدار داخل نظام التشغيل، فيمكن بسهولة ضبط أجهزة التخزين المتاحة دون تغيير شيء في ضبط العتاد. عملية إنشاء مصفوفات RAID في لينكس هي عملية مرنة للغاية، حيث يُسمَح بضبط مختلف أنواع ومستويات RAID. مفتوحة المصدر: البرمجيات التي نستعملها لضبط مصفوفات RAID في الأنظمة مفتوحة المصدر مثل لينكس و FreeBSD هي برمجيات مفتوحة المصدر أيضًا، وضبط المصفوفات متاحٌ لك وغير مخفي، ويمكن بكل سهولة قراءته وتطبيقه على أنظمة أخرى. فمثلًا، إذا كانت لدينا مصفوفة RAID أنشأناها على نظام أوبنتو، فسنتمكن ببساطة من نقلها إلى خادوم CentOS لاحقًا. هنالك احتمالٌ ضئيلٌ في أنَّك ستفقد الوصول إلى بياناتك بسبب بعض الاختلافات بين البرمجيات. لا توجد تكلفة إضافية: لا يتطلب إنشاء مصفوفات RAID برمجية أيّة قطع عتادية خاصة، لذا لن تكون هنالك تكلفة إضافية على خادومك عند استخدامها. بعض سلبيات استخدام مصفوفات RAID البرمجية: التبعية للبرمجيات: صحيحٌ أنَّ مصفوفات RAID البرمجية غير مرتبطة بعتاد معيّن، لكن عادةً سترتبط ببرمجية معيّنة التي أنشأتها فيها. فمثلًا يستخدم لينُكس mdadm بينما FreeBSD يستعمل مصفوفات RAID مبنية على GEOM، ولنظام ويندوز له نسخةٌ خاصةٌ به من البرمجيات التي تُتيح إنشاء مصفوفات RAID برمجية. وعلى الرغم من أنَّ مختلف نسخ البرمجيات المفتوحة المصدر يمكن أن تُصدِّر ضبطها فيما بينهما، إلا أنَّه لا يحتمل أن تتوافق الصيغة نفسها مع بقية برمجيات RAID. مشاكل في الأداء: قديمًا كانوا ينتقدون مصفوفات RAID البرمجية لأنها تُسبِّب بحملٍ إضافيٍ على النظام. فسيُستعمَل المعالج المركزي والذاكرة لإدارة المصفوفة، والتي كانت يمكن أن تُستعمَل لأمورٍ أخرى. لكن البرمجيات مثل mdadm التي تعمل على عتادٍ حديث قد أطاحت بهذا المخاوف، أي أنَّ استعمال المعالج يكون أصغريًا في أغلبية الحالات ولا نأخذه بعين الاعتبار. مصفوفات RAID التي تعتمد على البرمجيات بمساعدة العتاد النوع الثالث من مصفوفات RAID يدعى «hardware-assisted software RAID» أو «firmware RAID» أو «fake RAID». عمومًا يوفر هذا النوع ميزات RAID بتضمينه داخل اللوحة الأم أو عبر بطاقات RAID رخيصة الثمن. يتم تطبيق هذا النوع من المصفوفات عبر استخدام برمجيات على المتحكم أو البطاقة لإدارة مصفوفة RAID، لكنه يستخدم وحدة المعالجة المركزية لتشغيل تلك البرمجيات. ميزات هذا النوع من المصفوفات: دعم إقلاع أكثر من نظام تشغيل: وذلك لأنَّ مصفوفة RAID ستعمل عند الإقلاع، لذا يمكن استخدام أكثر من نظام تشغيل للمصفوفة، وهذا غير ممكن إذا استعملنا مصفوفات RAID برمجية. من سلبياتها: دعم محدود لمستويات RAID: عادةً تدعم RAID 0 أو RAID 1 فقط. تتطلب عتادًا خاصًا: مثل مصفوفات RAID العتادية، هذا النوع مقيدٌ بالعتاد الذي أنشأه ويديره، وهذه مشكلة كبيرة في حال كان موجودًا ضمن اللوحة الأم، فلو فشل متحكم RAID أو تعطل، فهذا يعني أنَّ عليك استبدال اللوحة الأم كلها لكي تستطيع الوصول مرةً أخرى إلى بياناتك. مشاكل في الأداء: مثل مصفوفات RAID العتادية، لا يوجد هنا معالج خاص بإدارة RAID، ويجب أن يتشارك المتحكم مع نظام التشغيل باستخدام المعالج المركزي. أغلبية مدراء الأنظمة يبقون بعيدين عن هذا النوع من مصفوفات RAID، لأنها تعاني من اجتماع مشاكل النوعَين الآخرَين. الاصطلاحات المستخدمة عند الحديث عن مصفوفات RAID سيساعدك التعرف على بعض هذه الاصطلاحات على فهم RAID بشكل أفضل. هذه بعض المصطلحات الشائعة التي قد تصادفك: مستوى RAID (RAID level): يشير «مستوى RAID» إلى العلاقة التي تجمع أجهزة التخزين. يمكن ضبط الأقراص بعدِّة طرائق، مما يؤدي إلى خصائص مختلفة للتعويض وللأداء. التوزيع (Striping): «التوزيع» هو عملية تقسيم البيانات المكتوبة على المصفوفة إلى أكثر من قرص. تُستخدَم هذه التقنية من مختلف مستويات RAID. عندما توزَّع البيانات على المصفوفة، فستُقسَّم إلى أجزاء صغيرة، ثم يكُتَب كل جزء إلى قرص واحد أو أكثر من الأقراص المُشكِّلة للمصفوفة. حجم الجزء (Chunk Size): عند توزيع البيانات، سيُحدِّد «حجم الجزء» مقدار البيانات التي سيحتوي كل جزء عليها. وتعديل حجم الجزء ليُطابِق خصائص الدخل والخرج التي تتوقعها قد يساعد في زيادة أداء المصفوفة. آلية تعادل القيمة (Parity): هذه آلية يتم إنجازها عبر حساب المعلومات من كتل البيانات (data blocks) المكتوبة إلى المصفوفة. وقد تستخدم معلومات parity لإعادة بناء البيانات إذا فشل أحد الأقراص. قد توضع معلومات parity في قرص منفصل عن الأقراص التي تحتوي البيانات التي تُحسَب بيانات parity منها، وتوزَّع في أغلبية حالات الضبط على عدِّة أجهزة للمقدرة على تعويض فشل أحد الأقراص ولزيادة الأداء. مصفوفات ذات الحالة المخفَّضة (Degraded Arrays): يمكن أن تعاني المصفوفات التي لها قدرة تعويضية (redundancy) أنواعًا مختلفةً من فشل الأقراص دون خسارة البيانات. فعندما تخسر المصفوفة قرصًا لكنها تستطيع إكمال عملها، فيُقال أنَّها أصبحت «بحالة مُخفَّضة» (degraded mode). يمكن إعادة بناء المصفوفات ذات الحالة المخفَّضة لترجع كما كانت بعد استبدال القرص المعطوب، لكنها قد تعاني من أداءٍ منخفض أثناء تلك الفترة. إعادة المزامنة (Resilvering أو Resyncing): «إعادة المزامنة» هو المصطلح المستخدم لإعادة بناء مصفوفة ذات الحالة المخفَّضة. واعتمادًا على ضبط RAID ونوع الفشل، سنتمكن من إجراء عملية إعادة المزامنة إما بنسخ البيانات من الملفات الموجودة في المصفوفة، أو عبر حساب البيانات باستخدام معلومات parity (parity information). المصفوفات المتشعبة (Nested Arrays): يمكن دمج مجموعات من مصفوفات RAID في مصفوفات أكبر. ونفعل ذلك عادةً للاستفادة من ميزات مستويي RAID أو أكثر. عادةً تُستخدَم المصفوفات ذات القدرة التعويضية (مثل RAID 1 أو RAID 5) كمكونات لإنشاء مصفوفة RAID 0 لزيادة الأداء. الامتداد (Span): للأسف، مصطلح «الامتداد» له معانٍ مختلفة عندما نتحدث عن المصفوفات. ..- في سياقات معيّنة، «الامتداد» يعني وصل قرصين أو أكثر مع بعضهما لتمثيلهما كجهاز منطقي وحيد، بدون تحسين في الأداء أو القدرة التعويضية. وهذا يُعرَف أيضًا بالترتيب الخطي (linear arrangement) عند التعامل مع برمجية mdadm في لينكس. ..- يمكن أن يشير «الامتداد» إلى المصفوفات التي تُجمَّع مع بعضها لإنشاء مستوى جديد من مستويات RAID وذلك في المصفوفات المتشعبة، مثل المصفوفات من المستوى RAID 10 (أي RAID 1+0). التحقق (Scrubbing أو Checking): هي عملية قراءة كل كتلة في المصفوفة للتأكد من عدم وجود أخطاء. وهذا يساعد في التأكد من أنَّ البيانات متماثلة في أكثر من وسيط تخزين، وسيمنع ذلك من حدوث أخطاء قد تؤدي إلى تلف في البيانات، وخصوصًا خلال العمليات الحساسة مثل إعادة بناء المصفوفة. ترجمة -وبتصرّف- للمقال An Introduction to RAID Terminology and Concepts لصاحبه Justin Ellingwood
-
رأينا في الدرس السابق أكثر ثلاثة أنماط شيوعًا لتحديد مواقع العناصر في صفحات HTML عبر CSS، وهي static و relative و absolute. سننظر في هذا الدرس إلى fixed و sticky، ثم سنناقش طريقة ترتيب العناصر فوق بعضها عبر z-index. طريقة fixed لتحديد مواقع العناصر هنالك قاعدة background-attachment: fixed تُطبَّق على صور الخلفية، وأيضًا توجد قاعدة position: fixed التي تُطبَّق على العناصر؛ حيث تسمح بأن يكون موقع العنصر ثابتًا نسبةً إلى الصفحة، مما يسمح بتمرير بقية العناصر مع بقاء العنصر في مكانه. ويُطبَّق ذلك عادةً على حاويات، فمن الأمثلة الشائعة هي الترويسات والتذييلات الثابتة. وكما عند ضبط العناصر ذات القاعدة position: absolute، ستُصبِح جميع العناصر ذات القاعدة position: static تحت أيّة محتوى له القاعدة position: fixed. هذه شيفرة HTML لعنصر ثابت يظهر على يسار الصفحة: <div id="fixed-pull-tab"> <img src="red-tab.png" style="float: right" alt="LEVI’S"> <p>This is an example of an element with <code>position: fixed;</code> applied to it, for this blog’s article on the CSS property. </div> استخدمتُ الخاصية box-shadow في CSS على الصورة لكي أوضِّح أنَّ الحاوية موجودة في «طبقة» تعلو بقية المستند: div#fixed-pull-tab { width: 300px; border: 1px solid #000; padding-left: 1em; background-color: rgba(255, 255, 37, 0.7); position: fixed; left: -265px; top: 200px; } div#fixed-pull-tab p { margin-right: 70px; } div#fixed-pull-tab img { box-shadow: 4px 4px 4px rgba(0, 0, 0, 0.33); } div#fixed-pull-tab:hover { left: 0; } وكما في position: absolute، يجب أن تُستخدَم القيمة fixed بحذر، حيث تسمح هذه الخاصية بإنشاء عناصر في صفحات الويب التي تتداخل مع غيرها من محتوى الصفحة أو تغطي عليها. دورة تطوير واجهات المستخدم ابدأ عملك الحر بتطوير واجهات المواقع والمتاجر الإلكترونية فور انتهائك من الدورة اشترك الآن حالة خاصة: العناصر الثابتة الموجودة داخل حاوية في الحالات العادية، سيُزال العنصر المُطبَّق عليه القاعدة position: fixed من المستند، وأيّة معلومات تُحدِّد مكانه نسبةً إلى العنصر <body> ستصبح غير متاحة. لكن، من الممكن وضع عنصر مُطبَّق عليه القاعدة position: fixed داخل عنصر آخر ومنسوبًا إليه، وذلك إذا أُجري CSS transform عليه. فلو كانت لدينا الشيفرة الآتية: <div id="container"> <div id="fixed"></div> </div> يمكن أن يصبح العنصر الداخلي «ثابتًا» بالنسبة إلى العنصر الأب باستخدام شيفرة CSS الآتية (دون السابقات الخاصة بالمتصفحات، لغرض وضوح الشيفرة): #container { transform: translateZ(0); } #fixed { position: fixed; } هذه «الميزة» الغربية هي جزء من مواصفات CSS، وهي مدعومة في جميع المتصفحات الحديثة التي جربتها (باستثناء IE 11)، وحسب معلوماتي، أول من اكتشف ذلك هو Eric Meyer، وأتوقع أنَّ هذه الميزة نادرة الاستخدام (أغلبية المطورين يفضلون استخدام absolute مع relative) لكن لا ضير من معرفة هذه المعلومة. طريقة sticky لتحديد مواقع العناصر مرت فترةٌ أصبحت فيها العناصر «الثابتة ديناميكيًا» هي ميزة التصميم الأساسية في الموقع، فإذا مرّرتَ إلى الأسفل فسيتحرك كل شيءٍ كما هو متوقع، لكن عندما يبلغ عنصرٌ معيّن (عادةً يكون شريط القائمة، أو إعلان في بعض الأحيان) أعلى الصفحة فسيثبت مكانه، بينما ستستمر بقية عناصر المستند بالتمرير أدناه؛ وعند التمرير إلى الأعلى فسيربط العنصر نفسه مرةً أخرى بالمستند. هذا السلوك (الذي هو دمجٌ بين position: static و position: fixed) كان يُضاف إلى الصفحة باستخدام jQuery (عبر إحدى الإضافات الكثيرة الموجودة لهذا الغرض). وكالعديد من الميزات المشهورة، سينتهي بهذا الأمر إلى أن يصبح جزءًا من المواصفة الرسمية، مما يعني أننا سنتمكن من فعل ذلك باستخدام CSS بمفردها، دون إطارات عمل، أو سكربتات، أو غير ذلك… لكن في هذه الحالة، كانت (وما زالت) عملية التحويل إلى مواصفة مليئةً بالمشاكل. كيف كان يُفتَرض لهذه الميزة أن تعمل كنّا نكتب هذه الميزة كقيمة جديدة: position: sticky، وذلك مع استخدامٍ ذكيٍ للخاصية top (وهي ترمز عند استخدامها مع sticky إلى المسافة من أعلى العنصر bodyالذي بعدها سيصبح العنصر «ثابتًا» عند التمرير؛ البدائل هي الخاصياتleftوbottomوright` للتمرير في تلك الاتجاهات)، وكان ذلك كافيًا لتغطية طيفٍ واسعٍ من حالات الاستخدام؛ وبهذا ستصبح طريقة الاستخدام سهلةً جدًا: #stickytest { position: sticky; top: 0px; } وعند تطبيق ما سبق على صورة (مثلًا)، فستبدو الشيفرة كما يلي: <img src="geckofoot.jpg" alt id="stickytest"> <p>Lorem ipsum… ملاحظة: افتراضنا أنَّ الصفحة تحتوي على محتوى بعد العنصر لكي يصبح العنصر #stickytest في أعلى نافذة المتصفح، وإذا لم تكن تحتوي الصفحة على عناصر أخرى، فلن يصل العنصر إلى المكان اللازم لكي «يثبت» مكانه. أنصحك بتعبئة الصفحة بكثير من النصوص لغرض التجربة. إذا جربتَ الشيفرة السابقة على نسخةٍ حديثةٍ من متصفح Firefox، فيجب أن تعمل عملًا صحيحًا. لكن عند الانتقال إلى بقية المتصفحات، فسنجد أمورًا عجيبة! 1. متصفح Safari 6.1+ (على الحاسوب وعلى الهاتف) يدعم القيمة sticky عبر سابقة (prefix) خاصة به. صحيحٌ أنَّ من غير الشائع أن تُطبَّق السابقة على القيمة، وليس على الخاصية. 2. هنالك أمرٌ بسيطٌ عليك الانتباه إليه ألا وهو أنَّ خاصية sticky في Safari تعمل إذا كانت العناصر لها القاعدة display: block، لذا يجب تعديل مثال الصورة السابق ليصبح: #stickytest { display: block; position: -webkit-sticky; position: sticky; top: 0px; } بالإضافة إلى: وضع عنصر sticky داخل حاوية لها القاعدة overflow: hidden سيؤدي إلى عدم تطبيق سلوك sticky. رسميًا، يجب أن يعمل sticky مع display: table، بما في ذلك خلايا الجدول، وهذا مفيدٌ عند التنقل في الجداول الطويلة مع إبقاء عناوين الأعمدة ظاهرةً. لكن للأسف لم تُطبَّق هذه الميزة في المتصفح. متصفح Chrome ينسحب من السباق ربما تجد في الويب بعض الصفحات التي تُصّر أنَّ متصفح Chrome يدعم القاعدة position: sticky كخيارٍ اختباري، وكان هذا صحيحًا… إلى أن أُلغي هذا الخيار تمامًا في Chrome 37. شعر فريق تطوير Google أنَّ إبقاء position: sticky هو تحدٍ لهم في مسعاهم في تحسين سرعة العرض في المتصفح، لهذا ألغيت هذه الميزة. وهذا يعني أنَّ علينا العودة إلى الطرق الالتفافية لإنشاء هذا السلوك في متصفح Chrome و Internet Explorer (الذي لم يدعم القيمة الجديدة قط). لحسن الحظ، هنالك بعض الخيارات المتاحة أمامنا: فلدى Filament Group حلٌّ يعتمد على jQuery، بالإضافة إلى غيره من الحلول. أفضِّل -شخصيًا- استخدام stickyfill من تطوير Oleg Korsunsky، والذي يمكن أن يعمل مع أو بدون jQuery. المثال الموجود في صفحة StickFill يُضيف سلوك sticky كفئة CSS، لكن من المرجَّح أن تُطبِّق ذلك على عنصرٍ وحيد، وإنشاء مُحدِّد يعتمد على المُعرِّف id هو أمرٌ منطقي. وفي هذا المثال، سأضيف إلى السكربت الموجود أسفل الصفحة السطرَ الآتي: Stickyfill.add(document.getElementById('stickytest')); لاحظ أنَّ قيم top و left و bottom و right للعنصر مُقاسةٌ من العنصر body، وهذا يتضمن أيّة هوامش موجودة للعنصر body. أبقِ الأمر بسيطًا صحيحٌ أنَّ position: sticky لها العديد من الميزات، لكن تسهل إساءة استخدامها. ولتفادي الكوارث التي تتعلق بواجهة المستخدم فسأنصحك باتباع ما يلي: - نظريًا، يمكن استخدام position: sticky لإبقاء العناصر ثابتةً داخل أيّ حاوية قابلة للتمرير، كما في هذا المثال؛ لكن رجاءً لا تستخدمها في أكثر من مكان في الصفحة، فلا نحتاج إلى ذلك! (إضافةً إلى أنَّ جميع الحلول الالتفافية المتوافرة لقاعدة position: sticky ستفشل في توفير هذه الميزة، وسيعمل المثال السابق في حاويةٍ في الصفحة لأنها تلك الحاوية عبارة عن عنصر iframe). - كن حذرًا للغاية عند استخدام position: sticky على شاشات الهاتف المحمول: فكل شيءٍ سيثبت مكانه سيأخذ مساحةً كبيرةً من الشاشة، مما يقلّل من المساحة الباقية لعرض محتواك. يجب أن تضبط العنصر ليكون ثابتًا sticky إذا كان ذلك ضروريًا جدًا أو كان مفيدًا للغاية، وليس لأنه «يبدو بشكلٍ جميل». تذكّر أنَّه من الأسهل للمستخدمين أن يُمرِّروا في الصفحة باللمس أعلى أو أسفل الشاشة، لذا لا تقف بطريقهم! لضمان استخدام sticky استخدامًا حكيمًا، فاكتب قاعدة @media التي تبطل تأثير position: sticky على الشاشات الصغيرة: @media all and (max-width: 600px) { #stickytest { position: static !important; } } ما سبق سيُعيد العنصر إلى مكانه الطبيعي في المستند إذا كان عرض الشاشة 600 بكسل أو أقل. ستحتاج إلى كتابة قاعدة مشابهة في JavaScript باستخدام matchMedia إذا كنتَ تستعمل حلًا التفافيًا. أعد كتابة السكربت أعلاه إلى شيءٍ شبيهٍ بما يلي: var sticky = document.getElementById('stickytest'); var screencheck = window.matchMedia("(max-width: 600px)"); Stickyfill.add(sticky); if (screencheck.matches) { Stickyfill.remove(sticky); } كقاعدة عامة، يجب أن تكون العناصر «الثابتة» هي نقطة لانقطاع المحتوى، فلا «تُثبِّت» العناصر في منتصف قطعة من المحتوى، مما يجعل النص يظهر أعلى وأسفل العنصر الثابت، وهذا أمرٌ يُشتِّت القارئ كثيرًا، ويُصعِّب من قراءة النص. وشبيهًا بما سبق، حاول أن تتفادى تثبيت العناصر التي تقسم جزءًا من محتوى نصي، مما يجبر المستخدم على التمرير بسرعة أبطأ لقراءة السطر بأكمله. احرص أنَّ لا تحتل العناصر الثابتة أكثر من الحد الأدنى المتوقع لنافذة المتصفح، فلو كانت أطول من حاويتها فلن يتمكن المستخدمون من رؤية كامل محتواها ولن يستطيعوا أيضًا قراءة بقية المحتوى الموجود في الصفحة. إضافةً إلى ما سبق، ربما تريد أن تُشير إلى أنَّ المحتوى تحت العنصر الثابت سيكون مخفيًا، وربما تستعمل تأثير الشفافية مثلًا عندما يُثبَّت العنصر، كتأثير عدم الوضوح على المحتوى خلف شريط الانتقال. فكرة أخرى هي تطبيق القاعدة position: sticky على سلسلة من العناصر، مما يجعلها تظهر بعضها تلو بعض عند نقاط مُحدِّدة أثناء التمرير. وعلى الرغم من أنَّ هذه الطريقة قد تكون فعالة، لكن يُحتَمَل أن تُربِك المستخدمين، لذا نفِّذها بعد أخذ الحيطة. للأسف، لا يوجد حدث باسم stuck في JavaScript للتبليغ أنَّ أحد العناصر قد أصبح بموضعٍ ثابتٍ. لكن يمكنك الآن اختبار ذلك يدويًا (بعض الطرائق الالتفافية تستخدم فئة class خاصة بالعناصر الثابتة للتعويض عن عدم وجود الحدث stuck). ترتيب العناصر فوق بعضها عبر z-index عندما توضع العناصر في الصفحة بمكانٍ مطلق (absolute) فيمكن أن تتداخل وتغطي على المحتوى العادي، وعلى بقية العناصر التي لها القاعدة position: absolute أيضًا. لكن عندما يحدث ذلك، فكيف سيُحدِّد المتصفح ما هو العنصر الذي يجب أن يكون في الأعلى؟ افتراضيًا، يُحدِّد المتصفح ترتيب العناصر فوق بعضها عبر ترتيب ورودها في الشيفرة. أفضل طريقة لتصور ذلك هي تخيل مجموعة أوراق لعب، وبعض أوراقها موزعةٌ على الطاولة، وتلك الأوراق هي المحتوى العادي للصفحة بما في ذلك العناصر ذات القيمة static و relative و fixed. وإذا تداخلت مع أوراقٍ أخرى موضوعة مسبقًا على الطاولة (وتلك هي العناصر ذات القيمة absolute)، فسيتم ترتيب الأوراق بناءً على ترتيب سحبها (أي أنَّ العناصر الحديثة ستظهر فوق العناصر الأقدم…). ففي مثالنا في الدرس السابق [أضف رابط درس 34676-CSS-Positioning-static-relative-absolute]، ظهرت الصور بترتيبٍ معيّن في الشيفرة، فعندما تداخلت الصور كانت صورة إسخيلوس في أسفل المجموعة، ثم أفلاطون فوقها، وفي الأعلى صورة ألكيبيادس. أسهل طريقة لإنشاء «طبقات» لعناصر ذات القاعدة position: absolute هي تغيير ترتيب ورودها في الشيفرة، فمثلًا لو غيرنا الشيفرة إلى: <div id="greek-figures"> <img src="plato-bust.jpg" alt="Plato" id="plato"> <img src="aeschylus-bust.jpg" alt="Aeschylus" id="aeschylus"> <img src="alcibiades-bust.jpg" alt="Alcibiades" id="alcibiades"> </div> فستنتج الصورة الآتية: صورة أفلاطون في المنتصف تحت الصورتين الأخريتين، لأنها تأتي أولًا في الشيفرة. ستبقى الصورة في نفس المكان، لكن ترتيبها قد تغيّر. لأسبابٍ مختلفة، قد لا نستطيع تغيير ترتيب العناصر في الشيفرة (أو لا نرغب في ذلك) لكننا نريد ترتيب العناصر بترتيبٍ يختلف عن تسلسل ورودها في الشيفرة. سنُعيد الشيفرة إلى حالتها الأصلية: <div id="greek-figures"> <img src="aeschylus-bust.jpg" alt="Aeschylus" id="aeschylus"> <img src="plato-bust.jpg" alt="Plato" id="plato"> <img src="alcibiades-bust.jpg" alt="Alcibiades" id="alcibiades"> </div> إذا أردنا إعادة ترتيب العناصر، لكننا لا نريد تعديل الشيفرة، فيمكننا إضافة الخاصية z-index إلى أنماط CSS التي تتحكم في الصور: body p { text-align: justify; } div#greek-figures { float: right; width: 250px; height: 450px; margin-left: 2em; } div#greek-figures img { height: 150px; width: 150px; position: absolute; } img#aeschylus { z-index: 2; } img#plato { top: 155px; right: 15px; z-index: 1; } img#alcibiades { top: 290px; z-index: 2; } الشيفرة السابقة ستؤدي إلى إظهار نفس نتيجة المثال الأول، لكن بدون الحاجة إلى تغيير شيفرة HTML. تُعتَبَر قيمة الخاصية z-index للعنصر body هي 0، وأيّة قيمة موجبة للخاصية z-index لأي عنصر آخر ستجعله يظهر فوق العنصر <body>. العناصر ذات الخاصية z-index والمسند إليها قيمةٌ سالبةٌ ستكون أسفله. انتبه أنَّه لو كان للعنصر body لون خلفية (عبر خاصية background-color) فستختفي تلك العناصر تحته. ما هو أعلى رقم يمكن إسناده للخاصية z-index القيمة العظمى للخاصية z-index هي 2147483647 في المتصفحات الحديثة. من المستحيل أن يكون لديك أكثر من مليارَي عنصر مكدس فوق بعضه في الصفحة، لذا لا تحاول استخدام هذا الرقم عند كتابة شيفرات CSS. ترجمة –وبتصرّف– لكل من: CSS Positioning: fixed position sticky: scroll-to-top-then-fixed in pure CSS Stacking order and z-index لصاحبها Dudley Storey
-
أحد أهم الأسئلة التي يطرحها أغلب المبتدئين بعد تعلّمهم أساسيات تعدد المواقع على ووردبريس هو: كيف أنقل موقع ووردبريس مستقل إلى موقع ضمن شبكة؟ أتى هذا الدرس ليجيب عن السؤال السابق، وذلك عبر اتباعك للخطوات الموجودة فيه لنقل موقعك إلى شبكة. سننظر في هذا الدرس إلى: كيفية استخدام الأداة Import/Export لنقل المحتوى. كيفية استخدام إضافة «Widget Settings» لنقل الودجات. كيفية تهيئة وتنظيف الموقع بعد نقله. اختيار طريقة للنقل سأريك في هذا الدرس طريقةً سهلةً لنقل موقعك عبر استعمال إضافتين، ومن ميزات هذه الطريقة السهولة والسرعة، وستؤدي إلى نقل كل شيء تقريبًا في أغلبية المواقع الاعتيادية. لكن إن أجريتَ العديد من التخصيصات على موقعك، أو أنفقتَ وقتًا طويلًا على ضبط الإضافات، فلن تؤدي هذه الطريقة إلى نقل جميع تلك الأمور. وعندها إما أن تأخذ وقتك بإعادة ضبط كل شيء يدويًا (انظر إلى آخر قسم من هذا الدرس) أو أن تنقل الموقع يدويًا عبر نسخ جداول قاعدة البيانات الضرورية. نقل جداول قاعدة البيانات يدويًا سيتطلب استخدام phpMyAdmin لتنزيل ملف SQL لجداول قاعدة البيانات، ثم تعديل الملف الناتج وإعادة رفعه لاستيراده عبر phpMyAdmin. سيوفر عليك ذلك «تنظيف» الموقع بعد نقله لكن العملية شاقة وصعبة بعض الشيء. ربما سنشرح ذلك في درسٍ منفصل، وأرجو ألّا تتحمس لتلك الطريقة، وإنما اتبع ما ورد في هذه المقالة أولًا. قبل أن تبدأ انتظر قليلًا، هنالك شيءٌ مهمٌ جدًا عليك فعله قبل أن تبدأ؛ ألا وهو أخذ نسخة احتياطية من الموقع الذي تريد نقله ولا تغفل أبدًا عن أخذ نسخة احتياطية أخرى للشبكة. للتذكرة، استخدم إحدى إضافات النسخ الاحتياطي المفضلة لديك. هل أخذتَ نسخةً احتياطيةً؟ حسنًا، لنبدأ الآن. تصدير المحتوى من الموقع القديم توفِّر ووردبريس أداة تُمكِّنك من استيراد وتصدير محتوى موقعك بسهولة. افتح الآن موقعك الذي تريد نقله (هذه صورةٌ لموقعي): اذهب إلى لوحة التحكم، ثم إلى «Tools > Export» (الأدوات > تصدير): ما لم تكن تريد تصدير أنواع معيّنة من المنشورات، فاترك خيار «All content» (كل المحتوى) مفعلًا ثم اضغط على زر «Download Export File» (تحميل ملف التصدير). ستُنشِئ ووردبريس ملف XML ثم سيُنزِّله متصفحك على حاسوبك. إنشاء موقع جديد في الشبكة افتح الشبكة التي تريد نقل الموقع إليها، وأنشِئ موقعًا جديدًا كما شرحنا سابقًا. تثبيت وتفعيل الإضافات والقوالب قبل أن تستورد المحتوى، عليك تثبيت نفس القالب الذي كنت تستخدمه على موقعك القديم وتفعيله للموقع الجديد الموجود على الشبكة. وافعل المِثل لأيّة إضافات أخرى. إذا لم تكن تعرف كيفية تثبيت وتفعيل القوالب والإضافات على الشبكة، فراجع السّلسلة آنفة الذّكر استيراد المحتوى إلى موقعك الجديد قبل أن تستورد المحتوى من موقعك القديم، فاذهب إلى قائمتَي المنشورات والصفحات في لوحة التحكم للموقع الجديد واحذف أي محتوى تجريبي أضافته ووردبريس عند إنشاء الموقع. احذف أيّة ودجات أيضًا، يجب أن يكون موقعك فارغًا. قبل أن تتمكن من استيراد المحتوى من موقعك القديم، ستحتاج إلى تثبيت إضافة WordPress Importer، وذلك بالذهاب إلى صفحة الإضافات في لوحة تحكم الشبكة وتثبيت تلك الإضافة (عليك البحث عن «WordPress Importer»). اذهب الآن في لوحة تحكم الموقع الجديد إلى «Tools > Import» (أدوات > استيراد) ثم مرِّر إلى الأسفل لتجد خيار الاستيراد من ووردبريس (WordPress). ستطلب ووردبريس منك اختيار ملف لرفعه: اضغط على زر اختيار الملف ثم انتقِ الملف الذي نزّلتَه منذ قليل على جهازك (يُفترَض به أن يتواجد في مجلد التنزيلات إلا إذا نقلتَه). تذكر أنَّك تبحث عن ملف XML. بعد أن تنتهي من ذلك فاضغط على زر «Upload file and import» (ارفع الملف واستورده). سيُطلَب منك اختيار فيما إذا كنت تريد إسناد المحتوى إلى مستخدمين موجودين في الشبكة، أو استيراد المستخدمين: اختر ما يناسبك. سأسندُ المنشورات إلى مستخدمٍ موجودٍ مسبقًا، لكن إذا كان موقعك متعدد المستخدمين ولكل مستخدمٍ له منشوراتٌ خاصةٌ به، فربما عليك استيراد المستخدمين أيضًا. في النهاية، اختر «Download and import file attachments» (تنزيل واستيراد المرفقات) لنسخ ملفات الوسائط من موقعك القديم ووضعها في مكانها الصحيح في الموقع الجديد. هذه إحدى أكثر ميزات أداة الاستيراد فائدةً، ولا أظن أنني لم أفعِّل هذا الخيار لأي موقع أستورد مقالاته من قبل! اضغط على زر الإرسال وستقوم أداة الاستيراد بعملها. في النهاية سترى رسالة تفيدك بانتهاء الاستيراد. انظر حينها إلى قائمة المنشورات في لوحة التحكم لترى أنَّ جميع المنشورات قد تم استيرادها بشكلٍ صحيح، وستجد صفحات موقعك أيضًا. لقد أنهينا هنا استيراد المحتوى، وحان الآن الوقت لاستيراد الودجات، وذلك عبر استخدام إضافة أخرى. نقل الودجات قبل نقل أيّة ودجات، عليك أن تتأكّد أنَّك قد فعَّلتَ نفس القوالب والإضافات على موقعك الجديد والتي كانت موجودةً في موقعك القديم. وأثناء تثبيتك للإضافات، فثبّت بطريقك إضافة «Widget Settings Import/Export» وفعِّلها على الموقع الجديد. ملاحظة: ستوضع الودجات في مناطق معيّنة مُعرَّفة من قِبَل قالبك، لذا إذا لم تُفعِّل القالب الصحيح فلن تعمل هذه الخطوة عملًا سليمًا. أيضًا إن كانت هنالك إضافات توفِّر ودجات خاصة بها، فلن يتم استيرادها إن لم تُثبِّت تلك الإضافات على الموقع الجديد. اذهب إلى لوحة التحكم في موقعك القديم وثبِّت وفعِّل إضافة Widget Settings أيضًا، ثم اذهب إلى «Tools > Widget Settings Export» للانتقال إلى صفحة التصدير: وما لم تكن تريد انتقاء بعض الودجات من موقعك القديم، فاختر «Select All Active Widgets»، ثم اضغط على زر «Export Widget Settings» لتنزيل ملف التصدير. بدِّل الآن إلى الموقع الجديد واذهب إلى «Tools > Widget Settings Import». اضغط على زر اختيار الملف واعثر على الملف الذي نزلتَه من قليل، لاحظ أنَّك تبحث عن ملف json هذه المرة، وليس XML. ثم اضغط على زر «Show widget settings» لرؤية الودجات الموجودة في الملف: اختر الودجات التي تريد استيرادها، أو اضغط على زر «Select All Active Widgets» وتأكّد أنك فعّلتَ خيار «Clear Current Widgets Before Import»، ثم اضغط على زر «Import Widget Settings». اذهب الآن إلى موقعك الجديد وتأكّد أنَّه أصبح شبيهًا بالقديم: «تنظيف» الموقع ستستورد الإضافتان السابقتان محتوى موقعك القديم إلى الجديد، لكنهما لن تستوردا جميع الضبط. وهذا يعني أنَّك قد تحتاج إلى تعديل بعض الإعدادات يدويًا. وهذا قد يتضمن: تعديل عنوان الموقع والوصف الخاص به. إجراء أيّة تعديلات أو تخصيصات على تصميم الموقع والتي أجريتها عبر صفحة «تخصيص القالب». تعديل إعدادات الإضافات. أنصحك بفتح كلا الموقعين في نافذتين مختلفين في متصفحك والنظر إلى ضبط الموقع القديم وتعديل ضبط الموقع الجديد بما يتوافق معه. التأكد أنَّ قوائم التنقل قد أضيفت إلى أمكانها الصحيحة في قالبك. ستنسخ إضافة الاستيراد القوائم لكن ربما لن تُسنِد القائمة الصحيحة إلى مكانها الصحيح إن كانت عندك أكثر من قائمة. إذا كان لديك نطاق وأردت نقله من موقع القديم، فعليك ربطه إلى موقعك الجديد الموجود في الشبكة. فبعد أن تنتهي من نسخ كل شيء بين الموقعين فستحتاج إلى تعديل ضبط DNS لنطاقه ليشير إلى الشبكة. ومن ثم ستحتاج إلى استخدام إضافة Domain Mapping في الشبكة لكي يُشير النطاق إلى موقعك بصورة سليمة. لتعليماتٍ تفصيليةٍ انظر إلى درس كيفية ربط النطاقات في شبكة ووردبريس في السّلسلة آنفة الذّكر [أضف رابط الدّرس] نقل موقع مستقل إلى شبكة أسهل مما تتخيل! أعلم من كثرة الأسئلة حول موضوع نقل موقع مستقل إلى شبكة أنَّ الكثيرين يظنون أنَّ الأمر مرعبٌ ومخيف، لكن كما رأيتَ في هذا الدرس أنَّ ذلك سهلٌ وبسيط! وأنصحك أن تضيف هذا الدرس إلى قائمة المفضلة في متصفحك وترجع إليه في كل مرة ستحتاج فيها إلى نقل موقع مستقل إلى شبكة. يمكنك عبر اتباعك للخطوات السابقة أن تنقل موقعك (أو موقع عميلك) إلى شبكة متعددة المواقع دون جهدٍ كبير. ترجمة -وبتصرّف- للمقال How to Move a Single WordPress Site into a Multisite Network لصاحبته Rachel McCollin
-
يهرع الكثير من المبتدئين إلى طرائق تحديد مواقع العناصر في CSS معتقدين أنها ستحل لهم جميع المشاكل التي يواجهونها في تخطيط الصفحة، لكن هذا ليس صحيحًا بالمطلق: هنالك جوانب أخرى في CSS مسؤولةٌ عن تخطيط الصفحة. وصحيحٌ أنَّ طرائق تحديد المواقع العناصر لها دورٌ لتلعبه في تخطيط الصفحة، لكن من الأحسن أن تعرف كيف ومتى عليك استخدام مختلف أنماط تحديد المواقع، عوضًا عن محاولة تجريبها لربما «حلّت» لك مشكلتك! طريقة static لتحديد مواقع العناصر افتراضيًا، يملك كل عنصر في صفحتك القاعدة position: static مطبقةً عليه، ولهذا السبب لن نحتاج إلى التصريح عن هذه الطريقة، إلا إذا كان ذلك ضروريًا لإلغاء تأثير خاصية position أخرى قد ورثها العنصر من غيره. الكلمة static لا تعني أنَّ العنصر سيبقى في مكانه في الصفحة، وفي الواقع أرى أنَّ هذه الكلمة غير دقيقة وكان يجب استخدام كلمة أخرى (مثل fluid) بدلًا عنها. طريقة تحديد مواقع العناصر الافتراضية تعني أنَّ العناصر لن تتداخل وتظهر فوق بعضها، أي أنَّ كل عنصر «سيدفع» العناصر الأخرى بعيدًا عنه، مستجيبًا إلى قياس ودقة والنسبة بين طول وعرض الجهاز الذي يعرض صفحة الويب. لنأخذ مثالًا بسيطًا لمحتوى صفحة: <p><img src="assets/images/pericles.jpg" style="float: left;" alt="Bust of Pericles"> Pericles was a prominent statesman, orator, and naval general of Athens during the city-states's <q>Golden Age</q>, from 448BCE until his death in 429. Pericles was a promoter of the arts (particularly plays), architecture (it was under his patronage that the Parthenon was built), and the principles of democracy, but he was also an instigator of war: Pericles is widely held to be responsible for maneuvering Athens into the disastrous Peloponnesian War with Sparta.</p> حجز كل عنصرٍ –في المثال السابق– مساحةً خاصةً به، فلن تظهر الصورة فوق النص، وسيبتعد النص قليلًا عن الصورة. تغيير قياس نافذة المتصفح سيُسبِّب بتضييق عرض الصفحة، وستلتف أسطر الفقرة حول الصورة وستدفع أي محتوى أدناها إلى الأسفل. وهذا جيد، لأنَّ الصفحة ستتأقلم مع أيّ قياس للشاشة وأي نسبة عرض إلى ارتفاع وأي دقة، ولن تظهر أيّة عناصر فوق بعضها. لاحظ أنَّ قاعدة «لا شيء سيتداخل، وكل شيء سينساب حول بقية العناصر» هي المبدأ الرئيسي لطريقة position: static إلا أنَّ هنالك بعض الاستثناءات. فمثلًا سيظهر النص فوق صورة الخلفية، ويمكن أن نلغي انسيابية العناصر بتحديد عرض ثابت على عناصر div الحاوية لبقية العناصر، ويمكن أن تتداخل العناصر أو تُزاح من الصفحة إذا طبقنا هامشًا (margin) سلبيًا عليها. لكن في الحالة العامة ستُطبَّق قاعدة static كما هي. العناصر المُطبَّق عليها القاعدة position: static –سواءً بتصريحنا بذلك، أو افتراضيًا– لا يمكن أن تملك الخاصيات التي سنتحدث عنها في الأقسام التالية (وهي top و left و bottom و right). العناصر التي لها القيمة static للخاصية position يمكن أن تُحرَّك فقط بتعديل قيم الخاصيتَين margin أو padding، أو عبر تعديل موقعها في شيفرة HTML. وهذا أمرٌ مقبولٌ بين المطورين وبسيطٌ وسهل التطبيق في أغلبية التصاميم. طريقة relative لتحديد مواقع العناصر من المهم ملاحظة أنَّ تطبيق القاعدة position: relative على أحد العناصر لن يُغيّر شيئًا بمفردها، فسيبقى العنصر يسلك سلوك العناصر ذات القيمة static لخاصية position (كما في القسم السابق). لكن القيمة relative قد أعطتنا وصولًا إلى الخاصيات top و left و bottom و right. فعند تطبيق القاعدة position: relative بالإضافة إلى إحدى الخاصيات السابقة، فسيحدث أمران: سيَخرُجُ العنصر من مكانه في المستند، لكن ستبقى المساحة الفارغة المحجوزة له باقيةً (كما لو كان static). سيُزاح العنصر بمقدارٍ مساوٍ للقيم المنسدة إلى الخاصيات top و left و bottom و right، نسبةً إلى موقعه الأصلي (static). ما يزال بالإمكان تطبيق الخاصية float على العناصر ذات القاعدة position: relative. سنُعدِّل في المثال السابق ليصبح كما يلي: <p><img src="assets/images/pericles.jpg" style="position: relative; top: 2em; right: 4em;" alt="Bust of Pericles"> Pericles was a prominent statesman, orator, and naval general of Athens during the city-states's <q>Golden Age</q>, from 448BCE until his death in 429. Pericles was a promoter of the arts (particularly plays), architecture (it was under his patronage that the Parthenon was built), and the principles of democracy, but he was also an instigator of war: Pericles is widely held to be responsible for maneuvering Athens into the disastrous Peloponnesian War with Sparta.</p> كما لاحظت، ستُزاح الصورة بمقدار 2em إلى الأسفل انطلاقًا من أعلى موقعها الأصلي، و 4em من اليمين. لاحظ كيف بقيت المساحة محجوزةً للعنصر الأصلي، وكيف يتلف النص حولها، وأنَّ الصورة ستتداخل مع بعض الأسطر النصية. ربما أسهل طريقة لكي تفهم فيها position: relative هي أنَّ تتخيل أنَّها تستخدم «لإزاحة» العناصر لكنك لا ترغب بالتأثير على تخطيط بقية الصفحة. وذلك لأنَّ المساحة المعطاة إلى العنصر الأصلي ما تزال موجودةً. إذ يمكنك بكل سهولة إعطاء قيم إلى خاصيات top و left و bottom و right (يمكن أيضًا استخدام القيم السلبية) دون أن تقلق من تأثير ذلك على بقية عناصر الصفحة. طريقة absolute لتحديد مواقع العناصر المطورون الذين يملكون المعلومات الكافية في CSS لكي يقعوا في مشاكل، مع المصممين المهووسين بأن تكون تصاميمهم دقيقة جدًا، سيجنحون إلى استخدام position: absolute استخدامًا مفرطًا؛ ويجادلون قائلين «بإمكاننا وضع أي شيء في صفحة الويب في المكان الذي نريده». لكنهم للأسف يغفلون عدِّة نقط مهمة، وسيقعون حتمًا في حالتين اللتين ستؤديان إلى حدوث «متاهة» مقعدة في الصفحة. لكن دعنا أولًا نرى ماذا تفعل قاعدة position: absolute بصفحتنا. ستصبح الشيفرة كما يلي: <p><img src="assets/images/pericles.jpg" style="absolute; top: 0; left: 30px;" alt="Bust of Pericles"> Pericles was a prominent statesman, orator, and naval general of Athens during the city-states's <q>Golden Age</q>, from 448BCE until his death in 429. Pericles was a promoter of the arts (particularly plays), architecture (it was under his patronage that the Parthenon was built), and the principles of democracy, but he was also an instigator of war: Pericles is widely held to be responsible for maneuvering Athens into the disastrous Peloponnesian War with Sparta.</p> عند تطبيق قاعدة position: absolute، فستفقد الخاصتان float و margin تأثيرهما، لذا أزلتُهما. تؤدي القيمة absolute إلى نزع الصورة من مكانها في المستند تمامًا، أي ستؤخذ وتُرفَع إلى أعلى المستند الذي سيظهر تحتها. باختصار: ستسلك صفحة الويب سلوكًا مشابهًا لسلوكها كما لو أنَّ الصورة غير موجودة من الأساس. لماذا إذًا يستعمل الكثيرون position: absolute؟ لأنَّنا نستطيع تحديد موضع العنصر –عند استخدام absolute– انطلاقًا من الزاوية العليا اليسرى للعنصر الحاوي لها، وهو العنصر body في حالتنا. قد تبدو لك position: absolute جذابةً، حيث يبدو أنَّها تعدك بوضع العناصر في مكانها بدقة شديدة. وهذا مغرٍ جدًا للمصممين التقليديين الذين يصممون تصاميم لسطح المكتب أو للطباعة، والمعتادين على التحكم بمكان كل شيء في صفحات A4، والذي لا يرون داعٍ للتصميمات المتجاوبة. لكنهم يرفضون أن يلاحظوا بضع نقاط: صفحات الويب ليست كالورق ذي القياس المعياري. فالشاشات والمتصفحات والأجهزة تملك أحجام ونسب ودقة مختلفة. واستخدام absolute لوضع العناصر في الصفحة يعني افتراض مجموعة من المتغيرات عن جهاز المستخدم، مما يؤثِّر سلبًا في مرونة الويب. بعد أن تُطبِّق position: absolute على أحد العناصر، فستجد نفسك تُطبِّق نفس القاعدة على كل العناصر الأخرى. وذلك لأنَّ position: absolute سينتزع العنصر من المستند، ويجب علينا تعديل موضع بقية العناصر للتأقلم مع ذلك ولضمان عدم تداخل العناصر التي لا تريدها أن تتداخل. وهذا سيؤدي إلى إنشاء قواعد CSS معقدة والتي لن تعمل كما يجب عند إضافة محتوى جديد إلى الصفحة (أكرِّر أنَّ الويب ليس صفحةً مطبوعةً، حيث تُعدَّل المحتويات وتُضاف إضافات بين الحين والآخر، ويجب أن يكون تصميمك مرنًا كفايةً للاستجابة إلى تلك التعديلات). واستخدام position: absolute يجعل التعديلات على الصفحة تأخذ وقتًا طويلًا وجهدًا كبيرًا. لماذا نستخدم إذًا position: absolute من الأساس؟ حسنًا، إذا استخدمنا absolute استخدامًا حكيمًا، فيمكن أن نستفيد منها لتداخل العناصر المنفصلة التي كانت لتُدمَج في صورةٍ وحيدةٍ. على سبيل المثال، لنقل أنَّك تريد الإضافة على المقالة السابقة ووضع صور أخرى من العصر الذهبي لأثينا. أي لديك عدِّة صور (إسخيلوس وأفلاطون وألكيبيادس)، وتريد أن تضعها على الجانب الأيمن لمستندك، وتريدها أن تتداخل مع بعضها. أحد الحلول هي تعديل الصور باستخدام فوتوشوب، بدمجها مع بعضها في صورةٍ وحيدة، لكن هذا سيمنعك من تعديل ترتيبها ومحاذاتها والتباعد بينها لاحقًا، وعليك حينها العودة إلى ملف فوتوشوب لإجراء تعديلاتك ثم إعادة التصدير ورفع الصورة من جديد. لكن بدلًا من كل ما سبق، لنحاول الإبقاء على الصور معزولةً ونضعها داخل عنصر <div>. شيفرة HTML هي: <div id="greek-figures"> <img src="aeschylus-bust.jpg" alt="Marble bust of Aeschylus" id="aeschylus"> <img src="plato-bust.jpg" alt="Marble bust of Plato" id="plato"> <img src="alcibiades-bust.jpg" alt="Marble bust of Alcibiades" id="alcibiades"> </div> نعلم أنَّ لهذه الصور نفس الأبعاد، لذا لن نحتاج إلى تحديد خاصيات height و width لكل واحدة على حدة. وإنما سنجعل ذلك ضمن أنماط CSS: div#greek-figures { float: right; } div#greek-figures img { height: 150px; width: 150px; position: absolute; } إذا حاولتَ عرض الصفحة الآن، فستجد أنَّ عنصر <div> قد تضائل، وظهرت صورةٌ وحيدةٌ فقط وهي خارجة عن مكانها. هل لديك أيِّة فكرة عن السبب؟ …[تريّث قليلًا وفكِّر بالسبب قبل إكمال القراءة]… الجواب: لقد طُبِّقَت القاعدة position: absolute على الصورة، لذا تم انتزاعها من مكانها في الصفحة، ولم تعد تستطيع «دفع» العناصر التي حولها. أما عنصر div بعد وضع الخاصية float له فسيحاول تحديد عرضه عبر محتوياته التي بداخله؛ لكن المحتوى (أي الصور) لها القيمة absolute، فلن تُحتَسَب، والصور هي المحتوى الوحيد الموجود في العنصر <div>، أي أنَّ العنصر <div> ليس له عرض! في النهاية، ستحاول كل صورة أن تضع نفسها داخل عنصر <div> في الزاوية العليا اليسرى، وهذا يعني أنَّ الصور ستتكدس فوق بعضها. لاحظ أنَّ آخر صورة داخل العنصر div ستكون في الأعلى (وسنتحدث عن هذا الأمر في درسٍ لاحق). لنحاول الآن حلّ المشاكل السابقة بتعديل CSS: body p { text-align: justify; } div#greek-figures { float: right; width: 250px; height: 450px; margin-left: 2em; } div#greek-figures img { height: 150px; width: 150px; position: absolute; } img#plato { top: 155px; right: 15px; } img#alcibiades { top: 290px; } (وفرنا خاصية height لعنصر div لأنَّ الصور التي موضعها absolute لن تساهم في توفير ارتفاع للعنصر؛ وبدون ارتفاع فلن تجد الأسطر النصية شيئًا لتلتف حوله. أضفنا بقية الخاصيات مثل text-align والهوامش لإظهار الصفحة بشكل جميل). سيعمل ما سبق كما ينبغي، لكنك ستتكشف شيئًا غريبًا. إذا عدَّلتَ الخاصية right لصورة أفلاطون إلى left، فلن تحصل على ما كنتَ تتوقعه. فبدلًا من قياس الموضع من الحاوية، فستُنسَب الصورة نفسها إلى أكبر حاوية وهي العنصر <body>. يمكننا الالتفاف على هذه المشكلة بإضافة قاعدة في أنماط CSS: div#greek-figures { float: right; width: 250px; height: 450px; margin-left: 2em; position: relative; } وستكون النتيجة النهائية هي: إذا كان العنصر الذي له القيمة absolute للخاصية position موجودًا ضمن عنصرٍ آخر تُطبَّق عليه القاعدة position: relative، فستُقاس إحداثيات العنصر انطلاقًا من الزاوية العليا اليسرى للحاوية التي يقع فيها؛ وإلا فستُقاس الإحداثيات انطلاقًا من الزاوية العليا اليسرى من العنصر body. عمومًا، إذا كنتَ تُصرّ على استخدام position: absolute فأنصحك بوضع عدِّة عناصر (التي لها القاعدة position: absolute) في «حاوية» (إما عنصر <div> عادي أو حتى <canvas>). مما يسمح لك بنقلها مع العناصر الموجودة داخلها دون مشاكل. ترجمة -وبتصرّف- للمقالات CSS Positioning: static, the default CSS Positioning: relative, the underappreciated CSS Positioning: absolute, the overused لصاحبها Dudley Storey
-
أصبحت تطبيقات الويب ذات الصفحة الوحيدة Single Page Apps رائجةً في هذه الفترة في تطوير الويب، فأمسى كل شخصٍ يريد أن ينُشِئ تطبيق ويب ذا صفحةٍ وحيدة. سأريك في هذا الدرس طريقةٍ سهلة لإنشاء تطبيقات الويب ذات الصفحة الوحيدة باستخدام jQuery ودون استخدام أيّة إطارات عمل مثل React أو Angular أو Vue …إلخ. لمحة لأننا نريد إنشاء تطبيق ويب ذا صفحةٍ وحيدة، فسنستخدم sammy.js للتوجيه (routing)، مكتبة Sammy هي مكتبة jQuery بمساحة تخزينية لا تتجاوز 5.2 كيلوبايت. سيبدو سكربت التوجيه المكتوب لإضافة Sammy كما يلي: var app = $.sammy(function() { this.get('#/', function() { //your function }); this.get('#about/', function() { //your function }); this.get('#contact/', function() { //your function }); }); علينا أولًا تهيئة التطبيق باستخدام $.sammy وتخزين نسخة من الكائن في المتغير app. يمكننا تعريف تعليمة «توجيه» (route) في sammy بالطريقة الآتية: this.get('path/',function(){ // ... }); هنالك دالة ستُستدعى لكل عملية توجيه، والتي يمكن أن نكتب بداخلها البنية المنطقية لها، ونربط البيانات اللازمة إلى كل «صفحة»، لأن كل عملية توجيه ستؤدي إلى إظهار «صفحة» مختلفة. بعد تعريف كل تعليمات التوجيه، فسنتمكن من تشغيل تطبيق الويب ذي الصفحة الوحيدة باستدعاء الدالة run() التابعة للكائن app كالتالي app.run(). تطبيق التدوين الذي سننشئه لتوضيح المفهوم الذي سنشرحه، فسنحاول إنشاء مثال واقعي. لنفترض أننا نريد إنشاء مدونة بسيطة، التي يوجد فيها صفحة رئيسية (أي صفحة Home) وصفحة معلومات (About). سنُنشِئ في صفحة index قائمة بالتدوينات، والضغط على أي واحدة منها سيأخذنا إلى صفحتها. يمكنك أن تجرب هذا التطبيق عمليًا هنا. سنستخدم صيغة JSON لقائمة التدوينات، وسنستخدم إضافة Sammy لعرضها. بنية الملفات - index.html <!-- main layout --> - app.js <!-- stores all our routing logic --> - css --- style.css - js --- jquery-1.11.3.min.js --- sammy.min.js --- sammy.template.js - data --- articles.json - templates <!-- the templates pages that will be injected into the main layout --> --- article.template --- article-detail.template --- about.template شيفرة HTML سنستخدم قالب HTML boilerplate لإنشاء شيفرة HTML: <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <script src="js/jquery-1.11.3.min.js" type="text/javascript"></script> <script src="js/sammy.min.js" type="text/javascript"></script> <script src="js/sammy.template.js" type="text/javascript"></script> <link rel="stylesheet" href="css/style.css" /> <script src="app.js"></script> </head> <body> <div class="header-container"> <header class="wrapper clearfix"> <nav> <ul> <li><a href="#/">Home</a></li> <li><a href="#/about/">About</a></li> <!-- defining nav url according to route--> </ul> </nav> </header> </div> <div class="main-container"> <div class="main wrapper clearfix"> <div id="app"> <!-- template will be injected here --> </div> </div> </div> </body> </html> تعريف التوجيهات //app.js (function($) { var app = $.sammy('#app', function() { this.use('Template'); this.around(function(callback) { var context = this; this.load('data/articles.json') .then(function(items) { context.items = items; }) .then(callback); }); this.get('#/', function(context) { context.app.swap(''); $.each(this.items, function(i, item) { context.render('templates/article.template', {id: i, item: item}) .appendTo(context.$element()); }); }); this.get('#/about/', function(context) { var str=location.href.toLowerCase(); context.app.swap(''); context.render('templates/about.template', {}) .appendTo(context.$element()); }); this.get('#/article/:id', function(context) { this.item = this.items[this.params['id']]; if (!this.item) { return this.notFound(); } this.partial('templates/article-detail.template'); }); this.before('.*', function() { var hash = document.location.hash; $("nav").find("a").removeClass("current"); $("nav").find("a[href='"+hash+"']").addClass("current"); }); }); $(function() { app.run('#/about/'); }); })(jQuery); هيئنا في البداية التطبيق داخل العنصر #app، حيث سنُضيف القوالب المختلفة بناءً على مسار التوجيه. سنستخدم أيضًا محرك قوالب باسم sammy template engine. this.use('Template'); سنحصل على بيانات المدونة من ملف articles.json باستخدام الدالة load() التابعة لمكتبة jQuery (يمكنك أيضًا استخدام $.get أو $.post)، وتخزين الناتج في المتغير context. حان الآن الوقت لتعريف تعليمة التوجيه لصفحة index باستخدام #/: this.get('#/', function(context) { context.app.swap(''); $.each(this.items, function(i, item) { context.render('templates/article.template', {id: i, item: item}) .appendTo(context.$element()); }); }); لدينا بيانات مخزنة في المتغير context، سنمرّ الآن عبر تلك البيانات عبر حلقة تكرار باستعمال الدالة $.each ثم عرضها في article.template. سنستخدم أيضًا الدالة context.app.swap() لكي نُفرِّغ العنصر الذي سنضع فيه المحتويات (أي #app) مما فيه قبل عرض القالب. <article> <section> <a href="#/article/<%= id %>"><h2><%= item.title %></h2></a> </section> </article> سنستخدم هنا مُحرِّك القوالب (templating engine) لكي نعرض القيم القابلة للتغيير باستخدام الصيغة <%= yourdata %>، يمكنك أيضًا إضافة رابط لصفحة تفاصيل كل مقالة باستخدام الصيغة #/article/<%= id %>. الضغط على رابط التدوينة سيأخذنا إلى قالب article-detail.template، حيث نستطيع إظهار صورة التدوينة وملخص عنها …إلخ. وخلف الكواليس، سنُعرِّف تعليمة توجيه إلى تفاصيل التدوينة في ملف app.js، وسنحصل على مُعرِّف التدوينة كمعامل (parameter) ثم نُمرِّر البيانات إلى article-detail.template. this.get('#/article/:id', function(context) { this.item = this.items[this.params['id']]; if (!this.item) { return this.notFound(); } this.partial('templates/article-detail.template'); }); وبشكلٍ شبيه، يمكننا إنشاء صفحة ثابتة باسم «about» ونعرضها عبر قالب about.template. this.get('#/about/', function(context) { var str=location.href.toLowerCase(); context.app.swap(''); context.render('templates/about.template', {}) .appendTo(context.$element()); }); لقد نسينا أهم خطوة، ألا وهي تهيئة التطبيق باستخدام app.run() حيث يمكنك تحديد مكان التوجيه الافتراضي لتطبيقك. إذا أردتَ أن تفتح صفحة about أولًا فيمكنك أن تكتب: $(function() { app.run('#/about/'); }); إذا أردتَ إجراء بعض العمليات قبل استدعاء كل تعليمة توجيه، فيمكنك استخدام الدالة before(). سنُجري في الأسطر الآتية تعديلاتٍ على قائمة التنقل (nav) اعتمادًا على مسار التوجيه الحالي: this.before('.*', function() { var hash = document.location.hash; $("nav").find("a").removeClass("current"); $("nav").find("a[href='"+hash+"']").addClass("current"); }); الخلاصة هذا درسٌ بسيطٌ جدًا لكي تأخذ فكرة عن كيفية عمل تطبيق ذي صفحةٍ وحيدةٍ باستخدام jQuery. يمكنك الآن المضي قدمًا وإنشاء تطبيقات ذات صفحة وحيدة. إحدى الأشياء التي عليك أن تأخذها بعين الاعتبار هي أنَّك ستحتاج إلى خادوم ويب لتشغيل التطبيق، ويمكنك أيضًا تجربة متصفح Firefox، لأنَّ متصفح Chrome يحجب طلبيات Ajax لأيّة بروتوكولات ما عدا http:// أو https://، لذا إذا كنتَ ستُشغِّل هذا السكربت على جهازك المحلي فلن يعمل لأنَّ مسارات الملفات المحلية تبدأ بالسابقة file://. ترجمة –وبتصرّف– للمقال Single Page Apps with jQuery Routing لصاحبه Arkaprava Majumder
- 1 تعليق
-
- single page apps
- spa
-
(و 1 أكثر)
موسوم في:
-
أهلًا بك إلى الدّرس الأخير من الدورة التدريبية الشاملة في ميزة تعدد المواقع في ووردبريس. سنواصل في هذا الدّرس استعراض ما تحتاجه لإدارة شبكة مواقعك على ووردبريس مُتعدّد المواقع بفاعلية. إن لم تقرأ الجزء السّابق فقد ترغب في الاطّلاع عليه أولا من هنا. قد ترغب أيضا في الاطّلاع على باقي مقالات هذه السّلسلة من هنا. أخذ نسخ احتياطية من شبكتك من المهم جدًا أن تأخذ نسخًا احتياطيةً من كامل شبكتك –ومن كل موقع موجود فيها– دوريًا. التواتر الذي عليك أخذ النسخ الاحتياطية فيه يتعمد على الزمن الفاصل بين تحديث مستخدميك للمحتوى الموجود على مواقعهم. الأمور التي يجب أخذها بعين الاعتبار عند النسخ الاحتياطي هنالك جانبان رئيسيان للنسخ الاحتياطي في شبكتك: نسخ المواقع في شبكتك على حدة احتياطيًا. نسخ كامل الشبكة احتياطيًا. من المستحسن أن تجري كلا الأمرين، وبهذه الطريقة ستتمكن من استعادة موقع معيّن إذا حدثت مشكلة فيه، أو ستتمكن من استعادة كامل الشبكة إن حدثت فيها مشكلة، أو حدثت مشكلة في أكثر من موقع. عليك أن تضعن بعين الاعتبار ما الذي ستنسخه عندما تنسخ المواقع أو الشبكة احتياطيًا: ملفات الإضافات والقوالب: لستَ مضطرًا إلى نسخ هذه الملفات احتياطيًا بنفس وتيرة نسخك لباقي العناصر، لأنها لا تتغير كثيرًا. الملفات المرفوعة: عليك أن تنسخ هذه الملفات احتياطيًا بوتيرة أكبر، لأن مستخدميك قد يضيفون ملفات مرفوعة جديدة في كل مرة يضيفون فيها محتوى جديد. قاعدة البيانات: عليك إبقاء قاعدة البيانات منسوخةً نسخًا احتياطيًا دوريًا، لأنَّك لا تريد المخاطرة بفقدان أيّ محتوى جديد أضافه مستخدموك. ربما تُقرِّر أن تنسخ قاعدة البيانات ومجلد uploads احتياطيًا في كل يوم، وملفات القوالب والإضافات كل أسبوع. لكن ربما يُنشِئ مستخدموك المحتوى بوتيرة أكبر، وبهذا عليك تقليل الفترة الفاصلة بين عمليات النسخ الاحتياطي. أمر آخر عليك أخذه بعين الاعتبار هو مكان احتفاظك بالملفات المنسوخة احتياطية وقاعدة البيانات. إضافات النسخ الاحتياطي الشهيرة تعطيك بعض الخيارات: تخزين النسخ الاحتياطية على خادومك: لا أنصحك بفعل ذلك بمفرده لأنَّه إذا واجه خادومك مشاكل، فربما لن تتمكن من الوصول إلى ملفات النسخ الاحتياطي. تسمح لك أغلبية الإضافات بتخزين ملفات النسخ الاحتياطي على خادومك وعلى مكانٍ آخر. استخدام خدمة تخزين سحابي من طرف ثالث مثل Dropbox أو Google Drive: وهذا فكرةٌ جيدةٌ إن كنتَ تملك حسابًا على أحد تلك المواقع، أو يمكنك أن تُهيئ حسابًا فيها إن شئت. إرسال النسخ الاحتياطية لك بالبريد الإلكتروني: بعض الإضافات المجانية لا توفر خيارًا إلا هذا الخيار. لكن ذلك قد يؤدي إلى امتلاء صندوق الوارد عندك وليس عمليًا كاستخدام خيار التخزين السحابي. عليك أن تستعمل إضافةً تُسهِّل إجراء الخيار الذي اخترته، والتي عليك ضبطها مرةً واحدةً فقط دون القلق على أداءها. أنصح دائمًا باستخدام إضافة مدفوعة مثل Snapshot Pro، التي تجعل عملية استعادة الملفات المنسوخة أسهل بكثير فيما إذا كنتَ تستعمل إضافةً مجانيةً. القدرة على استعادة المواقع بسرعة على شبكتك هو أمرٌ مهمٌ جدًا، لأنه يقلل من وقت توقف الموقع (أو الشبكة) عن العمل. استخدام إضافة Snapshot Pro لنسخ المواقع على شبكتك يمكنك استخدام إضافة Snapshot Pro لأخذ نسخ احتياطية من كل موقع على شبكتك على حدة. ستحتاج إلى فعل ذلك في كل مرة تُضيف فيها موقعًا إلى الشبكة، إذًا هذه الإضافة مناسبة للشبكات التي تتألف من مواقع خاصة بك أو خاصة بعملائك، أو الشبكات الصغيرة التي يُنشِئ فيها المستخدمون مواقعهم. إذا كان لديك الكثير من المستخدمين الذين يُنشِئون مواقعهم، فربما ستحتاج إلى استخدام إضافة بديلة لإبقاء كل الشبكة منسوخة احتياطيًا، وهذه أمرٌ حسنٌ، وسنفصِّله لاحقًا. بدايةً، ثبِّت إضافة Snapshot Pro عبر لوحة تحكم WPMU DEV وفعِّلها لكامل الشبكة. قبل إنشاء أيّة نسخ احتياطية، عليك أن تُضيف وجهات للأماكن التي تريد أن تُرسَل إليها النسخ الاحتياطية. اذهب إلى «Snapshots > Destinations» لكي ترى الخيارات: انقر على زر «Add New» لكل وجهة تريد إضافتها واتبع التعليمات. ستحتاج إلى السماح للإضافة بالوصول إلى حسابك إن كنتَ ستستخدم خدمة من طرف ثالث مثل Dropbox. بعد أن تفعل ذلك، يمكنك أن تضبط النسخ الاحتياطية. اذهب إلى «Snapshots > Add New» في لوحة تحكم مدير الشبكة لإنشاء نسخة من أحد المواقع. ابدأ بتعريف ما هو الموقع الذي ستأخذ نسخةً منه ثم أضف أيّة ملاحظات: ثم اختر الملفات التي تريد أخذ نسخةٍ احتياطيةٍ منها. ربما تريد إنشاء نسختين من نفس الموقع، واحدة فيها كل الملفات، وواحدة فيها الملفات المرفوعة فقط. أو ربما تريد إنشاء نسخة احتياطية وحيدة: إذا اخترتَ «Include common files» فسيتم تضمين الملفات المرفوعة في النسخة الاحتياطية فقط. أما إذا اخترت «Include selected files» فعليك حينها أن تختار ما هي الملفات التي عليك تضمينها في هذه النسخة الاحتياطية. في لقطة الشاشة السابقة، اخترتُ أخذ نسخة احتياطية من كل شي. الخطوة التالية هي اختيار ما هي جداول قاعدة البيانات التي تريد نسخها احتياطيًا، وما هي المدة الفاصلة بين عمليات النسخ: يمكنك تحديد جداول معيّنة أو كل الجداول المتعلقة بالموقع (وهذا هو الخيار الذي اخترتُه). يمكنك أن تختار تواتر أخذ النسخ الاحتياطية التلقائية: اخترتُ في الصورة السابقة أخذ النسخة الاحتياطية يوميًا. عليك بعد ذلك أن تُحدِّد عدد النسخ التي تريد الاحتفاظ بها على الخادوم. إذا تركت هذا الحقل مضبوطًا إلى 0، فسيتم الإبقاء على جميع النسخ الاحتياطية، لكن ذلك سيستهلك الكثير من المساحة التخزينية. غيّرتُ الرقم إلى 7، للإبقاء على النسخ الاحتياطية لأسبوعٍ كامل. إذا كنتَ تستضيف مواقع العملاء على شبكتك، فأنصحك بإبقاء ملفات النسخ الاحتياطي لشهر. في النهاية، حدِّد الوجهة التي تريد أن تحفظ النسخة الاحتياطية فيها: إذا اخترتَ وجهةً بعيدةً، فستحفظ الإضافة النسخ الاحتياطية محليًا أيضًا، إذا كنت تستخدم خدمة من طرف ثالث فيمكنك تحديد المجلد الذي تريد تخزين هذه النسخة الاحتياطية فيه. أجد أنَّ هذا مفيدٌ لأن هنالك أكثر من نسخة احتياطية لأكثر من موقع على كل شبكة من شبكاتي، ولا أريد تخزينها جميعًا في نفس المجلد. لذا سأنشِئ مجلدًا باسم الموقع في حقل «Directory (optional)»، ويمكنك استخدام نفس المجلد لتخزين أكثر من نسخة احتياطية، لذا لو كنتَ تُنشِئ أكثر من نسخة لكل موقع في شبكتك (على سبيل المثال، نسخة لقاعدة البيانات والملفات المرفوعة، ونسخة أخرى ذات تواتر أقل لكل الملفات) فيمكنك أن تحفظها جميعًا بنفس المكان. اضغط على زر «Create Snapshot» للانتهاء. ستُعرَض تفاصيل النسخة الاحتياطية الآن في صفحة Snapshots الرئيسية: يمكنك من هذه الصفحة تعديل النسخ الاحتياطية، أو تغيير تواتر النسخ، واستخدامها للقيام بعملية استعادة بضغطة زر واحدة. أخذ نسخ احتياطية من كامل الشبكة استخدام إضافة Snapshot Pro يسمح لك باستعادة موقع بضغط رز واحدة، وذلك يعني أيضًا أنَّه لو كان هنالك أكثر من موقع يعاني من مشاكل في شبكتك، فيمكنك أن تستعيد النسخة الاحتياطية دون التأثير على المواقع الأخرى في الشبكة. لكن ماذا لو حدثت مشكلة لكامل شبكتك وعليك أن تستعيد كل شيء؟ هنالك الكثير من الإضافات التي تسمح لك بأخذ نسخ احتياطية من كامل تثبيت ووردبريس (وستأخذ نسخة احتياطية لكامل الشبكة أيضًا). هنالك بعض الإضافات المدفوعة للقيام بذلك، لكن إن كنتَ تستعمل إضافة Snapshot Pro لأخذ نسخ احتياطية لكل موقع على حدة، فمن المرجح أنَّك تريد إضافةً مجانيةً للقيام بهذه المهمة. أنصحك بتثبيت وتفعيل إضافة من قائمة الإضافات المجانية للنسخ الاحتياطي واستخدامها لتهيئة عملية نسخ احتياطي مؤتمت لكامل الشبكة بشكلٍ دوري. شخصيًا أستخدمُ إضافة BackWPup التي تُرسِل نسخةً من قاعدة البيانات والملفات الخاصة بي إلى حساب Dropbox بشكلٍ دوري. المشكلة الوحيدة مع هذه النسخة المجانية هي أنَّها لا تحتوي على ميزة الاستعادة بنقرة واحدة، وهذا يعني أنَّه لو أردتُ استعادة شبكتي، فعليّ فعل ذلك يدويًا من قاعدة البيانات والملفات. إن لم تكن مرتاحًا بفعل ذلك، فربما ستفضِّل استخدام إضافة مدفوعة لنسخ كامل تثبيت ووردبريس (وليس فقط المواقع الموجودة على شبكتك كلًا على حدة). تحسين أمان الشبكة يعتمد مستخدموك وعملاؤك على شبكتك لاستضافة مواقعهم الثمينة، لذا عليك أن تتأكد أنَّ مواقعهم ستبقى آمنة. ولفعل ذلك عليك استخدام إضافة أمنية، مثل إضافة Defender. لننظر إلى كيفية تهيئتها. أولًا، ثبِّت إضافة Defender باستخدام لوحة تحكم WPMU DEV وفعِّلها على كامل الشبكة. ثم اذهب إلى «Defender > Dashboard» لتبدأ عملية التهيئة: تأمين الشبكة تأمين الشبكة يعني تصعيب حصول الأشخاص على صلاحيات غير مُصرَّح بها. ويمكنك فعلك ذلك في الصفحة الرئيسية للإضافة، أو في صفحة «Defender > Hardener». اتبع التعليمات التي تتلوها عليك الإضافة لجعل موقعك أكثر أمانًا. وهذا يتضمن أشياء مثل: تعديل سابقة قاعدة البيانات: جعل بنية قاعدة البيانات الخاصة بك أكثر غموضًا. تعطيل مُحرِّر الملفات: هذا يعطل صفحات التحرير للإضافات والقوالب، وهذا أمرٌ حسن! تعطيل trackbacks و pingbacks: حاجتك إلى فعل ذلك تعتمد فيما إذا كنتَ تريد أن تكون أنت ومستخدموك اجتماعيين. وهي تمنع الأشخاص من عمل pinging لشبكتك بشكل متكرر، مما قد يؤدي إلى حدوث خلل فيها. الوقاية من حدوث تسريب في المعلومات: وهذا يتضمن وضع ملفات .htaccess في المجلدات المناسبة لمنع المهاجمين من الوصول إلى محتواها. تعطيل تنفيذ PHP: وهذا يمنع المهاجمين من استخدام أيّة ثغرات في القوالب أو الإضافات لرفع لملفات PHP إلى موقعك وتشغيل شيفرات خبيثة. تحديث المفاتيح الأمنية: من الجيد تحديثها في فتراتٍ متقاربة لمنع القدرة على الوصول إليها واستعمالها. إذا فعلتَ ذلك، فسيتم تسجيل خروجك من موقعك (وكذلك الأمر لجميع المستخدمين)، لذا أفضِّل فعل ذلك في آخر الليل. مراقبة قوائم الحجب (blacklist): التحقق من أنَّك غير محجوب من محرك Google. سأذهب الآن إلى صفحة «Defender > Hardener» وستخبرني أنَّ كل شيءٍ مضبوطٌ ضبطًا صحيحًا: فحص موقعك بحثًا عن مشاكل يمكنك في Defender أن تقوم بفحصٍ يدوي وأن تضبط فحصًا مؤتمتًا للتحقق من أنَّ كل شيء على ما يرام في موقعك. لنبدأ بعمل فحص يدوي. اذهب إلى صفحة «Defender > Scan» ثم اضغط على زر «Scan my Website» وسيبدأ Defender بفحص شبكتك. اصبر قليلًا، قد يأخذ ذلك بعض الوقت، خصوصًا إذا كانت لديك الكثير من المواقع في شبكتك. يمكنك أن تهيئ عملية فحص مؤتمتة وذلك بالذهاب إلى «Defender > Dashboard» ثم التمرير إلى «Setup Automated Scans» والضغط على زر «Enable» لتفعيله: تحسين أداء الشبكة يرغب مستخدموك بأن تعمل مواقعهم بكفاءة عالية وسترغب أنت بأن تعمل الشبكة بسلاسة. يمكنك استخدام إضافة Hummingbird لتحسين الأداء. ابدأ بتثبيت الإضافة من لوحة تحكم WPMU DEV ثم تفعليها على كامل الشبكة. ثم اذهب إلى «Hummingbird > Dashboard» لترى نتائج اختبار إضافة Hummingbird لشبكتك: إذا مررتَ إلى الأسفل، فستجد أنَّ إضافة Hummingbird تعرض اقتراحات لتحسين الأداء. تلك الاقتراحات تعتمد على طريقة ضبطك للموقع. هذه هي النتائج الخاصة بموقعي: اتبع التعليمات الموجودة لتحسين الأداء، والتي تتضمن: التخزين المؤقت: يمكن للتخزين المؤقت أنَّ يُسرِّع وقت تحميل الصفحة. مراقبة الموقع: ستتحقق إضافة Hummingbird من أنَّ موقعك يعمل، وسترسِل إليك إشعارًا لتنبيهك إن كان لا يعمل. الضغط: وهذا يجعل الملفات أصغر مما يؤدي مما يُسرِّع من تحميلها. حذف الموارد التي توقف عرض الصفحة: وهذا ينقل الموارد مثل ملفات JavaScript و CSS إلى مكانها الصحيح في صفحات الموقع. تحسين حجم الصور: ثبِّت إضافة WP Smush Pro التي ستُحسّن الصور أثناء رفعك لهم. ثبِّتها ثم فعلها على كامل الشبكة، واتركها تعمل عملها بصمت. بعد أن اتبعتَ النصائح السابقة، فأجرِ اختبارًا آخر بالضغط على الزر الموجود في صفحة الإضافة الرئيسية. تحسّنت نتيجة موقعي من 70% إلى 86%: إذا أردتَ أن تُجري تعديلات أخرى لتصل إلى 100% تقريبًا، فتوفِّر لك إضافة Hummingbird نصائح إضافية لتتبعها. اذهب إلى «Hummingbird > Performance Report» ثم اضغط على أزرار «Improve Score» لمزيدٍ من المعلومات: إدارة شبكتك بكفاءة ستساعدها لكي تعمل بسلاسة إدارة شبكة ناجحة لا يعني تفعيل ميزة تعدد المواقع وانتظار إنشاء المواقع فيها، وإنما عليك أيضًا أن تراقب شبكتك للتأكد من تجنبك لأيّة مشاكل، ولإبقائها محدثةً دومًا ولتحسّن أداءها. إذا اتبعت الخطوات التي ذكرناها في هذا الجزء من الدورة، فستتمكن من تشغيل شبكتك بسلاسة دون مشاكل. أكملتَ الآن الدورة التدريبية لتعلم إنشاء وإدارة شبكة متعددة المواقع في ووردبريس، يجب أن تكون قد تعلمتَ فيها: ما هي ميزة تعدد المواقع وما فرقها عن المواقع المفردة المستقلة. كيفية تفعيل وضبط الشبكة متعددة المواقع. كيف تُضيف مواقع ومستخدمين إلى شبكتك بصفتك مديرًا للشبكة. كيف تُفعِّل قابلية إنشاء المواقع من قِبل المستخدمين وتُحسِّن من تجربة المستخدم خلال هذه العملية. كيف تستخدم الشبكة متعددة المواقع لاستضافة مواقع العملاء (أو مواقعك الخاصة) وتستعمل ربط النطاقات لتفعيل استخدام أكثر من نطاق. كيفية إنشاء مجتمع لمستخدمي شبكتك. كيفية إدارة الشبكة، بما في ذلك إبقاءها مُحدَّثةً دومًا، وتفادي المدونات المزعجة، وتحسين الأمان والأداء. إذا أردتَ المزيد من النصائح أو حلًا لمشاكل، فيمكنك أن تسأل في التعليقات أو أن تضيف أسئلة جديدة إلى قسم الأسئلة. ترجمة –وبتصرّف– للمقال WordPress Multisite Masterclass: Managing your Network لصاحبته Rachel McCollin.
-
سنشرح في هذا الدرس كيفية إعداد بيئة برمجية محليّة للغة بايثون 3 في توزيعة أوبنتو 16.04 أو دبيان 8. بايثون هي لغةٌ سهلة القراءة للغاية ومتنوعة ومتعددة الاستخدامات، واسمها مستوحى من مجموعة كوميدية بريطانية باسم «Monty Python»، وكان أحد الأهداف الأساسية لفريق تطوير بايثون هو جعل اللغة مرحةً وسهلة الاستخدام، وإعدادها بسيطٌ، وطريقة كتابتها مباشرة وتعطيك تقريرًا مباشرًا عند حدوث أخطاء، وهي خيارٌ ممتازٌ للمبتدئين والوافدين الجدد على البرمجة. إصدار بايثون 3 هو الإصدار الحالي من اللغة ويُعتَبَر أنَّه مستقبل بايثون. سيُرشِدُك هذا الدرس خطوةً بخطوة إلى كيفية تثبيت بايثون 3 على نظام لينكس المحلي عندك وذلك عبر سطر الأوامر، وصحيحٌ أنَّ هذا الدرس يشرح عملية التثبيت لتوزيعة أوبنتو 16.04 أو دبيان 8، إلا أنَّ المفاهيم الأساسية فيه تنطبق على أيّة توزيعة أخرى. المتطلبات المسبقة يجب أن يكون لديك حاسوبٌ يعمل بتوزيعة أوبنتو 16.04 أو دبيان 8 (أو أيّ إصدار آخر من دبيان)، وأن تكون لديك امتيازات إدارية على النظام، بالإضافة إلى اتصالٍ بالإنترنت. الخطوة الأولى: إعداد بايثون 3 سنُثبِّت ونضبط بايثون عبر سطر الأوامر، والذي هو طريقةٌ غيرُ رسوميةٍ للتعامل مع الحاسوب، فبدلًا من الضغط على الأزرار فستكتب نصًا وتعطيه للحاسوب لينفذه وسيُظهِر لك ناتجًا نصيًا أيضًا. يمكن أن يساعدك سطر الأوامر على تعديل أو أتمتة مختلف المهام التي تنجزها على الحاسوب يوميًا، وهو أداةٌ أساسيةٌ لمطوري البرمجيات، وهنالك الكثير من الأوامر التي عليك تعلمها لكي تتمكن من الاستفادة منه. هنالك مقالات في أكاديمية حسوب (كدرس مدخل إلى طرفيّة لينكس Linux Terminal) ستعلمك أساسيات سطر الأوامر، وهنالك كتاب «سطر أوامر لينكس» الذي يُعتَبر مرجعًا تفصيلًا لطريقة التعامل مع سطر الأوامر. ستجد تطبيق «Terminal» (البرنامج الذي تستعمله للوصول إلى سطر الأوامر) بالضغط على أيقونة Dash في الزاوية العليا اليسرى من الشاشة ثم كتابة «terminal» في شريط البحث، ثم الضغط على أيقونة التطبيق التي ستظهر بعدئذٍ. يمكنك بشكلٍ بديلٍ أن تضغط على Ctrl+Alt+T في لوحة المفاتيح بنفس الوقت لتشغيل تطبيق Terminal. أما على دبيان 8 فيمكنك فتح القائمة الموجودة أيضًا في الزاوية العليا اليسرى من الشاشة ثم البحث عن «terminal» في شريط البحث، ثم النقر على أيقونة التطبيق. يمكنك أيضًا أن تضغط على Ctrl+Alt+T في لوحة المفاتيح بنفس الوقت لتشغيل تطبيق Terminal. تأتي توزيعات أوبنتو 16.04 ودبيان 8 وإصدارات دبيان الأخرى مثبتةً مسبقًا مع بايثون 3 وبايثون 2. للتأكد أنَّك تملك آخر الإصدارات منها فحدِّث نظامك باستخدام apt-get: sudo apt-get update sudo apt-get -y upgrade الخيار -y يعني أنَّك توافق على تثبيت جميع الحزم القابلة للتحديث، لكن قد تحتاج إلى تأكيد ذلك عند تحديث النظام وذلك اعتمادًا على الحزم التي ستُحدَّث ونسخة نظامك. بعد إكمال العملية، يمكننا التحقق من إصدار بايثون 3 المُثبّت في النظام بكتابة: python3 -V ستحصل على مخرجات في نافذة الطرفية والتي ستريك ما هو إصدار بايثون المثبّت. قد يختلف الرقم بناءً على النسخة المثبتة في توزيعتك، لكن يجب أن يكون شبيهًا بما يلي: Python 3.5.2 لإدارة الحزم البرمجية الخاصة ببايثون، فثبّت pip: sudo apt-get install -y python3-pip الأداة pip هي أداةٌ تعمل مع لغة بايثون تُثَبِّت وتدير الحزم البرمجية التي قد نحتاج إلى استخدامها في تطوير مشاريعنا. يمكنك تثبيت حزم بايثون بكتابة الأمر: pip3 install package_name حيث عليك وضع اسم الحزمة أو المكتبة التابعة لبايثون مكان package_name مثل Django لتطوير الويب أو NumPy لإجراء حسابات علمية. لذا إن شئتَ تنزيل NumPy فيمكنك تنفيذ الأمر pip3 install numpy. بعد أن انتهينا من ضبط بايثون وتثبيت pip، فيمكننا الآن إنشاء «بيئة وهمية» (virtual environment) لمشاريعنا. الخطوة الثانية: إعداد بيئة وهمية تُمكِّنك البيئات الوهمية من إنشاء مساحة معزولة في حاسوبك مخصصة لمشاريع بايثون، مما يعني أنَّ كل مشروع تعمل عليه يملك مجموعة من الاعتماديات (dependencies) والتي لن تؤثِّر على غيره من المشاريع. يوفِّر لنا ضبط بيئةٍ برمجيةٍ تحكمًا أكبر بمشاريع بايثون وإمكانية التعامل مع إصداراتٍ مختلفةٍ من حزم بايثون. وهذا مهمٌ كثيرًا عندما تتعامل مع الحزم الخارجية. يمكنك ضبط أيُّ عددٍ تشاء من البيئات الوهمية، وكل بيئة تُمثِّل مجلدًا في حاسوبك الذي فيه عددٌ من السكربتات. علينا أولًا تثبيت وحدة (module) برمجية باسم venv، وهي جزءٌ من مكتبة بايثون3 القياسية، وذلك لكي نتمكن من استخدام الأمر pyvenv الذي سيُنشِئ البيئات الوهمية لنا. لنثبِّت venv على نظامنا بكتابة: sudo apt-get install -y python3-venv سنتمكن الآن من إنشاء بيئات وهمية بعد إتمام التثبيت، لنختار ما هو المجلد الذي سنضع فيه بيئات بايثون، أو لننشِئ مجلدًا جديدًا باستخدام الأمر mkdir كما يلي: mkdir environments cd environments بعد أن انتقلتَ إلى المجلد الذي تريد احتواء البيئات فيه، فتستطيع الآن إنشاء بيئة جديدة بتنفيذ الأمر الآتي: pyvenv my_env سيُنشِئ الأمر pyvenv مجلدًا جديدًا فيه بعض الملفات التي يمكننا عرضها باستخدام الأمر ls: ls my_env bin include lib lib64 pyvenv.cfg share تعمل هذه الملفات مع بعضها لضمان أنَّ مشاريعك معزولةٌ عن بقية النظام، لكي لا تختلط ملفات النظام مع ملفات المشاريع. وهذا أمرٌ حسنٌ لإدارة الإصدارات ولضمان أنَّ كل مشروع يملك وصولًا إلى حزمٍ معيّنة التي يحتاج لها. تتوافر أيضًا Python Wheels والتي هي صيغة بناء حزمٍ لبايثون والتي يمكن أن تُسرِّع من تطوير البرامج بتقليل عدد المرات التي تحتاج فيها إلى بناءٍ (compile) للمشروع، وهي موجودةٌ في مجلد share في توزيعة أوبنتو 16.04 لكنها ستكون في دبيان 8 في أحد مجلدات lib وليس في share. عليك تفعيل البيئة لاستخدامها، وذلك بكتابة الأمر الآتي الذي سيُنفِّذ سكربت التفعيل: source my_env/bin/activate يجب أن تظهر الآن سابقةٌ (prefix) في المِحث (prompt) والتي هي اسم البيئة المستخدمة، وفي حالتنا هذه يكون اسمها my_env، وقد يكون مظهر المِحَث مختلفًا في توزيعة دبيان، وذلك اعتمادًا على الإصدار المستخدم؛ لكن يجب أن تشاهد اسم البيئة بين قوسين في بداية السطر: (my_env) sammy@sammy:~/environments$ السابقة ستسمح لك بمعرفة أنَّ البيئة my_env مفعلة حاليًا، وهذا يعني أننا سنستخدم إعدادات وحزم هذه البيئة عند إنشائنا لمشاريع جديدة. ملاحظة: يمكنك داخل البيئة الوهمية أن تستخدم الأمر python بدلًا من python3 والأمر pip بدلًا من pip3 إن شئتَ. أما إذا كنتَ ستستخدم بايثون 3 خارج البيئة الوهمية، فيجب عليك حينها استخدام python3 و pip3 حصرًا. يجب أن تكون بيئتك الوهمية جاهزةً للاستخدام بعد اتباعك للخطوات السابقة. الخطوة الثالثة: إنشاء برنامج بسيط بعد أن أكملنا ضبط بيئتنا الوهمية، لننشِئ برنامجًا بسيطًا يعرض العبارة «Hello World!»، وبهذا سنتحقق من أنَّ البيئة تعمل عملًا صحيحًا، وستصبح طريقة إنشاء برامج بايثون مألوفةً لديك إن كنتَ وافدًا جديدًا على اللغة. علينا أولًا تشغيل محرر ملفات نصية لإنشاء ملف جديد، وليكن المحرر nano الذي يعمل من سطر الأوامر: (my_env) sammy@sammy:~/environments$ nano hello.py بعد فتح الملف في نافذة الطرفية، فاكتب البرنامج الخاص بنا: print("Hello, World!") أغلق محرر nano بالضغط على Ctrl+x ثم اضغط على y عندما يسألك عن حفظ الملف. بعد أن يُغلَق محرر nano وتعود إلى سطر الأوامر، فحاول تشغيل البرنامج: (my_env) sammy@sammy:~/environments$ python hello.py سيؤدي برنامج hello.py الذي أنشأتَه إلى طباعة الناتج الآتي في الطرفية: Hello, World! للخروج من البيئة، فاكتب الأمر deactivate وستعود إلى مجلدك الأصلي. الخلاصة تهانينا! لقد ضبطتَ الآن بيئة تطوير للغة بايثون 3 في جهازك الذي يعمل بتوزيعة أوبنتو أو دبيان، حان الآن الوقت للتعمق بلغة بايثون وإنشاء برامج رائعة! بالتوفيق. ترجمة -وبتصرّف- للمقال How To Install Python 3 and Set Up a Local Programming Environment on Ubuntu 16.04 لصاحبته Lisa Tagliaferri اقرأ أيضًا المقالة التالية: كيف تكتب أول برنامج لك المقالة السابقة: اعتبارات عملية للاختيار ما بين بايثون 2 و بايثون 3 المرجع الشامل إلى تعلم لغة بايثون كتاب البرمجة بلغة بايثون
-
تمهيد سنشرح في هذا الدرس كيفية إعداد بيئة برمجية محليّة للغة بايثون 3 في توزيعة أوبنتو 16.04 أو دبيان 8. بايثون هي لغةٌ سهلة القراءة للغاية ومتنوعة ومتعددة الاستخدامات، واسمها مستوحى من مجموعة كوميدية بريطانية باسم «Monty Python»، وكان أحد الأهداف الأساسية لفريق تطوير بايثون هو جعل اللغة مرحةً وسهلة الاستخدام، وإعدادها بسيطٌ، وطريقة كتابتها مباشرة وتعطيك تقريرًا مباشرًا عند حدوث أخطاء، وهي خيارٌ ممتازٌ للمبتدئين والوافدين الجدد على البرمجة. إصدار بايثون 3 هو الإصدار الحالي من اللغة ويُعتَبَر أنَّه مستقبل بايثون. سيُرشِدُك هذا الدرس خطوةً بخطوة إلى كيفية تثبيت بايثون 3 على نظام لينكس المحلي عندك وذلك عبر سطر الأوامر، وصحيحٌ أنَّ هذا الدرس يشرح عملية التثبيت لتوزيعة أوبنتو 16.04 أو دبيان 8، إلا أنَّ المفاهيم الأساسية فيه تنطبق على أيّة توزيعة أخرى. المتطلبات المسبقة يجب أن يكون لديك حاسوبٌ يعمل بتوزيعة أوبنتو 16.04 أو دبيان 8 (أو أيّ إصدار آخر من دبيان)، وأن تكون لديك امتيازات إدارية على النظام، بالإضافة إلى اتصالٍ بالإنترنت. الخطوة الأولى: إعداد بايثون 3 سنُثبِّت ونضبط بايثون عبر سطر الأوامر، والذي هو طريقةٌ غيرُ رسوميةٍ للتعامل مع الحاسوب، فبدلًا من الضغط على الأزرار فستكتب نصًا وتعطيه للحاسوب لينفذه وسيُظهِر لك ناتجًا نصيًا أيضًا. يمكن أن يساعدك سطر الأوامر على تعديل أو أتمتة مختلف المهام التي تنجزها على الحاسوب يوميًا، وهو أداةٌ أساسيةٌ لمطوري البرمجيات، وهنالك الكثير من الأوامر التي عليك تعلمها لكي تتمكن من الاستفادة منه. هنالك مقالات في أكاديمية حسوب (كدرس مدخل إلى طرفيّة لينكس Linux Terminal) ستعلمك أساسيات سطر الأوامر، وهنالك كتاب «سطر أوامر لينكس» الذي يُعتَبر مرجعًا تفصيلًا لطريقة التعامل مع سطر الأوامر. ستجد تطبيق «Terminal» (البرنامج الذي تستعمله للوصول إلى سطر الأوامر) بالضغط على أيقونة Dash في الزاوية العليا اليسرى من الشاشة ثم كتابة «terminal» في شريط البحث، ثم الضغط على أيقونة التطبيق التي ستظهر بعدئذٍ. يمكنك بشكلٍ بديلٍ أن تضغط على Ctrl+Alt+T في لوحة المفاتيح بنفس الوقت لتشغيل تطبيق Terminal. أما على دبيان 8 فيمكنك فتح القائمة الموجودة أيضًا في الزاوية العليا اليسرى من الشاشة ثم البحث عن «terminal» في شريط البحث، ثم النقر على أيقونة التطبيق. يمكنك أيضًا أن تضغط على Ctrl+Alt+T في لوحة المفاتيح بنفس الوقت لتشغيل تطبيق Terminal. تأتي توزيعات أوبنتو 16.04 ودبيان 8 وإصدارات دبيان الأخرى مثبتةً مسبقًا مع بايثون 3 وبايثون 2. للتأكد أنَّك تملك آخر الإصدارات منها فحدِّث نظامك باستخدام apt-get: sudo apt-get update sudo apt-get -y upgrade الخيار -y يعني أنَّك توافق على تثبيت جميع الحزم القابلة للتحديث، لكن قد تحتاج إلى تأكيد ذلك عند تحديث النظام وذلك اعتمادًا على الحزم التي ستُحدَّث ونسخة نظامك. بعد إكمال العملية، يمكننا التحقق من إصدار بايثون 3 المُثبّت في النظام بكتابة: python3 -V ستحصل على مخرجات في نافذة الطرفية والتي ستريك ما هو إصدار بايثون المثبّت. قد يختلف الرقم بناءً على النسخة المثبتة في توزيعتك، لكن يجب أن يكون شبيهًا بما يلي: Python 3.5.2 لإدارة الحزم البرمجية الخاصة ببايثون، فثبّت pip: sudo apt-get install -y python3-pip الأداة pip هي أداةٌ تعمل مع لغة بايثون تُثَبِّت وتدير الحزم البرمجية التي قد نحتاج إلى استخدامها في تطوير مشاريعنا. يمكنك تثبيت حزم بايثون بكتابة الأمر: pip3 install package_name حيث عليك وضع اسم الحزمة أو المكتبة التابعة لبايثون مكان package_name مثل Django لتطوير الويب أو NumPy لإجراء حسابات علمية. لذا إن شئتَ تنزيل NumPy فيمكنك تنفيذ الأمر pip3 install numpy. بعد أن انتهينا من ضبط بايثون وتثبيت pip، فيمكننا الآن إنشاء «بيئة وهمية» (virtual environment) لمشاريعنا. الخطوة الثانية: إعداد بيئة وهمية تُمكِّنك البيئات الوهمية من إنشاء مساحة معزولة في حاسوبك مخصصة لمشاريع بايثون، مما يعني أنَّ كل مشروع تعمل عليه يملك مجموعة من الاعتماديات (dependencies) والتي لن تؤثِّر على غيره من المشاريع. يوفِّر لنا ضبط بيئةٍ برمجيةٍ تحكمًا أكبر بمشاريع بايثون وإمكانية التعامل مع إصداراتٍ مختلفةٍ من حزم بايثون. وهذا مهمٌ كثيرًا عندما تتعامل مع الحزم الخارجية. يمكنك ضبط أيُّ عددٍ تشاء من البيئات الوهمية، وكل بيئة تُمثِّل مجلدًا في حاسوبك الذي فيه عددٌ من السكربتات. علينا أولًا تثبيت وحدة (module) برمجية باسم venv، وهي جزءٌ من مكتبة بايثون3 القياسية، وذلك لكي نتمكن من استخدام الأمر pyvenv الذي سيُنشِئ البيئات الوهمية لنا. لنثبِّت venv على نظامنا بكتابة: sudo apt-get install -y python3-venv سنتمكن الآن من إنشاء بيئات وهمية بعد إتمام التثبيت، لنختار ما هو المجلد الذي سنضع فيه بيئات بايثون، أو لننشِئ مجلدًا جديدًا باستخدام الأمر mkdir كما يلي: mkdir environments cd environments بعد أن انتقلتَ إلى المجلد الذي تريد احتواء البيئات فيه، فتستطيع الآن إنشاء بيئة جديدة بتنفيذ الأمر الآتي: pyvenv my_env سيُنشِئ الأمر pyvenv مجلدًا جديدًا فيه بعض الملفات التي يمكننا عرضها باستخدام الأمر ls: ls my_env bin include lib lib64 pyvenv.cfg share تعمل هذه الملفات مع بعضها لضمان أنَّ مشاريعك معزولةٌ عن بقية النظام، لكي لا تختلط ملفات النظام مع ملفات المشاريع. وهذا أمرٌ حسنٌ لإدارة الإصدارات ولضمان أنَّ كل مشروع يملك وصولًا إلى حزمٍ معيّنة التي يحتاج لها. تتوافر أيضًا Python Wheels والتي هي صيغة بناء حزمٍ لبايثون والتي يمكن أن تُسرِّع من تطوير البرامج بتقليل عدد المرات التي تحتاج فيها إلى بناءٍ (compile) للمشروع، وهي موجودةٌ في مجلد share في توزيعة أوبنتو 16.04 لكنها ستكون في دبيان 8 في أحد مجلدات lib وليس في share. عليك تفعيل البيئة لاستخدامها، وذلك بكتابة الأمر الآتي الذي سيُنفِّذ سكربت التفعيل: source my_env/bin/activate يجب أن تظهر الآن سابقةٌ (prefix) في المِحث (prompt) والتي هي اسم البيئة المستخدمة، وفي حالتنا هذه يكون اسمها my_env، وقد يكون مظهر المِحَث مختلفًا في توزيعة دبيان، وذلك اعتمادًا على الإصدار المستخدم؛ لكن يجب أن تشاهد اسم البيئة بين قوسين في بداية السطر: (my_env) sammy@sammy:~/environments$ السابقة ستسمح لك بمعرفة أنَّ البيئة my_env مفعلة حاليًا، وهذا يعني أننا سنستخدم إعدادات وحزم هذه البيئة عند إنشائنا لمشاريع جديدة. ملاحظة: يمكنك داخل البيئة الوهمية أن تستخدم الأمر python بدلًا من python3 والأمر pip بدلًا من pip3 إن شئتَ. أما إذا كنتَ ستستخدم بايثون 3 خارج البيئة الوهمية، فيجب عليك حينها استخدام python3 و pip3 حصرًا. يجب أن تكون بيئتك الوهمية جاهزةً للاستخدام بعد اتباعك للخطوات السابقة. الخطوة الثالثة: إنشاء برنامج بسيط بعد أن أكملنا ضبط بيئتنا الوهمية، لننشِئ برنامجًا بسيطًا يعرض العبارة «Hello World!»، وبهذا سنتحقق من أنَّ البيئة تعمل عملًا صحيحًا، وستصبح طريقة إنشاء برامج بايثون مألوفةً لديك إن كنتَ وافدًا جديدًا على اللغة. علينا أولًا تشغيل محرر ملفات نصية لإنشاء ملف جديد، وليكن المحرر nano الذي يعمل من سطر الأوامر: (my_env) sammy@sammy:~/environments$ nano hello.py بعد فتح الملف في نافذة الطرفية، فاكتب البرنامج الخاص بنا: print("Hello, World!") أغلق محرر nano بالضغط على Ctrl+x ثم اضغط على y عندما يسألك عن حفظ الملف. بعد أن يُغلَق محرر nano وتعود إلى سطر الأوامر، فحاول تشغيل البرنامج: (my_env) sammy@sammy:~/environments$ python hello.py سيؤدي برنامج hello.py الذي أنشأتَه إلى طباعة الناتج الآتي في الطرفية: Hello, World! للخروج من البيئة، فاكتب الأمر deactivate وستعود إلى مجلدك الأصلي. الخلاصة تهانينا! لقد ضبطتَ الآن بيئة تطوير للغة بايثون 3 في جهازك الذي يعمل بتوزيعة أوبنتو أو دبيان، حان الآن الوقت للتعمق بلغة بايثون وإنشاء برامج رائعة! بالتوفيق. ترجمة -وبتصرّف- للمقال How To Install Python 3 and Set Up a Local Programming Environment on Ubuntu 16.04 لصاحبته Lisa Tagliaferri
-
إذا كنتَ معتادًا على إدارة موقع ووردبريس مفرد، فستجد أنَّ هنالك بعض الاختلافات بين ذلك وبين إدارة شبكة. وستحتاج أيضًا إلى إدارة أيّة مواقع تملكها شخصيًا على شبكتك أيضًا: الموقع الرئيسي مثلًا. أهلًا بك إلى القسم الأخير (المكون من درسين) من الدورة التدريبية الشاملة في ميزة تعدد المواقع في ووردبريس؛ تعلمتَ في هذه السلسلة إلى الآن كيف تُفعِّل ميزة تعدد المواقع وتضبط شبكة من المواقع التي سيُنشئها المستخدمون، وتعلمتَ كيف تستضيف المواقع، وكيف تُطوِّر مجتمعًا. لكن بعد أن تنتهي من فعل كل ذلك، فستحتاج إلى معرفة كيف تدير وتصون شبكتك وتبقها تعمل على أتم وجه. ستتعلم في هذا الجزء (الدرس الحالي والدرس الأخير) كيف ستدير شبكتك بشكلٍ اعتيادي. حيث ستتعلم: الاختلافات الأساسية بين صفحات إدارة الشبكة متعددة المواقع وصفحات إدارة المواقع المفردة المستقلة. كيف تدير المستخدمين وتتفادى نشر محتوى مزعج (spam) وكيف تتفادى إنشاء مدونات تنشر مواد مزعجة (spammy blogs أو اختصارًا splogs). كيف تُبقي على شبكتك مُحدَّثةً دومًا: سواءً بالنسبة إلى نسخة ووردبريس نفسها، أو القوالب والإضافات. سأريك أفضل الممارسات لفعل ذلك. الطرائق التي يمكنك أن تستخدمها لإبقاء شبكتك منسوخةً نسخًا احتياطيًا وكيفية استعادة الشبكة بأكملها أو موقع منها إن حدثت مشكلة. كيفية تحسين الحماية في شبكتك. وفي النهاية، كيف تتأكد أنَّ شبكتك ستعمل بسلاسة وفعالية. لنبدأ بالنظر حول الاختلافات بين صفحات إدارة الشبكة والمواقع التي اعتدت على استخدامها. إدارة الشبكة وإدارة المواقع: الاختلافات الأساسية كمدير للشبكة، ستتمكن من الوصول إلى بعض الصفحات الإدارية الأخرى بالإضافة إلى تلك الصفحات التي تتوفر لك كمدير للموقع. لقد تعاملتَ مسبقًا مع العديد من تلك الصفحات خلال هذه الدورة. هنالك مجموعة كاملة من الصفحات الإدارية التي يمكنك الوصول إليها بالضغط على رابط «My Sites» (مواقعي) في شريط الإدارة، ثم «Netword Admin» (إدارة الشبكة)، الذي سيأخذك إلى لوحة تحكم مدير الشبكة: تحتوي لوحة تحكم مدير الشبكة على: الصفحة الرئيسية وصفحة التحديثات. قسم «Sites» (المواقع)، الذي يتضمن صفحة «All Sites» (كافة المواقع) التي تسمح لك بإدارة المواقع على شبكتك؛ وصفحة «Add New Site» (أضف موقعًا جديدًا) لكي تُنشِئ منها موقعًا جديدًا. قسم «Users» (الأعضاء)، الذي يتضمن صفحة كافة الأعضاء التي تمكنك من مشاهدة وإدارة المستخدمين الموجودين على شبكتك، وصفحة لإضافة مستخدم جديد إلى شبكتك. قسم «Themes» (القوالب)، الذي يتضمن صفحة تمكنك من تفعيل القوالب المثبتة، وصفحة لإضافة القوالب حيث تستطيع فيها تثبيت قوالب جديدة، وهنالك محرر يسمح لك بتعديل الشيفرة الخاصة بالقوالب المثبتة على شبكتك. لا تستعمل صفحة المحرر على الإطلاق! تعديل القوالب هكذا لا يعطيك طريقة لحفظ تعديلاتك، وإن سببتَ بتعطيل قالب، فقد يؤدي ذلك إلى تعطيل كامل شبكتك. إذا احتجت إلى تعديل قالب، فافعل ذلك باستخدام محرر نصي. قسم «Plugins» (الإضافات)، الذي يتضمن صفحة يمكنك فيها تحديث الإضافات، وتفعيل الإضافات التي ثبتَها على كامل الشبكة. وصفحة لتثبيت الإضافات، وصفحة لتحرير شيفرة الإضافة، وأكرِّر أنَّ عليك تفادي استخدام المحرر. قسم «Settings» (الإعدادات)، الذي يتضمن صفحة «Network Settings» (إعدادات الشبكة) التي يمكنك فيها ضبط الشبكة، وصفحة «Network Setup» (تهيئة الشبكة) التي ستتمكن عبرها من الوصول إلى الشيفرة التي يجب وضعها في ملفَي .htaccess و wp-config.php؛ وسيحتوي هذا القسم أيضًا على أيّة صفحات لضبط الإضافات التي ثبتها على شبكتك. إذا كنتَ عضوًا في WPMU DEV فستملك وصولًا إلى WPMU DEV Dashboard، التي يمكنك استخدامها لتثبيت وإدارة القوالب والإضافات الخاصة بموقع WPMU DEV: إذا تابعتنا عبر الأقسام السابقة من هذه السلسلة، فمن المرجح أنَّك استخدمتَ العديد من الصفحات السابقة: في مقدّمة هذه السلسلة، اطلعتَ على لمحة عن الصفحات السابقة والفرق بينها وبين صفحات لوحة تحكم إدارة الموقع. في قسم «التفعيل والضبط»، استخدمتَ صفحة «Network Setup» (تهيئة الشبكة) للوصول إلى الشيفرة التي عليك إضافتها إلى ملفَيwp-config.php و .htaccess؛ ثم استخدمتَ قسم «Users» (أعضاء) وقسم «Sites» (المواقع) لإضافة مواقع ومستخدمين جدد؛ واستعملتَ قسمَي «Themes» (القوالب) و «Plugins» (الإضافات) لتثبيت وتفعيل القوالب والإضافات. في قسم «تسجيل المستخدمين والمواقع» ، استخدمتَ صفحة «Network Settings» (ضبط الشبكة) لتضبط عملية تسجيل المستخدمين والمواقع، وقسم «Users» (أعضاء) لمشاهدة وتعديل بيانات المستخدمين الجدد. في قسم «مواقع العملاء وربط النطاقات»، استخدمتَ صفحة ضبط Domain Mapping التي وضعتها إضافة Domain Mapping في قسم «Settings» (الإعدادات). في قسم «إنشاء مجتمع»، استخدمتَ الصفحات الجديدة التي وفرتها الإضافات في قسم «Settings» (الإعدادات)، بالإضافة إلى صفحة «Plugings» (الإضافات) ولوحة تحكم WPMU DEV لتثبيت وتفعيل إضافات على كامل الشبكة بغرض إدارة المجتمع. أما في الجزء الحالي من السلسلة، فسنزور بعض الصفحات السابقة، وسنستخدم أخرى جديدة خاصة بالإضافات. إدارة المستخدمين وتفادي المحتوى المزعج طريقة تخزين معلومات المستخدمين في شبكة متعددة المواقع تختلف قليلًا عن المواقع المفردة. كل مستخدم مسجل في أحد المواقع على شبكتك يملك سجلًا وحيدًا في قاعدة البيانات، وسيكون مستخدمًا لكامل شبكتك. لكن ذلك لا يعني أنَّه يملك وصولًا إلى كامل الشبكة: حيث ستُخزِّن ووردبريس بيانات وصفية (metadata) مرتبطة بكل مستخدم التي تُشير إلى ما هي المواقع التي يملك وصولًا لها وبأي درجة من الامتيازات. لذا يمكن لشخصٍ وحيد أن يكون مديرًا لأحد المواقع، وكاتبًا في آخر، ومشتركًا في عدِّة مواقع أخرى. سيملك هذا الشخص سجلًا وحيدًا في جدول wp-users في قاعدة البيانات، ولن يكون له أكثر من سجل منفصل لكل موقع على الشبكة. هذا يعني أنَّ المستخدمين يمكن أن يُضافوا من قِبلك (كمدير للشبكة) أو من قِبل مدراء المواقع. يمكن لمدير الموقع أن يُضيف مستخدمًا جديدًا إلى موقعه وإلى شبكتك (إن سمحتَ بذلك بالطبع)، ويمكنهم أيضًا –أي مدراء المواقع– أن يُضيفوا مستخدمًا موجودًا في الشبكة إلى موقعهم. إن لم تُفعِّل إمكانية إنشاء مستخدمين جدد من قِبل مدراء المواقع، فسيتمكنون فقط من إضافة أعضاء موجودين مسبقًا في الشبكة إلى مواقعهم. يمكنك –كمدير للشبكة– أن تُدير المستخدمين عبر صفحة «Users» (أعضاء) في لوحة تحكم الشبكة: يمكنك هنا أن تُعدِّل بيانات أحد المستخدمين أو تحذفهم، بنفس الطريقة التي اعتدتَ على استعمالها في المواقع المفردة. في الجزء الثالث من هذه الدورة « تسجيل المستخدمين والمواقع»، تعلمتَ كيف تضبط تسجيل المستخدمين والمواقع، سامحًا بتسجيل المستخدمين في شبكتك وإنشائهم لمواقعهم الخاصة؛ لكن ماذا لو بدأ أولاءك المستخدمون بإنشاء مدونات مزعجة (splogs) على شبكتك؟ هنالك طريقتان لمنع ذلك: تغيير الضبط لمنع إنشاء المواقع إلا من المستخدمين الموجودين مسبقًا أو من الأشخاص الذين يملكون عنوان بريد إلكتروني موجود على نطاق معيّن. استخدام إضافة مضادة للمدونات المزعجة. الخيار الأول أبسط، والذي هو الحاجة إلى تغيير ضبط الشبكة. ولفعل ذلك، اذهب إلى «Settings > Network Settings» (الإعدادات > إعدادات الشبكة) ثم انتقل إلى قسم «Registration Settings» (إعدادات التسجيل): تملك بعض الخيارات لتقليل عدد المدونات المزعجة: غيّر خيار «Allow new registrations» (السماح بالتسجيل) إلى «Logged in users may register new sites» (السماح للأعضاء المتصلين بتسجيل مواقع جديدة). استخدم حقل «Banned Names» (الأسماء الممنوعة) لحجب أيّة أسماء يستعملها المستخدمون المزعجون لإنشاء مواقع جديدة. استخدم حقل «Limited Email Registrations» (نطاقات البريد الإلكتروني المسموحة) لتقييد إمكانية إنشاء مواقع جديدة إلى أشخاصٍ يملكون بريدًا إلكترونيًا ينتمي إلى أحد النطاقات التي تُحدِّدها في هذا الحقل. هذا الخيار مفيدٌ إن كانت شبكتك تابعةً لمنظمةٍ التي يملك كلُ شخصٍ فيها عنوان بريد متشابه، لكن هذا الخيار سيكون مُقيِّدًا لشبكتك إن كانت مفتوحةً وعامةً. استخدم حقل «Banned Email Domains» (نطاقات البريد الإلكتروني الممنوعة) لتحديد أسماء نطاقات البريد الإلكتروني التي يستعملها المستخدمون المزعجون لإنشاء مواقع على شبكتك. إذا كنتَ ترغب أن يُسجِّل عندك أكبر قدر ممكن من المستخدمين غير المزعجين، فلن ترغب باستخدام الأشياء السابقة، وفي هذه الحالة، يمكنك استخدام إضافة Anti-Splog للتخلص من المستخدمين المزعجين. حجب المدونات المزعجة باستخدام إضافة Anti-Splog إضافة Anti-Splog ذات مستوى أعلى من الإضافات العادية، حيث تسمح لك بالوصول إلى مستودع كبير من البيانات الذي يحتوي معلومات حول المدونين المزعجين ومن أين يأتون؛ وبناءً على المعلومات المجموعة من المستخدمين الآخرين لهذه الإضافة ومن شبكة Edublogs، ستتمكن من الوصول إلى قاعدة بيانات تحتوي على معلومات المستخدمين المزعجين، وهذا يعني أنَّ الإضافة ستستخدم تلك المعلومات لحجب أولاءك الأشخاص الذين لا تريد أن تسمح لهم بإنشاء موقع على شبكتك. هذه الإضافة شبيهة بإضافة Akismet لكن للشبكات. لنبدأ بإعداد الإضافة على الشبكة, علينا أولًا تثبيتها وتفعيلها على عموم الشبكة من لوحة تحكم WPMU DEV. ستُنشِئ هذه الإضافة قسمًا جديدًا في قائمة لوحة تحكم مدير الشبكة اسمه Anti-Splog. لضبط هذه الإضافة وجعلها تعمل، اذهب إلى «Anti-Splog > Settings»: سترى تحذيرًا يخبرك أنَّك ستحتاج إلى إدخال مفتاح API الخاص بك قبل أن تعمل هذه الإضافة. ولفعل ذلك، انقر على رابط «Get your API key and register your server here» في الصفحة السابقة، والذي سيأخذك إلى صفحة «Anti-Splog API» في حساب WPMU DEV الخاص بك: مرِّر إلى الأسفل لتصل إلى قسم «Register a Site»، ويجب أن يكون نطاق شبكتك موجودًا مسبقًا في حقل «Multisite Domain». تحقق من صحته وغيّره إلى النطاق الصحيح لشبكتك إن لزم الأمر؛ ثم اضغط على زر «Add Site». يجب أن يُضاف الموقع إلى قائمة المواقع المسجلة. انسخ الآن مفتاح API واذهب إلى موقعك مرةً أخرى، وافتح صفحة ضبط إضافة Anit-Splog والصق المفتاح في حقل «API Key». ثم اضغط على زر «Check Key» للتحقق منه. إذا جرى كل شيءٍ على ما يرام، فسيُحفَظ مفتاح API وسيتحول لون الحقل إلى اللون الأخضر. إذا لم يعمل، فارجع إلى صفحة Anti-Splog API وتحقق أنَّك أدخلتَ النطاق بشكلٍ صحيح. ملاحظة: إذا كانت شبكتك مثبتةً في مجلدٍ فرعي من نطاقك الرئيسي، فاستخدم النطاق الرئيسي لتسجيل موقعك، وليس النطاق الكامل. هنالك شيءٌ آخر عليك فعله قبل أن تبدأ باستخدام الإضافة الذي هو نقل ملف blog-suspended.php من الإضافة إلى مجلد wp-content. ولفعل ذلك ستحتاج إلى وصول FTP إلى خادومك. افتح عميل FTP (ربما يكون جزءًا من محررك النصي أو قد يكون عميلًا منفصلًا مثل FileZilla)، واذهب إلى مجلد wp-content/plugins/anti-splog واعثر على ملف blog-suspended.php. إن لم تجده هناك، فافتح مجلد /includes وستجد ملفًا باسم blog-suspended-template.php، فانسخه وأعد تسميته إلى blog-suspended.php. انقل ذاك الملف إلى مجلد wp-content. ارجع إلى موقعك وأعد فتح صفحة ضبط إضافة Anti-Splog، أو حدِّثها إن كنتَ فيها. ستلاحظ اختفاء رسالة التحذير التي تطلب منك أن تنقل الملف: ملاحظة: إذا بقيت رسالة التحذير موجودةً، فتأكَّد أنَّك نقلتَ الملف إلى المكان الصحيح، وأعدتَ تسميته بالاسم المناسب إن أنشأتَ نسخةً من ملف blog-suspended-template.php. عليك الآن ضبط الإضافة. تملك إضافة Anti-Splog الكثير من خيارات الضبط، وعلى الرغم من أنَّك بدأتَ لتوِّك في استخدامها، لكن من الأفضل البدء باستخدام الخيارات الافتراضية ثم تعديلها مع مرور الوقت إن احتجت إلى ذلك. يمكنك معرفة المزيد عن خيارات الضبط في لسان «Usage» في صفحة الإضافة على WPMU DEV: جعل شبكتك محدَّثةً دومًا جزءٌ مهمٌ من عملية إدارة الشبكة هو إبقاء الشيفرات البرمجية محدثةً دومًا، وهذا يضمن لك أنَّك تعمل على آخر وأكثر نسخة أمانًا من الشيفرات البرمجية التي تحتوي على تحسينات في الشيفرة أو حلول لبعض العلل. لكن عليك اختبار أيّة تحديثات على نسخة من شبكتك قبل تحديث موقعك الإنتاجي. إذا سبب تحديثٌ ما مشاكل، فقد يؤثر ذلك على جميع مواقع الشبكة ولن يكون عملاؤك أو مستخدموك سعداء بذلك، لذا عليك أن تتحقق من عدم حدوث أيّة مشاكل عند التحديث. نصائح لإبقاء شبكتك محدَّثةً لإبقاء شبكتك محدثةً دون مواجهة أيّة مشاكل، فالتزم بتطبيق هذه النصائح: أنشِئ نسخةً محليةً من شبكتك على حاسوبك المحلي (ربما باستخدام MAMP). الخطوات مماثلة لإنشاء نسخة من موقع ووردبريس مفرد، ويمكنك أن تتعلم فعل ذلك بالتفصيل في درس كيفية تنصيب ووردبريس محليا باستخدام MAMP، استخدم هذا الموقع لتجربة التحديثات. بشكلٍ بديل، من الأفضل إنشاء نسخة من شبكتك على نفس الخادوم. هذا أفضل لأنَّ البيئة التي تجرِّب عليها مماثلة للشبكة الإنتاجية، لذا ستتمكن من معرفة أيّة مشاكل تتعلق بالخادوم عند تجربتك للتحديث. استشر مزود خدمة الاستضافة ليساعدك في إنشاء هذه النسخة. خذ نسخًا احتياطيةً من شبكتك، فلو واجهتَ أيّة مشاكل مع التحديثات، فيمكنك بسرعة أن تعود إلى النسخة غير المحدثة من شبكتك. سنفصِّل ذلك في الدرس القادم. استخدم إضافة Multisite Enhancements لكي ترى ما القوالب أو الإضافات التي تستعملها المواقع الموجودة في شبكتك. وبهذا ستعلم أيّ المواقع التي عليك اختبارها عندما تُحدِّث قالبًا أو إضافةً ما. تحديث ووردبريس نفسها أو قالب أو إضافة هو أمرٌ لا يستطيع فعله إلا مدير الشبكة. أي أنَّ مدراء المواقع لا يستطيعون فعل ذلك، ولن يستطيعوا أن يروا إشعارات التحديثات في لوحة التحكم الخاصة بهم. لننظر الآن إلى كيفية تحديث إضافة، على سبيل المثال. تحديث إضافة عندما يجب تحديث إضافة مثبتة على شبكتك، فستجد دائرةً حمراء صغيرة بجوار عنصرّي «Updates» (تحديثات) و «Plugins» (إضافات) في قائمة لوحة التحكم. عندما تذهب إلى صفحة «Updates» (تحديثات) فستشاهد كل الإضافات القابلة للتحديث فيها: لتحديث إضافة، فاخترها ثم اضغط على زر «Update Plugins» (تحديث الإضافات). ستُحدِّث ووردبريس الإضافة وستُعلِمُك عندما ينتهي الأمر: ملاحظة: يمكنك تحديث الإضافات من صفحة «Plugins» (الإضافات)، حيث يمكنك تحديث كل إضافة على حدة باستخدام بالنقر على الرابط أسفل اسمها. والأمر سيانٌ للقوالب. بعد أن تفعل ذلك على النسخة الاختبارية من شبكتك وتجرِّب الإضافة المحدثة، فيمكنك أن تفعل المثل لشبكتك الإنتاجية. ترجمة –وبتصرّف– للمقال WordPress Multisite Masterclass: Managing your Network لصاحبته Rachel McCollin.
-
تمهيد OwnCloud هو خادوم مشاركة ملفات الذي يسمح لك بتخزين المحتوى الخاص بك مثل المستندات والصور في مكانٍ مركزي بشكلٍ يشبه خدمة Dropbox. الاختلاف بينهما هو أنَّ ownCloud هو برمجية حرة ومفتوحة المصدر، مما يسمح لأي شخص باستخدامه وتفحّص شيفرته، وهذا يعني أيضًا تحكمك بأمان وحماية بياناتك المهمة تمامًا مما يجنِّبُك استخدام خدمات استضافة من طرفٍ آخر. سنُثبِّت ونضبط في هذا الدرس نسخة من ownCloud على خادوم أوبنتو 16.04. المتطلبات المسبقة ستحتاج إلى ما يلي لإكمال الخطوات المذكورة في هذا الدرس: الوصول إلى مستخدم بامتيازات الجذر على خادومك: يُمكنك اتباع هذا الدّرس لإنشاء مستخدم يملك وصولًا إلى امتيازات الجذر عبر الأمر sudo. خدمات LAMP: يتطلب ownCloud وجود خادوم ويب وقاعدة بيانات ومُفسِّر PHP لكي يعمل بشكلٍ صحيح؛ إذا أعددتَ خدمات LAMP (أي Linux و Apache و MySQL و PHP) فستُحقِّق هذا الشرط. يشرح لك هذا الدرس كيفية تثبيت وضبط تلك الخدمات. شهادة SSL: طريقة ضبط الشهادة تختلف فيما إذا كنتَ تملك اسم نطاق (domain name) ليشير إلى خادومك أم لا. إذا كان لديك اسم نطاق فأسهل طريقة لتأمين موقعك هي استخدام «Let’s Encrypt» والذي يوفِّر لك شهادات مجانية وموثوقة، راجع درس تنصيب شهادة SSL مجانية عبر خدمة Let’s encrypt على خادوم لينكس لمزيدٍ من المعلومات. إذا لم يكن لديك نطاق، وكنت تتبع هذا الدرس لتجربة ownCloud أو لاستخدامه استخدامًا شخصيًا، فيمكنك إنشاء شهادة موقّعة ذاتيًا؛ والتي ستوفِّر نفس نوع التشفير، لكن دون التحقق من هوية النطاق. اتبع درس كيفية إنشاء شهادات SSL موقعة ذاتيًا لمزيدٍ من المعلومات. الخطوة الأولى: تثبيت ownCloud لا تتوافر حزمة ownCloud في مستودعات أوبنتو الافتراضية، لكن برمجية ownCloud توفِّر مستودعًا خاصًا لتوزيعة أوبنتو. علينا أولًا تنزيل مفتاح الإصدارة (release key) باستخدام الأمر curl ثم استيراد ذاك المفتاح باستخدام الأمر apt-key: curl https://download.owncloud.org/download/repositories/stable/Ubuntu_16.04/Release.key | sudo apt-key add - ... % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 1358 100 1358 0 0 2057 0 --:--:-- --:--:-- --:--:-- 2057 OK يحتوي الملف Release.key على مفتاح PGP عمومي الذي يمكن للأداة apt استخدامه للتأكّد أنَّ الحزم التي سننزلّها لبرمجية ownCloud هي حزمٌ موثوقة. إضافةً إلى استيراد المفتاح، يجب علينا إنشاء ملف باسم owncloud.list فيه عنوان مستودع ownCloud في مجلد sources.list.d التابع للأداة apt: echo 'deb http://download.owncloud.org/download/repositories/stable/Ubuntu_16.04/ /' | sudo tee /etc/apt/sources.list.d/owncloud.list نفِّذ الأمر apt-get update بعد إضافة المستودع الجديد لكي نُعلِمَ apt بالتغيير الذي أحدثناه: sudo apt-get update أخيرًا، نستطيع تثبيت ownCloud باستخدام الأمر apt-get install: sudo apt-get install owncloud ونتيجةً لتثبيت ownCloud سيُضاف ملفُ ضبطٍ جديدٍ إلى مجلد ضبط أباتشي (Apache)؛ استخدم الأمر systemctl لإعادة تشغيل أباتشي لكي يقرأ ملف الضبط: sudo systemctl restart apache2 بعد تثبيت خادوم ownCloud، حان الوقت لضبط قاعدة البيانات للاستخدام. الخطوة الثانية: ضبط قاعدة بيانات MySQL علينا بادئ الأمر أن نُسجِّل دخولنا إلى MySQL بحسابٍ له امتيازاتٌ إدارية: mysql -u root -p أدخِل كلمة المرور التي ضبطتها للمستخدم root التابع لقاعدة بيانات MySQL عندما ثبّتَها. يجب إنشاء قاعدة بيانات منفصلة لخادوم ownCloud لتخزين البيانات الإدارية، وصحيحٌ أنَّ تستطيع تسمية قاعدة البيانات بأيِّ اسمٍ تشاء، لكنني فضَّلتُ استخدام owncloud لتبسيط الأمور. نفِّذ الأمر الآتي في سطر أوامر MySQL: CREATE DATABASE owncloud; ملاحظة: يجب أن تنتهي جميع أوامر وتعابير MySQL بفاصلة منقوطة ;، تأكّد أنَّك لم تنسها إن واجهت أيّة مشاكل عند تنفيذ الأوامر المذكورة هنا. أنشِئ بعد ذلك مستخدمًا جديدًا في MySQL للتعامل مع قاعدة البيانات الجديدة. إنشاء قواعد بيانات ذات غرضٍ وحيد وإنشاء مستخدمين مخصصين لإدارتها هو أمرٌ حسنٌ من ناحية سهولة الإدارة والأمان. وكما عند تسمية قاعدة البيانات، اختر ما تشاء اسمًا للمستخدم، إلا أنَّنا اخترنا الاسم owncloud في هذا الدرس. نفِّذ الأمر الآتي في سطر أوامر MySQL: GRANT ALL ON owncloud.* to 'owncloud'@'localhost' IDENTIFIED BY 'set_database_password'; تنويه: ضع كلمة مرورك في الأمر السابق بدلًا من set_database_password. بعد السماح للمستخدم الجديد بالوصول إلى قاعدة البيانات، فحدِّث امتيازات الوصول لكي تضمن أنَّ النسخة الحالية التي تعمل من MySQL تعرف عن التعديلات الأخيرة التي أجريتَها: FLUSH PRIVILEGES; لقد انتهى ضبطنا لقاعدة MySQL، وبالتالي يمكننا الخروج من جلسة MySQL بكتابة: exit بعد تثبيت ownCloud وضبط قاعدة بياناته، فنحن الآن جاهزون لضبط خادوم ownCloud نفسه. الخطوة الثالثة: ضبط ownCloud للوصول إلى واجهة الويب التابعة لبرمجية ownCloud فافتح متصفح الويب واذهب إلى الرابط الآتي: https://server_domain_or_IP/owncloud إذا استخدمتَ شهادةً موقعةً ذاتيًا، فسترى تحذيرًا لأنَّ الشهادة غير موقعة من سلطة يثق بها متصفحك. لا تقلق، هذا طبيعيٌ جدًا، إذا كنتَ مهتمًا بالتشفير وليس بالتحقق من صحة الشهادة، فاضغط على الزر أو الرابط الملائم للمتابعة إلى صفحة إدارة ownCloud. ستبدو الصفحة شبيهةً بما يلي: أنشِئ الآن حساب مدير باختيار اسم مستخدم (لا يجدر بك استخدام اسم مثل «admin» لأسبابٍ أمنية) وكلمة مرور. قبل الضغط على زر «Finish setup» فاضغط على رابط «Storage & database»: اترك خيار «Data folder» كما هو واضغط على زر «MySQL/MariaDB» في قسم «Configure the database»، أدخِل معلومات قاعدة البيانات والتي ضبطتها في الخطوة السابقة. ما يلي هو مثالٌ يُطابِق معلومات قاعدة البيانات التي أدخلناها منذ قليل: اضغط على زر «Finish setup» للتسجيل في ownCloud. ستظر نافذة بعنوان «A safe home for all your data»: اضغط على إشارة × في الزاوية العليا اليمنى من النافذة لكي تصل إلى الواجهة الرئيسية: يمكنك من تلك الواجهة إنشاء أو رفع الملفات إلى منصة التخزين السحابي الخاصة بك! الخلاصة يملك ownCloud أغلبية ميزات خدمات التخزين السحابي، حيث يمكن مشاركة المحتوى بين المستخدمين أو عبر روابط URL عامة. ميزة استخدام ownCloud هي تخزين البيانات بأمان في مكانٍ تتحكم فيه أنت. استكشف الواجهة وتثبّت بعض الإضافات عبر متجر ownCloud لمزيدٍ من الميزات. ترجمة -وبتصرّف- للمقال How To Install and Configure ownCloud on Ubuntu 16.04 لصاحبه Michael Lenardson
-
يمكن أن تكون الغاية من شبكة متعددة المواقع أكثر من مجرد إنشاء مجموعة من المواقع، إذ يمكن أن تُشكِّل مجتمعًا. وستوفِّر لمستخدمي شبكتك طريقةً رائعةً لإنشاء مواقع ومحتوى خاص بهم، ويمكنك أيضًا أن تُقرِّب بين أولائك المستخدمين. الشبكات متعددة المواقع الكبيرة مثل WordPress.com و Edublogs تُساعِد مُستخدميها لكي يعثروا على محتوى رائع ويتواصلوا مع بعضهم بعضًا وذلك بارتباطهم كمجتمع. هنالك عدِّة خيارات متاحةٌ لك للقيام بذلك، والتي تعتمد على طبيعة شبكتك وعلى احتياجات مستخدميك، بعض هذه الخيارات يُمكن أن يُضاف خلال توسّع شبكتك لكنه بعضها الآخر يجب أن يُضبَط منذ البداية. هذا هو الدرس الثامن في سلسلتنا المكونة من عشرة دروس التي تشرح التعامل مع الشبكات متعددة المواقع في ووردبريس، ستتعلم في هذه السلسلة كل ما تحتاج له لكي تُنشِئ شبكتك، وتضيف المواقع إليها أو تسمح للمستخدمين بذلك، بالإضافة إلى إدارة الشبكة. وستتعلم كيف تتأكد أنَّ شبكتك آمنة وأداؤها عالٍ، وكيف يمكنك أن تُنشِئ مجتمعًا ناجحًا من المستخدمين والمواقع. ستتعلم في هذا الدرس عن: إنشاء شبكة اجتماعية في موقعك الرئيسي مع إتاحة خيار للمستخدمين لكي يُنشِئوا مدونات خاصة بهم. السماح للمستخدمين بمشاهدة محتوى المستخدمين الآخرين في لوحة التحكم، وعرض المحتوى المُفضّل عندهم والموجود في الشبكة على موقعهم الخاص. عرض المحتوى الجديد أو المُميّز في الشبكة (بما في ذلك المنشورات والتعليقات) في موقعك الرئيسي، وحثّ الزوار على تصفح بقية المواقع على الشبكة. عرض المحتوى الجديد أو المُميّز في الشبكة على مواقع أخرى فيها. السماح لمستخدميك بالتواصل المباشر بين بعضهم وذلك بجعلهم «أصدقاء» عبر لوحة التحكم. من غير المحتمل أن تفعل كل ما سبق، ولهذا يُفضَّل أن تأخذ بعض الوقت في التخطيط لمجتمعك أولًا وتتعرف على احتياجات مستخدميك وما الذي عليك توفيره لهم. لنبدأ. استخدام شبكة متعددة المواقع كمجتمع: أمثلة حقيقية أكبر شبكتين متعددتي المواقع في العالم يُمثِّلان مجتمعًا للمستخدمين والقراء. يحثّ موقعا WordPress.com و Edublogs المستخدمين على متابعة بعضهم والاستفادة من محتوى الآخرين. إذا كنتَ مستخدمًا لمنصة WordPress.com أو نظام Calypso الجديد للإدارة أو كنت تستعمل نسخة ووردبريس مفردة، فستتمكن من الوصول إلى Reader، الذي يمكِّنك من قراءة المحتوى الجديد في المدونات التي تتابعها: ولدى Edublogs ميزة Reader في لوحة التحكم، التي تسمح لك برؤية آخر المحتوى المنشور في مواقعك المفضَّلة على الشبكة: سأريك في هذا الدرس كيف تستخدم بعض الإضافات المتاحة لمجتمع Edublogs لكي تتمكن من إعداد مجتمع خاص بك. التعرف على احتياجات مجتمعك قبل أن تضبط مجتمعًا وتُقرِّر ما هي الإضافات التي ستحتاج إلى استخدامها، عليك أن تتعرف على احتياجات المجتمع وكيف سيعمل. اسأل نفسك الأسئلة الآتية: هل سيكون تفاعل المستخدم في الموقع الرئيسي، أم في لوحة التحكم الخاصة بمواقعهم؟ هل سيحتاج المستخدمون إلى إنشاء أحداث (events) ومجموعات …إلخ. لدعم نشاط المجتمع؟ هل سيتمكن المستخدمون من الوصول بسهولة إلى محتوى المواقع الأخرى في الشبكة؟ هل سيتمكن المستخدمون من مشاركة المحتوى المنشور من المستخدمين الآخرين؟ هل سيحتاج المستخدمون إلى تفاعلات اجتماعية بما في ذلك المنشورات والتعليقات والنقاشات؟ ما هو المحتوى الذي ستعرضه أو تشاركه في موقعك الرئيسي؟ ما هي نسبة المحتوى المعروض لعامة الزوار، وما هي نسبة المحتوى الخاص بمستخدمي الشبكة؟ الإجابات عن الأسئلة السابقة ستُحدِّد مدى امتداد شبكتك تحت أحد العناوين الآتية: التفاعلات الاجتماعية، واستهلاك المحتوى، ومشاركة المحتوى. ربما يكون أحدها هو الهدف الرئيسي من شبكتك، واحتمال أن يكون الخياران الآخران ثانويين. على سبيل المثال: شبكة يكون غرضها الأساسية هو تمكن عملية إنشاء المدونات (مثل Edublogs أو WordPress.com) ستركِّز على ذلك، وتُضيف إمكانية مشاركة المحتوى المُنشَأ على تلك المدونات وأيّة جوانب اجتماعية كميزات في الواجهة الأمامية (front-end) والسند الخلفي (backend). موقع يهدف إلى إنشاء تواصل اجتماعي بين أعضاء المجتمع سيُركِّز على جعل ذلك يعمل بشكل جيد في الموقع الرئيسي، مع إمكانية السماح للمستخدمين بإنشاء مواقع خاصة بهم. قد يكون BuddyPress هو أهم مكوِّن في مثل هكذا مواقع. إذا أردت أن تسمح للمستخدمين المحتملين بأخذ عينة من المحتوى على شبكتك، فستركِّز على الإضافات التي تسمح لك بمشاركة المحتوى المنشور في الشبكة في الواجهة الأمامية لموقعك، لكي يتمكن الزوار من قراءته. لننظر الآن إلى ما سبق بالتفصيل. الاستفادة من المحتوى المنشور على الشبكة يسمح موقع Edublogs و WordPress.com للمستخدمين برؤية المحتوى الجديد من أرجاء الشبكة في لوحة التحكم الخاصة بهم، وهذا يعني أنَّه في كل مرة يُسجِّل المستخدم دخوله فيها، فسيرى ما الذي نشره المستخدمون الآخرون. وهذا يحثّ ويشجِّع المستخدمين على تصفح الشبكة والاستفادة من المحتوى بالإضافة إلى تشجيع نشرهم لمحتوى جديد على أمل أن يراه الآخرون ويبدؤوا متابعتهم. لننظر إلى كيفية إعداد ذلك في الشبكة باستخدام إضافة Reader. قبل أن تبدأ: تثبيت إضافة Post Indexer قبل تبدأ بتثبيت أيّة إضافات للمشاركة والاستفادة من المحتوى الموجود على الشبكة، فستحتاج إلى تثبيت وتفعيل إضافة Post Indexer على جميع مواقع الشبكة. وهذا ضروريٌ لكي تعمل الإضافات مثل Reader، و Recent Global Posts، و Recent Global Comments (التي سنتحدث في أمرها قريبًا). ثبِّت إضافة Post Indexer من صفحة تحكم WPMU DEV في موقعك، ثم تأكَّد أن الإضافة مُفعَّلة لعموم الشبكة. لن تحتاج إلى ضبط أيّة إعدادات لهذه الإضافة، فستعمل عملها تلقائيًا دون تدخل. تثبيت وضبط إضافة Reader عليك الآن تثبيت إضافة Reader عبر لوحة تحكم WPMU DEV وتفعيلها على عموم الشبكة. لضبط الإعدادات اللازمة لهذه الإضافة، فاذهب في لوحة تحكم الشبكة إلى «Settings > Reader»: يمكنك هنا أن تُحدِّد كيف سيعمل Reader. في أول قسم «Where should the Reader be?» (أين يجب أن تظهر إضافة Reader) اختر «The Reader should replace the default WordPress Dashboard Home page» (يجب أن تستبدل إضافة Reader الصفحة الرئيسية للوحة التحكم). ثم اختر ما هي الأمور التي تريد من Reader عرضها في القسم الذي يليه. اضغط على زر «Save Changes» لحفظ الإعدادات. بعد أن تفعل ذلك، انتقل إلى لوحة التحكم لأحد المواقع التي تديرها. هذه صورة للموقع الرئيسي عندي: يجب أن تكون متابعًا لموقعك افتراضيًا. ستُعرَض المنشورات الحديثة من ذاك الموقع في الصفحة الرئيسية للوحة التحكم؛ وإذا لم يُعرَض أيُّ شيءٍ، فأنشِئ بعض المنشورات! :-) متابعة المواقع الأخرى في الشبكة مستخدمو شبكتك –سواءً كانوا مدراء للمواقع أم لم يكونوا كذلك– يستطيعون أن يتابعوا بعضهم بعضًا على الشبكة. وسيظهر محتوى من تلك المواقع في لوحة التحكم. للعثور على مواقع لكي تتابعها، فابحث عن عنوان أحد المنشورات، أو ابحث عبر وسمٍ (tag) ما، أو عبر كاتبٍ معيّن. من صفحة Reader، اكتب عبارة البحث في حقل البحث الموجود في الزاوية العليا اليمنى، واختر ما الذي تريد البحث عنه (عنوان [Title]، أو كاتب [Author]، أو وسم [Tag])، ثم اضغط على زر «Search». وستشاهد جميع المنشورات التي تُطابِق عبارة البحث: يمكنك عرض تلك المنشورات بالضغط فوقها أو يمكنك متابعة المدونات بالنقر فوق زر «Follow» الظاهر أسفل كل منشور في صفحة نتائج البحث. ستظهر منشورات المدونة التي تابعتها الآن في صفحة Reader: يمكن للمستخدمين أن يعثروا على مواقع ليتابعوها إذا شاركتَ المحتوى المُميّز أو آخر المنشورات على موقعك الرئيسي. ثم الضغط على ذاك المحتوى والنقر فوق أيقونة «Follow» على الشريط الإداري عند تصفح الموقع. ستتعلم في القسم التالي عن كيفية مشاركة المحتوى على موقعك الرئيسي. مشاركة المحتوى عبر الشبكة بالإضافة إلى قراءة محتوى مأخوذ من الشبكة في لوحة التحكم، يمكنك أنت ومستخدموك أن تُشاركوا المحتوى عبر الشبكة على الواجهة الأمامية لمواقعكم. هنالك عدِّة طرائق لفعل ذلك: مشاركة المحتوى الذي تتابعه عبر Reader، باستخدام ودجة (widget) توفرها إضافة Reader. استخدام شيفرة مُختصرة (shortcode) لمشاركة المنشورات على صفحة في موقعك الرئيسي باستخدام إضافة Recent Global Posts. استخدام ودجة لمشاركة المنشورات على الشريط الجانبي أو التذييل، وذلك باستخدام إضافة Recent Global Posts Widget. إضافة ودجة للتعليقات على الشريط الجانبي أو على التذييل باستخدام إضافة Recent Comments Widget. استخدام إضافة Live Stream Widget لعرض حيّ لآخر المحتوى في شبكتك في أيّة منطقة مخصصة للودجات. كما ترى، هنالك خياراتٌ كثيرةٌ أمامك. أغلبية تلك الإضافات يمكن إضافتها فقط إلى الموقع الرئيسي، ما عدا ودجة Reader. وبدلًا من شرح كل هذه الإضافات، فسأريك أمرين: كيفية إنشاء صفحة في موقعك الرئيسي التي تعرض المحتوى الحديث. كيفية إضافة المحتوى الحديث إلى منطقة مخصصة للودجات في أيّ موقع على شبكتك. قبل البدء: تثبيت إضافة Post Indexer إن لم تفعل ذلك إلى الآن، فثبّت إضافة Post Indexer وفعِّلها لكامل الشبكة. راجع التعليمات المذكورة في القسم السابق. إنشاء صفحة لعرض المحتوى الحديث في موقعك الرئيسي طريقة رائعة لحثّ الناس على التسجيل في شبكتك وتشجيعهم ليصبحوا جزءًا من المجتمع هو عرض المحتوى الحديث في الشبكة على موقعك الرئيسي. على سبيل المثال، موقع WordPress.com فيه صفحة Discover التي يمكنك أن تقرأ فيها أفضل المقالات المنشورة حديثًا التي أنشأها المستخدمون: لذا، لنضبط صفحة على الموقع الرئيسي في الشبكة، ولفعل ذلك ستحتاج إلى تثبيت وتفعيل إضافة Recent Global Posts. تهيئة الصفحة اذهب الآن إلى لوحة تحكم مدير الموقع لموقعك الرئيسي، وأنشِئ صفحة جديدة باسم «Latest Content» (أو أي اسم يحلو لك!). اكتب فيها بعض المحتوى لجذب انتباه الزوار وأخبرهم ما الغرض من هذه الصفحة. ثم اكتب [globalrecentposts] وهذه شيفرة (shortcode) ستستعملها الإضافة لملأ الصفحة بأحدث المنشورات في عموم شبكتك. هذه هي الصفحة الخاصة بي عند تحريرها: انشر صفحتك وعاينها في الواجهة الأمامية. هذه صفحتي: ملاحظة: الأشخاص ذوو البصر الثاقب سيلاحظون أنني أضفت ودجة لتسجيل الدخول إلى الشريط الجانبي لموقعي الرئيسي. وهذا يسمح للمستخدمين بتسجيل الدخول بسهولة إن نسوا كيف يصلون إلى صفحة تسجيل الدخول الخاصة بهم. استخدمتُ إضافة Login Widget with Shortcode لفعل ذلك. حسنًا، سيظهر محتوى رائع لكي يغري المستخدمين. لحسن الحظ، لشيفرة Shortcode لإضافة Recent Posts بعضُ المعاملات (parameters) التي تستطيع استخدامها لتوفير المزيد من المعلومات. لاستخدام تلك المعاملات، اكتبها داخل الأقواس المربعة مع شيفرة Shortcode: number="5": عدد المنشورات التي تريد عرضها title_characters="250": العدد الأقصى للمحارف في كل عنوان content_characters="200": العدد الأقصى للمحارف في كل مُدخَلة (entry) title_content_divider="-": ما الذي تريد استخدامه لفصل العنوان عن المحتوى. إن لم تُحدَّد قيمة هذا المعامل، فسيُعرَض المحتوى تحت العنوان title_link="no": افتراضيًا، يوضع رابط للمنشور، يمكنك استخدام هذا المعامل لتغيير ذلك show_avatars="yes": عرض صورة Avatar لكاتب المقالة إن كانت صور avatar مفعَّلة على موقعك avatar_size="32": قياس صورة avatar posttype="post-type": استخدم هذه المعامل لتحديد نوع المنشور الذي يجب عرضه. النوع الافتراضي هو post، لاحظ أنَّك تستطيع تحديد نوع واحد فقط من المنشورات القيم المذكورة في الأمثلة السابقة هي قيم توضيحية فقط، يمكنك أن تضع القيم الملائمة لحالتك. أريد أن أضيف صور avatar وعرض مقتطف من المنشور. ولفعل ذلك سأضع [globalrecentposts content_characters="250" show_avatars="yes" avatar_size="40" ] بدلًا من [globalrecentposts]. احفظ الصفحة، واعرضها في المتصفح وستشاهد شيئًا شبيهًا بما يلي: حسنًا، هذا أفضل بكثير! لنضف الآن رابطًا لحث الزوار على التسجيل. اضف بعض النص تحت شيفرة shortcode التي تعرض آخر المنشورات، وضع رابطًا لصفحة التسجيل الموجودة في wp-signup.php، والتي أنشأتَها في درسٍ سابقٍ في هذه السلسلة. لفعل ذلك، اكتب النص في صفحة التحرير، ثم اضغط على أيقونة الرابط والصق رابط URL لصفحة التسجيل: وأضف أيضًا رابطًا إلى صفحة Latest Content في شريط التنقل الرئيسي. هذه هي النسخة النهائية من الصفحة: إذا أردتَ أن تثير إعجاب زوار الموقع بكفاءة، فأنصحك باستخدام بعض التنسيق في قالبك لكي تجعل رابط التسجيل بارزًا أكثر ولكي تجعل المنشورات تظهر بشكلٍ أفضل وتستطيع تمييزها عن بعضها بسهولة، بالإضافة إلى حذف النقاط التي تظهر قبل عنوان المنشور. لكن ذلك خارجٌ عن نطاق هذه السلسلة، لذا سأترك الأمر لك! مشاركة المحتوى على المواقع باستخدام ودجة Reader إذا ثبّتتَ إضافة Reader، فيمكن لمدراء المواقع إضافة ودجة خاصة بهذه الإضافة إلى موقعهم لكي يعرضوا المحتوى الذي يتابعونه في الشبكة على زوار موقعهم. يمكنك فعل ذلك في صفحة الودجات أو التخصيص في لوحة التحكم. وسنستعمل هنا صفحة التخصيص. اذهب إلى «Appearance > Customize» (مظهر > تخصيص) ثم اختر «Widgets» (ودجات)، ثم اختر منطقة الودجات التي تريد أن تتعامل معها (اخترتُ أنا الشريط الجانبي): اضغط على زر «Add a Widget» (أضف ودجت) ثم اختر «Reader: Recent Posts» واملأ حقل «Title» (العنوان)، واختر عدد المنشورات التي تريد عرضها، واضبط الخيارات الأخرى مثل تاريخ النشر، والمقتطف، والكاتب. يمكنك أن تختار ما الذي تريد عرضه: المنشورات المميزة، أو المنشورات من المواقع التي تتابعها، أو منشوراتك، أو المنشورات من كل المواقع في الشبكة، أو المنشورات المشهورة في الشبكة، أو آخر المنشورات في الشبكة. اخترتُ المنشورات التي أتابعها: بعد أن تفعل ذلك، اضغط على زر «Save & Publish» (حفظ ونشر) ثم تحقّق من ظهور الودجة في الواجهة الأمامية لموقعك: يمكنك أيضًا أن تستعمل الودجة لإظهار محتوى من عموم الشبكة، أو إظهار منشوراتك الخاصة؛ لذا قد ترغب باستعمالها أكثر من مرة أو في أكثر من منطقة مخصصة للودجات. إنشاء شبكة اجتماعية إنشاء مجتمع في شبكتك هو عنصرٌ مساهمٌ في التواصل الاجتماعي. إذا أردتَ أن يعمل موقعك الرئيسي كشبكة اجتماعية متكاملة، فثبّت إضافة BuddyPress، لكن إن لم تكن تحتاج إلى كل وظائف BuddyPress، فيمكنك استخدام إضافة Friends للسماح للأعضاء بإنشاء ارتباطات، وإضافة Messaging للسماح لهم بإرسال رسائل لبعضهم بعضًا. قد ترغب أيضًا بالسماح لمستخدميك أن يرفعوا صورة avatar خاصة دون استخدام Gravatar، وعليك حينها استخدام إضافة WP User Avatar. السماح للمستخدمين برفع صورة Avatar لا يملك أغلبية الأشخاص حسابًا على Gravatar وربما لا يريد مستخدموك أن يُهيئوا واحدًا. يمكنك حينها تثبيت إضافة WP User Avatar للسماح لمستخدميك بإضافة صورة شخصية من صفحة حساباتهم. ثبِّت الإضافة وفعِّلها على كامل الشبكة كالمعتاد. لرفع صورة، سيذهب المستخدم إلى «Users > Your Profile» (أعضاء > حسابك)، ثم مرِّر إلى الأسفل لتصل إلى حقل «Image» (الذي يقع تحت حقل «Profile Picture» [صورة الحساب] بمسافة كبيرة!): اضغط على زر «Choose Image» ثم ارفع صورتك الجديدة: في النهاية، اضغط على «Update Profile» (تحديث الحساب) وستتغير صورة حسابك، كما ترى في الصورة التالية للواجهة الأمامية للموقع: السماح للمستخدمين بالتواصل مع بعضهم بعضًا للسماح للمستخدمين بالتواصل مع بعضهم بعضًا، فثبِّت إضافة Friends من لوحة WPMU DEV وفعِّلها على كامل الشبكة. يمكنك أن تسمح لهم بإرسال الرسائل لبعضهم أيضًا، وذلك بتثبيت إضافة Massaging وتفعيلها على كامل الشبكة. عليك الآن ضبط الإضافة بالذهاب إلى صفحة «Friends Settings» في قائمة لوحة التحكم، ومن هنا يمكنك تعديل قوالب البريد الإلكتروني التي تستعملها الإضافة لإخطار المستخدمين بوجود أعضاء آخرين يريدون التواصل معهم: أجرِ أيّة تعديلات تريدها، ثم اضغط على زر «Save Changes». وستحتاج إلى الضغط على زر «Save Changes» لكل قالب تريد تعديله، وليس مرةً واحدةً فقط. لإرسال طلب صداقة، فسيذهب مستخدموك إلى صفحة «Friends > Find Friends» في قائمة لوحة التحكم. ومن ثم يكتبون اسم المستخدم، أو الاسم المرئي، أو عنوان البريد الإلكتروني للشخص الذي يريدون إنشاء صداقة معه ثم الضغط على Search: ومن ثم الضغط على رابط «Add» الظاهر بجوار الصورة. الشخص الذي أرسلتَ له طلب الصداقة سيحصل على إشعار على البريد الإلكتروني. وعندما يسجلون الدخول إلى موقعهم، سيذهبون إلى «Friends > Friend Requests» لرؤية الطلبات الجديدة: يمكنك أن ترى موقعهم أولًا بالضغط على رابط «View Blog»، وتستطيع قبول طلب الصداقة أو رفضه؛ وسيحصل الشخص الذي أرسل طلب الصداقة على رسالة بريدية تخبره بردِّك. عندما يذهب أحدكما إلى صفحة Friends، فسيرى الشخص الآخر مذكورًا فيها: يمكن للمستخدمين أن يرسلوا لبعضهم رسائل بالضغط على رابط «Send Message»: اكتب الرسالة التي تريدها، ثم اضغط «Send» وسيحصل المستخدم الآخر على بريد إلكتروني لينبهه إلى رسالتك. يمكنك أن تستخدم بعض خيارات التنسيق المتاحة لك كما لو كنتَ تُنسِّق مقالةً. لرؤية الرسائل الواردة، اذهب إلى صفحة «Inbox» في قائمة المدير: يمكنك إرسال الرسائل من هذه الصفحة، ومن صفحة الأصدقاء أيضًا. إنشاء مجتمع سيُحسِّن من شبكتك إضافة ميزات المجتمع إلى شبكة متعددة المواقع سيمنح المستخدمين شيئًا أكبر من مكان لإنشاء مواقع. سيتمكنون أيضًا من الاستفادة من محتواهم المفضل بمشاركته مع الآخرين والتواصل معهم مباشرةً. يمكنك أيضًا استخدام ميزات المجتمع لإظهار ما تحتويه شبكتك في موقعك الرئيسية وتظهِر أنَّ شبكتك رائعة. إنشاء مجتمع يجعل شبكتك ذات قيمة أكبر للمستخدمين وسيساعدك على اكتشاف طاقاتهم. ترجمة –وبتصرّف– للمقال WordPress Multisite Masterclass: Creating a Community لصاحبته Rachel McCollin
-
يملك لينُكس أنظمةً صلبةً وأدواتٍ عمليةً لإدارة الأجهزة والعتاد، بما في ذلك أجهزة التخزين. سنشرح في درسنا هذا كيفية تمثيل تلك الأجهزة في لينكس وكيف يمكن تحويل المساحات الخام إلى مساحاتٍ تخزينيةٍ قابلةٍ للاستخدام على الخواديم. ما هو التخزين الكتلي؟ التخزين الكتلي (Block storage) هو اسمٌ آخر لما تدعوه نواة لينُكس بالجهاز الكتلي (block device). والجهاز الكتلي هو قطعةٌ من العتاد التي يمكن استعمالها لتخزين البيانات، مثل أقراص التخزين الصلبة الاعتيادية (HDD) أو أقراص التخزين ذات الحالة الثابتة (solid state drive أي SSD) أو وحدات الذاكرة الفلاشية (flash memory stick) …إلخ. تلك تسمى «أجهزةً كتليةً» لأنَّ النواة تتعامل مع العتاد على أنَّه كتلٌ ثابتةُ الحجم، أو قطعٌ من المساحة. بشكلٍ أساسي، التخزين الكتلي هو ما نعتبر أنَّه التخزين الاعتيادي المتواجد في الحواسيب، والذي –بعد ضبطه وإعداده– سيعمل على أنَّه جزءٌ من شجرة نظام الملفات الحالية، وستتمكن من قراءة أو كتابة المعلومات منه وإليه بسلاسة. ما هي الأقسام في الأقراص؟ الأقسام (partitions) هي طريقةٌ لتقسيم جهاز التخزين إلى وحدات قابلة للاستخدام أصغر حجمًا، إذ أنَّ القسم هو جزءٌ من جهاز التخزين الذي يمكن معاملته بطريقةٍ مشابهةٍ لطريقة التعامل مع القرص نفسه. يسمح لك التقسيم بتجزئة المساحة المتوافرة لديك واستخدام كل قسمٍ لغرضٍ مختلف. وهذا يعطي المستخدمين الكثير من المرونة سامحًا لهم بتجزئة النظام لديهم لتحديثه بسهولة أو لتثبيت أكثر من نظام تشغيل أو لإنشاء مساحة تبديل (swap) أو لاستخدام أنظمة ملفات خاصة على تلك الأجزاء. وصحيحٌ أنَّ الأقراص يمكن أن تُهيّئ (format) وتُستعمَل دون تقسيم، إلا أنَّ بعض أنظمة التشغيل تتوقع وجود «جدول أقسام» (partition table) حتى ولو كان هنالك قسمٌ وحيدٌ في القرص؛ لذا يُستحسَن ويُنصَح عمومًا إنشاء أقسام في الأجهزة الجديدة لضمان مرونة استخدامها مهما كانت الظروف. MBR أم GPT؟ من المهم عند تقسيم القرص معرفة ما هي «صيغة» التقسيم التي ستستعملها، وسينتهي بك المطاف بالاختيار بين MBR (اختصار للعبارة Master Boot Record) و GPT (اختصار للعبارة GUID Partition Table). MBR هو نظام التقسيم التقليدي الذي بقي مُستخدَمًا طيلة 30 عامًا الماضية؛ ونتيجةً لعمره الطويل، فهو يعاني من بعض المحدوديات التي لها وقعٌ كبير. فمثلًا لا يمكننا استخدامه للأقراص التي حجمها التخزيني أكبر من 2 تيرابايت، ولا يمكن إنشاء أكثر من أربعة أقسام رئيسية (primary partitions)؛ ونتيجةً لذلك نضبط عادةً القسم الرابع على أنَّه «قسمٌ ممتد» (extended partition) الذي سيُنشَأ داخله «أقسامٌ منطقيةٌ» (logical partitions). وهذا يسمح لك بتجزئة آخر قسم لإنشاء أي عدد إضافي من الأقسام. GPT على الجانب الآخر هو تخطيط حديث للتقسيم الذي يحاول حلّ بعضًا من المشكلات الموروثة من MBR، الأنظمة التي تستعمل GPT يمكن فيها إنشاء أي عددٍ نريده من الأقسام، لكن هذا محدودٌ عادةً بالقيود المفروضة من نظام التشغيل نفسه. إضافةً إلى ما سبق، لا تعاني أقراص GPT من محدوديات في حجم القرص، ومعلوماتُ جدولِ الأقسامِ متوافرةٌ في مواضعَ عدَّة مما يحميها من التلف. يمكن أيضًا كتابة سجل «protective MBR» الذي يخبر الأدوات التي تتعامل مع أقراص MBR فقط أنَّ القرص قيد الاستخدام حاليًا. من الأفضل في أغلبية الحالات اختيار GPT ما لم يمنعك نظام تشغيلك أو الأدوات التي ستستعملها من ذلك. التهيئة وأنظمة الملفات صحيحٌ أنَّ نواة لينكس يمكنها التعرف على الأقراص الخام (raw disks) إلا أنَّ القرص لا يمكن أن يُستعمل كما هو؛ وإنما يجب تهيئته (format) قبل استعماله. التهيئة هي عملية كتابة نظام ملفات إلى القرص وتجهيزه لإجراء عمليات لها علاقة بالملفات. أما نظام الملفات (filesystem) فهو النظام الذي يُنظِّم البيانات ويتحكم بكيفية كتابة المعلومات إلى القرص والحصول على المعلومات من القرص؛ فبدون نظام الملفات لن تتمكن من استخدام جهاز التخزين لأيّة عمليات لها علاقة بالملفات. هنالك الكثير من صيغ أنظمة الملفات المختلفة، والتي تتباين فيما بينها بامتلاكها لميزاتٍ مختلفة، بما في ذلك دعمُ أنظمة التشغيل. لكن بشكلٍ أساسي، تمنح جميع أنظمة الملفات للمستخدم تمثيلًا مألوفًا للقرص، لكن الميزات التي يدعمها كل نظام ملفات وآلية سماحه للمستخدم بالتعامل وإجراء عمليات على القسم مختلفةٌ تمامًا. بعضٌ من أشهر أنظمة الملفات المتاحة للينكس: Ext4: أشهر نظام ملفاتٍ افتراضيٍ في لينكس هو Ext4 (اختصار للعبارة the fourth version of the extended filesystem) وهو نظام ملفات ذو سجل (journaled)، ومتوافق مع الأنظمة القديمة، ومستقر للغاية، ومدعومٌ دعمًا واسعًا وتتوافر له أدواتٌ كثيرة؛ وهو خيارٌ جيدٌ إن لم تكن لديك احتياجاتٌ خاصة. XFS: نظام ملفات XFS متخصصٌ بموضوع الأداء وبالملفات كبيرة الحجم، وستتم تهيئته بسرعة وأداؤه جيد عند التعامل مع الملفات الكبيرة ومع الأقراص الضخمة. ولديه ميزة أخذ snapshot من نظام الملفات. يعتمدXFS على تسجيل البيانات الوصفية (metadata journaling) فقط والذي يختلف عن تسجيل البيانات الوصفية والبيانات نفسها؛ وهذا يؤدي إلى سرعةٍ في الأداء، لكن قد يؤدي في الوقت نفسه إلى حدوث تلفٍ في البيانات في حال حدوث فقدان غير متوقع للطاقة الكهربائية. Btrfs: نظام ملفات Btrfs هو نظامٌ حديثٌ له ميزاتٌ كثيرة وهو من نمط copy-on-write بدل كونه journaled، هذه المعمارية تسمح لبعض وظائف إدارة الحجوم (volume management) بأن تُدمَج مع طبقة نظام الملفات، بما في ذلك snapshots، والنسخ (cloning)، والحجوم (volumes) …إلخ. لكن نظام ملفات Btrfs ما يزال يواجه مشاكل عند التعامل مع الأقراص الممتلئة. هنالك بعض الجدال الدائر حول جاهزية نظام الملفات هذا لاستعماله في بيئات العمل الإنتاجية، وينتظر الكثير من مدراء الأنظمة أن يصل Btrfs إلى درجةً أكبر من الدعم والانتشار. ZFS: هو نظام ملفاتٍ من نمط copy-on-write وفيه مدير حجوم (volume manager) بمجموعة متينةٍ ومستقرةٍ من الميزات. يحتوي أيضًا على ميزاتٍ ممتازةٍ لضمان سلامة البيانات المُخزَّنة عليه، ويمكنه التعامل مع أقسام ذات مساحات تخزينية كبيرة، وفيه ميزات إدارة الحجوم التقليدية مثل snapshotting و cloning، ويمكن فيه تنظيم الحجوم (volumes) إلى مصفوفة RAID أو مصفوفات شبيهة بمصفوفات RAID لغرض إنشاء نظام تخزيني مستقر وذي أداءٍ عالٍ. أما عن وضع دعم ZFS في لينكس، فيجدر بالذكر أنَّ له تاريخٌ جدليٌ نتيجةً لمخاوف من رخصة استعماله. أصبحت توزيعة أوبنتو توفِّر وحدة ثنائية (binary module) من وحدات النواة للتعامل معه، وتضع توزيعة دبيان الشيفرة المصدرية له في مستودعاتها، لكن لم يُحدَّد دعمه في بقية التوزيعات بعد. كيف يُدير لينُكس أقراص التخزين ملفات التخزين الموجودة في /dev من المعروف أنَّ كل شيء في لينُكس (تقريبًا) يُمثَّل بملف؛ بما في ذلك الأجهزة العتادية مثل أجهزة التخزين والتي تُمثَّل في النظام كملفات في مجلد /dev، وعمومًا تبدأ أسماء الملفات التي تُمثِّل أجهزة التخزين بالحرفين sd أو hd متبوعَين بحرفٍ آخر؛ فمثلًا: أوّل قرص تخزين على الخادوم يكون اسمه شبيهًا بالاسم /dev/sda. تملك الأقسام على تلك الأجهزة ملفاتٍ هي الأخرى ضمن مجلد /dev، ممثلةً بإضافة رقم القسم إلى نهاية اسم الجهاز، فعلى سبيل المثال، أوّل قسمٍ في القرص المذكور في المثال السابق سيكون على الشكل /dev/sda1. وعلى الرغم من أنَّ ملفات الأجهزة /dev/sd* و /dev/hd* هي الطريقة التقليدية للإشارة إلى الأجهزة والأقسام، إلا أنَّ هنالك جانبٌ سلبيٌ لاستخدام تلك المسارات، إذ أنَّ نواة لينكس تُقرِّر ما هو الجهاز الذي سيحصل على الاسم الفلاني عند كل إقلاعٍ للنظام، لذا قد يودي ذلك إلى تضاربات حيث تتغير أسماء عقد الأجهزة. حلٌ التفافيٌ على هذه المشكلة هو احتواء المجلد /dev/disk على مجلدات فرعية تَنظُمُ الأقراص والأقسام بطرائق ثابتةٍ لا تتغير؛ وتلك المجلدات تحتوي على وصلاتٍ رمزيةٍ (symbolic links) التي تُنشَأ عند الإقلاع لتشير إلى ملفات /dev/[sh]da* الصحيحة. تُسمى تلك الوصلات وفقًا لنوع طريقة التنظيم والموضَّحة باسم المجلد (على سبيل المثال، ستسمى الوصلات حسب «لُصيقة» [label] القسم في مجلد /dev/disk/by-partlabel). ستُشير تلك الوصلات دومًا إلى الأجهزة الصحيحة، لذا يمكننا استخدامها كمُعرِّفات ثابتة لأجهزة التخزين. بعض (أو جميع) المجلدات الآتية موجودةٌ ضمن مجلد /dev/disk: by-label: أغلبية أنظمة الملفات لها آلية لإعطاء لُصيقة سامحةً بإسناد أسماء يُحدِّدها المستخدم إلى القرص أو القسم؛ يحتوي هذا المجلد على وصلاتٍ مسماةٍ تِبعًا للُصيقات التي كتبها المستخدم. by-uuid: المُعرِّفات العالمية الفريدة (اختصارًا UUIDs) هي سلسلةٌ طويلةٌ فريدةٌ من الحروف والأرقام التي يمكن أن تُستعمَل كمُعرِّف لوسيط التخزين. تلك المُعرِّفات ليست سهلة القراءة من البشر، لكنها فريدة، وستبقى ثابتةً حتى لو بدَّلنا الخادوم أو النظام؛ لذا من الأفضل استخدام مُعرِّفات UUID للإشارة إلى أجهزة التخزين التي قد تُنقَل بين الأنظمة بين الحين والآخر، لأنَّ من غير المحتمل أن يحدث تضاربٌ في الأسماء. by-partlabel و by-partuuid: توفِّر جداول GPT لافتاتٍ ومعرِّفات UUID خاصة بها، والتي يمكن أن تُستعمَل أيضًا بغرض تمييز الأقسام، وتعمَل بنفس طريقة عَمَل المجلدين السابقين، إلا أنَّها تستعمل مُعرِّفات خاصة بجداول GPT. by-id: يحتوي هذا المجلد على وصلات مُولَّدةٌ أسماؤها من الرقم التسلسلي لجهاز التخزين وللجهاز الموصول إليه، وتلك الأسماء غير ثابتة تمامًا، لأنَّ طريقة وصل الجهاز إلى النظام قد تُغيّر من اسم وصلات المجلد by-id. by-path: وكما في مجلد by-id، تعتمد الوصلات الموجودة في هذا المجلد على أجهزة التخزين الموصول إلى النظام نفسه، وتُبنى تلك الوصلات اعتمادًا على طريقة تمثيل العتاد الذي يُستعمَل للوصول إلى وسيط التخزين في نظام التشغيل. وللوصلات الموجودة في هذا المجلد نفس الإشكاليات التي تواجهها تلك الموجودة في by-id لأنَّ وصل جهاز التخزين إلى منفذٍ آخر قد يؤدي إلى تغيير هذه القيمة. يُفضَّل عادةً استخدام by-label أو by-uuid إذ أنَّ تمثيلها للأقراص ثابتٌ. وصل أجهزة التخزين الكتلية تُستعمَل ملفات الأجهزة الموجودة في /dev للتواصل مع التعريف القادر على التعامل مع الجهاز المُعيّن في النواة؛ لكن يجب إنشاء طبقة تُمكّننا من معاملة الجهاز كوسيط تخزين يحتوي على مساحةٍ تخزينيةٍ قابلةٍ للاستعمال. في لينكس وغيره من الأنظمة الشبيهة بيونكس (Unix-like)، يُمثَّل نظام التشغيل كشجرة ملفات موحّدة بغض النظر عن عدد الأجهزة الفيزيائية التي تُستعمَل فيه؛ ولكي يُستعمَل نظامُ ملفاتٍ أو قرصٌ في النظام، فيجب ربطه بمكانٍ ما في تلك الشجرة. عملية «الوصل» (mounting) تعني ربط قسم مُهيئ أو قرص إلى مجلدٍ موجودٍ ضمن نظام ملفات لينُكس؛ ومن ثم سنتمكّن من الوصول إلى محتويات القرص أو القسم من ذاك المجلد. توصل الأقراص أو الأقسام دومًا في مجلدات فارغة مخصصة لهذا الغرض (الوصل في مجلد غير فارغ يعني أنَّنا لن نتمكن من الوصول إلى محتويات المجلد حتى نفصل [unmount] القرص أو القسم). هنالك الكثير من خيارات الوصل التي يمكن ضبطها لتعديل سلوك الأجهزة الموصولة، على سبيل المثال، يمكن أن يوصل القرص بوضع «القراءة فقط» لضمان عدم تغيير محتوياته. ينصح معيار هيكلة نظام الملفات باستخدام /mnt أو مجلدٍ فرعيٍ داخله لوصل أنظمة الملفات مؤقتًا. إذا كان وصلك للأقراص مؤقتًا فهذا أفضل مكانٍ لوصلها؛ لكن المعيار لم يُقدِّم أيّة اقتراحات لمكان وصل وسائط التخزين الدائمة، لذا يمكنك وصلها أينما تشاء؛ لكن في أغلبية الحالات توصل وسائط التخزين الدائمة في مجلد /mnt أو في مجلدٍ فرعيٍ داخله. جعل الوصل دائمًا باستخدام /etc/fstab تنظر أنظمة لينكس إلى ملفٍ يدعى /etc/fstab (أي filesystem table) الذي يُحدِّد ما هي أنظمة الملفات التي يجب وصلها أثناء الإقلاع. توصل أنظمة الملفات غير الموجودة في ذاك الملف تلقائيًا (باستثناء تلك المُعرَّفة بملفات systemd .mount، التي ليست شائعةً حاليًا). ملف /etc/fstab بسيطٌ جدًا، فكلُ سطرٍ فيه يُمثِّل نظام ملفاتٍ مختلفٍ الذي يجب أن يوصل؛ يُحدِّد هذا السطر ما هو الجهاز الكتلي، وما هي نقطة الوصل (mount point) التي سيُربَط إليها، وما هي صيغة القسم، وما هي خيارات الوصل، بالإضافة إلى معلوماتٍ أخرى. إدارة متقدمة لأجهزة التخزين صحيحٌ أنَّ أغلبية الاستخدامات البسيطة لا تحتاج إلى بُنى إدارية إضافية، إلا أنَّنا سنحصل على أداءٍ عالٍ ومرونة وقدرة على تعويض تلف الأقراص عند استخدامنا لطرائق الإدارة المتقدمة. ما هي مصفوفات RAID؟ مصفوفات RAID ترمز إلى «redundant array of independent disks»، وهي تقنية إدارة تخزين تسمح لك بتجميع الأجهزة مع بعضها لإدارتها كجهاز تخزين وحيد له ميزاتٌ إضافيةٌ. خصائص مصفوفة RAID تعتمد على مستوى RAID المستعمل، والذي يُعرِّف ما هو عدد الأقراص في المصفوفة وكيف تتعلق ببعضها. للمستوى المختار تأثيرٌ على الأداء والقدرة على تعويض تلف الأقراص، بعض المستويات الشائعة هي: RAID 0: يعتمد هذا المستوى على «توزيع البيانات» (drive striping) والذي يعني أنَّه عندما تُكتَب البيانات إلى المصفوفة، فستُقسَّم وتوزَّع على الأقراص الموجودة في المصفوفة، وهذا يعني زيادةً في الأداء لأنَّ بالإمكان الكتابة على أو القراءة من أكثر من قرص في آنٍ واحد. الجانب السلبي لهذا المستوى هو عندما يحدث عطبٌ في أحد الأقراص فسنفقد جميع المعلومات في كامل المصفوفة، لعدم وجود قرص يحتوي على معلوماتٍ كافيةٍ لإعادة بناء المصفوفة. RAID 1: مستوى RAID 1 يعتمد على إنشاء نسخة مماثلة للبيانات (drive mirroring). فأي شيء يُكتَب إلى مصفوفة RAID 1 سيُكتَب على عدِّة أقراص؛ الميزة الأساسية لهذا المستوى هو القدرة على تعويض الأقراص، مما يعني أنَّ البيانات ستبقى موجودةً في المصفوفة حتى لو حدث عطبٌ في أحد الأقراص؛ وذلك لأنَّ عدِّة أقراص تحتوي على نفس البيانات، لكن في المقابل سيؤدي ذلك تقليل المساحة التخزينية للمصفوفة إلى النصف. RAID 5: مستوى RAID 5 يوزِّع البيانات على عدِّة أقراص بشكلٍ شبيهٍ بمستوى RAID 0؛ لكن هذا المستوى يتضمن تكرار توزيع جزء من البيانات على قرصٍ آخر، وهذا يعني أنَّه لو حدثت مشكلة في أحد الأقراص، فستتمكن بقية الأقراص من إعادة بناء المصفوفة باستخدام البيانات المُكرَّرة التي يمكن تجميعها معًا. تلك البيانات المكررة كافية لإعادة بناء قرصٍ وحيد، وهذا يعني أنَّ المصفوفة ستتمكن من إعادة بناء نفسها إن حدث عطبٌ في قرصٍ وحيدٍ فقط. يؤدي تكرار توزيع البيانات إلى تقليل المساحة التخزينية لكامل المصفوفة إلى ما يعادل المساحة التخزينية لقرصٍ وحيد. RAID 6: يملك المستوى RAID 6 نفس خصائص RAID 5، إلا أنَّه يُكرِّر جزءًا من البيانات على قرصين، وهذا يعني أنَّ مصفوفات RAID 6 ستتمكن من إعادة بناء نفسها إن فقدت قرصين؛ وستتأثر المساحة التخزينية لكامل المصفوفة بتكرار البيانات، وهذا يعني أنَّ المساحة التخزينية القابلة للاستخدام لكامل المصفوفة مساويةٌ للمساحة التخزينية لقرصين. RAID 10: هذا المستوى هو دمجٌ بين المستويين 1 و 0، فبدايةً ستُنشَأ مجموعتين متماثلتين (mirrored) من المصفوفات؛ ثم ستُوزَّع البيانات عليها، وهذا يُنشِئ مصفوفةً لها نفس القدرة التعويضية لكن أداءها عالٍ. لكن هذا المستوى يتطلب عددًا كبيرًا نسبيًا من الأقراص، والمساحة التخزينية القابلة للاستخدام هي نصف مساحة جميع الأقراص. ما هو LVM؟ LVM، أو مدير الحجوم المنطقية (Logical Volume Manager) هو نظامٌ يُشكِّل «طبقةً» تعلو البنية الفيزيائية لوسائط التخزين وخصائصها لتوفير مرونة عالية وقدرات كبيرة. يسمح لك LVM بإنشاء مجموعة من الأجهزة الفيزيائية وإدارتها كما لو أنَّها قرصٌ وحيد، ويمكنك تقسيم المساحة عند الحاجة إلى «حجوم منطقية» (logical volumes) والتي تعمل عمل الأقسام. يعمل LVM بناءً على الأقسام العادية، ويحّل الكثير من المحدوديات الموجودة في الأقسام التقليدية، فعلى سبيل المثال، يمكنك بكل سهولة عند استخدام حجوم LVM أن توسِّع الأقسام وتُنشِئ أقسامًا تمتد على أكثر من قرص، وتأخذ نسخ snapshot من الأقسام، وتنقل الحجوم إلى أقراص فيزيائية مختلفة. يجدر بالذكر أنَّ بالإمكان استخدام LVM مع مصفوفات RAID ذات الأداء والوفرة العالية لتوفير نظام إدارة مرن. ما هي الخطوة القادمة؟ إذا كان لديك جهاز تخزين جديد تريد استخدامه مع نظام لينكس، فألقِ نظرةً على هذه المقالة التي ستُرشِدُكَ إلى طريقة تقسيم وتهيئة ووصل نظام الملفات الجديد الذي ستُنشِئه. يجب أن تكفيك المقالة السابقة لأغلبية حالات الاستخدام حيث سيكون همّك الرئيسي هو زيادة القدرات التخزينية. لتعلم المزيد عن مهام إدارة أجهزة التخزين الأساسية، فانظر إلى هذه المقالة ترجمة -وبتصرّف- للمقال An Introduction to Storage Terminology and Concepts in Linux لصاحبه Justin Ellingwood
-
رأيتُ في الآونة الأخيرة الكثير من الأشخاص يشقون طريقهم بصعوبة في CSS، انطلاقًا من المبتدئين إلى المبرمجين المحترفين؛ بعضهم لا يحب طريقة عمل CSS، ويرون أنَّ استبدال لغة أخرى بلغة CSS هو أمرٌ حسن، وكانت هذه هي نقطة انطلاق مفسرات CSS (مثل Sass و Less)؛ وبعضهم الآخر يستخدم إطارات العمل على أمل أنَّ ذلك سيجعلهم يكتبون شيفرات أقل (ورأينا في درس «ربما لا تحتاج إلى إطار عمل للغة CSS » أنَّ ذلك ليس صحيحًا)؛ بينما تخلى بعض المطورين عن استخدام CSS تمامًا وبدؤوا باستعمال JavaScript بدلًا عنها. لكنك لا تحتاج دومًا إلى استخدام مُفسِّر CSS في مشاريعك، ولستَ بحاجةٍ إلى استعمال إطار عمل كبير كنقطة بداية لمشروعك، ومن المؤكد أنَّ فكرة استعمال JavaScript لغير غرضها الأصلي هي فكرةٌ سيئة. سنطالع في هذا الدرس بعض التلميحات والنصائح لكيفية أفضل لكتابة شيفرات CSS سهلة الصيانة، لذا ستصبح ملفات الأنماط أقصر، وفيها قواعد أقل، وستشعر أنَّ CSS أصبحت أداةً مفيدةً واستخدامها مريح بدلًا من أن تفكر في عواقب استعمالها! إنشاء محددات غير مخصصة تعتمد لغة CSS على التصريح عن «محددات» (selectors) التي تضع فيها القواعد التنسيقية التي تريد تطبيقها على العناصر الموجودة في شجرة DOM. وهنالك بعض القواعد التي لها أولوية على القواعد الأخرى، كتلك التي عُرِّفَت داخل الخاصية style في العنصر نفسه. على سبيل المثال، إذا كانت لدينا شيفرة HTML و CSS الآتية: <button class="button-warning"> .button-warning { background: red; } button, input[type=submit] { background: gray; } بغض النظر عن أنَّ القاعدة .button-warning قد عرِّفَت قبل قاعدة button, input[type=submit]، لكن لخاصية background فيها أولوية على خاصية background المُعرَّفة في قاعدة button, input[type=submit]. لكن لماذا؟ ما هو المعيار الذي تتبعه لغة CSS لتقرر ما هي القواعد التي لها أولوية على غيرها؟ الجواب هو «التحديد»، فبعض المحددات تُعتبَر أنَّها مخصصة أكثر من غيرها: فمثلًا المُحدِّد #id له أولوية على محدد .class. ماذا يحدث لو استخدمنا مُحدِّد أكثر تخصيصًا مما يلزم؟ ماذا لو أردنا لاحقًا تجاوز تلك القواعد، سنحتاج حينها إلى مُحدِّد أكثر تخصيصًا. ماذا لو أردنا بعد ذلك أن نتجاوز تلك القيم… نعم سنحتاج إلى مُحدِّد أكثر تخصيصًا، وهكذا حتى تصبح المحددات أطول وأعقد وسينتهي بها المطاف لتمسي صعبة الصيانة والتطوير. لذا عليك عند كتابة المُحدِّدات أن تسأل نفسك: هل هذا هو أقل مُحدِّد تخصيصًا الذي يعمل عملًا صحيحًا هنا؟ جميع قواعد التحديد مُعرَّفة بشكلٍ رسمي في مواصفة «W3C CSS Selectors»، وستجد في تلك الصفحة جميع التفاصيل المتعلقة بمُحدِّدات CSS. إذا أردتَ مقالةً سهلة الفهم فاطلع على هذه المقالة. لا تعالج المشاكل بإضافة قواعد جديدة لنتخيل هذا الموقف الذي يتكرر كثيرًا: هنالك علّة في شيفرة CSS وعرفتَ أنَّ أحد عناصر DOM مُنسَّقٌ تنسيقًا خاطئًا، وأدركتَ أنَّ السبب هو وراثته (inherit) لخاصيةٍ لا يجب أن يرثها. رجاءً لا تضف شيفرة CSS جديدة لحل المشكلة، فبفعلك لذلك ستصبح الشيفرات عندك كثيرة، وسيصبح تحديد العلل المستقبلية أصعب. فبدلًا من ذلك، توقف، واستخدام أدوات المطوِّر في متصفحك لتفحص العنصر ومعرفة ما الذي يرثه من خاصيات، ومعرفة ما هي القاعدة التي تُطبَّق على العنصر والتي لا تريدها، ثم تعديل تلك القاعدة لكي لا تؤدي إلى تلك النتيجة. يمكنك إظهار الأنماط التي يرثها أحد العناصر في متصفح Firefox بالضغط بالزر الأيمن على العنصر ثم اختيار «Inspect element». انظر إلى الخاصيات الموروثة، ولاحظ كيف سترى جميع القواعد المُطبَّقة على العنصر، وبالترتيب الذي طُبِّقَت فيه. أي أنَّ القواعد الموجودة في الأعلى هي القواعد الأكثر تحديدًا ولها أولولية على القواعد التي تليها. يمكنك أن ترى وجود خط يمر ببعض الخاصيات، وهذا يعني أنَّ هنالك قاعدة أكثر تخصيصًا أدت إلى تجاوز هذه القاعدة. يمكنك –إضافةً إلى رؤية القواعد المُطبَّقة على العنصر– أن تُفعِّل أو تلغي تفعيل بعض الخاصيات أو أن تجري تعديلات حية على قيمها ثم تلاحظ النتائج، وهذا مفيدٌ جدًا عند محاولة إصلاح العلل. قد يتضمن الحل اللازم تطبيقه لإصلاح العلة تعديلًا في إحدى القواعد، أو تغييرًا لقاعدةٍ ما في مكانٍ آخر في صفحة الأنماط؛ وقد يتطلب إصلاح العلة إضافةَ قاعدةٍ جديدةٍ… لكن المهم أن تعلم ما هو الإجراء الصحيح الذي عليك اتخاذه لإصلاح المشكلة. أقترح عليك أيضًا أن تنظر في إعادة هيكلة الشيفرات (code refactoring)، فصحيحٌ أنَّ CSS ليست لغةً برمجيةً، إلا أنَّها «شيفرات» وعليك أن تأخذ بعين الاعتبار نفس الأمور التي تفعلها مع شيفرات JavaScript أو بايثون: يجب أن تكون الشيفرات مرتبةً وسهلة القراءة ويمكن إعادة هيكلتها عند الحاجة. لا تستخدم !important هذه النصيحة مضمّنة في القسم السابق، إلا أنني فضَّلتُ ذكرها بمفردها لأهميتها: لا تستخدم !important في شيفرة CSS! الكلمة المحجوزة !important هي ميزة في CSS تسمح لك بتجاوز الترتيب الافتراضي للأولويات، وهي تستعمل عادةً إن استعجلت إصلاح علّة لكنك لا تملك وقتًا أو ليست عندك رغبة في إصلاحها بمعرفة مسببها الأصلي… من الشائع أيضًا استعمال الكلمة المحجوزة !important عندما تَستخدم إطار عمل CSS ذو قواعد مخصصة جدًا، ومن الصعب تجاوز تلك القيم. عندما تُضيف !important إلى خاصيةٍ ما، فسيتجاهل المتصفح جميع القواعد التي لها أولوية عليها (أي أنَّ القاعدة «أكثر تخصيصًا»)، وستجد نفسك في ورطة عندما تستعمل !important لتجاوز قاعدة أخرى قد اُستخدمَت فيها !important أيضًا. الاستعمال المشروع الوحيد للكلمة !important هو عند استخدامك لأدوات التطوير لمحاولة حل مشكلة ما، فعليك في بعض الأحيان أن تعرف ما هي القيم اللازم ضبطها لإصلاح العلة، واستخدام !important في أدوات التطوير وتعديل قواعد CSS تعديلًا حيًا سيسمح لك بمعرفة تلك القيم مع تجاهل القيم الموروثة. بعد أن تعرف ما هي القيم الصحيحة، فعد إلى الشيفرة وانظر ما هي القواعد التي تتضمن تلك الخاصيات، وعدِّلها كما ينبغي. لا تجعل px و % هي كل ما تستخدمه من الواحدات التعامل مع px (البسكلات) و % (النسب المئوية) أصبح بدهيًا، لذا سنشرح بعض الواحدات الأقل شهرةً. em و rem من أشهر الواحدات النسبية هي em، حيث يكافئ 1em قياس الخط التابع لذلك العنصر. لتكن لدينا شيفرة HTML الآتية: <article> <h1>Title</h1> <p>One Ring to bring them all and in the darkness bind the.</p> </article> وسنستخدم قاعدة CSS وحيدة: article { font-size: 1.25em; } تُطبِّق أغلبية المتصفحات قياسًا بمقدار 16 بكسل إلى العنصر الجذر (root element) افتراضيًا (بالمناسبة، يمكن تعديل هذه القيمة من المستخدم، وهذه ميزةٌ رائعةٌ تُسهِّل من قابلية الوصول). أي ستُعرَض نصوص العنصر article بخاصية font-size ذات القيمة 20 بكسل (أي 16 * 1.25). لكن ماذا عن العنصر h1؟ لفهم ما الذي يحدث تمامًا فسنضيف قاعدة CSS أخرى إلى صفحة الأنماط: h1 { font-size: 1.25em; } صحيحٌ أنَّ قيمة الخاصية font-size هي 1.25em أيضًا، أي نفس قياس العنصر article، لكن علينا أن نأخذ بعين الاعتبار أنَّ الخاصية em هي خاصية تجميعية، أي لو كان العنصر h1 ابنًا (child) مباشرًا للعنصر body على سبيل المثال، فستكون قيمة الخاصية font-size هي 20 بكسل (أي 16 * 1.25)؛ لكن عنصر h1 في مثالنا موجودٌ داخل عنصرٍ (العنصر article هنا) له قيمةٌ للخاصية font-size تختلف عن العنصر الجذر، ففي هذه الحالة قياس الخط هو 1.25 مضروبًا بقيمة الخاصية font-size التي يرثها العنصر h1، أي سيكون قياس الخط النهائي للعنصر h1 الموجود داخل العنصر article هو 25 بكسل (أي 16 * 1.25 * 1.25). الواحدة em متعددة الاستخدامات وتجعل من السهل تغيير جميع القياسات في الصفحة (حتى لو غيرناها ديناميكيًا)، ولا تُستعمَل فقط على قيمة الخاصية font-size وإنما يمكن توظيفها في الخاصيات الأخرى مثل line-height أو width. إذا أعجبتكَ فكرة استخدام واحدة قياس نسبةً إلى الحجم الأساسي، لكن لم تحب موضوع تجميع القيم، فيمكنك حينها استخدام rem، واحدة rem شبيهةٌ جدًا بواحدة em إلا أنَّها تتجاهل تجميع القيم، وتأخذ قياس العنصر الجذر فقط. إذا أخذنا شيفرة CSS للمثال السابق وبدلنا واحدة em إلى rem للعنصر h1: article { font-size: 1.25em; } h1 { font-size: 1.25rem; } ستملك جميع عناصر h1 الخاصية font-size بقيمة 20 بكسل (بافتراض أنَّ قياس العنصر الجذر هو 16px)، بعض النظر إن كان العنصر h1 داخل عنصر article أم لا. vw و vh واحدات vm و vh تُمثِّل نسبة من أبعاد «إطار العرض» (viewport)، حيث 1vw هي 1% من عرض «إطار العرض»، بينما 1vh هي 1% من ارتفاع «إطار العرض». هذه الواحدات مفيدة للغاية، وخصوصًا عندما تريد إنشاء عنصر يأخذ كامل الشاشة (مثل الخلفيات الغامقة للأقسام). واحدات أخرى هنالك واحدات أخرى غير شائعة أو مستعملة بكثرة، لكن قد تصادفك في مسيرتك البرمجية، يمكنك تعلم المزيد من المعلومات عنها في هذا الدرس. استخدم flexbox تحدثنا عن هذا من قبل في درسٍ سابقٍ عن إطارات عمل CSS «ربما لا تحتاج إلى إطار عمل للغة أضفCSS» ، لكن لا ضير من التذكير أنَّ flexbox سيُبسِّط عملية إنشاء تخطيطات الصفحات أو لمحاذاة العناصر. إذا كان flexbox جديدًا عليك فانظر إلى هذا الدرس التمهيدي. أجيب بنعم على السؤال البدهي الذي سيخطر ببالك: «هل يمكن استخدام flexbox في الوقت الراهن؟». دعم flexbox في المتصفحات تجاوز نسبة 94%، لذا يمكنك استخدامه حالًا إلا إن كنتَ تريد دعم المتصفحات القديمة. لذا يمكنك التوقف عن كتابة عناصر div الكثيرة ذات الخاصية float والتي يصعب اكتشاف الأخطاء فيها وصيانتها. راقب أيضًا التطويرات في مجال تنسيق تخطيط الصفحة وخصوصًا Grid ، الذي سيُسهِّل كثيرًا من إنشاء تخطيط الصفحة. عند استخدام مُفسِّر CSS… مفسِّرات CSS مثل Sass أو Less مشهورة جدًا في عالم تطوير الواجهات الأمامية لصفحات الويب، وهي أدواتٌ مفيدةٌ جدًا وتسمح لنا (عند استخدامها استخدامًا صحيحًا) أن نعمل بكفاءة كبيرة مع CSS. لا تسرف في تشعّب المُحدِّدات إحدى الميزات الشائعة في مُفسِّرات CSS هي تشعّب المحددات (selector nesting)، فمثلًا هذه شيفرة Less: a { text-decoration: none; color: blue; &.important { font-weight: bold; } } ستُحوَّل إلى قواعد CSS الآتية: a { text-decoration: none; color: blue; } a.important { font-weight: bold; } تسمح هذه الميزة لنا بكتابة شيفرات أقل، وتجميع القواعد التي تؤثر على العناصر التي تأتي مع بعضها (عمومًا) في شجرة DOM، وهذه الميزة تساعدك في اكتشاف العلل وإصلاحها. لكن من الشائع أيضًا الإفراط في استخدام هذه الميزة مما يجعلك تعيد كتابة شجرة DOM بكاملها في محددات CSS، لذا إذا كانت لدينا شيفرة HTML الآتية: <article class="post"> <header> <!-- … --> <p>Tags: <a href="..." class="tag">irrelevant</a></p> </header> <!-- … --> </article> فقد تجد ما يلي في شيفرة CSS: article.post { // ... ستُذكَر القواعد الأخرى هنا header { // ... p { // ... a.tag { background: #ff0; } } } } الجانب السلبي الرئيسي لهذا هو أنَّ مُحدِّدات CSS الناتجة هي مُحدِّدات مخصصة جدًا، وشرحنا من قبل أنَّ علينا تفادي استخدامها. هنالك سلبيات أخرى للاستخدام المفرط للتشعّب، والتي ذُكِرَت في هذا الدرس. باختصار: لا تجعل تشعّب مُحدِّدات CSS في مفسرات CSS يولِّد قواعد لن تفكر في كتابتها يدويًا دون مُفسِّر. استخدام include أو استخدام extend؟ ميزة أخرى مفيدة لمُفسِّرات CSS تدعى «mixins»، وهي مجموعة من قواعد CSS القابلة لإعادة الاستخدام، فمثلًا لنقل أننا نريد تنسيق الأزرار (buttons)، وأغلبية الأزرار لها نفس خاصيات CSS الأساسية؛ لذا يمكننا إنشاء mixin كما يلي في Less: .button-base() { padding: 1em; border: 0; } ثم إنشاء قاعدة كالآتية: .button-primary { .button-base(); background: blue; } والتي ستولِّد شيفرة CSS: .button-primary { padding: 1em; border: 0; background: blue; } كما ترى، من المفيد جدًا إعادة هيكلة (واستخدام) الشيفرات المكررة. وإلى جانب «تضمين» (including) بُنية mixin، هنالك خيارٌ آخر هو «توسعة» (extending) أو «وراثة» تلك البنية (يختلف المصطلح المستعمل اعتمادًا على الأداة المستخدمة). والتي ستَدمِج عدة مُحدِّدات في نفس القاعدة. لنشاهد مثالًا عمليًا عن توسعة بنية mixin السابقة (أي .button-base): .button-primary { &:extend(.button-base) background: blue; } .button-danger { &:extend(.button-base) background: red; } والتي ستحوّل إلى شيفرة CSS الآتية: .button-primary, .button-danger { padding: 1em; border: 0; } .button-primary { background: blue; } .button-danger { background: red; } بعض المقالات والدروس الموجودة على الويب تخبرنا أن نستخدم طريقة «include» فقط، والأخرى تطلب منا استخدام طريقة «extend» فقط؛ لكن الواقع هو أنَّ كلا الطريقتين ستنتجان شيفرات CSS مختلفة، وليس من الخطأ استخدام أي واحدة منهما، لكن قد يُفضَّل استخدام إحداهما على الأخرى في بعض الحالات. كيف تختار بينهما؟ أكرِّر أنَّ قاعدة «هل ستكتب هذه الشيفرة يدويًا» تنطبق هنا. الخلاصة أرجو أن يؤثر هذا الدرس عليك ويجعل طريقة كتابتك لشيفرات CSS أفضل؛ تذكَّر ما قلتُ لك سابقًا: CSS هي شيفرات، ويجب أن تعاملها بنفس طريقة معاملتك لبقية الشيفرات. فإن أعطيتها الاهتمام اللازم فسترد لك الجميل :-) . ترجمة -وبتصرّف- للمقال CSS coding techniques لصاحبه Belén Albeza
-
تمهيد هنالك الكثير من الأدوات المتوفرة لإدارة التخزين في لينكس، لكن هنالك عددٌ قليلٌ منها نستعمله يوميًا لإدارة وصيانة أجهزة التخزين. سأريك في هذا الدرس بعضًا من أشهر الأدوات التي تستعمل لإدارة نقاط الوصل وأجهزة التخزين وأنظمة الملفات. لن نشرح في هذا الدرس كيفية تهيئة أجهزة التخزين لأوّل استعمال لها في لينكس، إذ شرحنا ذلك في درسٍ بعنوان «كيفية تقسيم وتهيئة أجهزة التخزين في لينكس» الذي يبيّن لك كيفية إعداد جهاز تخزين جديد إن لم يكن مضبوطًا من قبل. للمزيد من المعلومات حول الاصطلاحات والمفاهيم المستخدمة في هذا الدرس، فراجع درس «تقديم إلى اصطلاحات ومفاهيم التخزين في لينكس». معرفة القدرة التخزينية والمساحة المستخدمة عبر df غالبًا ما تكون أهم معلومة تريد معرفتها عن وسائط التخزين في جهازك هي القدرة التخزينية والمساحة المستخدمة في أجهزة التخزين الموصولة إلى النظام. لمعرفة ما المساحة التخزينية المتوافرة إجمالًا وكم نسبة استخدامها، فسنستعين بالأمر df، الذي يعرض ناتجه مقدرًا بالكيلوبايت، لكنك لن تستفيد عادةً من ذلك لذا أضف الخيار -h إلى الناتج لعرضه بصيغةٍ سهلة القراءة: df -h Filesystem Size Used Avail Use% Mounted on udev 238M 0 238M 0% /dev tmpfs 49M 624K 49M 2% /run /dev/vda1 20G 1.1G 18G 6% / tmpfs 245M 0 245M 0% /dev/shm tmpfs 5.0M 0 5.0M 0% /run/lock tmpfs 245M 0 245M 0% /sys/fs/cgroup tmpfs 49M 0 49M 0% /run/user/1000 /dev/sda1 99G 60M 94G 1% /mnt/data وكما تلاحظ، القسم /dev/vda1 الموصول في / ممتلئٌ بنسبة 6% وفيه 18 غيغابايت من المساحة التخزينية الفارغة، بينما القسم /dev/sda1 موصولٌ في /mnt/data وهو فارغٌ وفيه 94 غيغابايت من المساحة التخزينية. الأسطر الأخرى تستخدم أنظمة الملفات tmpfs و devtmpfs والتي هي الذاكرة المؤقتة (volatile memory) ممثلةً كما لو أنَّها وسيطُ تخزينٍ دائمٍ. يمكننا استثناء تلك القيم من الناتج بكتابة الأمر: df -h -x tmpfs -x devtmpfs Filesystem Size Used Avail Use% Mounted on /dev/vda1 20G 1.1G 18G 6% / /dev/sda1 99G 60M 94G 1% /mnt/data الناتج الحالي يُركِّز على عرض استخدام الأقراص بإزالة بعض الأجهزة الخاصة التي لن ننظر إليها عادةً. معرفة معلومات عن الأجهزة الكتلية باستخدام lsblk الجهاز الكتلي هو قطعةٌ من العتاد التي يمكن استعمالها لتخزين البيانات، مثل أقراص التخزين الصلبة الاعتيادية (HDD) أو أقراص التخزين ذات الحالة الثابتة (solid state drive أي SSD) أو وحدات الذاكرة الفلاشية (flash memory stick) …إلخ. والأجهزة الكتلية هي أقراصٌ فيزيائيةٌ التي تُكتَب عليها أنظمة الملفات، وتُحدِّد أنظمة الملفات بدورها كيفية تخزين الملفات والبيانات على القرص. يمكن استعمال الأداة lsblk لعرض معلومات عن الأجهزة الكتلية الموجودة في النظام. تَتبَع الميزات المتاحة لهذه الأداة للنسخة المُثبَّتة، لكن يمكن عمومًا استخدام الأداة lsblk لعرض معلومات عن القرص نفسه، بالإضافة إلى عرض معلومات عن طريقة التقسيم وأنظمة الملفات التابعة لتلك الأقسام. إذا نفّذنا الأمر lsblk دون وسائط فسيُظهِر أسماء الأجهزة، والأرقام الرئيسية (major) والثانوية (minor) والتي تستخدم من نواة لينكس لتتبع الأقراص والأجهزة، وفيما إذا كان القرص قابلًا للإزالة، ومساحته التخزينية، وفيما إذا كان موصولًا بنمط «القراءة فقط»، ونوعه (أي قرص أم قسم)، ونقطة الوصل. تتطلب بعض الأنظمة استخدام امتيازات الجذر (أي استخدام الأمر sudo) لعرض الناتج عرضًا صحيحًا، وهذا ما سنفعل في المثال الآتي: sudo lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT sda 8:0 0 100G 0 disk vda 253:0 0 20G 0 disk └─vda1 253:1 0 20G 0 part / أهم الأجزاء المعروضة في الناتج السابق هي الاسم الذي يُشير إلى اسم الجهاز في مجلد /dev، ومساحته التخزينية، ونقطة الوصل. يمكنك أن ترى في الناتج السابق أنَّنا نملك قرصًا (/dev/vda) فيه قسمٌ وحيد (/dev/vda1) الموصول في / وقرصًا آخر (/dev/sda) الذي لم يُقسَّم بعد. للحصول على معلوماتٍ متعلقة بإدارة القرص والقسم، فمرِّر الخيار --fs الذي يعمل في بعض الإصدارات: sudo lsblk --fs NAME FSTYPE LABEL UUID MOUNTPOINT sda vda └─vda1 ext4 DOROOT c154916c-06ea-4268-819d-c0e36750c1cd / إذا لم يكن الخيار --fs متوافرًا في نسختك، فيمكنك أن تطلب إظهار نفس الناتج السابق باستخدام الخيار -o NAME,FSTYPE,LABEL,UUID,MOUNTPOINT. للحصول على معلومات حول بنية القرص، فنفِّذ الأمر: sudo lsblk -t NAME ALIGNMENT MIN-IO OPT-IO PHY-SEC LOG-SEC ROTA SCHED RQ-SIZE RA WSAME sda 0 512 0 512 512 1 deadline 128 128 2G vda 0 512 0 512 512 1 128 128 0B └─vda1 0 512 0 512 512 1 128 128 0B هنالك المزيد من الاختصارات المتوافرة لعرض مختلف المعلومات عن أقراصك وأقسامك. يمكنك عرض جميع المعلومات باستخدام الخيار -0 أو يمكنك تحديد ما هي الحقول التي تريدها بتحديد اسمها باستخدام الخيار -o. خيار المساعدة -h سيعرض جميع الحقول المتاحة: lsblk -h . . . Available columns (for --output): NAME device name KNAME internal kernel device name . . . SUBSYSTEMS de-duplicated chain of subsystems REV device revision VENDOR device vendor For more details see lsblk(8). فصل ووصل أنظمة الملفات عليك قبل استخدامٍ قرصٍ جديدٍ أن تُقسِّمه، وأن تُهيئه بنظام ملفاتٍ معيّن، ثم تصله. عملية التقسيم والتهيئة تُجرى عادةً لمرة واحدة، لذا لن نناقشها هنا، وكما ذكرتُ في بداية هذا الدرس، تستطيع العثور على معلوماتٍ تفصيلية حول تقسيم قرص وتهيئة قسمٍ فيه في هذه المقالة. أما الوصل (mounting) فهو أمرٌ تفعله كل حين، فوصل نظام ملفاتٍ يعني أنَّه أصبح متاحًا للاستخدام داخل النظام في نقطة الوصل المُحدَّدة. ونقطة الوصل هي مجلدٌ الذي يمكننا الوصول عبره إلى نظام الملفات. يوجد أمرَين يُكمِّلان بعضها بعضًا ويستخدمان لإدارة عملية الوصل هما mount و umount. يُستعمَل الأمر mount لوصل نظام ملفات إلى شجرة الملفات الحالية، ففي نظام لينكس هنالك شجرة ملفات وحيدة لكامل النظام بغض النظر عن عدد الأجهزة الفيزيائية التي تتألف منها. أما الأمر umount (انتبه أنَّ اسم الأمر هو umount وليس unmount) فيُستعمَل لفصل نظام ملفات. إضافةً إلى الأمرين السابقين، يوجد أمرٌ باسم findmnt الذي يفيد بجمع معلومات عن حالة أنظمة الملفات الموصولة. استخدام الأمر mount أبسط طريقة لاستخدام mount هي تمرير مسار القسم ثم نقطة الوصل التي تريد وصله إليها: sudo mount /dev/sda1 /mnt نقطة الوصل –التي هي آخر وسيط والذي يُحدِّد أين يجب وصل نظام الملفات الجديد– يجب أن تُشير دائمًا إلى مجلدٍ فارغ. يمكنك تحديد بعض الخيارات عند الوصل، وصحيحٌ أنَّ الأمر mount سيحاول معرفة نوع نظام الملفات، لكن من الأفضل تمرير نوع نظام الملفات عبر الخيار -t. فلنظام ملفات Ext4 نكتب: sudo mount -t ext4 /dev/sda1 /mnt هنالك الكثير من الخيارات الأخرى التي تُغيّر طريقة وصل نظام الملفات؛ حيث تتواجد خيارات الوصل العامة في قسم «FILESYSTEM INDEPENDENT MOUNT OPTIONS» في صفحة الدليل man mount، ويوجد أيضًا أقسام لمختلف أنظمة الملفات تحت عنوان «FILESYSTEM SPECIFIC MOUNT OPTIONS» في نفس صفحة الدليل السابقة لشرح الخيارات الخاصة بأنظمة ملفات معيّنة. يمكنك تمرير الخيارات الأخرى باستخدام -o، فمثلًا يمكنك وصل القسم باستخدام الخيارات الافتراضية (والتي هي rw,suid,dev,exec,auto,nouser,async) بكتابة -o defaults، أما إذا أردتَ مثلًا أن تتجاوز إذن السماح بالقراءة والكتابة وتريد وصل القسم للقراءة فقط، فيكنك إضافة الخيار ro والذي سيتجاوز الخيار rw من defaults: sudo mount -t ext4 -o defaults,ro /dev/sda1 /mnt لوصل جميع أنظمة الملفات الموجودة في ملف /etc/fstab فمرِّر الخيار -a: sudo mount -a عرض خيارات وصل أنظمة الملفات يمكن عرض خيارات الوصل المستعملة مع قسمٍ معيّن بتمرير مسار نقطة الوصل إلى الأمر findmnt، فمثلًا لو مررنا نقطة الوصل التي استعملناها في المثال السابق لوصل نظام الملفات للقراءة فقط إلى الأمر findmnt فسيبدو الناتج شبيهًا بما يلي: findmnt /mnt TARGET SOURCE FSTYPE OPTIONS /mnt /dev/sda1 ext4 ro,relatime,data=ordered يمكن أن تستفيد من هذا خير استفادة إن كنت تجرِّب عدِّة خيارات ووجدت ضالتك في إحداها، فتستطيع حينها أن تستعمل findmnt لمعرفة ما هي خيارات الوصل لإضافتها إلى ملف /etc/fstab أو إذا أردتَ وصل القسم يدويًا في المستقبل. فصل نظام الملفات يستعمل الأمر umount لفصل نظام ملفات معيّن، أكرِّر أنَّ الأمر هو umount وليس unmount. الشكل العام للأمر بسيطٌ جدًا وهو تمرير نقطة الوصل أو الجهاز الموصول إلى الأمر umount. تأكّد أنَّك لا تستخدم أيّة ملفات في نقطة الوصل ولا توجد أيّة برامج (بما في ذلك الصَدَفَة [shell] التي تستعملها) تعمل داخل نقطة الوصل: cd ~ sudo umount /mnt لن تحتاج غالبًا إلى أيّة خيارات خاصة عند فصل أنظمة الملفات. الخلاصة صحيحٌ أنَّ الأدوات التي شرحناها في مقالتنا هذه ليس كثيرةً، لكنها تكفي احتياجاتك اليومية بخصوص إدارة الأقسام وأجهزة التخزين. ترجمة -وبتصرّف- للمقال How To Perform Basic Administration Tasks for Storage Devices in Linux لصاحبه Justin Ellingwood
-
أهلًا بك في هذه السلسلة التي تتحدث عن تأثيرات التمرير (Scrolling Effects)، سنستعرض في هذه السلسلة عددٌ من تأثيرات التمرير وسنشرح آلية عملها وسنجرِّبها عمليًا. يمكننا الاستفادة من الحدث scroll في JavaScript لإجراء تأثيرات عند تمرير صفحة الويب؛ لكن إن فعلنا ذلك دون إتقان فالنتيجة كارثية، أما إذا أحسنا صنعنا فيمكن لتأثيرات التمرير أن تبهر الزوار وتشعرهم أنَّ موقعك مميز. تحدثنا في المقالتين السابقتين عن التأثيرات الآتية: إخفاء صورة خلفية تدريجيًا عند التمرير توضيح الصورة عند التمرير تدوير العناصر عند التمرير تأثير اختلاف المظهر parallax إظهار صورة الخلفية عند التمرير باستخدام CSS فقط تمرير سلس للصفحة تطبيق تأثير عدم الوضوح على المحتوى خلف شريط الانتقال وسنشرح في هذه المقالة (الثالثة) طريقة إنشاء: عنصر قابل للتمرير مع إمكانية وصول مخصصة من لوحة المفاتيح تأثير غروب الشمس باستخدام SVG إظهار فيديو في الخلفية صور متحركة بتأثير parallax باستخدام CSS 3D و JavaScript سأقدِّم لك في بداية كل قسم رابطًا لتجربة المثال تجربةً حيةً على المتصفح. سيسهل عليك كثيرًا أن تفهم الشرح والشيفرات بعد تجربتك للتأثير. عنصرٌ قابلٌ للتمرير مع إمكانية وصول مخصصة من لوحة المفاتيح (تجربة حية) كقاعدة عامة، إخفاء المعلومات المهمة داخل عنصر قابل للتمرير هي فكرةٌ سيئة، لكنه تُستعمَل عادةً من المصممين لأنها تبدو «ذات مظهرٍ جيد» بدلًا من التفكير حول قابلية استخدامها؛ لكن هنالك حالات يمكن فيها من الضروري فعل ذلك، وعندئذٍ يجب أن تكون الروابط داخل تلك العناصر قابلةً للوصول عبر لوحة المفاتيح. شيفرات HTML و CSS الأساسية تقريبًا جميع العناصر يمكن أن تُضبَط لها الخاصية overflow: scroll، لذا لن يصعب علينا إنشاء شيفرة HTML. سأذكر في هذا المثال بعض الأماكن في أفريقيا: <ol id="scrolling-list"> <li><a href=#><img src="tunisia.jpg" alt>Tunisia</a> <li><a href=#><img src="botswana.jpg" alt>Botswana</a> <li><a href=#><img src="south-africa.jpg" alt>South Africa</a> <li><a href=#><img src="kenya.jpg" alt>Kenya</a> <li><a href=#><img src="nigeria.jpg" alt>Nigeria</a> <li><a href=#><img src="tanzania.jpg" alt>Tanzania</a> </ol> ستعرض شيفرة CSS التي سنكتبها القائمةَ بارتفاعٍ معيّن، الخاصية height نفسها لن تؤثر على طريقة العرض، فالقاعدة العامة هي أنَّ المحتوى سيُعرَض دومًا حتى لو تجاوز حدود العنصر الحاوي له. إذا أردنا أن نعكس هذا السلوك، فعلينا القيام بخطواتٍ معيّنة، وفي هذه الحالة، سنضبط الخاصية overflow-y: scroll لنتيح إمكانية التمرير داخل القائمة. لاحظ استخدامنا للكلمة المحجوزة currentcolor وغيرها من الاختصارات التي تجعل عملية التطوير أسهل. ol#scrolling-list { font-size: 0; background: #333; list-style-type: none; padding-left: 0; height: 230px; overflow-y: scroll; font-weight: 100; color: #999; } ol#scrolling-list li { border-bottom: 1px dashed; } ol#scrolling-list li a { font-size: 1.2rem; text-decoration: none; line-height: 2; color: currentcolor; display: block; transition: .4s background; } ol#scrolling-list li a img { width: 20%; vertical-align: top; margin-right: .5rem; } عملية تخصيص شريط التمرير أصبحت محدودة: ففي وقتٍ سابقٍ كان متصفحا Internet Explorer و Firefox يستعملان مُحدِّدات CSS (CSS selectors) لفعل ذلك، لكنهما أهملا دعمها لاحقًا. ما يزال بإمكاننا تخصيص شريط التمرير في المتصفحات التي تعتمد على المحرك Webkit، بسلسلة من المُحدِّدات الخاصية بهذا النوع من المتصفحات (والتي تُشبه تلك التي نستعملها لتخصيص حقل range للإدخال): ol#scrolling-list::-webkit-scrollbar { background: #000; } ol#scrolling-list::-webkit-scrollbar-thumb { background-color: hsl(33,100%,50%); } في النهاية، سنُخصِّص حالة :hover للروابط وسنُخصِّص حالة :focus أيضًا بتجميعهما معًا وذلك لتوضيح ما هو الرابط الذي نُحدِّده عبر لوحة المفاتيح: ol#scrolling-list li a:hover, ol#scrolling-list li a:focus { background: #111; } تحسين قابلية الوصول باستخدام JavaScript بافتراض أنَّ لديك إمكانية كاملة للتنقل باستخدام لوحة المفاتيح في متصفحك (أسهل متصفح لتجربة ذلك هو Chrome، إذ تتطلب بقية المتصفحات أن تضبط بعض الخيارات أولًا) وستجد أنَّك إذا ضغطتَ على زر TAB فستنتقل بين الروابط في السلسلة، فبعد أن تصبح داخل السلسلة ستتمكن من الانتقال إلى الأمام (أي إلى الروابط التالية) باستخدام TAB أو إلى الخلف (أي إلى الروابط السابقة) باستخدام SHIFT+TAB، وتتحكم أزرار الأسهم بتمرير العنصر. لا يوجد شيءٌ خاطئٌ في ما سبق، لكن في بعض الحالات سترغب بالسماح للمستخدم باستعمال أزرار الأسهم لاختيار العناصر في القائمة بدلًا من التمرير. سنحتاج في البداية إلى تحديد بعض الكائنات باستخدام JavaScript: var locales = document.getElementById('scrolling-list'), listItems = locales.children, allLnks = new Array(); for (var i = 0;i<listItems.length;i++) { allLnks[i] = listItems[i].firstElementChild; } المتغير listItems يمثِّل العناصر المُشكِّلة للقائمة، بينما allLnks فهو مصفوفة للروابط الموجودة داخل عناصر القائمة. ولأننا وضعنا تلك العناصر داخل بعضها بعضًا فهذا سيجعل بقية السكربت معقدة قليلًا: locales.addEventListener('keydown', function(e) { var focusedElement = document.activeElement, index = allLnks.indexOf(focusedElement); if (index >= 0) { if (e.keyCode == 40 || e.keyCode == 39) { if (focusedElement.parentNode.nextElementSibling) { var nextNode = focusedElement.parentNode.nextElementSibling.firstElementChild; nextNode.focus(); } else { listItems[0].firstElementChild.focus(); } } if (e.keyCode == 38 || e.keyCode == 37) { if (focusedElement.parentNode.previousElementSibling) { var previousNode = focusedElement.parentNode.previousElementSibling.firstElementChild; previousNode.focus(); } else { locales.lastElementChild.firstElementChild.focus(); } } } }); أنشأنا دالةً لمعالجة الحدث keydown (الذي يُطلَق عندما يُضغَط على أحد الأزرار في لوحة المفاتيح) عندما يَحدُثُ داخل الكائن locales، لكننا نريد أن نُغيّر سلوك مفاتيح الأسهم إذا كان أحد عناصر القائمة مُركَّزًا عليه (focused)، وإلا فسنتحكّم بسلوك مفاتيح الأسهم من بداية تحمل الصفحة، وهذا ما سيمنع المستخدمين من التمرير في الصفحة باستخدامها. لفعل ذلك سنتحقق من العنصر المُركَّز عليه حاليًا (عبر document.activeElement) وسنرى إن كان يُطابِق أحد عناصر مصفوفة الروابط التي أنشأناها، فإن طابق أحدها فسنتحقق إن كان الزر المضغوط مساوٍ لرمز السهم السفلي أو الأيمن، فإن كان كذلك فسيتم التحقق من وجود عنصرٍ يلي العنصرَ الحالي، فإن وجد فسيتم نقل التركيز إلى العنصر التالي، وإلا فسيتم التركيز على أوّل عنصر في القائمة. الشيفرة الخاصة بتغيير سلوك السهم العلوي أو الأيسر مشابهة لما سبق، حيث سيُنقَل التركيز إلى العنصر الذي يسبق العنصر الحالي، وسيُنقَل التركيز إلى آخر رابط إن وصلنا إلى أعلى القائمة. الخلاصة إذا فكّرتَ قليلًا بالسكربت وخططت له، فيمكنك إنشاء شريط تنقل جميل وقابل للوصول، وذلك بتطبيق ما تعلمته هنا لكن مع بعض التحسينات. تأثير غروب الشمس باستخدام SVG (تجربة حية) الرسوميات التي تصوِّر الطبيعة مناسبةٌ جدًا لتأثيرات parallax، وعادةً تتحرك عناصر تلك الرسوميات شاقوليًا، وتستخدم عددًا هائلًا من صور PNG (التي لها شفافية) كطبقات. وخطر ببالي أنَّه يمكن توظيف رسومات SVG كبديل ممتاز لما سبق: حيث أنَّ حجم الصورة صغيرٌ جدًا، ويمكن إعادة تلوين عناصرها أو تحريكهم كلًا على حدة كما هو ظاهر في هذا المثال. بناء الهضبات مستوية السطح تتألف الصورة من سلسلة من الهضبات مستوية السطح التي هي مسارات مغلقة (closed paths)، باستثناء الشمس التي هي دائرة مُنشَأة بعنصر <circle>: <svg id="arizona" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 750 279"> <circle id="sun" fill="#FFF7EB" cx="655" cy="128" r="41.5"/> <path fill="hsl(32, 89%, 75%)" d="M750 ... "/> <path fill="hsl(31, 74%, 71%)" d="M745 ..." /> أنشأنا المسارات البعيدة أولًا، أي أنَّ أبعد هضبة ستُعرَّف في البداية، ثم تليها الأقرب فالأقرب. السماء والتدرجات بدلًا من إنشاء عنصر <rect> للسماء، فسيتم ملء خلفية عنصر <svg> باستخدام CSS: #arizona { background: hsl(47, 100%, 86%); } استخدام ألوان HSL (سواءً داخل شيفرات SVG أو عبر أنماط CSS) هو المفتاح الرئيسي لهذا التأثير، وذلك بتغير درجة السطوع (luminosity) لكل عنصر وذلك عند التمرير، وبذلك سنعطي انطباعًا بشروق أو غروب الشمس. الجزء الصعب هو استخراج قيمة HSL لكل عنصر، ولفعل ذلك سأستخدم التعابير النمطية (regular expressions) في JavaScript، هذه الشيفرة تُعرِّف التعبير النمطي الذي سنستخدمه مع جمع بعض المعلومات عن عنصر SVG: var regex = /hsl\((\d+),\s*([\d.]+)%,\s*([\d.]+)%\)/, arizona = document.getElementById("arizona"), mesaLayers = arizona.querySelectorAll("path"), SVGoffsettop = arizona.getBoundingClientRect().top, vertHeight = arizona.getBoundingClientRect().height, sun = document.getElementById("sun"); المتغير mesaLayers يضم جميع العناصر المُشكِّلة للهضبات معًا، وسيتم التعامل مع التمرير داخل دالة: function scrollHandler() { if (window.scrollY < vertHeight) { Array.prototype.forEach.call(mesaLayers, function(layer) { var layerFill = layer.getAttribute("fill"), vertRoll = Math.abs(window.scrollY - vertHeight) / vertHeight; hslComponents = layerFill.match(regex).slice(1), newLum = parseFloat(hslComponents[2]) * vertRoll; layer.style.fill = "hsl(" + hslComponents[0] +", " + hslComponents[1] + "%, " + newLum + "%)"; arizona.style.background = "hsl(48, " + 100 * vertRoll + "%, " + 88 * vertRoll + "%)"; sun.style.transform = "translate3d(0," + window.scrollY / 10 + "px, 0)"; }) } هذه الدالة تفعل ما يلي بالترتيب: الحصول على الخاصية fill لكل عنصر path تحديد مدى تمرير النافذة استخلاص قيمة HSL من كل عنصر path تعديل سطوع العنصر اعتمادًا على مقدار التمرير إعادة تجميع لون HSL لكل عنصر path الذي يضم السطوع الجديد، وتطبيقه على كل عنصر تعديل خاصية background لعنصر SVG، وأيضًا اعتمادًا على مقدار التمرير تمرير عنصر sun إلى الأسفل باستخدام translate3d لإنشاء تأثير الغروب ملاحظة: لا تعمل ميزة CSS transforms على عناصر SVG في متصفح Internet Explorer أو Edge بعد، على الرغم من أنَّ مفترض أن تدعم الإصدارات القادمة تلك الميزة. تُستدعى الدالة باستخدام requestAnimationFrame لتحسين الأداء: window.onscroll = function() { window.requestAnimationFrame(scrollHandler); } تبطيء التأثير قد تواجه إشكاليات عند ربط العناصر بالتمرير، فقد تتحول العناصر بسرعة كبيرة مما يجعلك تفقد شعورك بالتأثير… لذا فإنَّ أسهل طريقة لتبطيء التأثير هي استخدام مقياس للتمرير. غيّر الشيفرة السابقة لتصبح كما يلي: if (window.scrollY < SVGoffsettop * 4) { Array.prototype.forEach.call(mesaLayers, function(layer) { var layerFill = layer.getAttribute("fill"), vertRoll = Math.abs((window.scrollY / 4 ) - SVGoffsettop) / SVGoffsettop; … الخلاصة وأمور يمكن تحسينها عادةً يُستعمَل هذا التأثير بعد ضبط الخاصية position: fixed على عنصر SVG لإبقائه ظاهرًا أثناء تمرير الصفحة، إلا أنني لم أفعل ذلك هنا لأغراضٍ توضيحية. يمكن أيضًا دمج تأثير parallax معه عند التمرير، لكنني قررتُ أن أركِّز على تأثير غروب الشمس فقط. هنالك جانبان يمكن تطويرهما في السكربت: تكرار استخراج قيم ألوان HSL وتركيبها، فمن الأفضل جعل تلك القيم كخاصيات لكل عنصر لكي يتم الوصول إليها بسهولة عبر السكربت، بدلًا من إعادة حسابها كل مرة. ألوان خلفية السماء مكتوبة ضمن السكربت؛ ومن الأفضل إسناد الألوان باستخدام CSS، مما يجعل السكربت قادرًا على التعامل مع التغييرات في العرض دون الحاجة إلى تكرار التغييرات. إظهار فيديو في الخلفية (تجربة حية) نُشِرَت مقالة عن كيفية إنشاء فيديو في كامل خلفية الصفحة باستخدام HTML5 ، لكن أتت أسئلة على ذاك المقال للسؤال عن كيفية إنشاء فيديو يظهر خلف المحتوى، لكن يمكن تمريره كباقي محتويات الصفحة. فاجأني ذلك قليلًا، لأنَّ بالإمكان فعل ذلك باستخدام CSS مع نفس التقنيات التي نستعملها مع الصور… لكن أتتني الفرصة هنا لإعطاء مثال عن أنماط الاندماج (blend modes). الشيفرات تبدو شيفرة إضافة مقطع الفيديو تقليديةً، حيث سنضعها داخل وسم <main> (بدلًا من وضعها مباشرةً بعد العنصر <body> كما في المقالة الأصلية)، وسأفترض في هذا المثال أنَّ وسم video موجودٌ داخل العنصر <header> ضمن وسم <main>: <main> <header> <video autoplay loop> <source src="forest-fire.webm"> <source src="forest-fire.mp4"> </video> </header> ملاحظة: يجب أن يتبع الفيديو نفس القواعد العامة لمقاطع الفيديو التي تعمل في الخلفية الموجودة في المقالة الأصلية. يجب تنسيق الفيديو بأنماط CSS مماثلة لتلك التي كنتَ ستستعملها لعرض الصور المتجاوبة بكامل العرض: main { width: 80%; max-width: 750px; margin: 0 auto; } main > header video { width: 100%; height: auto; } ملاحظة: إذا أردتَ أن يظهر الفيديو بكامل عرض الشاشة، فبدِّل قيمة الخاصيتين width و max-width للعنصر main لتوسعته. يجب إضافة «طبقة» أمام مقطع الفيديو فيها ترويسة ورابط للانتقال إلى محتوى الصفحة. العناصر التالية يجب أن توضع بعد الوسم <video>: <h1>A world Aflame</h1> <a href="#maincontent">▼</a> </header> سيؤدي الضغط على الرابط إلى الانتقال إلى العنصر ذي المعرِّف maincontent. يجب أن نُعدِّل CSS الآن للسماح بإظهار العناصر الجديدة كطبقة تعلو مقطع الفيديو: main > header { position: relative; } أنماط CSS للترويسة <h1> وللرابط: main > header h1 { position: absolute; bottom: 40%; left: 1rem; font-size: 4rem; text-transform: uppercase; mix-blend-mode: overlay; } main > header a { display: block; text-decoration: none; font-size: 2rem; color: #fff; opacity: .5; position: absolute; bottom: 1.5rem; width: 100%; text-align: center; transition: .3s; animation: downwardprompt 2s 1s; } main > header a:hover { opacity: 1; } سيتم تطبيق تأثير حركي على السهم بعد عدِّة ثواني من تحميل الصفحة، مما يلفت انتباه المستخدم إليه: @keyframes downwardprompt { to { transform: translateY(2rem); opacity: 0; } } هذا كل ما في الأمر، بالطبع يمكنك القيام بالكثير باستخدام هذه التقنية، إلا أنَّ شيفرات CSS الأساسية ستبقى نفسها تقريبًا. صور متحركة بتأثير parallax باستخدام CSS 3D و JavaScript (تجربة حية) صحيحٌ أنَّ هنالك الكثير من الطرائق والتقنيات الموجودة على الويب لإنشاء تأثير parallax، لكنني أرى أنَّها تُزِّيف تأثير العمق في الصور، لكنني وجدتُ أنَّ تقنيةCSS 3D تسمح بتغيير مكان الصور على المحور z، مما يجعل تأثير تغيير المنظور حقيقيًا أثناء تحريك الصور إلى الأعلى وإلى الأسفل. وصحيحٌ أنَّ شيفرة هذا المثال ما تزال بدائيةً وبسيطةً، إلا أنَّني أرى أنها تستحق المشاركة. الشيفرات الأساسية هنالك شيفرة HTML بسيطة جدًا في هذا المثال، وهي عبارة عن عنصر <div> بسيط: <div id="parallax-container"> </div> سيُملأ هذا العنصر بالصور المُحمَّلة عبر شيفرة JavaScript، لكن علينا أولًا أن نضبط الأنماط اللازمة لعنصر <div> وللصور التي ستظهر داخله: #parallax-container { background: #16161d; margin: 0; overflow: hidden; perspective: 1200px; height: 100vh; width: 100vw; transform-style: preserve-3d; } #parallax-container img { transform-origin: center; box-shadow: 0 0 12px 12px rgba(0, 0, 0, 0.4); position: relative; } ملاحظة: إن لم تكن تألف التعامل مع واحدات vw و vh أو CSS 3D، فاقرأ المزيد عنها في هذه السلاسل. الصور المتحركة الخطوة التالية هي إضافة الصور، وتنسيقها باستخدام CSS، ثم جعل JavaScript تخفيها ثم تُجري عمليات عليها لتحقيق التأثير المطلوب. ولأنَّ أسماء ملفات الصور لها نفس النمط في هذا المثال (أي wave1.jpg و wave2.jpg …إلخ.) فيمكنني استخدام JavaScript لتوليد أسماء الملفات مع إنشاء بعض المتغيرات التي ستلزمنا لاحقًا في السكربت: var container = document.getElementById("parallax-container"), waveSrc = [], waves = [], imgLoc = "", j = 0; for (var i = 0; i < 10; i++) { waveSrc[i] = imgLoc+"wave"+(i+1)+".jpg"; } سنحتاج أيضًا إلى بعض الأرقام العشوائية، لذا سأولدها باستخدام هذه الدالة: function getRandomInRange(min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; } سنحتاج أيضًا إلى مرجع (reference) إلى الصور التي جرى تحميلها، بالإضافة إلى عرض وارتفاع الشاشة الحالي (بافتراض أنَّ نافذة المتصفح مُكبَّرَة). var screenWidth = window.screen.width, screenHeight = window.screen.height; وعند اكتمال تحميل الصور وإضافتها إلى عنصر <div>، فسنوفِّر لها خاصيات –وهي .xPlane و .yPlane و .zPlane– بقيمٍ عشوائية، والتي ستُحدِّد موضع الصورة في فضاءٍ ثلاثي الأبعاد. سأترك قيم الخاصية alt في هذا المثال فارغةً وذلك للاختصار: function preloadImage(filename){ var img=new Image(); img.onload = function(){ img.xPlane = getRandomInRange(-500, screenWidth - 500); img.yPlane = getRandomInRange(500, 1000); img.zPlane = getRandomInRange(300,2000); img.style = "transform: translate3d(" + img.xPlane +"px, " + img.yPlane + "px, -" + img.zPlane +"px)"; container.appendChild(img); }; imgLoc = ""; img.src= imgLoc + filename; img.alt = ""; waves[j] = img; j++; } function loadImages(){ for (var i = 0; i < waveSrc.length; ++i) { var filename = waveSrc[i]; preloadImage(filename); } } أخيرًا، ستُحرَّك الصور باستخدام دالة: function moveImages(){ waves.forEach(function(image) { image.yPlane = image.yPlane - 2; image.style.cssText = "transform: translate3d(" + image.xPlane+"px, " + image.yPlane+"px, -" + image.zPlane + "px); z-index: " + image.zIndex; }); window.requestAnimationFrame(moveImages); } وسيتم تشغيل المثال باستدعاء الدوال المناسبة في نهاية السكربت: loadImages(); window.addEventListener("load", function() { window.requestAnimationFrame(moveImages); }); تحسينات إضافية على المثال ما يزال هذا المثال مبدئيًا، وهنالك عدِّة أشياء يمكن إجراؤها لتطويره: 1. سيستمر تشغيل السكربت حتى بعد أن تختفي الصور من أعلى العنصر الحاوي لها، وستستمر بالحركة إلى اللانهاية؛ لذا من الأفضل أنَّ نُزيل الصور من بداية المصفوفة بعد اختفائها ثم إضافتها مرةً أخرى لتظهر مجددًا. 2. ربما من الأفضل أنَّ نُقلِّل من العشوائية في مواضع الصور، فالآن يمكن أن تظهر إحدى الصور خلف صورةٍ أخرى مباشرةً، أو قريبة منها كثيرًا في البُعد z (وبالتالي ستتحرك الصورتان بسرعةٍ قريبةٍ من بعضهما). ولفعل ذلك علينا أن نقارن أماكن الصور الجديدة بتلك التي أنشأناها من قبل في المصفوفة، وتوليد قيمة جديدة إن كانت القيمتان متقاربتين. 3. سيتم تحريك الصور تلقائيًا، إذا أردتَ أن تربط حركة الصور بتغيير شريط التمرير في الصفحة، فعليك أن تُغيّر موضع الصور بالنسبة إلى window.scrollY. ترجمة وبتصرّف للمقالات A Custom Scrolling Element With Keyboard Accessibility و Scrolling Background Video with Layered Content و A Scrolling SVG Sunset و Parallax Image Scrolling Animation with CSS 3D and JavaScript لصاحبها Dudley Storey
-
أهلًا بك في هذه السلسلة التي تتحدث عن تأثيرات التمرير (Scrolling Effects)، سنستعرض في هذه السلسلة عددٌ من تأثيرات التمرير وسنشرح آلية عملها وسنجرِّبها عمليًا. يمكننا الاستفادة من الحدث scroll في JavaScript لإجراء تأثيرات عند تمرير صفحة الويب؛ لكن إن فعلنا ذلك دون إتقان فالنتيجة كارثية، أما إذا أحسنا صنعنا فيمكن لتأثيرات التمرير أن تبهر الزوار وتشعرهم أنَّ موقعك مميز. تحدثنا في المقالة السابقة عن التأثيرات الآتية: إخفاء صورة خلفية تدريجيًا عند التمرير توضيح الصورة عند التمرير تدوير العناصر عند التمرير تأثير اختلاف المظهر parallax أما المقالة الحالية (الثانية) فهي تتضمن التأثيرات الآتية: إظهار صورة الخلفية عند التمرير باستخدام CSS فقط تمرير سلس للصفحة تطبيق تأثير عدم الوضوح على المحتوى خلف شريط الانتقال وسنشرح في آخر مقالة طريقة إنشاء: عنصر قابل للتمرير مع إمكانية وصول مخصصة من لوحة المفاتيح تأثير غروب الشمس باستخدام SVG إظهار فيديو في الخلفية صور متحركة بتأثير parallax باستخدام CSS 3D و JavaScript سأقدِّم لك في بداية كل قسم رابطًا لتجربة المثال تجربةً حيةً على المتصفح. سيسهل عليك كثيرًا أن تفهم الشرح والشيفرات بعد تجربتك للتأثير. إظهار صورة الخلفية عند التمرير باستخدام CSS فقط (تجربة حية) طريقة عرض جميلة وشائعة هي «إظهار صورة الخلفية عند التمرير»: فكلما مَرَّرنا إلى الأسفل، فستصبح صورة الخلفية المخفية ظاهرةً للمستخدم. صحيحٌ أنَّ طريقة العرض هذه أصبحت شائعة في الآونة الأخيرة، إلا أنَّها جيدة حيث تجعل المحتوى مركَّزًا ومختصرًا إلى بضع صور وفقرات قصيرة من النص. يُحقَّق هذا التأثير عادةً باستخدام إطار عمل من إطارات JavaScript مع إحدى الإضافات؛ وهذا غير ضروري أبدًا في المتصفحات الحديثة، وسأريك طريقة فعل ذلك. «النوافذ والجدران» الفكرة الأساسية لهذا التأثير هي إنشاء سلسلة من «النوافذ» المفتوحة و«الجدران» المغلقة فوق بعضها بعضًا، وكلٌ منها له نفس الطول والعرض الخاص بإطار العرض (viewport). لنبدأ بإنشاء شيفرة HTML بسيطة. يمكن إنشاء «النوافذ» و«الجدران» من أيّ عنصر HTML قادر على احتواء العناصر الأخرى؛ وسنستخدم في هذا المثال وسوم <section>: <section> <h1>Come To Iceland</h1> </section> <section> <h1>The last settled part of Europe, much of Iceland remains pristine and untouched.</h1> </section> … لجعل قياس جميع العناصر صحيحًا، فسأحذف أيّة هوامش (margin) من العنصر <body>، تأكد أنَّ العناصر <section> مُقاسة عبر border-box، وتأكد أنَّ لكل عنصرٍ منها له نفس ارتفاع إطار العرض باستخدام واحدات vm. يجب تنسيق النص ليستخدم نفس الواحدات السابقة: body { margin: 0; } section { box-sizing: border-box; height: 100vh; text-align: center; padding: 2vw; font-size: 6vw; } عناصر <section> تأخذ كامل عرض نافذة المتصفح، ولتوسيط محتواها فسنستعمل flexbox، ويجب إجراء المثل على عناصر <section> التي ستعرض صور الخلفية، لذا سأُضمِّن أنماطها أيضًا: section { display: flex; align-items: center; justify-content: center; text-align: center; flex-direction: column; background-size: cover; background-repeat: no-repeat; background-attachment: fixed; } تُستخدم الخاصية flex-direction لإغلاق أيّة «نوافذ» التي تحتوي عدِّة أسطر نصية. ويجب علينا إضافة نمط خاص بأوّل عنصر <section> لأنَّ النص فيه أكبر، ولونه أبيض، ومكتوبٌ بأحرفٍ كبيرة، مع استخدام الخاصية text-shadow لإضافة ظل لتميزه عن الخلفية: section:first-of-type { text-transform: uppercase; color: #fff; font-size: 8vw; text-shadow: 0 0 5px rgba(0,0,0,0.4); } عناصر <section> الزوجية لها خلفية بيضاء: section:nth-of-type(even) { background: #fff; } أما عناصر <section> الفردية فلها صور خلفية: section:nth-of-type(1) { background-image: url(iceland-fjords.jpg); } section:nth-of-type(3) { background-image: url(iceland-pool-faces.jpg); } section:nth-of-type(5) { background-image: url(iceland-ice.jpg); } وهذا كل ما في الأمر! صحيحٌ أنَّ المثال السابق يعمل على المتصفحات الحديثة فقط والتي تدعم vh و vm و flexbox؛ وإذا كنتَ تنوي دعم المتصفحات القديمة فعليك استخدام بدائل مثل نمط العرض table-row لكل عنصر <section> … تمرير سلس للصفحة (تجربة حية) تتواجد في HTML ميزة الانتقال إلى أماكن معيّن في الصفحة، وذلك بتوفير خاصية id للعنصر الذي تريد الانتقال إليه، ومن ثم ربط ذلك عبر عناصر <a>. لكن الحركة غير سلسة وستنتقل فوريًا إلى العنصر الهدف؛ ولكن بغرض تحسين طريقة عرض واستخدام الموقع، فيتطلّب أحيانًا تصميم الموقع أن يتم التمرير بشكلٍ سلسٍ أو بطيء إلى نقطةٍ معيّنةٍ في الصفحة. قديمًا كانت تُستعمَل jQuery لذلك، لكن من غير المعقول تحميل إطار عمل كامل لاستخدام هذه الميزة فقط؛ وتوفِّر JavaScript طريقةً أفضل وأسرع (من ناحية الأداء) وهي الدالة window.scrollTo. سنستخدم عنصر <a> كأساس لهذه التقنية، وبهذه الطريقة سيتم الانتقال إلى الهدف حتى لو لم تعمل شيفرة التمرير السلس لسببٍ من الأسباب. <a href="#destination">Click me: I’m <em>smoooooth</em>.</a> … <p id="destination">This is the target, further down the page. وكما هو واضح، يجب أن تكون الصفحة طويلةً بعض الشيء وتمتد إلى ما بعد أسفل إطار العرض لكي تعمل هذه التقنية، لأنَّه إذا عُرِضَت كامل محتويات الصفحة في نافذة المتصفح، فلا حاجة إلى التمرير من الأساس؛ ولهذا السبب عليك أن تضع الكثير من المحتوى في الصفحة للتجربة. طريقتان للتمرير بسلاسة قد يبدو الأمر مربكًا بعض الشيء، إلا أنَّ البنية البرمجية للتمرير السلس موجودة في CSS وفي JavaScript، وأنَّ بعض المتصفحات تدعم تلك البنية البرمجية والأخرى لا تدعمها (انظر فقرة «دعم المتصفحات» في الأسفل). ففي CSS إذا أردنا أنَّ يكون التمرير سلسًا لأحد العناصر (وعادةً ما نستخدم العنصر body لكن ذلك ليس ضروريًا) فعلينا أن نضبط الخاصية scroll-behavior ونسند القيمة smooth إليها: body { scroll-behavior: smooth; } لاحظ أنَّ كلمة «behavior» (في scroll-behavior) لا تحتوي على حرف «u». طريقة JavaScript سنضيف شيفرة JavaScript إلى نهاية الصفحة لكي تُنفَّذ بعد انتهاء تحميل الصفحة: var anchorLink = document.querySelector("a[href='#destination']"), target = document.getElementById("destination"); anchorLink.addEventListener("click", function(e) { if (window.scrollTo) { e.preventDefault(); window.scrollTo({"behavior": "smooth", "top": target.offsetTop}); } }) الدالة querySelector تستعمل نفس طريقة كتابة محدِّدات CSS للعثور على أوّل رابط الذي يشير إلى #destination؛ والضغط على هذا الرابط سيؤدي إلى تنفيذ عبارة شرطية للتأكد من دعم المتصفح للدالة scrollTo، فإن دعمها المتصفح فستوقف الدالة e.preventDefault المتصفحَ من الانتقال مباشرةً إلى الفقرة الهدف، وسنستخدم الدالة scrollTo بدلًا من ذلك بعد ضبطها ليكون التمرير سلسًا. تأخذ الدالة scrollTo وسيطين هما behavior و top، مع وسيطٍ اختياريٍ هوleft، ويقبل آخر وسطين إحداثيات المكان الذي نريد الانتقال إليه. يمكن استخدام الدالةwindow.scrollفي المثال السابق، لأنَّ وظيفتها مماثلة لوظيفة الدالةwindow.scrollTo`. مقارنةً مع استخدام إطار عمل، فإنَّ هذه الطريقة أبسط بكثير؛ لكن الجانب السلبي لها هو أنَّها لا تسمح للمصمم بتغيير دالة التوقيت أو حركات التمرير، لتجنّب استعمال المصممين استعمالًا سلبيًا لها. إنشاء سكربت عام السكربت السابق يعمل عمله بشكلٍ صحيح، لكنه يتطلب أن تعرف ما هو اسم العنصر الهدف، ولا يمكن تطبيقه إلا على رابطٍ وحيد. ماذا إذا أردت إنشاء سلسلة من الروابط التي تُشير إلى عناصر مختلفة؟ سنحتاج في هذه الحالة إلى جعل السكربت عامًا. سنبدأ السكربت بإنشاء دالة التي تسمح لنا بمعالجة كل رابط بحلقة forEach: var forEach = function (array, callback, scope) { for (var i = 0; i < array.length; i++) { callback.call(scope, i, array[i]); } }; ثم سأُحدِّد جميع الروابط، وأرى ما هو العنصر التي تشير إليه، ومن ثم سأطبِّق scrollTo عند النقر عليها: var anchorLinks = document.querySelectorAll("a[href^='#']"); if (window.scrollTo) { forEach(anchorLinks, function(index, element) { var target = document.getElementById(element.getAttribute("href").substring(1)); element.addEventListener("click", function(el) { el.preventDefault(); window.scrollTo(0, target.offsetTop); }) }); } لاحظ أنَّ هذا قد يتطلب وضع الخاصية scroll-behavior لعنصر body كما سبق ذكره. دعم المتصفحات هنالك إشكالية وحيدة عند استخدام هذه الطريقة في الوقت الراهن ألا وهي دعم المتصفحات؛ حيث تعمل الدالة window.scrollTo في متصفحات الويب الحديثة. ولأننا كتبنا السكربت بطريقة تجعله يتحقق أولًا من دعم المتصفح للدالة scrollTo، فستعمل الصفحة بشكل سليم على المتصفحات القديمة إلا أنَّ التمرير سيكون فوريًا وليس سلسًا؛ ويمكنك أن تستعمل إحدى الإضافات أو الطرائق الأخرى لدعم المتصفحات القديمة. تطبيق تأثير عدم الوضوح على المحتوى خلف شريط الانتقال (تجربة حية) أحد أنماط تصميم الواجهات الشائعة خصوصًا بعد إصدار نسخة iOS 7 هو شريط الانتقال الذي تظهر محتويات الصفحة التي خلفه مشوشةً؛ ربما تظن أنَّ تطبيق المُرشِّح blur في CSS هو الطريقة السهلة والواضحة لتطبيق هذا التأثير في صفحة ويب، وهذا صحيحٌ إلا أنَّ هنالك إشكالية: تأثيرات CSS ستُطبَّق على المحتوى داخل العنصر وليس خلفه. أي لا يوجد تأثير من تأثيرات CSS الذي يمكن أن يؤدي إلى تشويش العناصر خلفه، باستثناء خاصية اختبارية متوافرة في متصفح Safari 9 فقط باسم -webkit-backdrop-filter-؛ لكن بالطبع سنجد حلًا! إنشاء شريط الانتقال الشريط نفسه هو عنصرٌ فارغٌ يملك القيمة fixed للخاصية position، وعناصر التنقل تأتي «فوق» ذاك العنصر باستعمال نفس الأبعاد. سأكتبُ ذلك باستخدامSass لأنَّها أقصر: #blurrycontent { padding: 1rem; top: 0; left: 0; width: 100%; height: 5rem; overflow: hidden; position: fixed; filter: blur(4px); } nav { @extend #blurrycontent; filter: none; text-align: right; } يجب أن تتواجد بقية الصفحة داخل العنصر <main>، وليس داخل العنصر <body>، وذلك لأسبابٍ سنوضِّحها بعد لحظات: <main id="content"> <h1>London</h1> <p>With roots at least 7,000 years old, London is an accretion of artifacts old and new, from the remnants of wooden Neolithic settlements buried in the mud of the Thames to gleaming 21st century spires of glass and steel… </main> ولأنَّ العنصرين #blurrycontent و <nav> متموضعَين فوق بعضهما في مكانٍ ثابتٍ في أعلى الشاشة، فيجب تنسيق العنصر <main> لكي يأخذ مكان بقية المحتوى: main { margin: 0; background: url(london_background.jpg); background-size: cover; padding: 2rem; } حسنًا، تبدو الصفحة جيدةً، لكننا لم نرَ أيّة تأثيرات في منطقة شريط التنقل عندما يتم التمرير؛ وهذا ما سنفعله في الخطوة الآتية. إنشاء تأثير «الزجاج»! كما ذكرتُ في البداية، لا تُطبّق تأثيرات CSS إلا على المحتوى الموجود داخل العنصر، وليس تحته؛ لذا سنأخذ نسخةً من العنصر <main> ونضعها داخل العنصر #blurrycontent باستخدام الدالة cloneNode عبر سكربت موجود في أسفل الصفحة: var pageContent = document.getElementById("content"), pagecopy = pageContent.cloneNode(true), blurryContent = document.getElementById("blurrycontent"); blurryContent.appendChild(pagecopy); قد لا تستطيع ملاحظة التأثير في هذه المرحلة، لأنَّ المحتوى الموجود داخل العنصر #blurrycontent لن يُمرَّر مع بقية المستند، وعلينا مزامنة حركتهما بإضافة السطر الآتي إلى السكربت: window.onscroll = function() { blurryContent.scrollTop = window.pageYOffset; } بعد أن ربطناهما مع بعضهما بعضًا، فيمكننا أن نُمرِّر الصفحة وسنحصل على نفس المحتوى الموجود تحت شريط التنقل في عنصر #blurrycontent لكنه مشوش. ولأنَّ العنصر <nav> غير موجود داخل العنصر #blurrycontent فلن يخضع لتأثير عدم الوضوح. محدوديات هذه الطريقة كما هو واضح، إنشاء نسخة من محتوى الصفحة وتطبيق تأثير عدم الوضوح عليها سيؤدي إلى عبءٍ إضافيٍ على المتصفح وعلى المعالج الرسومي، لذا كن حذرًا في ذلك وقدِّر كمية المحتوى الموجود ضمن العنصر <main> قبل نسخه. الدالة cloneNode تنسخ العنصر نسخًا حيًا، أي أنَّ أيّة تعديلات على العنصر الأصلي ستُطبَّق أيضًا على العنصر المنسوخ، لكن ربما تلاحظ تأثيرًا بسيطًا حتى تتم مزامنة كلا النسختين. هذه أربع نقاط أخيرة يجب ملاحظتها: لأنَّ بعض إصدارات متصفح Internet Explorer لا تدعم تأثيرات CSS (وأوقف المتصفح دعم النسخة الخاصة به من هذا التأثير، والتي كانت متاحةً في الإصدارات القديمة منه)، فلن تلاحظ أيّة تغييرات في شريط التنقل في متصفح IE. يجب أن تتجنب استخدام العناصر ذات الموضع الثابت (fixed) في صفحات الويب على الهواتف الذكية والأجهزة اللوحية، فمنذ فترةٍ قريبةٍ كانت طريقة تعامل متصفحات الهواتف مع position: fixed سيئةً، وسيتم حجز مساحة من الشاشة الصغيرة. وصحيحٌ أنَّ هذا التأثير مستوحى من أحد أنظمة الهواتف، ألا أنَّه من الأفضل إيقافه في الشاشات الصغيرة باستخدام مجموعة من media queries (أو يمكنك أن تصمم الموقع للهواتف أولًا [mobile-first] ولا تُشغِّل التأثير حتى تصبح الشاشة بمقاسٍ معيّن). يجب أخذ قابلية الوصول (Accessibility) بعين الاعتبار عند إنشاء مثل هذا التأثير، فستُفسِّر قارئات الشاشة شجرة DOM، وليس ما تراه على الشاشة، وهذا يعني أنَّ قارئات الشاشة ستحصل على نسختين من محتوى الصفحة افتراضيًا، ولتنجب ذلك فسأضع aria-hidden="true" في العنصر #blurrycontent: <div id="blurrycontent" aria-hidden="true"></div> وبهذا سترى قارئات الشاشة النسخةَ الأصلية من الصفحة فقط دونًا عن النسخة الموجودة في العنصر #blurrycontent. يجب أن تكون حذرًا عند نسخ العناصر التي لها الخاصية id، فقد يؤدي تكرار قيم الخاصية id إلى تضاربات ومشاكل في CSS و JavaScript. ترجمة وبتصرّف للمقالات Background Reveal Scroll In Pure CSSو Smooth Page Scroll in 5 Lines of JavaScript و Scroll-Behind Blurred Site Navigation Barلصاحبها Dudley Storey
-
أداة mysqladmin هي أداةٌ سطريةٌ (أي تعمل من سطر الأوامر) تأتي مع خادوم MySQL ويستعملها مدراء قواعد البيانات لإجراء مهام أساسية لإدارة قواعد MySQL مثل ضبط كلمة مرور المستخدم root أو تغييرها، ومراقبة عمليات mysql وإعادة تحديث امتيازات المستخدمين والتحقق من حالة الخدمة …إلخ. سنضع في هذا الدرس بعض أوامر mysqladmin المفيدة والمُستعمَلة من مدراء النظام أو مدراء قواعد البيانات يوميًا. يجب أن يكون خادوم MySQL مثبتًا على نظامك لإجراء هذه المهام. إذا لم يكن خادوم MySQL مثبتًا على نظامك، أو كنتَ تستعمل إصدارًا قديمًا منه، فأنصحك بتثبيت أو تحديث نسختك كما ذكرنا في هذه المقالة. 1. كيفية ضبط كلمة مرور المستخدم root في MySQL؟ إذا كانت لديك نسخةٌ حديثةُ التثبيت من خادوم MySQL، فلن تحتاج إلى استخدام كلمة مرور للاتصال بها عبر المستخدم root، لكن ذلك ليس آمنًا، وأنصحك بضبط كلمة مرور له، وذلك بتنفيذ الأمر الآتي: # mysqladmin -u root password YOURNEWPASSWORD 2. كيفية تغيير كلمة مرور المستخدم root؟ إذا أردتَ تحديث أو تغيير كلمة مرور المستخدم root في قواعد بيانات MySQL، فيمكنك الاستعانة بالأمر الآتي. لنفترض مثلًا أنَّ كلمة مرورك القديمة هي 123456 وأردتَ الآن تغييرها إلى كلمةٍ أخرى ولتكن xyz123: # mysqladmin -u root -p123456 password 'xyz123' 3. كيفية التحقق إذا كان خادوم MySQL يعمل؟ استعمل الأمر الآتي لتعرف إن كان خادوم MySQL يعمل أم لا: # mysqladmin -u root -p ping Enter password: mysqld is alive 4. كيف أعرف إصدار MySQL الذي أعمل عليه؟ الأمر الآتي سيُظهِر إصدار MySQL المُثبَّت على خادومك، إضافةً إلى حالته: # mysqladmin -u root -p version Enter password: mysqladmin Ver 8.42 Distrib 5.5.28, for Linux on i686 Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Server version 5.5.28 Protocol version 10 Connection Localhost via UNIX socket UNIX socket /var/lib/mysql/mysql.sock Uptime: 7 days 14 min 45 sec Threads: 2 Questions: 36002 Slow queries: 0 Opens: 15 Flush tables: 1 Open tables: 8 Queries per second avg: 0.059 5. كيف أعرف ما هي حالة خادوم MySQL الآن؟ يمكن أن يُظهِر الأمر mysqladmin حالة uptime بالإضافة إلى عدد الخيوط (threads) وإحصائيات عن الاستعلامات: # mysqladmin -u root -ptmppassword status Enter password: Uptime: 606704 Threads: 2 Questions: 36003 Slow queries: 0 Opens: 15 Flush tables: 1 Open tables: 8 Queries per second avg: 0.059 6. كيفية التحقق من حالة جميع متغيرات خادوم MySQL وقيمها؟ استخدم الخيار extended-status لأمر mysqladmin لرؤية حالة جميع متغيرات خادوم MySQL والقيم المرتبطة بها. يجب أن تكون المخرجات شبيهةً بما يلي: # mysqladmin -u root -p extended-status Enter password: +------------------------------------------+-------------+ | Variable_name | Value | +------------------------------------------+-------------+ | Aborted_clients | 3 | | Aborted_connects | 3 | | Binlog_cache_disk_use | 0 | | Binlog_cache_use | 0 | | Binlog_stmt_cache_disk_use | 0 | | Binlog_stmt_cache_use | 0 | | Bytes_received | 6400357 | | Bytes_sent | 2610105 | | Com_admin_commands | 3 | | Com_assign_to_keycache | 0 | | Com_alter_db | 0 | | Com_alter_db_upgrade | 0 | | Com_alter_event | 0 | | Com_alter_function | 0 | | Com_alter_procedure | 0 | | Com_alter_server | 0 | | Com_alter_table | 0 | | Com_alter_tablespace | 0 | +------------------------------------------+-------------+ 7. كيفية معرفة قيم جميع المتغيرات المُفعّلة لخادوم MySQL؟ لرؤية جميع القيم التي تعمل حاليًا في خادوم MySQL، أدخِل الأمر الآتي: # mysqladmin -u root -p variables Enter password: +---------------------------------------------------+----------------------------------------------+ | Variable_name | Value | +---------------------------------------------------+----------------------------------------------+ | auto_increment_increment | 1 | | auto_increment_offset | 1 | | autocommit | ON | | automatic_sp_privileges | ON | | back_log | 50 | | basedir | /usr | | big_tables | OFF | | binlog_cache_size | 32768 | | binlog_direct_non_transactional_updates | OFF | | binlog_format | STATEMENT | | binlog_stmt_cache_size | 32768 | | bulk_insert_buffer_size | 8388608 | | character_set_client | latin1 | | character_set_connection | latin1 | | character_set_database | latin1 | | character_set_filesystem | binary | | character_set_results | latin1 | | character_set_server | latin1 | | character_set_system | utf8 | | character_sets_dir | /usr/share/mysql/charsets/ | | collation_connection | latin1_swedish_ci | +---------------------------------------------------+----------------------------------------------+ 8. كيفية التحقق من جميع العمليات التي يستخدمها خادوم MySQL؟ الأمر الآتي سيعرض جميع العمليات التي تستعملها استعلامات قواعد بيانات MySQL: # mysqladmin -u root -p processlist Enter password: +-------+---------+-----------------+---------+---------+------+-------+------------------+ | Id | User | Host | db | Command | Time | State | Info | +-------+---------+-----------------+---------+---------+------+-------+------------------+ | 18001 | rsyslog | localhost:38307 | rsyslog | Sleep | 5590 | | | | 18020 | root | localhost | | Query | 0 | | show processlist | +-------+---------+-----------------+---------+---------+------+-------+------------------+ 9. كيفية إنشاء قاعدة بيانات على خادوم MySQL؟ استخدم الأمر الآتي لإنشاء قاعدة بيانات جديدة في MySQL: # mysqladmin -u root -p create databasename Enter password: للتحقق من إنشائها: # mysql -u root -p Enter password: Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 18027 Server version: 5.5.28 MySQL Community Server (GPL) by Remi Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | databasename | | mysql | | test | +--------------------+ 8 rows in set (0.01 sec) mysql> 10. كيفية حذف قاعدة بيانات في خادوم MySQL؟ لحذف قاعدة بيانات في خادوم MySQL، فأدخِل الأمر الآتي. سيُطلَب منك الموافقة على ذلك بكتابة الحرف y: # mysqladmin -u root -p drop databasename Enter password: Dropping the database is potentially a very bad thing to do. Any data stored in the database will be destroyed. Do you really want to drop the 'databasename' database [y/N] y Database "databasename" dropped 11. كيفية إعادة تحميل أو إعادة تحديث الامتيازات في MySQL؟ الأمر reload سيطلب من الخادوم إعادة تحميل جداول الامتيازات، بينما الأمر refresh سيؤدي إلى إعادة قراءة جميع الجداول وإعادة فتح ملفات التسجيل (log files): # mysqladmin -u root -p reload; # mysqladmin -u root -p refresh 12. كيفية إيقاف خادوم MySQL بأمان؟ لإيقاف خادوم MySQL إيقافًا آمنًا، فاكتب الأمر الآتي: mysqladmin -u root -p shutdown Enter password: أو يمكنك استخدام الأمرين الآتيين لتشغيل أو إيقاف خادوم MySQL: # /etc/init.d/mysqld stop # /etc/init.d/mysqld start 13. بعض أوامر «التنظيف» هذه بعض أوامر التنظيف (flush) مع شرحٍ لها: flush-hosts: حذف جميع معلومات المُضيف من التخزين المؤقت. flush-tables: «تنظيف» جميع الجداول. flush-threads: تنظيف التخزين المؤقت للخيوط (threads). flush-logs: تنظيف السجلات. flush-privileges: إعادة تحميل جداول الامتيازات (مثل reload). flush-status: مسح متغيرات الحالة (status variables). # mysqladmin -u root -p flush-hosts # mysqladmin -u root -p flush-tables # mysqladmin -u root -p flush-threads # mysqladmin -u root -p flush-logs # mysqladmin -u root -p flush-privileges # mysqladmin -u root -p flush-status 14. كيفية «قتل» عمليات عملاء MySQL المتوقفة؟ يمكنك استخدام الأمر الآتي للتعرف على عمليات عملاء MySQL المتوقفة (sleeping): # mysqladmin -u root -p processlist Enter password: +----+------+-----------+----+---------+------+-------+------------------+ | Id | User | Host | db | Command | Time | State | Info | +----+------+-----------+----+---------+------+-------+------------------+ | 5 | root | localhost | | Sleep | 14 | | | | 8 | root | localhost | | Query | 0 | | show processlist | +----+------+-----------+----+---------+------+-------+------------------+ يمكنك الآن تشغيل الأمر الآتي مع استخدام الخيار kill متبوعًا برقم العملية كما يلي: # mysqladmin -u root -p kill 5 Enter password: +----+------+-----------+----+---------+------+-------+------------------+ | Id | User | Host | db | Command | Time | State | Info | +----+------+-----------+----+---------+------+-------+------------------+ | 12 | root | localhost | | Query | 0 | | show processlist | +----+------+-----------+----+---------+------+-------+------------------+ أما إذا أردت «قتل» (اصطلاح «قتل» [kill] في يونكس يعني إيقاف العملية قسريًا) أكثر من عملية معًا، فافصل بين أرقام العمليات بفاصلة كما في المثال الآتي: # mysqladmin -u root -p kill 5,10 15. كيفية تشغيل أكثر من أمر لأداة mysqladmin معًا؟ إذا أردت تشغيل أكثر من أمر mysqladmin معًا فيمكنك فعل ذلك بذكرها بعضها تلو بعض كالآتي: # mysqladmin -u root -p processlist status version Enter password: +----+------+-----------+----+---------+------+-------+------------------+ | Id | User | Host | db | Command | Time | State | Info | +----+------+-----------+----+---------+------+-------+------------------+ | 8 | root | localhost | | Query | 0 | | show processlist | +----+------+-----------+----+---------+------+-------+------------------+ Uptime: 3801 Threads: 1 Questions: 15 Slow queries: 0 Opens: 15 Flush tables: 1 Open tables: 8 Queries per second avg: 0.003 mysqladmin Ver 8.42 Distrib 5.5.28, for Linux on i686 Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Server version 5.5.28 Protocol version 10 Connection Localhost via UNIX socket UNIX socket /var/lib/mysql/mysql.sock Uptime: 1 hour 3 min 21 sec Threads: 1 Questions: 15 Slow queries: 0 Opens: 15 Flush tables: 1 Open tables: 8 Queries per second avg: 0.003 16. كيفية الاتصال بخادوم MySQL بعيد للاتصال بخادوم MySQL بعيد فاستخدام الخيار -h (أي host، ويعني المضيف) وبعده عنوان IP للخادوم البعيد: # mysqladmin -h 172.16.25.126 -u root -p 17. كيفية تنفيذ أمر على خادوم MySQL بعيد لنقل أنك تريد معرفة حالة (status) خادوم MySQL بعيد، فسيكون الأمر حينئذٍ كالآتي: # mysqladmin -h 172.16.25.126 -u root -p status 18. تشغيل وإيقاف استنساخ MySQL على خادوم ثانوي استخدم الأمرين الآتيين لتشغيل أو إيقاف استنساخ MySQL (أي MySQL replication): # mysqladmin -u root -p start-slave # mysqladmin -u root -p stop-slave 19. كيفية تخزين معلومات التنقيح في MySQL إلى السجلات معلومات التنقيح هي المعلومات التي تخبرنا ما هو استخدام الذاكرة ومعلومات متفرقة عن الاستعلامات، ويمكننا كتابتها إلى ملف سجل MySQL باستخدام الأمر الآتي: # mysqladmin -u root -p debug Enter password: 20. كيفية رؤية الخيارات المتاحة للاستخدام في mysqladmin لمعرفة المزيد من خيارات الأمر mysqladmin وطريقة استخدامه، فاطلع على المساعدة التي تظهر بكتابة الأمر الآتي، والذي سيعرض قائمة بالخيارات المتوافرة: # mysqladmin --help حاولتُ قدر المستطاع أن أُضمِّن أغلبية أوامر mysqladmin مع أمثلةٍ عنها في هذا الدرس، لكن لا مانع من محاولة استكشاف غيرها، وربما تشاركنا بها في التعليقات. ترجمة -وبتصرّف- للمقال 20 MySQL (Mysqladmin) Commands for Database Administration in Linux لصاحبه Ravi Saive
-
تمهيد يمكن أن يكون تحضير قرصٍ جديدٍ للاستخدام في نظام لينكس سهلًا وسريعًا، حيث هنالك الكثير من الأدوات، وصيغ أنظمة الملفات، ومخططات التقسيم التي يمكن أن تُعقِّد العملية إذا كانت لديك احتياجيات خاصة، لكن إن أردتَ أن تُشغِّل جهاز التخزين بسرعة، فالأمر سهلٌ جدًا. سنشرح في هذا الدرس العمليات الآتية: التعرف على قرصٍ جديدٍ في النظام. إنشاء قسمٍ وحيدٍ الذي يمتد على كامل القرص (تتوقع أغلبية أنظمة التشغيل وجود جدول أقسام، حتى لو كان هنالك نظام ملفاتٍ وحيدٍ في القرص). تهيئة القسم بنظام ملفات Ext4 (نظام الملفات الافتراضي في أغلبية توزيعات لينكس). وصل وضبط الوصل التلقائي لنظام الملفات عند الإقلاع. تثبيت الأدوات علينا استخدام الأداة parted لتقسيم القرص، وقد تكون مثبتةً على الخادوم في أغلبية الحالات. إذا كنتَ على خادوم أوبنتو أو دبيان ولم تكن الأداة parted مثبتةً بعد، فيمكنك تثبيتها بكتابة ما يلي في سطر الأوامر: sudo apt-get update sudo apt-get install parted أما إذا كنتَ على خادوم CentOS أو فيدورا، فيمكنك تثبيتها بكتابة: sudo yum install parted التعرف على القرص الجديد في النظام قبل أن نضبط القرص، فيجب أن نتمكن من التعرف عليه بشكلٍ صحيحٍ في الخادوم. إذا كان القرص جديدًا كليًّا، فأسهل طريقة للتعرف عليه في الخادوم هي معرفة إن كان جدول التقسيمات موجودًا. فإذا طلبنا من parted أن يعرض مخطط الأقسام لجميع أقراصنا، فسيعطينا رسالة خطأ لأيّة أقراص لا تملك مخطط أقسام صحيح. يمكننا أن نستعمل هذه المعلومة لمساعدتنا على التعرف على القرص الجديد: sudo parted -l | grep Error يجب أن ترى رسالة الخطأ unrecognized disk label للأقراص الجديدة غير المُقسَّمة: Error: /dev/sda: unrecognised disk label يمكنك أيضًا استخدام الأمر lsblk والبحث عن القرص الذي له المساحة التخزينية الصحيحة وليس له أيّة أقسام تابعة له: lsblk الناتج: NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT sda 8:0 0 100G 0 disk vda 253:0 0 20G 0 disk └─vda1 253:1 0 20G 0 part / تحذير: تذكر أنَّ عليك التحقق من ناتج lsblk في كل مرة قبل إجراء التغييرات. فمُعرِّفات الأقراص /dev/sd* و /dev/hd* قد لا تشير إلى نفس القرص بعد إعادة الإقلاع، وهذا يعني أنَّك قد تخاطر بتقسيم أو تهيئة القرص الخاطئ إن لم تتحقق من مُعرِّف القرص قبل ذلك. حاول استخدام مُعرِّفات الأقراص الثابتة مثل /dev/disk/by-uuid أو /dev/disk/by-label أو /dev/disk/by-id. راجع مقالة «مدخل إلى مُصطلحات ومفاهيم التخزين في لينكس» لمزيد من التفاصيل. بعد أن تعلم ما هو الاسم الذي أسندته النواة إلى قرصك، فيمكنك البدء بتقسيمه. تقسيم القرص الجديد كما ذكرنا في التمهيد، سننشِئ قسمًا وحيدًا يمتد على كامل القرص. اختيار أحد معايير التقسيم علينا أولًا تحديد ما هو معيار التقسيم الذي نود استخدامه، إذ أنَّ GPT هو معيار تقسيم حديث، بينما MBR له دعمٌ واسعٌ في أنظمة التشغيل. إن لم تكن عندك متطلباتٌ خاصة، فمن الأفضل أن تختار GPT. نفِّذ الأمر الآتي على القرص الذي تريد تقسيمه لاختيار GPT: sudo parted /dev/sda mklabel gpt أما إذا أردتَ استخدام MBR، فنفِّذ الأمر الآتي بدلًا من الأمر السابق: sudo parted /dev/sda mklabel msdos إنشاء قسم جديد بعد اختيار صيغة جدول الأقسام، فحان الآن الوقت لإنشاء قسم يمتد على كامل القرص بكتابة الأمر الآتي: sudo parted -a opt /dev/sda mkpart primary ext4 0% 100% إذا نفَّذنا الأمر lsblk الآن، فسنشاهد القسم الجديد مذكورًا في القائمة: NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT sda 8:0 0 100G 0 disk └─sda1 8:1 0 100G 0 part vda 253:0 0 20G 0 disk └─vda1 253:1 0 20G 0 part / إنشاء نظام ملفات على القسم الجديد أصبح لدينا الآن قسمٌ جديدٌ متاحٌ للاستخدام، لذا علينا الآن تهيئته بنظام ملفات Ext4؛ وذلك بتمرير مسار القسم إلى الأداة mkfs.ext4. يمكننا إضافة لافتة (label) للقسم باستخدام الخيار -L. سيساعدك اختيار اسمٍ واضحٍ على التعرف على القسم بسهولة وسرعة. ملاحظة: من المهم أنَّ تمرِّر اسم القسم وليس كامل القرص. تذكّر أنَّ أسماء الأقراص في لينُكس تشبه sda و sdb و hda …إلخ. أما الأقسام على تلك الأقراص فلها رقمٌ ملحقٌ بآخر اسمها، أي أنَّ عليك استخدام اسمٍ يشبه sda1 وليس sda. sudo mkfs.ext4 -L datapartition /dev/sda1 إذا أردتَ أن تُغيّر لافتة القسم بعد إنشائه، فاستعمل حينها الأمر e2label كما يلي: sudo e2label /dev/sda1 newlabel يمكننا إظهار جميع الطرائق التي يمكنك التعرف فيها على القسم باستخدام lsblk؛ حيث نريد أن نعرض الاسم ,واللُصيقة ومُعرِّف UUID التابعين للقسم. بعض إصدارات lsblk تُظهِر جميع تلك المعلومات إذا كتبنا: sudo lsblk --fs إذا لم تُظهِر النسخة الموجودة عندك كل الحقول اللازمة، فيمكنك طلب إظهارها يدويًا: sudo lsblk -o NAME,FSTYPE,LABEL,UUID,MOUNTPOINT يجب أن يظهر لك ناتجٌ شبيهٌ بالناتج الآتي، وكلُّ سطرٍ فيه يضمُّ الطرائق المختلفة التي يمكنك استعمالها للإشارة إلى نظام الملفات الجديد: NAME FSTYPE LABEL UUID MOUNTPOINT sda └─sda1 ext4 datapartition 4b313333-a7b5-48c1-a957-d77d637e4fda vda └─vda1 ext4 DOROOT 050e1e34-39e6-4072-a03e-ae0bf90ba13a / وصل نظام الملفات الجديد يمكنك الآن وصل نظام الملفات لكي تستعمله. ينصح معيار هيكلة نظام الملفات باستخدام /mnt أو مجلدٍ فرعيٍ داخله لوصل أنظمة الملفات مؤقتًا. إذا كان وصلك للأقراص مؤقتًا فهذا أفضل مكانٍ لوصلها؛ لكن المعيار لم يُقدِّم أيّة اقتراحات لمكان وصل وسائط التخزين الدائمة، لذا يمكنك وصلها أينما تشاء؛ سنصل القسم في هذا الدرس داخل المجلد /mnt/data. أنشِئ المجلد باستخدام الأمر: sudo mkdir -p /mnt/data وصل نظام الملفات مؤقتًا إذا أردتَ وصل نظام الملفات مؤقتًا، فنفِّذ الأمر الآتي: sudo mount -o defaults /dev/sda1 /mnt/data وصل نظام الملفات تلقائيًا عند الإقلاع إذا أردتَ أن تصل نظام الملفات تلقائيًا في كل مرة يُقلِع فيها الخادوم، فعدِّل ملف /etc/fstab بمحرِّرك النصي المفضَّل: sudo nano /etc/fstab نفَّذنا سابقًا الأمر sudo lsblk --fs لعرض ثلاثة مُعرِّفات لنظام الملفات الذي أنشأناه؛ يمكننا استخدام أي منها في ملف fstab؛ وسنستعمل في مثالنا هذا طريقة «اللُصيقة» (label)، لكنك تستطيع أن ترى كيف تبدو الأسطر التي تستعمل الطرائق الأخرى مذكورةً في التعليقات: . . . ## Use one of the identifiers you found to reference the correct partition # /dev/sda1 /mnt/data ext4 defaults 0 2 # UUID=4b313333-a7b5-48c1-a957-d77d637e4fda /mnt/data ext4 defaults 0 2 LABEL=datapartition /mnt/data ext4 defaults 0 2 ملاحظة: يمكنك تعلم المزيد عن مختلف الحقول في ملف /etc/fstab في صفحة الدليل man fstab، لمعلوماتٍ إضافيةٍ عن خيارات الوصل المتوفرة لنظام ملفات معيّن فراجع صفحة الدليل man [filesystem] (أي مثلًا man ext4). لكن الأسطر الموجودة في المثال السابق تكفيك مبدئيًا. يُضاف الخيار discard في بعض الأحيان لأقراص SSD لتفعيل «TRIM» بشكلٍ مستمر، وهنالك جدالٌ قائمٌ عن تأثير ذلك على الأداء؛ وأغلبية التوزيعات تتضمن طريقةً لإجراء TRIM كل فترة كبديلٍ عن تشغيله بشكلٍ مستمر. احفظ الملف الآن بعد أن تنتهي من تعديله. إذا لم تصل نظام الملفات من قبل، فيمكنك وصله الآن بكتابة: sudo mount -a اختبار نظام الملفات الموصول بعد أن وصلنا القسم، فعلينا أن نتأكد من أنَّنا قادرون على الوصول إلى نظام الملفات. يمكننا التحقق إن كان القرص متاحًا بالنظر إلى ناتج الأمر df: df -h -x tmpfs -x devtmpfs Filesystem Size Used Avail Use% Mounted on /dev/vda1 20G 1.3G 18G 7% / /dev/sda1 99G 60M 94G 1% /mnt/data يجب أن تشاهد المجلد lost+found داخل المجلد /mnt/data، والذي يُشير عادةً إلى جذر أنظمة ملفات Ext*: ls -l /mnt/data total 16 drwx------ 2 root root 16384 Jun 6 11:10 lost+found يمكننا أيضًا التحقق من أنَّ نظام الملفات موصولٌ مع القدرة على القراءة والكتابة إليه بالكتابة إلى ملفٍ اختباري: echo "success" | sudo tee /mnt/data/test_file اقرأ الملف من القرص للتأكّد من القدرة على قراءة الملفات: cat /mnt/data/test_file success يمكنك حذف الملف بعد التحقق من أنَّ نظام الملفات الجديد يعمل عملًا سليمًا: sudo rm /mnt/data/test_file الخلاصة يجب أن يكون قرصك الآن مُقسَّمًا ومُهيّئًا وموصولًا وجاهزًا للاستخدام؛ وما شرحناه في هذا الدرس يُمثِّل الخطوط الأساسية لكيفية تحويل قرص خام إلى نظام ملفات يمكن للينكس أن يستعمله للتخزين. هنالك طرائق أخرى أكثر تعقيدًا للتقسيم والتهيئة والوصول والتي قد تستفيد منها في بعض الحالة، لكن ما سبق كافٍ كنقطة انطلاق لكيفية إعداد قرص للاستخدام الاعتيادي. ترجمة -وبتصرّف- للمقال How To Partition and Format Storage Devices in Linux لصاحبه Justin Ellingwoo
-
قاعدة البيانات هي بُنيةٌ هيكليةٌ تحتوي على مجموعة من البيانات المُخزَّنة إلكترونيًا؛ وكان مفهوم قواعد البيانات معروفًا لدى أسلافنا قبل وجود الحواسيب، لكن إنشاء وصيانة تلك القواعد كان أمرًا شاقًا ومملًا. فلنقل أنَّ لدينا قاعدة بيانات فيها 100 صفحة، وأردتَ أن تبحث عن جميع الموظفين الذين يتقاضون أقل من 50 ألف دولار سنويًا، فتخيّل مدى صعوبة الأمر ومقدار الوقت الذي سيستغرقه في ذاك الحين. أما حاليًا، فأنت تصادف قواعد البيانات في كل مكان، إذ تعمل ملايين قواعد البيانات في أنحاء العالم لتخزين والحصول على أي نوع من أنواع البيانات كالبيانات العسكرية وسجلات الموظفين أو حتى مواقع الويب وتقنياتها. تُصنّف قواعد البيانات عمومًا على أنها جزءٌ من «السند الخلفي» (back-end)، وذلك لعدم ظهورها للمستخدم النهائي ولعدم تعامل المستخدم معها مباشرةً. إذ تعمل قواعد البيانات مع لغةٍ برمجيةٍ مثل PHP أو VB أو ASP.NET وتطلب تلك اللغات من قواعد البيانات إجراء عملية ما. تتوافر عدِّة خواديم قواعد بيانات وعملاءٍ لها مثل Oracle و MySQL و MySQLi و MariaDB و MongoDB …إلخ. تتشابه طريقة التعامل مع هذه البيانات، والبنية اللغوية لأوامرها شبه متماثلة، واحتراف التعامل مع إحداها يعني أنَّك ستستطيع التحكم بأريحية مع البقية، وعملية تعلم كتابة الاستعلامات (queries) هي عملية سهلة وممتعة. لنبدأ ببعض الاستعلامات البسيطة على قواعد البيانات؛ وسنستخدم قواعد MySQL التي تأتي مع أغلبية توزيعات لينُكس افتراضيًا، وتستطيع بسهولة تثبيتها من مستودعات توزيعتك إن لم تكن مثبتةً لديك. لكن ربما ينتابك فضولٌ حول معنى «استعلام» (Query)، فبأبسط الكلمات: هي شيفرةٌ بسيطةٌ (أو أمر) تُرسَل إلى قواعد البيانات للحصول على النتيجة المطلوبة. تثبيت قواعد بيانات MySQL يمكنك استخدام مديرَي الحزم yum أو apt لتثبيت قواعد بيانات MySQL: # yum install mysql mysql-client mysql-server (on Yum based Systems) # apt-get install mysql mysql-client mysql-server (on Apt based Systems) تشغيل خادوم MySQL تستطيع تشغيل خدمة MySQL كالآتي: # service mysqld start أو: # service mysql start أذكِّرك أنَّ رمز # في بداية السطر يعني أنَّ عليك تنفيذ الأمر بامتيازات الجذر. سيُطلَب منك أثناء تثبيت قاعدة بيانات MySQL إعداد كلمة مرور لحساب المدير فيها… بعدئذٍ ستتمكن من الوصول إلى مِحَث (prompt، أي المكان الذي تكتب فيه الأوامر) MySQL بتنفيذك للأمر الآتي: # mysql -u root -p ضع اسم المستخدم الذي ضبطته بدلًا من root، وأدخِل كلمة مرورك عند طلبها، فإذا كانت معلومات الدخول صحيحةً، فيمكنك أن تشاهد مِحَث MySQL مباشرةً: Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 195 Server version: 5.5.31-0+wheezy1 (Debian) Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. Mysql> تستطيع الآن البدء بتنفيذ الاستعلامات وتعلم إنشاء الاستعلامات. إنشاء قاعدة بيانات سنُنشِئ الآن قاعدة بيانات باسم tecmint كالتّالي: mysql> create database tecmint ; Query OK, 1 row affected (0.02 sec) mysql> ظهر عندنا أنَّ الاستعلام السابق قد نُفِّذَ تنفيذًا سليمًا، وهذا يعني أنَّ قاعدة البيانات قد أُنشِئَت. يمكنك التحقق من وجود قاعدة البيانات الجديدة بتنفيذ الاستعلام الآتي: mysql> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | tecmint | | test | +--------------------+ 9 rows in set (0.00 sec) mysql> لاحظ وجود قاعدة البيانات في مخرجات الاستعلام أعلاه. اختيار قاعدة البيانات علينا قبل إجراء الاستعلامات على إحدى قواعد البيانات أن نختارها، وذلك باستخدام التعليمة use كما يلي: mysql> use tecmint; Database changed mysql> إنشاء الجداول في MySQL لنقل أننا نريد إنشاء جدول باسم minttec في قاعدة البيانات وفيه ثلاثة حقول: mysql> CREATE TABLE minttec ( -> id Int(3), -> first_name Varchar (15), -> email Varchar(20) -> ); Query OK, 0 rows affected (0.08 sec) mysql> لاحظ أنَّ الاستعلام السابق قد أعاد OK مما يعني أنَّ الجدول قد أُنشِئ دون أخطاء. نفِّذ الاستعلام الآتي للتحقق من إنشاء الجدول: mysql> show tables; +-------------------+ | Tables_in_tecmint | +-------------------+ | minttec | +-------------------+ 1 row in set (0.00 sec) mysql> جيد، كل شيء يسير كما ينبغي. يمكننا أن نُطالِع الأعمدة التي أنشأتها في جدول minttec كما يلي: mysql> show columns from minttec; +------------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +------------+-------------+------+-----+---------+-------+ | id | int(3) | YES | | NULL | | | first_name | varchar(15) | YES | | NULL | | | email | varchar(20) | YES | | NULL | | +------------+-------------+------+-----+---------+-------+ 3 rows in set (0.00 sec) mysql> سأخبرك الآن عن أنواع البيانات الموجودة في الجدول السابق ومعانيها: - int: عدد صحيح. - varchar: سلسلة من المحارف التي لا يتجاوز طولها الرقم المُعرَّف. القيمة الرقمية التي تأتي بعد النوع هي «طول» الحقل الذي ستُخزَّن فيه البيانات. لنقل الآن أننا نريد إضافة عمود جديد باسم last_name بعد العمود first_name سنقوم بذلك على النّحو التّالي: mysql> ALTER TABLE minttec ADD last_name varchar (20) AFTER first_name; Query OK, 0 rows affected (0.16 sec) Records: 0 Duplicates: 0 Warnings: 0 ثم سنتحقق من أعمدة الجدول: mysql> show cسolumns from minttec; +------------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +------------+-------------+------+-----+---------+-------+ | id | int(3) | YES | | NULL | | | first_name | varchar(15) | YES | | NULL | | | last_name | varchar(20) | YES | | NULL | | | email | varchar(20) | YES | | NULL | | +------------+-------------+------+-----+---------+-------+ 4 rows in set (0.00 sec) mysql> إضافة أعمدة في MySQL سنضيف الآن عمودًا باسم country بعد العمود email كالتّالي: mysql> ALTER TABLE minttec ADD country varchar (15) AFTER email; Query OK, 0 rows affected (0.16 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> لنتحقق من إضافة العمود: mysql> show columns from minttec; +------------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +------------+-------------+------+-----+---------+-------+ | id | int(3) | YES | | NULL | | | first_name | varchar(15) | YES | | NULL | | | last_name | varchar(20) | YES | | NULL | | | email | varchar(20) | YES | | NULL | | | country | varchar(15) | YES | | NULL | | +------------+-------------+------+-----+---------+-------+ 5 rows in set (0.00 sec) mysql> إضافة قيمة إلى الحقول ماذا لو أردنا إضافة قيم إلى حقول الجدول؟ سنقوم بذلك كالتّالي: mysql> INSERT INTO minttec VALUES ('1' , 'Ravi' , 'Saive' , 'raivsaive@xyz.com' , 'India' ); Query OK, 1 row affected (0.02 sec) mysql> ماذا عن إضافة أكثر من قيمة واحدة في آنٍ واحد: mysql> INSERT INTO minttec VALUES ('2' , 'Narad' , 'Shrestha' , 'narad@xyz.com' , 'India' ), ('3' , 'user' , 'singh' , 'user@xyz.com' , 'Aus' ), ('4' , 'tecmint' , '[dot]com' , 'tecmint@gmail.com' , 'India' ); Query OK, 3 rows affected (0.05 sec) Records: 3 Duplicates: 0 Warnings: 0 سنتحقق من إدخال المعلومات السابقة في الجدول: mysql> select * from minttec; +------+------------+-----------+-------------------+---------+ | id | first_name | last_name | email | country | +------+------------+-----------+-------------------+---------+ | 1 | Ravi | Saive | raivsaive@xyz.com | India | | 2 | Narad | Shrestha | narad@xyz.com | India | | 3 | user | singh | user@xyz.com | Aus | | 4 | tecmint | [dot]com | tecmint@gmail.com | India | +------+------------+-----------+-------------------+---------+ 4 rows in set (0.00 sec) mysql> حذف قيم في حقول الجدول لنقل أنَّ المُدخَلة الثالثة في الناتج السابق لم تكن صحيحةً ونريد أن نحذفها: mysql> DELETE FROM minttec WHERE id = 3; Query OK, 1 row affected (0.02 sec) التحقق من تنفيذ الاستعلام السابق: mysql> select * from minttec; +------+------------+-----------+-------------------+---------+ | id | first_name | last_name | email | country | +------+------------+-----------+-------------------+---------+ | 1 | Ravi | Saive | raivsaive@xyz.com | India | | 2 | Narad | Shrestha | narad@xyz.com | India | | 4 | tecmint | [dot]com | tecmint@gmail.com | India | +------+------------+-----------+-------------------+---------+ 3 rows in set (0.00 sec) تحديث قيم في حقول الجدول لنفترض أننا نريد تعديل السجل ذي المُعرِّف 4 (أي id=4): mysql> UPDATE minttec SET id = 3 WHERE first_name = 'tecmint'; Query OK, 1 row affected (0.02 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> لاحظ أنَّ الاستعلام السابق ليس مثاليًا، فستُغيّر الحقل id إلى القيمة 4 لكل سجل يكون اسمه الأول مساويًا للقيمة tecmint. من الجيد استخدام مُطابقة أكثر من عمود واحد في عبارة WHERE لتقليل نسبة حدوث خطأ، كما في الاستعلام الآتي: mysql> UPDATE minttec SET id = 6 WHERE first_name = 'tecmint'AND last_name = '[dot]com'; Query OK, 1 row affected (0.03 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> حذف أحد أعمدة الجدول لنفترض أنَّك تحتاج إلى حذف أحد أعمدة الجدول غير الضرورية، ولنقل أنَّه العمود country: mysql> ALTER TABLE minttec drop country; Query OK, 3 rows affected (0.15 sec) Records: 3 Duplicates: 0 Warnings: 0 mysql> عرض بُنية الجدول: mysql> select * from minttec; +------+------------+-----------+-------------------+ | id | first_name | last_name | email | +------+------------+-----------+-------------------+ | 1 | Ravi | Saive | raivsaive@xyz.com | | 2 | Narad | Shrestha | narad@xyz.com | | 6 | tecmint | [dot]com | tecmint@gmail.com | +------+------------+-----------+-------------------+ 3 rows in set (0.00 sec) mysql> إعادة تسمية الجداول في MySQL ربما لا تجد اسم minttec ذا معنى، وتريد تحويله مثلًا إلى tecmint_table سنقوم بتغييره كالتّالي: mysql> RENAME TABLE minttec TO tecmint_table; Query OK, 0 rows affected (0.03 sec) mysql> عرض جميع الجداول لرؤية جميع الجداول الموجودة في قاعدة البيانات الحالية: mysql> show tables; +-------------------+ | Tables_in_tecmint | +-------------------+ | tecmint_table | +-------------------+ 1 row in set (0.00 sec) mysql> لاحظ إعادة تسمية الجدول. لنأخذ الآن نسخةً احتياطيةً من قاعدة البيانات السابقة، وذلك عبر تنفيذ استعلامٍ من سطرٍ وحيد دون استخدام أيّة أدواتٍ معقدة. نفِّذ الشيفرة أدناه في سطر الأوامر وليس في مِحَث MySQL: # mysqldump -u root -p tecmint > tecmint.sql check the dumped file on your desktop which would have contents something like -- MySQL dump 10.13 Distrib 5.5.31, for debian-linux-gnu (i686) -- -- Server version 5.5.31-0+wheezy1 -- Dump completed on 2013-09-02 12:55:37 من المستحسن الإبقاء على نسخ احتياطية لقواعد بياناتك، فاستعادة قاعدة بيانات MySQL هو أمرٌ بسيطٌ ويجرى بتنفيذ أمرٍ قصيرٍ في سطر الأوامر (أكرِّر، في سطر الأوامر وليس في مِحَث MySQL). لكن ما رأيك أن نحذف قاعدة البيانات أولًا لنرى كيف ستتم عملية الاستعادة؟ حذف قاعدة بيانات mysql> drop database tecmint; Query OK, 1 row affected (0.02 sec) تحقق من وجود قاعدة بيانات باسم tecmint في خادوم قواعد البيانات عندك: mysql> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | my_database | | mysql | | performance_schema | | phpmyadmin | | sisso | | test | +--------------------+ 7 rows in set (0.00 sec) mysql> رائع، لقد فقدنا قاعدة البيانات :-) لكن لا تقلق، فلقد أخذنا نسخةً احتياطيةً منها منذ قليل. استعادة قاعدة بيانات من نسخةٍ احتياطيةٍ منها نفِّذ الأمر الآتي لاستعادة قاعدة البيانات: # mysql -u root -p tecmint < tecmint.sql Enter password: ERROR 1049 (42000): Unknown database 'tecmint' ماذا حدث؟ لقد واجهنا رسالة خطأ، فنحن لم نُنشِئ قاعدة بيانات باسم tecmint بعد. لذا اذهب إلى مِحَث MySQL وأنشِئها: mysql> create database tecmint; Query OK, 1 row affected (0.00 sec) mysql> حان الآن الوقت لتنفيذ أمر الاستعادة في سطر الأوامر: # mysql -u root -p tecmint < tecmint.sql Enter password: لم تظهر بوجهنا أيّة رسائل خطأ مرعبة، لنتحقق الآن من وجود القاعدة في خادومنا: mysql> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | tecmint | | test | +--------------------+ 8 rows in set (0.00 sec) ثم سنتحقق من محتويات قاعدة البيانات (أي جداولها): mysql> show tables from tecmint; +-------------------+ | Tables_in_tecmint | +-------------------+ | tecmint_table | +-------------------+ 1 row in set (0.00 sec) mysql> وليطمئن قلبنا، سنرى محتويات الجدول: mysql> select * from tecmint_table; +------+------------+-----------+-------------------+ | id | first_name | last_name | email | +------+------------+-----------+-------------------+ | 1 | Ravi | Saive | raivsaive@xyz.com | | 2 | Narad | Shrestha | narad@xyz.com | | 6 | tecmint | [dot]com | tecmint@gmail.com | +------+------------+-----------+-------------------+ 3 rows in set (0.00 sec) هذه ليست نهاية المطاف، ما زال أمامنا مناقشة بعض المفاهيم مثل primary key، و foreign key… ترجمة -وبتصرّف- للمقال MySQL Basic Database Administration Commands – Part I.
-
- 1
-
- mysql
- قواعد اليبانات
-
(و 1 أكثر)
موسوم في:
-
أهلًا بك في هذه السلسلة التي تتحدث عن تأثيرات التمرير (Scrolling Effects)، سنستعرض في هذه السلسلة عددًا من تأثيرات التمرير وسنشرح آلية عملها وسنجرِّبها عمليًا. يمكننا الاستفادة من الحدث scroll في JavaScript لإجراء تأثيرات عند تمرير صفحة الويب؛ لكن إن فعلنا ذلك دون إتقان فالنتيجة كارثية، أما إذا أحسنا صنعنا فيمكن لتأثيرات التمرير أن تبهر الزوار وتشعرهم أنَّ موقعك مميز. هذه هي المقالة الأولى في هذه السلسلة، والتي تتضمن التأثيرات الآتية: إخفاء صورة خلفية تدريجيًا عند التمرير توضيح الصورة عند التمرير تدوير العناصر عند التمرير تأثير اختلاف المظهر parallax أما المقالة الثانية والثالثة فهي تتضمن التأثيرات الآتية: إظهار صورة الخلفية عند التمرير باستخدام CSS فقط تمرير سلس للصفحة تطبيق تأثير عدم الوضوح على المحتوى خلف شريط الانتقال إنشاء عنصر قابل للتمرير مع إمكانية وصول مخصصة من لوحة المفاتيح تأثير غروب الشمس باستخدام SVG إظهار فيديو في الخلفية صور متحركة بتأثير parallax باستخدام CSS 3D و JavaScript سأقدِّم لك في بداية كل قسم رابطًا لتجربة المثال تجربةً حيةً على المتصفح. سيسهل عليك كثيرًا أن تفهم الشرح والشيفرات بعد تجربتك للتأثير. إخفاء صورة خلفية تدريجيًا عند التمرير (تجربة حية) إذا كنتَ مِن مَن يستعملون صورًا كخلفية لكامل صفحة الويب، فاستخدام تأثير إخفاء تلك الصورة تدريجيًا عند التمرير هو أمرٌ حسن، حيث يمكّنك ذلك من استخدام أيّة صورة كخلفية دون التأثير على وضوح العناصر أو قابلية قراءة النص. ولعدم قدرة CSS على الاستجابة مباشرةً إلى موضع شريط التمرير، فنحن بحاجةٍ إلى استخدام بعض شيفرات JavaScript لمعرفة موضع التمرير لأحد العناصر. التقنية التي سأشرحها لك هنا سنستخدم فيها أنماط CSS أيضًا لإنشاء تأثير الإخفاء والتي ستُحدَّث ديناميكيًا عبر JavaScript. طريقة التفافية للتعويض عن عدم وجود الخاصية background-opacity للأسف لا يوجد لحد الآن خاصية باسم background-opacity لتحديد شفافية الخلفية؛ لكن من الممكن إنشاء التأثير عبر استخدام ميزة تعدد الخلفيات في CSS: حيث سنضع الصورة كطبقة (layer)، ثم الطبقة الثانية هي تدرجٌ لوني سنستخدم في ألوانه الشفافية alpha. لذا ستبدو شيفرة CSS كالآتي: body { background: linear-gradient(rgba(255, 255, 255, 0), rgba(255, 255, 255, 0)), url(times-square-perspective.jpg); background-repeat: no-repeat; background-attachment: fixed !important; background-size: 100% !important; background-position: center top !important; padding: 1rem; padding-top: 45%; color: #fff; } التدرج اللوني (الذي سيتم وضعه فوق الصورة، لأنَّه عُرِّفَ أولًا) غير ظاهر حاليًا، لأنَّ قيمة الشفافية alpha هي 0 للونين المشكلين للتدرج. استخدمنا الكلمة المفتاحية !important للتأكّد أنَّ شيفرة JavaScript –التي سنُطبِّقها بعد قليل– لن تتمكن من إلغاء قيم خاصيات CSS السابقة. شيفرة HTML تحتوي على ما يلي: <h1>New York Stories</h1> <p>In my younger and more vulnerable years… في النهاية، علينا وضع العنصر h1 في الأعلى: h1 { text-shadow: 0 0 5px rgba(0,0,0,0.5); font-size: 4rem; color: #fff; line-height: 1; position: absolute; top: 10px; } ولكي تصبح الفقرة قابلةً للقراءة، فعلينا أن نحوِّل التدرج اللوني إلى اللون الأبيض تمامًا، مما يؤدي إلى إخفاء صورة الخلفية. تعديل التدرجات اللوني في CSS باستخدام JavaScript أضف شيفرة JavaScript الآتية في أسفل الصفحة: var nystories = document.querySelector("p").offsetTop; window.onscroll = function() { if (window.pageYOffset > 0) { var opac = window.pageYOffset / nystories; document.body.style.background = "linear-gradient(rgba(255, 255, 255, " + opac + "), rgba(255, 255, 255, " + opac + ")), url(times-square-perspective.jpg) no-repeat"; } } في الشيفرة السابقة، قيمةُ المتغير nystories هي موضع أوّل فقرة في الصفحة. عندما يبدأ المستخدم بالتمرير فستُنشِئ الشيفرة السابقة متغيرًا باسم opac الذي سيُقسِّم الموضع «الحالي» للنافذة على الموضع «البدائي» لأول فقرة. ومن ثم ستُجمَع النتيجة مع قيم rgb لألوان التدرج اللوني مكان قيمة الشفافية alpha، مما يعطي التأثير بإخفاء صورة الخلفية عندما يتم تمرير الصفحة. هذا أحد الأمثلة البسيطة عن التمرير، ما زال في جعبتنا المزيد. توضيح الصورة عند التمرير (تجربة حية) أعجبتني اللمسة الجميلة في تطبيق توتير على هواتف iPhone: عندما تمرّر إلى الأسفل في صفحة «Me» فستصبح صورة الترويسة غير واضحة وسيتم تقريبها. أرى أنَّ من المفيد تقليد هذه التقنية في متصفحات الويب، خصوصًا للصور البارزة التابعة للمقالات… شيفرة HTML بسيطة للغاية: <article> <header> <img src="placid-pond.jpg" alt> </header> … </article> وفي نفس الصفحة سنضيف شيفرة SVG: <svg xmlns="http://www.w3.org/2000/svg" width="0" height="0"> <filter id="blur"> <feGaussianBlur stdDeviation="0" /> </filter> </svg> الغرض من وضع شيفرة SVG السابقة هو إضافة تأثير عدم الوضوح (blur) في متصفح Firefox، والذي لا يدعم إلى الآن «مُرشّحات CSS» (CSS Filters)؛ لاحظ أنَّ خاصية العرض والارتفاع لعنصر svg لها القيمة 0، لذا لن يؤثِّر على تخطيط الصفحة. سنضيف تأثير عدم الوضوح عبر أنماط CSS: header { overflow: hidden; font-size: 0; } article header img { width: 100%; height: auto; filter: url(#blur); } شيفرة JavaScript أكثر تعقيدًا مما سبق. يجب في البداية أن نضع جميع الشيفرات داخل دالة التي ستستدعى عندما يتم التمرير في المتصفح: window.onscroll = function (event) { } سنحتاج إلى الكثير من المعلومات داخل هذه الدالة. المتغيرات التي سنستعملها هي: var headerImg = document.querySelector("article header img"), headerImgOffset = headerImg.getBoundingClientRect(), imgTop = headerImgOffset.top, imgBottom = headerImgOffset.bottom, imgHeight = headerImg.offsetHeight, viewportHeight = document.documentElement.clientHeight, blur = document.getElementById("blur"), svgblur = blur.getElementsByTagName("feGaussianBlur")[0], topEffectStart = Math.abs((viewportHeight – imgHeight)/5); اقرأ الأسطر السابقة بتمعّن، يجب أن تبدو لك المتغيرات منطقيةً: المتغير headerImg يشير إلى صورة الترويسة الموجودة في أعلى المقالة (وللتبسيط، سأعتبر أنَّ الصفحة فيها مقالة وحيدة، وعنصر header وحيد). المتغير headerImgOffset يسمح لنا بالوصول إلى مكان وأبعاد الصورة، وفي حالتنا سنستخدم imgTop و imgBottom و imgHeight. المتغير viewportHeight يمثِّل ارتفاع نافذة المتصفح. المتغير blur يشير إلى شيفرة SVG في الصفحة، أما svgBlur فهو العنصر الذي سيسبِّب تأثير عدم الوضوح في متصفح Firefox. المتغير topEffectStart هو الفرق بين ارتفاع «إطار العرض» (viewport) الحالي وارتفاع الصورة، ومقسومًا على 5. وهذا يعني أنَّ تأثير عدم الوضوح سيبدأ فقط إذا كانت صورة الترويسة في الخُمس العلوي من نافذة المتصفح. استخدمتُ الدالة Math.abs لكي أحصل دومًا على عددٍ موجب، لأنَّ من الممكن أن تكون الصورة «أطول» من ارتفاع إطار العرض الحالي. بعد توضيح كل ما سبق، فلنضف عبارةً شرطيةً داخل الدالة: if (imgTop < topEffectStart && imgBottom > 0 ) { blurFactor = Math.abs(imgTop / 100); scaleFactor = 1+Math.abs(imgTop / 1000); headerImg.style.webkitFilter = "blur(" + blurFactor + "px)"; svgblur.setAttribute("stdDeviation", blurFactor); headerImg.style.webkitTransform = "scale(scaleFactor)"; headerImg.style.transform = "scale(scaleFactor)"; } هذا يعني إذا كان أعلى الصورة موجودٌ في أول خُمس من نافذة إطار العرض وما زالت الصورةُ معروضةً وظاهرةً للمستخدم، فافعل ما يلي: أخذ الموقع الحالي لأعلى الصورة نسبةً إلى أعلى إطار العرض، وتقسيم الناتج على 100، وتحويل الناتج إلى عدد عشري موجب، وتسمية الناتج باسم blurFactor. وبطريقةٍ مشابهة، سنأخذ الفرق، ونُقسِّمه على 1000 (لأن تغيير المقياس [scale] حساسٌ أكثر من تأثير عدم الوضوح) ومن ثم سنجمع العدد 1 مع الناتج، ونسمِّه scaleFactor. سنُطبِّق blurFactor (بعد إضافة “px” إليه) على صورة الترويسة، وذلك بوضعه كقيمة لمُرشِّح Webkit Blur. وبطريقةٍ مشابهة، سنُغيّر قيمة stdDeviation لنفس قيمة blurFactor وذلك لتطبيق التأثير في متصفح Firefox. في النهاية، سنسند قيمة scaleFactor إلى خاصية transform في CSS لصورة الترويسة. إحدى ميزات استخدام scale و blur معًا هي القدرة على إخفاء تأثير عدم الوضوح في جوانب الصورة، والتي لا يمكن إخفاؤها حتى باستخدام overflow: hidden في الحالات العادية. يمكن استخدام نفس السكربت السابق مع بعض التعديلات لكي يتم التركيز أو توضيح الصورة عندما تكون في منتصف الصفحة، مما يجذب انتباه المستخدم إليها. تدوير العناصر (المسننات) عند التمرير (تجربة حية) سأريك في هذا المثال كيفية تدوير العناصر أثناء تمرير الصفحة باستخدام JavaScript مباشرةً دون أيّة مكتبات خارجية. ضبط المسننات سيتم وضع المسننين في الصفحة باستخدام قيم id فريدة لكلٍ منهما؛ ولمّا كانا عبارةً عن رسوميات متجهة (vector shapes) فمن المعقول أن نُنشئهما باستخدام SVG: <div id="gearbox"> <img src="gear.svg" alt id="leftgear"> <img src="gear.svg" alt id="rightgear"> </div> هنالك الكثير من الخيارات لطريقة وضع المسننات: ففي أغلبية الأحيان سنستعمل موضعًا ثابتًا لها (أي position: fixed)، ومن الممكن أيضًا وضعها في مكانٍ معيّن ثم سيصبح موقعها ثابتًا عندما يتم التمرير بعدها (أي position: sticky). سأستعمل في هذا المثال flexbox لفصل العناصر، وسأستخدم الواحدات vm لقياسها؛ ويمكن أيضًا أن يكون موضع المسننات static وبالتالي ستختفي المسننات عند تمرير الصفحة. #gearbox { display: flex; justify-content: space-between; } #leftgear, #rightgear { width: 20vw; max-width: 20%; height: auto; } تدوير المسننات تدوير العناصر سهلٌ للغاية، كل ما عليك فعله هو إضافة الشيفرة الآتية في أسفل الصفحة: var leftgear = document.getElementById("leftgear"), rightgear = document.getElementById("rightgear"); window.addEventListener("scroll", function() { leftgear.style.transform = "rotate("+window.pageYOffset+"deg)"; rightgear.style.transform = "rotate(-"+window.pageYOffset+"deg)"; }); سيدور كل مسنن بنفس مقدار تمرير النافذة مقدرًا بالبكسل والذي سيحوّل إلى درجات. لتسريع أو تبطيء دوران المسننات نسبةً إلى مقدار التمرير، فيمكنك جعل window.pageYOffset جزءًا من تعبيرٍ رياضيٍ بسيط (كالقسمة أو الضرب بالرقم 2 على سبيل المثال). تفادي «تعليق» المسننات مشكلة شائعة مع أيّة تقنية التي تتعامل مع التمرير هي «تعليق» العناصر حيث ستحاول مطابقة مدخلات المستخدم. أسهل حل للتعامل مع هذه الإشكالية هو تحريك العناصر عندما يصبح المتصفح جاهزًا للتعامل مع تلك الحركة، وذلك عبر requestAnimationFrame. ولفعل ذلك سنُجعل الدالة addEventListener تستمع إلى حدث خاص (custom event): window.addEventListener("optimizedScroll", function() { … }) وقبل دالة معالجة الحدث، أضف دالةً مجهولةً (anonymous function): ;(function() { var throttle = function(type, name, obj) { var obj = obj || window; var running = false; var func = function() { if (running) { return; } running = true; requestAnimationFrame(function() { obj.dispatchEvent(new CustomEvent(name)); running = false; }); }; obj.addEventListener(type, func); }; throttle ("scroll", "optimizedScroll"); })(); طريقة سهلة لإنشاء تأثير اختلاف المظهر (تجربة حية) نَشَرَ «Adam Mustill» تقنيةً ذكيةً جدًا لإنشاء تأثير اختلاف المظهر (Parallax) عبر تعديل واحدة root em. يتساءل الكثيرون عن كيفية إنشاء تأثيرات اختلاف المظهر، وارتأيتُ أنَّ هذه الطريقة قد تكون نقطة بداية جيدة لتعلم إنشاء هذا التأثير. تأثير اختلاف المظهر (Parallax) يتطلب عادةً عمليات معالجة معقدة لعدد كبير من عناصر DOM المنفصلة، لكن التقنية التي سنستخدمها هنا تُسهِّل علينا معالجة العناصر بتغيير قياسٍ وحيد، وهي تستغل ميزة غريبة بعض الشيء لواحدة القياس em: إذا كان قياس العنصر الأب والعناصر الأبناء بواحدة em، فإن القياس النهائي للأبناء هو ناتج ضربها مع بعضها. وصحيحٌ أنَّ هذا السلوك قد يُسبِّب لنا صداعًا (وهو سببٌ وجيهٌ لاستخدام rem إن استطعنا) إلا أنَّ له ميزتين في هذه الحالة: 1. وحدة القياس em لها دعم أقوى في المتصفحات نسبةً إلى rem. 2. تتطلب em وجود عنصر أب، وهذا يعني أنَّ تأثير اختلاف المظهر يمكن أن يُطبَّق على حاوية معيّنة؛ أما في طريقة rem التي ابتكرها Adam، فإنَّ كل شيءٍ موجود في عنصر <body> سيتأثّر بالتمرير إلا إذا اتخذتَ إجراءاتٍ معينةً للحد من ذلك. ولقد حسّنتُ أيضًا من شيفرة Adam وجعلتها سطرًا وحيدًا من شيفرات JavaScript، بدلًا من عدِّة أسطر من jQuery، مما يُحسِّن من الأداء. شيفرات HTML و CSS شيفرة HTML لهذا المثال بسيطةٌ جدًا: إذ هنالك ثلاث صور وترويسة داخل عنصر <div>: <div id="parallax"> <h1>Simple EM Parallax Technique</h1> <img src="candles.jpg" alt> <img src="cherry-tree.jpg" alt> <img src="pagoda-surrounded-by-trees.jpg" alt> </div> وأنماط CSS ليست معقدةً أبدًا: #parallax { background-image: url(blurred-background-small.jpg); background-size: cover; padding-top: 62.5%; overflow: hidden; position: relative; font-size: .1em; } #parallax * { position: absolute; } #parallax img { width: 40%; height: auto; box-shadow: 0 .2em 8px 4px rgba(0,0,0,0.5); } #parallax h1 { font-size:3rem; color: #fff; z-index: 2; top: 0; text-transform: uppercase; width: 100%; text-align: center; text-shadow: 0 .2em 5px rgba(0,0,0,0.4); } #parallax img:nth-of-type(1) { left: 5%; bottom: 22em; } #parallax img:nth-of-type(2) { left: 28%; z-index: 3; bottom: 8em; } #parallax img:nth-of-type(3) { left: 55%; bottom: 12em; } الأمور المهمة التي يجب ملاحظتها هي القيمة الافتراضية الصغيرة جدًا لقياس الحاوية #parallax بواحدة em، بالإضافة إلى قيم bottom لكل صورة، وأنَّ نص الترويسة مقاسٌ بواحدة rem وليس em. شيفرة JavaScript شيفرة JavaScript هي عبارة عن سطرٍ وحيدٍ فقط يجري تعديلًا على إحدى خاصيات CSS: window.onscroll = function() { if (window.pageYOffset > 0) { document.getElementById("parallax").style.fontSize = (window.pageYOffset/20)*.1+"em"; } } بشرح مبسّط: سيؤدي التمرير إلى تغيير قيمة الخاصية font-size لحاوية #parallax، وهذا التغيير يعتمد على عدد البكسلات التي تم تمريرها، مقسومةً على 20، مضروبةً بقيمة 0.1 em والتي هي حجم الخط الأصلي. التمرير إلى الأسفل سيؤدي إلى زيادة قيمة الخاصية bottom لكل صورة مما يدفعها نحو الأعلى؛ لكن الترويسة لن تتأثر لأنها مُقاسة بواحدة rem، وهي ذات خاصية z-index مناسبة مما يسمح للصور بالمرور أمامها وخلفها. الخلاصة استعرضنا التأثيرات السابقة بسرعة، بقي عليك أن تتمعّن بشيفراتها، وتحاول إيجاد استخدامات أخرى للتقنيات التي رأيتها. ترجمة وبتصرّف للمقالات: Fade A Responsive Background Image On Scroll Scroll-to-Focus Effect For Hero Images Rotate Elements on Scroll with JavaScript Easy Parallax Effects With Em لصاحبها Dudley Storey
- 1 تعليق
-
- 1
-
لشبكات ووردبريس متعددة المواقع الكثير من الاستعمالات، حيث يمكنك استخدمها لإنشاء شبكة مثل Edublogs التي تُساعِد الآخرين على إنشاء موقعٍ خاصٍ بهم، أو يمكنك استخدمها لشبكةٍ من المواقع أو المدونات التابعة لمنظمتك، ويمكنك أيضًا استخدامها لاستضافة مواقع لك أو لعملائك. إذا كنتَ كالغالبية من مطوري ومصممي الويب، فمكن المرجح أنَّك تملك عددًا كبيرًا من النطاقات التي سجّلتها والمواقع التي أنشأتها (أو التي ما زلتَ تعمل عليها)، ولا شكّ أنَّ ذلك قد يسبب لك الصداع. وبشكلٍ مشابه، إذا كنتَ تدير شركة أو كنتَ عاملًا حرًا توفِّر استضافةً لمواقع عملائك، فستحتاج إلى إبقاء عدِّة نسخ من ووردبريس محدثةً باستمرار، وهذا سيستهلك وقتًا منك. تستطيع ميزة الشبكات متعددة المواقع أن تحل هذه المشكلة لك. هذا هو الدرس السادس في سلسلتنا المكونة من عشرة دروس التي تشرح التعامل مع الشبكات متعددة المواقع في ووردبريس، ستتعلم في هذه السلسلة كل ما تحتاج له لكي تُنشِئ شبكتك، وتضيف المواقع إليها أو تسمح للمستخدمين بذلك، بالإضافة إلى إدارة الشبكة. وستتعلم كيف تتأكد أنَّ شبكتك آمنة وأداؤها عالٍ، وكيف يمكنك أن تُنشِئ مجتمعًا ناجحًا من المستخدمين والمواقع. ستتعلم في هذا الجزء من السلسلة كيف تستعمل الشبكات متعددة المواقع لاستضافة مواقع لك أو لعملائك، التي ستبدو وكأنها مواقع منفصلة. حيث سيمتلك كلٌ منها نطاقًا خاصًا به، وسيشعر الزوار أنَّ تلك المواقع منفصلة، سأريك أيضًا كيفية استخدام ميزة تعدد المواقع لتحسين سير عملك وسأعطيك بعض النصائح حول كيفية تتفادى المشاكل المحتملة، ثم سأشرح لك (في الدرس القادم) عملية ربط النطاقات بالتفصيل لكي تتمكن من ضبط الشبكة متعددة المواقع الخاصة بك ضبطًا سليمًا. استخدام الشبكة متعددة المواقع لاستضافة مواقعك أو مواقع عملائك أتوقع أنَّك تشعر كم أنني معجبٌ بميزة تعدد المواقع وأنني أستعملها لمختلف التطبيقات. أحد تلك التطبيقات هو استضافة مواقع العملاء. أدير شركةً صغيرة لتطوير الويب، وتكون أغلبية مواقع عملائي متشابهة وليست كبيرة جدًا والتي يمكن استضافتها بسهولة على شبكة من المواقع؛ بغض النظر أنَّ بعض عملائي لديهم استضافة خاصة أو يحتاجون إلى تثبيت ووردبريس مستقل بسبب بعض الخصوصيات في مواقعهم. أنا أفعل ذلك لمواقع العملاء، لكن لا يوجد سببٌ يمنعك من استخدام شبكة لاستضافة مواقعك الخاصة على أكثر من نطاق. التقنيات التي سنستعملها متماثلة. لننظر أولًا على إيجابيات وسلبيات ما سبق. إيجابيات استخدام شبكة متعددة المواقع لمواقع العملاء هنالك بعض المنافع الأساسية لاستضافة أغلبية مواقع العملاء في تثبيت ووردبريس وحيد: توفير مساحة على الخادوم. توفير الوقت اللازم لتثبيت ووردبريس في كل مرة أبدأ فيها العمل على موقع جديد. توفير الوقت اللازم لتحديث أكثر من نسخة ووردبريس. توفير الوقت اللازم لتحديث الإضافات والقوالب في عدِّة نسخ من ووردبريس. هذا يعني أنني أستطيع استخدام نفس الإضافات على أكثر من موقع دون الحاجة إلى تثبيتها مرارًا وتكرارًا. هذا يعني أنَّني أستطيع تثبيت إضافات مثل Support System للتواصل مع العملاء في مكانٍ واحد. بالنسبة لي، هذا يجعل الأمور أكثر فعالية، لكن علي أنَّ أعمل بطريقة تلائم المواقع التي تعمل على شبكة، وإجراء بعض الأمور للتأكد من عدم وقوعي ببعض المشاكل. سلبيات استضافة الكثير من المواقع في تثبيت ووردبريس وحيد من المحتمل أنَّ يقرأ هذا الكلام أشخاصٌ يجزعون من إبقاء كل هذه المواقع الثمينة في مكانٍ واحد. أعلم أنَّ هنالك البعض الذين يظنون أنَّ مخاطر فعل ذلك تفوق فوائده. إن كنتَ من هؤلاء، فيمكنك أن تستمر باستخدام تثبيت ووردبريس منفصل لكل موقع. هنالك بالفعل بعض السلبيات الناجمة عن استخدام شبكة لاستضافة جميع مواقعك: حجم قاعدة البيانات: قد تبدأ قاعدة البيانات بالتضخم بعد فترة من الزمن، لكن إذا تمكنت مواقع WordPress.com و Edublogs من استخدام شبكة متعددة المواقع لاستضافة ملايين المواقع، فلا يوجد سببٌ يمنعك من التعلم من تجربتهم لتوسعة تثبيت ووردبريس عندك. الحماية: إذا تم اختراق الشبكة متعددة المواقع، فستتأثر جميع المواقع المُستضافة عليها. هذا أمرٌ مرعبٌ، أليس كذلك؟ بلى! لكن من خبرتي عندما كنتُ ضحيةً للاختراق، كان ذلك على مستوى الخادوم، وأثّرَ ذلك على جميع المواقع المستضافة على أيّة حال. لكن عليك أنَّ تتأكد أنَّ مستوى الحماية والأمان في شبكتك عالٍ، خصوصًا إن كنتَ تستضيف عددًا كبيرًا من المستخدمين. إذا تعطّل شيءٌ ما، فسيُعطِّل كل الشبكة. هذه هو السبب لماذا لا يجدر بك إجراء تحديث على شبكتك الإنتاجية إلّا بعد أن تجرّبه على موقعٍ تجريبي أولًا. سننظر في هذه النقطة قريبًا. الأداء: لن تستطيع استضافة العديد من المواقع في تثبيت ووردبريس وحيد إن كنت تعمل على استضافة رخيصة وبطيئة أو محدودة بحجم قاعدة البيانات أو التراسل الشبكي أو رفع الملفات. إذا قررتَ أنت أو أحد عملائك أن تنقل الموقع إلى خارج الشبكة في المستقبل، فذلك أصعب من عملية نقل قاعدة بيانات موقع مفرد إلى خادوم جديد أو شركة استضافة أخرى. لكن ذلك ليس مستحيلًا، وهنالك طريقتان لفعل ذلك: يمكنك استخدام إضافات (طريقة أسهل لكنها قد تكون غير عملية) أو يمكنك تصدير الجداول اللازمة من قاعدة البيانات (وهذه الطريقة أصعب لكن أسرع وعملية ومرنة أكثر). هذا يعني أنَّ استخدام شبكة لاستضافة أكثر من موقع ستعمل بأفضل ما يمكن إذا تحقق الشرطان الآتيان: أخذت احتياطاتك وتأكدتَ أنَّ الشبكة آمنة ولن تتعطل بسهولة. تعمل بطريقة معينة تجعل نفس الشيفرة تتكرر في جميع أو أغلبية المواقع التي تطورها (مثلًا الإضافات والقوالب). تذكَّر أنَّ لأغلبنا قائمةٌ فيها الإضافات الأساسية التي نُثبِّتُها على كل موقع جديد نطوره. لننظر إلى معنى ما سبق عمليًا. تفادي السلبيات: الاحتياطات الوقائية هنالك بعض الاحتياطات الوقائية التي عليك اتخاذها لتتفادى المشاكل التي ذكرتا سابقًا: خذ نسخة احتياطيةً لشبكتك بشكلٍ دوري: كل يوم على الأقل، وأكثر من ذلك إن كانت مواقعك تُحدَّث يوميًا. استخدامُ إضافة Snapshot Pro لأخذ نسخة احتياطية للمواقع على شبكتي، وأستعمل Updraft Plus للتأكد من أخذ نسخة احتياطية من كامل قاعدة البيانات، وهذا يعني أنَّ لو تعطَّل موقعٌ واحد، فسأستخدم ميزة الاستعادة في إضافة Snapshot لاستعادته، وإذا حدثت مشاكل مع كل الشبكة، فسيكون عندي نسخةٌ احتياطيةٌ من قاعدة البيانات وسأعيد تثبيتها يدويًا. ابقِ شبكتك آمنةً قدر الإمكان. راجع سلسلة «تنصيب ووردبريس بأمان» وطبِّق النصائح الموجودة فيها. المخاطر الموجودة في شبكة المواقع زيادةً عن المواقع المفردة هي أنَّك تملك عددًا أكبر من المواقع ومستخدمين أكثر. يمكنك أن تُطبِّق الاحترازات الأمنية أثناء تسجيل الموقع وعملية تسجيل المستخدم لكي تتأكد أنَّ الآخرين لن يستطيعوا استعمال أسماء معيّنة لمواقعهم، ولحجب القدرة على تسجيل المواقع من نطاقات معينة، ولإبعاد المستخدمين المزعجين وعدم السماح للمستخدمين بضبط كلمات مرور ضعيفة. إن لم تسمح بتسجيل المواقع والمستخدمين من قِبل الزوار، فتأكّد أنَّ العملية التي ستتبعها في إنشاء المواقع آمنة. لا تُحدِّث ووردبريس أو الإضافات أو القوالب على شبكتك الإنتاجية قبل تجربة التحديث على نفس الإصدار في نسخة تجريبية من الشبكة أولًا. النسخة التجريبية هي نسخة من شبكتك التي يكون الغرض منها هو اختبار التحديثات أو ما شابه ذلك (وهي مختلفة عن النسخة «التطويرية» التي تتواجد عادةً في حاسوبك المحلي). من المستحسن أن تستضيف النسخة التجريبية على نفس الخادوم الذي يُشغِّل شبكتك الإنتاجية لذا ستتمكن من التجربة في نفس الشروط تقريبًا. احرص على حجب وصول محركات البحث وحاول إبقاء قاعدة البيانات مُحدَّثةً قدر الإمكان باستخدام إضافة للنسخ الاحتياطي أو أداة مثل Vagrant. استضف شبكتك عند مزود استضافة مختص بإدارة مواقع ووردبريس إن استطعتَ تحمل التكاليف. حيث سيعتنون بعملية النسخ الاحتياطي والحماية ويتمكنون من استعادة الشبكة ويوفرون لك بيئة تجريبية أيضًا. تحدَّث مع مزود الخدمة عن أفضل إعداد للاستضافة يلائم حالتك، مثل خادوم VPS (اختصار للعبارة virtual private server) الذي يناسب تثبيت الشبكات متعددة المواقع. استخدم إضافة أو أكثر من الإضافات التي ننصح بها لإدارة الشبكة لتسهيل عملية الإدارة. إحدى الإضافات التي أرى أنَّها مفيدةً كثيرًا هي Multisite Enhancements، لأنها تُساعدني بموضوع التحديثات عبر إظهار ما هي المواقع التي تستعمل قوالب أو إضافات معيّنة. وهذا يعني أنَّني سأعرف ما هي المواقع التي عليّ اختبارها. استخدم الشيفرات من مصادر تثق بها فقط، أو اكتب الشيفرات الخاصة بك، هذا الأمر مهمٌ لجميع أنواع مواقع ووردبريس، لكنه مهم جدًا في الشبكات متعددة المواقع، لأنه إذا كان لديك عدِّة مواقع تُشغِّل عدِّة قوالب وإضافات، فعليك أن تتأكَّد أنَّ كل إضافاتك وقوالبك تعمل عملًا صحيحًا مع بعضها بعضًا. إذا كنتَ تستعمل شيفراتٍ من طرف ثالث، فأنا أنصحك بأن تستقي تلك الشيفرات من موقع WPMU DEV، إذ أنَّ القوالب والإضافات من ذاك الموقع تعمل بتناغم مع بعضها وهي مُحسّنة خصيصًا لشبكات المواقع. أحاول اتباع النصائح السابقة ولم أواجه مشاكل مع الشبكات متعددة المواقع حتى الآن. الشبكات متعددة المواقع، وأسلوب عملك لكن استخدام الشبكات متعددة المواقع لاستضافة مواقع العملاء لا يعني تفادي المشكلات التي ذكرناها سابقًا فحسب، لكنه متعلقٌ أيضًا بأسلوب وسير العمل. هنالك جوانب متعلقة بأسلوب عملك التي ستجعل التطوير لشبكة متعددة المواقع أسهل وأيسر. وهذا يعني اتباع أسلوب عمل يجعل استخدام الشبكات أمرًا يزيد الكفاءة والفعالية، ويجعل من استخدام الشبكات طريقًا أفضل للتطوير بدلًا من استخدام عدد كبير من مواقع ووردبريس المفردة المستقلة. لننظر إلى بعض هذه الجوانب: ستعمل مع نفس القوالب لجميع مواقع شبكتك، أو «قالب ابن» (child theme) لنفس القالب الأب الأساسي. قد يتحقق هذا الشرط إذا استخدمتَ نظامًا لبناء القوالب مثل Upfront أو أحد إطارات عمل ووردبريس الموجودة. شخصيًا، لدي إطار عمل للقوالب خاصٌ بي الذي طوَّرتُه لأستخدمه في مواقع العملاء، ومن ثم أُنشِئ قالبًا ابنًا لكل مشروع جديد. يملك هذا القالب الكثير من الدوال (functions) والخطافات (hooks) التي أستفيد منها لجعل كل موقع مميز وفريد ولكي أضيف شيفراتٍ خاصة. وأستخدم أيضًا شيفرات CSS مكتوبة بطريقة تجعلني أستطيع تعديل مظهر الموقع الجديد بأقل قدر من العناء. يمكنك تثبيت مجموعة الإضافات نفسها لكل موقع تُنشِئه. كانت لدي قائمة بالإضافات الأساسية التي أثبِّتها على كل موقع قبل أن أستعمل الشبكات متعددة المواقع لاستضافة مواقع العملاء؛ وهذه القائمة تتضمن إضافات لأخذ نسخ احتياطية، ولتحسين SEO، ولتحسين الأداء والحماية. أما الآن، فبدلًا من الحاجة إلى تثبيت تلك الإضافات على كل موقع جديد، فأثبتها وأفعِّلها على الشبكة فحسب. تستطيع تحسين خدمة الزبائن باستخدام إضافات للدعم أو التدريب. استخدام إضافة مثل Support System تسمح لعملائك بطرح مشكلاتهم لكي تستطيع الإجابة عنها ثم تحول ذلك إلى «أسئلة شائعة» (FAQ) لعرضها في موقعك الرئيسي إن شئت. أستخدم هذا على إحدى شبكاتي لكي أُبقي على جميع نقاشات الدعم مع العملاء في مكانٍ واحد. إذا أردت أن توفِّر درسًا تعليميًا لعملائك وتُظهِر لهم كيف يستعملوا موقعهم، فيمكنك تثبيت إضافة مثل Integrated Video Tutorials التي تسمح لك بتقديم شرح مصور للعملاء؛ كل ما عليك فعله هو نشر الدرس التعليمي على شبكتك وسيصبح متاحًا لجميع العملاء. إذا أردتَ أن تُنشِئ مجتمعًا بين عملائك، فإن الشبكة متعددة المواقع هي منصةٌ رائعةٌ لإنشاء مجتمع، ولا يوجد سببٌ يمنعك من فعل ذلك مع عملائك. سنتحدث بالتفصيل عن هذا الموضوع في الجزء القادم من هذه السلسلة. حسنًا، يمكنك الآن أن تعي ماذا يعني استخدام شبكة متعددة المواقع لاستضافة عدِّة مواقع لعملائك (أو مواقع خاصة بك) على نطاقات مختلفة، ما ستحتاج له الآن هو معرفة كيف ستفعل ذلك، وهذا ما سنناقشه في الدرس القادم. ترجمة –وبتصرّف– للمقال WordPress Multisite Masterclass: Client Sites and Domain Mapping لصاحبته Rachel McCollin