لوحة المتصدرين
المحتوى الأكثر حصولًا على سمعة جيدة
المحتوى الأعلى تقييمًا في 10/10/21 في كل الموقع
-
أريد رفع قاعدة البيانات لدي إلى الاستضافة ماهي الخطوات التي يجب أن أقوم بها؟2 نقاط
-
لا تختلف الملفات من منظور برمجي عن الملفات التي نستخدمها في برامج معالجة الكلمات أو أي برامج أخرى، والتي نفتحها ونكتب فيها بعض المهام أو التعليمات ثم نغلقها مرةً أخرى، لكن أحد الفروق الرئيسية هنا هو أننا نقرأ الملف تتابعيًا، أي نقرأ سطرًا واحدًا في كل مرة من بدايته، ورغم أن برامج معالجة الكلمات تنتهج هذا النهج أيضًا، إلا أنها تحتفظ بالملف كله في الذاكرة أثناء عملنا عليه، ثم تنفذ عملية الكتابة كلها عند إغلاقها، وهناك فرق آخر بين الملفات البرمجية والعادية، وهو أننا حين نبرمج فإننا نفتح الملف للقراءة فقط أو الكتابة فقط، وننفذ الكتابة بإنشاء ملف جديد من الصفر أو إلغاء ملف موجود والكتابة فوقه، أو بإلحاق الملف الجديد إلى ملف موجود من قبل، كما يمكن العودة في الملفات البرمجية إلى بداية الملف أثناء معالجته. الدخل والخرج بالملفات لنطبق مثالًا عمليًا، ولنفترض وجود ملف اسمه menu.txt، يحتوي على قائمة من الوجبات: steak & eggs steak & chips steak & steak لنكتب برنامجًا يقرأ الملف ويعرض الخرج كما يفعل أمر cat في صدفة يونكس، وأمر type في صدفة ويندوز. # (r) افتح الملف للقراءة inp = open("menu.txt","r") # اقرأ الملف سطرًا سطرًا for line in inp: print( line ) # أغلق الملف مرة أخرى inp.close() تأخذ open() وسيطين، الأول هو اسم الملف الذي يمكن أن يكون متغيرًا أو سلسلةً نصيةً مجردةً literal string كما فعلنا هنا، والوسيط الثاني هو الوضع الذي نفتح به الملف، حيث يمكن فتحه للقراءة فقط r أو للكتابة w، كما نحدد هل هو للاستخدام النصي أم للاستخدام الثنائي binary، وذلك بإضافة محرف b إلى r أو w في حالة الاستخدام الثنائي، كما يلي: open(fn,"rb") لاحظ أننا نقرأ الملف في حلقة for، التي تتصرف في بايثون مثل حلقة foreach في تجميعة، إذ تعيد كل عنصر في التجميعة، ويمكن النظر إلى الملف النصي على أنه تجميعة من الأسطر، وهكذا تقرأ الحلقة كل سطر على حدة. ثم نغلق الملف باستخدام دالة مسبوقة بمتغير ملف، وتُعرف هذه الصياغة باستدعاء التابع method invocation كما شرحنا في المقال السابق حول البرمجة باستخدام الوحدات، ويمكن تقريب مفهوم متغير الملف بأنه وحدة تحتوي الدوال التي تعمل على الملفات، ونستوردها في كل مرة ننشئ متغيرًا من نوع ملف. تُغلَق الملفات تلقائيًا في بايثون في نهاية البرنامج، لكن من الأفضل أن نتعود على إغلاق الملفات إغلاقًا صريحًا، لأن نظام التشغيل قد لا يكتب البيانات إلى الملف إلا عند إغلاقه لأسباب تتعلق بتسريع أدائه، مما يعني أن بياناتنا قد لا تكتَب إلى الملف إذا خرج البرنامج فجأةً، لذا يفضَّل التعود على إغلاق الملف بمجرد الانتهاء من الكتابة فيه. كما أننا لم نحدد المسار الكامل للملف الموجود في الشيفرة أعلاه، لذا سنتعامل مع الملف على أنه موجود في المجلد الحالي، لكن يمكن تمرير الاسم الكامل للمسار إلى open() بدلًا من اسم الملف مجردًا. قد نواجه مشكلةً بسيطةً في هذا الشأن في نظام ويندوز، إذ يُستخدم المحرف \ لفصل المجلدات في مسارات ويندوز، لكن نفس المحرف له معنىً خاص آخر في سلاسل بايثون، لذلك يفضل استخدام المحرف / عند تحديد المسارات في بايثون لضمان عملها على أي نظام تشغيل بما فيها ويندوز. عند التعامل مع ملف طويل لن نستطيع عرضه كاملًا على الشاشة مرةً واحدةً، وعلينا التوقف بعد كل شاشة كاملة، لذا نستخدم المتغير line_count ونزيده بعد قراءة كل سطر، ثم نتحقق هل يساوي 25 -إذا كانت الشاشة تحتوي على 25 سطرًا- أم لا، ثم سنطلب من المستخدم أن يضغط على زر ما عندما يساوي 25، وليكن زر الإدخال مثلًا، قبل إعادة ضبط عداد line_count إلى الصفر والمتابعة بعد ذلك. توجد طريقة أخرى لقراءة الملفات باستخدام حلقة while وتابع لكائن الملف اسمه readline()، وتمتاز هذه الطريقة بأننا نستطيع التوقف عن معالجة الملف بمجرد العثور على البيانات التي نريدها، مما يسرع الأداء كثيرًا إذا كنا نتعامل مع ملفات طويلة، لكنها أعقد، لذا سننظر في مثالنا السابق باستخدام هذه الطريقة لنشرحها: # افتح الملف للقراءة inp = open("menu.txt","r") # اقرأ الملف واطبع كل سطر while True: line = inp.readline() if not line: break print( line ) # أغلق الملف inp.close() لاحظ أننا استخدمنا تقنية break التي ذكرناها في مقال مقدمة في البرمجة الشرطية، وذلك للخروج من الحلقة إذا كان السطر فارغًا، إذ يَعُد السطر الفارغ بالاصطلاح البولياني قيمة false، ثم طبعنا كل سطر وكررنا الحلقة مرةً أخرى، ثم أغلقنا الملف بعد الخروج من حلقة while. وإذا رغبنا في التوقف عند نقطة ما في الملف، فسيكون ذلك بشرط فرع branch condition داخل حلقة while، فإذا اكتشفنا شرط الإيقاف فسنستدعي break أيضًا لتنتهي الحلقة. هذا كل ما يتعلق بفتح الملف وقراءته والتعامل معه بالطريقة التي تريدها مما سبق، لكن في المثال السابق ملاحظة صغيرة، فالأسطر المقروءة من الملف لها محرف سطر جديد في نهايتها، لذا سيكون لدينا أسطر فارغة إذا استخدمنا print() التي تضيف محرف السطر الجديد الخاص بها، ولتجنب هذا الأمر وفّرت بايثون تابع سلسلة نصية اسمه strip() يحذف المسافات البيضاء أو المحارف التي لا تُطبع من كلا طرفي السلسلة النصية، كما توجد توابع مثل rstrip وlstrip اللذين يُحذفان المسافات من جانب واحد فقط، وبناءً عليه نستطيع إصلاح مشكلة المسافات إذا استبدلنا السطر التالي بسطر print() السابق: print( line.rstrip() ) # احذف الجانب الأيمن فقط end إذا أردنا إنشاء أمر نسخ في بايثون، فإننا نفتح ملفًا جديدًا في وضع الكتابة ثم نكتب الأسطر إليه بدلًا من طباعتها، سننشئ ملفًا اسمه MENU.BAK يكافئ الملف MENU.TXT: # افتح الملفين للقراءة والكتابة على الترتيب inp = open("menu.txt","r") outp = open("menu.bak","w") # اقرأ الملف ناسخًا كل سطر إلى الملف الجديد for line in inp: outp.write(line) print( "1 file copied..." ) # أغلق الملفات inp.close() outp.close() لاحظ أننا أضفنا تعليمة print() في النهاية كي نطمئن المستخدم بحدوث شيء ما، لأن التغذية الراجعة للمستخدم تنفع ولا تضر، ولم نتعرض هنا لمشاكل مع محارف الأسطر الجديدة لأننا كتبنا نفس السطر line الذي قرأناه، لكن إذا كنا نكتب سلاسل نصيةً ننشئها بأنفسنا، أو سلاسل حذفنا منها محارف الأسطر الجديدة من قبل، فسيكون علينا إضافة سطر جديد إلى نهاية سلسلة الخرج، كما يلي: outp.write(line + '\n') # \n => سطر جديد لننظر في كيفية تطبيق هذا في برنامج النسخ. سنضيف تاريخ اليوم في الأعلى بدلًا من مجرد نسخ القائمة، وبهذا نستطيع إنشاء قائمة يومية من ملف نصي للوجبات يسهل تعديله، وكل ما علينا فعله هو كتابة بعض الأسطر في بداية الملف الجديد قبل نسخ ملف menu.txt، كما يلي: import time # MENU.TXT أنشئ القائمة اليومية وفقًا لـ # افتح الملفات للقراءة والكتابة على الترتيب inp = open("menu.txt","r") outp = open("menu.prn","w") # أنشئ سلسلة تاريخ اليوم today = time.localtime(time.time()) theDate = time.strftime("%A %B %d", today) # أضف نص الإعلان وسطرًا فارغًا outp.write("Menu for %s\n\n" % theDate) # إلى ملف جديد menu.txt انسخ كل سطر من for line in inp: outp.write(line) print( "Menu created for %s..." % theDate ) # أغلق الملفات inp.close() outp.close() لاحظ أننا نستخدم وحدة time للحصول على تاريخ اليوم time.time()، وتحويله إلى صف tuple من القيم (time.localtime()) التي تُستخدم لاحقًا بواسطة time.strftime() -انظر توثيق الوقت والتاريخ في بايثون من موسوعة حسوب- لإنتاج سلسلة نصية تبدو بالشكل التالي عندما ندخلها في رسالة عنوان باستخدام تنسيق السلاسل النصية: Menu for Sunday September 19 Spam & Eggs Spam &... لم يُطبع إلا سطر واحد فارغ رغم إضافتنا لمحرفين \n في نهاية السلسلة النصية، وذلك لأن أحدهما كان السطر الجديد عند نهاية العنوان نفسه، وهذا يظهر جانبًا مزعجًا في إدارة عملية إنشاء محارف الأسطر الجديدة وحذفها. إلحاق البيانات ثمة أمر آخر في معالجة الملفات، إذ قد نرغب في إلحاق بيانات بنهاية ملف موجود، ويمكن فعل هذا بفتح الملف للإدخال، وقراءة البيانات إلى قائمة، ثم إلحاق البيانات إليها، ثم كتابة القائمة كلها إلى إصدار جديد من الملف القديم، ولن يُحدث هذا مشكلةً إذا كان الملف قصيرًا؛ أما إذا كان كبيرًا -أكبر من 100 ميجا بايت مثلًا-، فستنفد الذاكرة التي يجب أن تحتفظ بالقائمة، وسيستغرق الأمر زمنًا طويلًا. لحسن الحظ لدينا وضع يسمى "a" والذي نستطيع تمريره إلى open()، فيسمح لنا بإلحاق البيانات مباشرةً إلى ملف موجود بمجرد كتابتها، وإذا لم يكن الملف موجودًا، فسيُفتح ملف جديد كما لو كنا قد حددنا الوضع "w". لنفترض أن لدينا ملف سجل نستخدمه لالتقاط رسائل الخطأ، ولا نريد أن نحذف رسائل الخطأ الموجودة كلما جاءت رسالة جديدة، لذا يمكن إلحاق الخطأ في الملف كما يلي: def logError(msg): err = open("Errors.log","a") err.write(msg) err.close() قد نرغب -من الناحية العملية- بتقييد حجم الملف بشكل ما، والتقنية الشائعة لذلك هي إنشاء اسم ملف مبني على التاريخ، فإذا تغير التاريخ فسننشئ ملفًا جديدًا، مما يسهل على مشرفي النظام أن يجدوا أخطاء يوم بعينه، وأرشفة ملفات الأخطاء القديمة إذا لم نعد بحاجة إليها. تذكر أن وحدة time من مثال القائمة أعلاه يمكن استخدامها لإيجاد التاريخ الحالي. بنية With في بايثون قدم الإصدار الثالث من بايثون طريقةً جديدةً سهلةً للعمل مع الملفات، لا سيما عند التكرار على محتوياتها، وتستخدم هذه الطريقة بنيةً جديدةً اسمها with، بالشكل التالي: with open('Errors.log',"r") as inp: for line in inp: print( line ) لاحظ أننا لم نستخدم close()، إذ تضمن with إغلاق الملف في نهايتها، وهكذا يكون التعامل مع الملفات أكثر موثوقيةً، وهذه الطريقة هي التي يُنصح بها لفتح الملفات في الإصدار الثالث من بايثون، وقد اخترنا استخدام الأسلوب القديم open/close لأن أغلب لغات البرمجة تستخدمه، وهو أكثر وضوحًا وصراحةً من أسلوب with، لكن إذا أردت أن تستخدم بايثون خاصةً فمن الأفضل استخدام with. بعض العثرات في أنظمة التشغيل تتعامل أنظمة التشغيل مع الملفات بطرق مختلفة، مما قد يسبب مشاكل في برامجنا إذا أردناها أن تعمل على عدة أنظمة تشغيل، ونخص بالذكر منها مشكلتين اثنتين: الأسطر الجديدة تشكل الملفات النصية والأسطر الجديدة منطقةً غامضةً تختلف فيها أنظمة التشغيل من حيث كيفية تنفيذها، وتمتد جذور تلك الاختلافات إلى الأيام الأولى لتواصل البيانات والتحكم في الآلات الكاتبة البرقية teleprinters الميكانيكية، وملخص الأمر أن لدينا ثلاثة طرق مختلفة للإشارة إلى السطر الجديد: \r: محرف إعادة العربة (CR: Carriage Return). \n: محرف تغذية السطر (LF: Line Feed). \r\n زوج CR/LF. تُستخدم التقنيات الثلاث في أنظمة تشغيل مختلفة، فنظام MS DOS مثلًا -وويندوز بالتبعية- يستخدم التقنية الثالثة، أما يونكس -بما في ذلك لينكس- فيستخدم الطريقة الثانية، بينما تستخدم أبل الطريقة الأولى في نظام ماك أو إس القديم، وتستخدم الطريقة الثانية في نظام MacOS X وما بعده بما أن هذا النظام ما هو إلا يونكس. وعلى المبرمج أن يجري اختبارات كثيرةً ويتخذ إجراءات مختلفةً لكل نظام تشغيل، ليتعامل مع هذا التعدد لنهايات الأسطر. لكن اللغات الحديثة -بما في ذلك بايثون- توفر تسهيلات للتعامل مع هذه الفوضى بالنيابة عنا، وتحل بايثون هذه المشكلة في وحدة os التي تعرّف متغيرًا اسمه linesep يُضبط على محرف السطر الجديد الذي يستخدمه نظام التشغيل، مما يسهل عملية إضافة الأسطر الجديدة، كما ينتبه التابع rstrip() إلى نظام التشغيل عندما يحذف هذه المحارف، وهكذا نستخدم هذا التابع لنريح أنفسنا من عناء التفكير في الأسطر الجديدة التي تُحذف من الأسطر المقروءة من الملف، كما نضيف os.linesep إلى السلاسل النصية التي تُكتب إلى الملف. فإذا أنشأنا ملفًا على نظام تشغيل ثم عالجناه على نظام تشغيل آخر غير متوافق مع الأول، فلا نستطيع إلا أن نوازن نهاية السطر مع os.linesep لنعرف الفرق. تحديد المسارات هذه المشكلة تخص مستخدمي ويندوز أكثر من غيرهم، فقد ذكرنا سابقًا أن كل نظام تشغيل يحدد مسارات الملفات باستخدام محارف مختلفة لفصل الأقراص والمجلدات والملفات عن بعضها، وأن الحل العام لهذا هو استخدام وحدة os التي توفر متغير os.sep لتعريف محرف فصل المسار الخاص بالمنصة الحالية، ولن نحتاج إلى ذلك كثيرًا في المواقف العملية، لأن المسار سيختلف لكل حاسوب على أي حال، لذا سنُدخِل المسار الكامل مباشرةً في سلسلة نصية -ربما سلسلة لكل نظام تشغيل نعمل عليه-، لكن لهذا عقبة كبيرة بالنسبة لمستخدمي ويندوز، فقد رأينا في القسم السابق أن بايثون تتعامل مع السلسلة '\n' على أنها محرف السطر الجديد، أي أنها تأخذ محرفين وتعاملهما مثل محرف واحد، ولدينا كثير من مثل هذه التسلسلات الخاصة من المحارف التي تبدأ بشرطة مائلة خلفية \، ومنها: \n: سطر جديد. \r: إعادة العربة. \t: جدول أفقي. \v: جدول رأسي، يعني أحيانًا صفحةُ جديدة. \b: زر backspace. \0nn: أي شيفرة ثمانية عشوائية، مثل \033 التي تشير إلى زر الهروب Esc. فإذا كان لدينا ملف اسمه test.dat ونريد فتحه في بايثون من خلال تحديد مسار ويندوز كامل، فستكون الشيفرة: >>> f = open('C:\test.dat') لكن ما يحدث هو أن بايثون سترى الزوج \t على أنه محرف جدول وستخبرنا أنها لا تستطيع إيجاد ملف باسم 😄 est.dat، ولحل هذه المشكلة لدينا ثلاث طرق، هي: نضع r أمام السلسلة النصية، لنخبر بايثون أن تتجاهل أي شرطة مائلة خلفية، وتعاملها على أنها سلسلة نصية خام. نستخدم شرطات مائلة أمامية / بدلًا من الخلفية، وستتوافق بايثون مع ويندوز ليخرجا لنا المسار، وهذا الحل يجعل الشيفرة قابلةً للعمل على أنظمة التشغيل الأخرى. استخدام شرطتين خلفيتين \\ بما أن بايثون ترى محرفي الشرطتين المزدوجتين على أنهما شرطة خلفية واحدة. وعلى ذلك سيفتح أي سطر مما يلي ملف البيانات الخاص بنا بشكل سليم: >>> f = open(r'C:\test.dat') >>> f = open('C:/test.dat') >>> f = open('C:\\test.dat') لاحظ أن هذه المشكلة مقصورة على السلاسل المجردة التي نكتبها في شيفرة برنامجنا، أما إذا قرئت سلاسل المسار من ملف أو من المستخدم، فستفسر بايثون محارف \ وتستخدمها كما هي دون مشاكل. دليل جهات الاتصال لقد كتبنا دليل جهات اتصال في مقال البيانات وأنواعها، ثم زدنا عليه وطورناه في فصل قراءة البيانات من المستخدم، وسنجعله في هذا المقال تطبيقًا مفيدًا بحفظه في ملف، إلى جانب قراءة ذلك الملف عند بدء التشغيل، وبما أننا سنفعل ذلك من خلال كتابة بعض الدوال، فسنستخدم بعضًا مما شرحناه في المقالات السابقة من هذه السلسلة. سيحتاج التصميم الأولي دالةً لقراءة الملف عند بدء التشغيل، ودالةً أخرى عند نهاية البرنامج، كما سننشئ دالةً تزود المستخدم بقائمة من الخيارات، ودالةً مستقلة لكل خيار في تلك القائمة، ستسمح القائمة للمستخدم بما يلي: إضافة مدخل في دليل جهات الاتصال. حذف مدخل منه. البحث عن مدخل موجود من قبل وعرضه. الخروج من البرنامج. تحميل دليل جهات الاتصال import os filename = "addbook.dat" def readBook(book): if os.path.exists(filename): with open(filename,'r') as store: for line in store: name = line.rstrip() entry = next(store).rstrip() book[name] = entry نلاحظ هنا أننا نستورد الوحدة os التي نستخدمها للتحقق من أن مسار الملف موجود قبل فتحه، ونعرِّف اسم الملف مثل متغير مستوى وحدة module level variable لنستخدمه في تحميل البيانات وحفظها. سنستخدم أيضًا rstrip() لحذف محرف السطر الجديد من نهاية السطر، ودالة next() التي تجلب السطر التالي من الملف إلى داخل الحلقة، وهذا يعني أننا نقرأ سطرين في نفس الوقت أثناء عمل الحلقة، ودالة next هي جزء من خاصية في بايثون تسمى بالمكرر، وهي خاصية لن نشرحها في هذه السلسلة بما أنها خاصة ببايثون كلغة برمجة، لكننا سنقول أن كل تجميعات بايثون وملفاتها وبعض الأمور الأخرى يُنظر إليها على أنها مكرَّرات أو أنواع قابلة للتكرار، ويمكن معرفة المزيد عن هذه الخاصية في توثيق بايثون. حفظ دليل جهات الاتصال def saveBook(book): with open(filename, 'w') as store: for name,entry in book.items(): store.write(name + '\n') store.write(entry + '\n') لاحظ أننا نحتاج إلى إضافة محرف السطر الجديد '\n' عندما نكتب البيانات، وأننا نكتب سطرين لكل إدخال، فهذا يعكس حقيقة أننا عالجنا سطرين عند قراءة الملف. الحصول على مدخلات المستخدم def getChoice(menu, length): print( menu ) prompt = "Select a choice(1-%d): " % length choice = int( input(prompt) ) return choice نلاحظ أننا نستقبل معامِل طول يخبرنا عدد المداخل الموجودة، مما يسمح لنا بإنشاء محث يحدد نطاق الأعداد المناسب. إضافة مدخل def addEntry(book): name = input("Enter a name: ") entry = input("Enter street, town and phone number: ") book[name] = entry حذف مدخل def removeEntry(book): name = input("Enter a name: ") del(book[name]) العثور على مدخل def findEntry(book): name = input("Enter a name: ") if name in book: print( name, book[name] ) else: print( "Sorry, no entry for: ", name ) الخروج من البرنامج لن نكتب دالةً مستقلةً للخروج من البرنامج، بل سنجعل خيار الإنهاء اختبارًا في حلقة while الخاصة بالقائمة، لذا سيكون البرنامج الرئيسي كما يلي: def main(): theMenu = ''' 1) إضافة مدخل 2) حذف مدخل 3) العثور على مدخل 4) الخروج والحفظ ''' theBook = {} readBook(theBook) while True: choice = getChoice(theMenu, 4) if choice == 4: break if choice == 1: addEntry(theBook) elif choice == 2: removeEntry(theBook) elif choice == 3: findEntry(theBook) else: print( "Invalid choice, try again" ) saveBook(theBook) لم يبق الآن إلا استدعاء main() عند تشغيل البرنامج، وهنا سنستخدم القليل من سحر بايثون: if __name__ == "__main__": main() تسمح لنا هذه الشيفرة الغامضة باستخدام أي ملف بايثون مثل وحدة، وذلك باستيراده import أو مثل برنامج عبر تشغيله، والفرق هنا هو أن بايثون تضبط المتغير الداخلي __name__ عند استيراد البرنامج على اسم الوحدة، لكن إذا شغّلنا الملف مثل برنامج، فستُضبط قيمة __name__ على "__main__"، هذا يعني أن دالة main() لا تُستدعى إلا إذا شغلنا الملف مثل برنامج وليس عند استيراده. إذا كتبنا هذه الشيفرة في ملف نصي وحفظناه باسم addressbook.py، فيجب أن يكون قابلًا للتشغيل في أي محث لنظام تشغيل بكتابة ما يلي: C:\PROJECTS> python addressbook.py أو بالنقر المزدوج عليه مثل أي ملف في مدير الملفات في ويندوز، ليشغَّل في نافذة CMD خاصة به، تُغلَق عند تحديد خيار الإغلاق، أو باستخدام ما يلي في لينكس: $ python addressbook.py يُعَد هذا البرنامج المكون من ستين سطرًا نموذجًا لما يجب أن تكون قادرًا على كتابته الآن بنفسك، وهو أداة مفيدة على حالته تلك، رغم أننا سنضيف إليه بعض الأشياء التي ستحسّنه في المقال التالي. جافاسكربت وVBScript ليس لدى جافاسكربت وVBScript القدرة على معالجة الملفات، وذلك لمنع أي أحد من قراءة ملفاتك عند تحميلك لصفحة ويب مثلًا، لكن هذا يقيد فائدة اللغة نفسها ونطاق استخدامها من ناحية أخرى. توجد طريقة لجعلهما تعالجان الملفات باستخدام WSH كما فعلنا في الوحدات القابلة لإعادة الاستخدام من قبل، إذ توفر WSH كائن FileSystem يسمح لأي لغة WSH بقراءة الملفات. سننظر في مثال جافاسكربت بالتفصيل، ثم نعرض شيفرةً مشابهةً من لغة VBScript من أجل الموازنة بينهما، وكما رأينا من قبل فإن العناصر الأساسية ما هي إلا استدعاءات لكائنات WScript. لربما يجب أن نشرح نموذج الكائن FileSystem قبل أن ننظر في الشيفرة، فنموذج الكائن هو مجموعة من الكائنات المرتبطة ببعضها، والتي يمكن للمبرمج استخدامها. يتكون نموذج كائن FileSystem من كائن FSO وعدد من كائنات File، بما في ذلك كائن TextFile الذي سنستخدمه، كما توجد بعض الكائنات المساعدة مثل TextStream. ما سنفعله هنا هو إنشاء نسخة من كائن FSO ثم نستخدمها لإنشاء كائنات TextFile، ثم ننشئ كائنات TextStream كي نستطيع قراءة النصوص فيها وكتابتها أيضًا، كذلك فكائنات TextStream نفسها هي التي نقرؤها من الملفات أو نكتبها. اكتب الشيفرة أدناه في ملف باسم testFiles.js وشغله باستخدام cscript كما ذكرنا في قسم WSH من المقال السابق. فتح ملف يجب أن ننشئ كائن FSO أولًا، ثم ننشئ كائن TextFile منه كي نتمكن من فتح ملف في WSH: var fileName, fso, txtFile, outFile, line; // احصل على اسم الملف fso = new ActiveXObject("Scripting.FileSystemObject"); WScript.Echo("What file name? "); fileName = WScript.StdIn.Readline(); // للقراءة inFile افتح // للكتابة outFile افتح inFile = fso.OpenTextFile(fileName, 1); // mode 1 = Read fileName = fileName + ".BAK" outFile = fso.CreateTextFile(fileName); إغلاق الملفات inFile.close(); outFile.close(); شرح المثال في VBScript احفظ ما يلي في testFiles.ws وشغله باستخدام: cscript testfiles.ws أو ضع الجزء الذي بين وسوم script في ملف باسم testFile.vbs وشغله، حيث تسمح صيغة ws. بدمج شيفرة جافاسكربت وVBScript في نفس الملف باستخدام عدة وسوم script: <?xml version="1.0"?> <job> <script type="text/vbscript"> Dim fso, inFile, outFile, inFileName, outFileName Set fso = CreateObject("Scripting.FileSystemObject") WScript.Echo "Type a filename to backup" inFileName = WScript.StdIn.ReadLine outFileName = inFileName & ".BAK" ' open the files Set inFile = fso.OpenTextFile(inFileName, 1) Set outFile = fso.CreateTextFile(outFileName) ' read the file and write to the backup copy Do While not inFile.AtEndOfStream line = inFile.ReadLine outFile.WriteLine(line) Loop ' close both files inFile.Close outFile.Close WScript.Echo inFileName & " backed up to " & outFileName </script> </job> التعامل مع الملفات غير النصية يُعَد التعامل مع الملفات النصية أكثر ما يفعله المبرمج، غير أننا قد نحتاج إلى معالجة بيانات ثنائية أحيانًا، وسنشرح هذا الجزء في بايثون فقط لندرة حدوثه في جافاسكربت وVBScript. الترميز الثنائي للبيانات يجب أن ننظر في كيفية تمثيل البيانات وتخزينها على الحاسوب قبل أن نتحدث عن كيفية الوصول إليها داخل ملف ثنائي، حيث تُخزَّن البيانات في هيئة تسلسلات من الأرقام الثنائية أو البتات، والتي تُجمع في مجموعات من 8 بتات تسمى البايت، أو 16بتًا تسمى الكلمة، في حين أن المجموعة التي تتكون من 4 بتات تسمى أحيانًا بالحلمة. قد يكون للبايت الواحد نمط من 256 نمط للبتات، وتعطى هذه الأنماط قيمًا من 0 إلى 255، كما يجب أن تُحوَّل المعلومات التي نعالجها في برامجنا من سلاسل نصية وأعداد وغيرها إلى سلاسل من تلك البايتات، لذا يخصَّص نمط بايت معين لكل محرف نستخدمه في السلاسل النصية، ورغم وجود عدة نظم ترميز للبيانات، إلا أن أشهرها هو ترميز آسكي ASCII، لكن هذا الترميز لا يحوي إلا 128 محرفًا فقط، وهذا بالكاد يكفي للغة الإنجليزية فقط، لذا طوِّر معيار ترميز جديد سمي بالترميز الموحد أو اليونيكود Unicode، والذي يَستخدم كلمات البيانات لتمثيل المحارف بدلًا من البايتات، ويشتمل على أكثر من مليون محرف، ثم يمكن بعد ذلك ترميز تلك المحارف في مجرى بيانات مضغوط أكثر. إن أكثر ترميزات اليونيكود شيوعًا هو UTF-8، ويتوافق توافقًا كبيرًا مع آسكي، بحيث أن أي ملف متوافق مع آسكي يتوافق أيضًا مع UTF-8، رغم أن العكس قد لا يكون صحيحًا. يوفر اليونيكود عددًا من الترميزات التي يعرِّف كل منها البايت الذي يمثل قيمةً عدديةً من اليونيكود، أو "نقطةً رمزيةً" وفق اصطلاح اليونيكود. وهذا النظام المعقد هو الثمن الذي كان يجب دفعه من أجل بناء شبكة حواسيب عالمية تعمل بمختلف اللغات التي يستخدمها البشر، لكن المتحدثين بالإنجليزية لم يكن عليهم القلق بشأن اليونيكود إلا عند قراءة البيانات من ملف ثنائي، على الرغم من أن الإصدار الثالث لبايثون يَعُد السلاسل النصية سلاسل يونيكود، لذا يجب أن نعلم الترميز المستخدم من أجل تفسير البيانات الثنائية تفسيرًا صحيحًا. تدعم بايثون نصوص اليونيكود دعمًا كاملًا، فتنظر إلى سلسلة المحارف المرمَّزة على أنها سلسلة بايتات لها النوع bytes، بينما يكون للسلسلة غير المرمزة النوع str، ويكون الترميز الافتراضي هو UTF-8، ولهذا بعض شواذ، نظريًا على الأقل، ولن نشرح استخدام المحارف التي ليست UTF-8 في هذه السلسلة، لكن يمكن مراجعة مستند How-To في موقع بايثون. ما نريد الإشارة إليه من كل هذا هو أن المجرى الثنائي لنص اليونيكود المرمَّز يعامَل مثل سلسلة من البايتات، وتوفر بايثون دوالًا لتحويل (أو فك ترميز) قيم bytes لتكون قيم str، بالمثل يجب أن تحوَّل الأعداد إلى ترميزات ثنائية أيضًا، فعلى الرغم من أن قيم البايتات تكفي في حالة الأعداد الصغيرة، إلا أن الأعداد الأكبر من 255 أو الأعداد السالبة أو الكسور تحتاج إلى عمل آخر، وقد ظهرت عدة ترميزات معيارية للبيانات العددية، والتي تستخدمها أغلب لغات البرمجة ونظم التشغيل، فمثلًا: يعرِّف المعهد الأمريكي للهندسة الكهربية والإلكترونية IEEE عدة ترميزات للأعداد ذات الفاصلة العائمة floating point numbers، وتهدف هذه الجهود إلى حل مشكلة التفسير الصحيح للبيانات الثنائية، فمن المهم للغاية أن نحولها إلى النوع الصحيح عند قراءتها، بما أنه يتعين علينا تفسير أنماط البتات الخام إلى النوع الصحيح المناسب للبرنامج الذي نعمل عليه، وعلى ذلك من الممكن أن نفسر مجرى بيانات كُتب أصلأ على أنه سلسلة نصية في صورة مجموعة من الأعداد ذات الفاصلة العائمة، ورغم أن المعنى الأصلي له سيُفقد، إلا أن أنماط البتات يمكن أن تمثل أي واحد منهما. فتح الملفات الثنائية وإغلاقها يتمثل الفرق الجوهري بين الملفات النصية والثنائية في أن الملفات النصية تتكون من ثمانيات octets -جمع ثُماني، وهو الشيء المكون من ثمانية أجزاء-، لكن الاسم الأشهر لها هو بايتات، ويمثل كل بايت حرفًا. تُحدَّد نهاية الملف بنمط بايت خاص يُعرف باسم EOF، وهو اختصار لعبارة نهاية الملف End Of File؛ بينما يحتوي الملف الثنائي على بيانات ثنائية عشوائية، ومن ثم لا يمكن استخدام قيمة بعينها لتحديد نهاية الملف، لذا نحتاج إلى وضع عمليات مختلف لقراءة تلك الملفات، فعند فتح ملف ثنائي في بايثون أو في أي لغة أخرى، فيجب أن نحدد أنه يُفتَح في الوضع الثنائي، أو المخاطرة بقطع البيانات التي نقرؤها عند أول محرف eof تجده بايثون في تلك البيانات. يمكن تنفيذ ذلك في بايثون بإضافة b إلى معامِل الوضع mode parameter كما يلي: binfile = open("aBinaryFile.bin","rb") لا يختلف هذا عن فتح ملف نصي إلا في قيمة الوضع "rb"، ونستطيع استخدام أي وضع آخر، لكن مع إضافة حرف b، فنستخدم "wb" للكتابة، و"ab" للإلحاق، كما لا يختلف إغلاق الملف الثنائي عن الملف النصي، فنستدعي التابع close() لكائن الملف المفتوح: binfile.close() وبما أننا فتحنا الملف في الوضع الثنائي، فلا داعي لإعطاء بايثون أي معلومات إضافية، فهي تعرف كيف تغلق الملف. الوحدة struct توفّر بايثون وحدةً اسمها struct لترميز البيانات الثنائية وفك ترميزها، وهي تتصرف مثل سلاسل التنسيق التي استخدمناها لطباعة البيانات المختلطة، إذ توفر سلسلةً تمثل البيانات التي نقرؤها وتطبقها على مجرى البايتات الذي نحاول تفسيره، ومن الممكن استخدام هذه الوحدة لتحويل مجموعة من البيانات إلى مجرى البايت للكتابة، إما إلى ملف ثنائي أو حتى خط اتصالات communications line. هناك الكثير من رموز تنسيق التحويل المختلفة، لكننا لن نستخدم إلا رموز الأعداد الصحيحة integers والسلاسل النصية strings هنا؛ أما البقية فيمكن قراءة المزيد عنها في توثيق بايثون الرسمي. إن رمز تنسيق التحويل للأعداد الصحيحة هو i، ورمز السلاسل النصية s، وتتكون سلاسل تنسيق الوحدة struct من سلاسل من الرموز فيها أرقام مسبقة التعليق pre-pended، حيث توضح عدد العناصر التي نحتاج إليها، مع استثناء لرمز s الذي يشير العدد مسبق التعليق فيه إلى طول السلسلة النصية، حيث تعني 4s مثلًا سلسلةً من أربعة محارف (أربعة محارف وليس أربعة سلاسل نصية). لنفترض أننا نريد كتابة تفاصيل العنوان، في برنامج دليل جهات الاتصال الذي شرحناه أعلاه، في صورة بيانات ثنائية، حيث يكون رقم الشارع فيها عددًا صحيحًا والبقية سلسلةً نصيةً. رغم أن هذا الاختيار سيء لأن أرقام الشوارع تتضمن حروفًا أحيانًا، إلا أن سلسلة التنسيق ستكون كما يلي: 'i34s' # نفترض وجود 34 محرف في العنوان ولكي نعالج مسألة الأطوال المختلفة للعناوين، فسنكتب دالةً تنشئ السلسلة الثنائية كما يلي: def formatAddress(address): fields = address.split() number = int(fields[0]) rest = bytes(' '.join(fields[1:],'utf8') # أنشئ سلسلة بايت format = "i%ds" % len(rest) # أنشئ سلسلة التنسيق return struct.pack(format, number, rest) لقد استخدمنا تابع السلسلة split() أعلاه لتقسيم سلسلة العنوان النصية إلى أجزائها، وقسمناها في حالتنا إلى قائمة من الكلمات، ثم استخرجنا الجزء الأول ليكون رقم الشارع، بعد ذلك استخدمنا تابع سلسلةٍ نصية آخر هو join لدمج الحقول المتبقية معًا مع الفصل بينها بمسافة. كذلك نحتاج إلى تحويل السلسلة النصية إلى مصفوفة bytes لأن هذا هو ما تستخدمه وحدة srtuct، ويكون طول تلك السلسلة هو ما نحتاج إليه في سلسلة تنسيق struct، لذا نستخدم دالة len() بالتوازي مع سلسلة تنسيق عادية لبناء سلسلة تنسيق struct. ستعيد formatAddress() تسلسلًا من البايتات يحتوي على التمثيل الثنائي لعنواننا، وبما أن لدينا البيانات الثنائية فسنرى كيف نستطيع كتابتها إلى ملف ثنائي، ثم قراءتها مرةً أخرى. القراءة والكتابة باستخدام struct لننشئ ملفًا ثنائيًا يحتوي على سطر عنوان واحد باستخدام الدالة formatAddress() المعرَّفة أعلاه، وهنا سنحتاج إلى فتح الملف للكتابة في وضع 'wb'، وترميز البيانات وكتابتها إلى الملف، ثم إغلاق الملف. import struct f = open('address.bin','wb') data = "10 Some St, Anytown, 0171 234 8765" bindata = formatAddress(data) print( "Binary data before saving: ", repr(bindata) ) f.write(bindata) f.close() نستطيع التحقق من أن البيانات في صورة ثنائية بفتح address.bin في محرر نصي، وسنرى حينها أن المحارف لا زالت قابلةً للقراءة لكن الرقم اختفى، فإذا فتحنا الملف في محرر نصي يدعم الملفات الثنائية مثل ViM أو Emacs، فسنجد أن بداية الملف فيها 4 بايت، حيث سيبدو الأول منها مثل محرف سطر جديد، أما البقية فتبدو أصفارًا، وذلك لأن القيمة العددية للسطر الجديد هي 10، كما نرى هنا باستخدام بايثون: >>> ord('\n') 10 تعيد الدالة ord() في هذا المثال القيمة العددية لأي محرف، لذا فإن أول أربعة بايتات هي 10,0,0,0 في النظام العشري، أو 0xA,0x0,0x0,0x0 في النظام الست عشري، وهو النظام المستخدم عادةً في عرض البيانات الثنائية بما أنه أكثر اختصارًا من استخدام الأرقام الثنائية الخالصة. يُأخذ العدد الصحيح في حاسوب ذي معمارية 32 بت أربعة بايتات، لذا فإن القيمة العددية "10" قد حُولت بواسطة وحدة struct إلى تسلسل من 4 بايتات هو 10,0,0,0. وتضع معالجات إنتل البايت الأقل أهميةً في البداية، وهنا سنحصل على القيمة الثنائية الحقيقية من خلال قراءة التسلسل عكسيًا 0,0,0,10، وهي القيمة الصحيحة 10 ممثلةً بأربعة بايتات عشرية؛ أما بقية البيانات فهي السلسلة النصية الأصلية، لذا تظهر بصيغتها المحرفية العادية. يجب الانتباه إلى عدم حفظ الملف من داخل محرر Notepad، فرغم أنه يستطيع تحميل بعض الملفات الثنائية، إلا أنه لا يستطيع حفظ الملفات الثنائية، لذا سيحول القيم الثنائية إلى نصوص، مما سيؤدي إلى تخريب البيانات الحقيقية. لم يكن امتداد الملف الذي استخدمناه .bin إلا للشرح، إذ ليس له تأثير حقيقي في كون الملف نصيًا أم ثنائيًا، وتستخدم بعض أنظمة التشغيل هذه الامتدادات لتحديد البرنامج الذي يفتح الملفات، لكن يمكن تغيير الامتداد بإعادة تسمية الملف ببساطة، ولن يتغير المحتوى الذي فيه، إذ سيظل ثنائيًا أو نصيًا كما كان، فإذا أعدنا تسمية ملف نصي بحيث نجعل امتداده .exe مثلًا، فسيعامله ويندوز على أنه ملف ثنائي تنفيذي، لكننا سنحصل على خطأ عند محاولة تشغيله مثل ملف تنفيذي، وذلك لأن النص الموجود فيه ليس شيفرةً ثنائيةً تنفيذية، فإذا أرجعناه إلى التسمية الأصلية له ثم فتحناه في Notepad، فسنجده كما كان قبل التسمية بالضبط، بل لو فتحناه في Notepad أثناء تسميته بامتداد .exe لفتحه المحرر مثل ملف نصي أيضًا. نحتاج إلى أن فتح الملف في وضع rb لقراءة بياناتنا الثنائية مرةً أخرى، فنقرأ البيانات في تسلسل من البايتات ثم نغلق الملفK ونفك البيانات باستخدم سلسلة تنسيق struct. سيبقى السؤال هنا حول كيفية معرفة شكل سلسلة التنسيق، والإجابة هنا هي أننا نحتاج إلى إيجاد السلسلة الثنائية من تعريف الملف، وتوفر عدة مواقع على الويب هذه المعلومات، فشركة أدوبي مثلًا تنشر تعريف تنسيقها الثنائي لصيغة PDF الخاصة بها، وفي حالتنا هذه سنعرف أنها يجب أن تكون السلسلة التي أنشأناها في formatAddress()، وهي 'iNs'، حيث N رقم متغير. توفر وحدة struct بعض الدوال المساعدة التي تعيد حجم كل نوع من أنواع البيانات، لذلك فإن شغلنا محث بايثون وأجرينا بعض التجارب، فسنستطيع معرفة عدد بايتات البيانات التي سنحصل عليها لكل نوع بيانات، وهكذا نستطيع تحديد قيمة N: >>> import struct >>> print struct.calcsize('i') 4 >>> print struct.calcsize('s') 1 وبما أننا نعرف أن بياناتنا ستترك 4 بايتات للعدد وبايتًا واحدًا لكل محرف، فستكون N هي إجمالي طول البيانات ناقصًا منه 4، لنجرب استخدام هذا لقراءة ملفنا: import struct f = open('address.bin','rb') data = f.read() f.close() fmtString = "i%ds" % (len(data) - 4) number, rest = struct.unpack(fmtString, data) rest = rest.decode('utf8') #convert bytes to string address = ' '.join((str(number),rest)) print( "Address after restoring data:", address ) لاحظ أننا اضطررنا إلى تحويل rest إلى سلسلة نصية باستخدام دالة decode() لأن بايثون رأتها من النوع bytes الذي لن يعمل مع join(). وهكذا نكون قد شرحنا ملفات البيانات الثنائية بما يكفي في هذا المقال، وقد بينا أنها تأتي بعدة تعقيدات، ولا ننصح باستخدامها ما لم يكن ثمة سبب مقنع، لكن هذا الشرح كاف لتستطيع قراءة الملفات الثنائية عند الحاجة إلى ذلك، طالما عرفت ما هي البيانات الممثلة في تلك الملفات ابتداءً. الوصول العشوائي إلى الملفات يشير الوصول العشوائي إلى التحرك مباشرةً إلى جزء بعينه من الملف، دون قراءة البيانات التي بين نقطة البدء والبيانات المطلوبة، وتوفر بعض لغات البرمجة نوع ملف مفهرس خاص يستطيع فعل ذلك بسرعة عالية، لكنه مبني في أغلب اللغات على الوصول المتتابع للملفات، الذي كنا نستخدمه منذ بداية هذه السلسلة إلى الآن. يقوم الوصول العشوائي على مفهوم مؤشر يشير إلى الموضع الحالي في الملف، أي عدد البايتات التي تفصلنا عن البداية حرفيًا، ونستطيع تحريك هذا المؤشر بالنسبة إلى موضعه الحالي أو نسبةً إلى بداية الملف، كما نستطيع أن نطلب من الملف أن يخبرنا بالمكان الحالي للمؤشر. ونستخدم طول سطر ثابت -ربما بحشو سلاسل البيانات الخاصة بنا بمسافات أو بعض المحارف الأخرى عند الحاجة- كي نقفز إلى بداية سطر ما، من خلال ضرب طول السطر بعدد الأسطر، وهذا ما يوحي بالوصول العشوائي للبيانات في الملف. أين أنا؟ لتحديد مكاننا في ملف ما نستخدم التابع tell() الخاص بالملف، فإذا فتحنا ملفًا وقرأنا ثلاثة أسطر، فعندها سنستطيع أن نسأل الملف حينها كم قرأنا من الملف حتى الآن. لننظر في مثال ليتضح المعنى، حيث سننشئ ملفًا بخمسة أسطر نصية لها نفس الطول -وتساوي الطول هنا ليس ضروريًا وإنما هو لتوضيح المثال-، بعدها سنقرأ ثلاثة أسطر ونسأل أين نحن، ثم نعود إلى البداية ونقرأ سطرًا واحدًا ونقفز إلى السطر الثالث ونطبعه، ثم نعود إلى السطر الثاني، كما يلي: # (+ \n) أنشئ 5 أسطر من عشرين محرفًا testfile = open('testfile.txt','w') for i in range(5): testfile.write(str(i) * 20 + '\n') testfile.close() # اقرأ ثلاثة أسطر واسأل أين نحن testfile = open('testfile.txt','r') for line in range(3): print( testfile.readline().strip() ) position = testfile.tell() print( "At position: ", position, "bytes" ) # عد إلى البداية testfile.seek(0) print( testfile.readline().strip() ) # كرر السطر الأول lineLength = testfile.tell() testfile.seek(2*lineLength) # اذهب إلى نهاية السطر 2 print( testfile.readline().strip() ) # السطر الثالث testfile.close() لقد استخدمنا الدالة seek() لتحريك المؤشر، والعملية الافتراضية هنا هي تحريكه إلى رقم البايت المحدد كما رأينا هنا، لكن يمكن إضافة وسطاء آخرين لتغيير تابع الفهرسة المستخدم. لاحظ أيضًا أن القيمة التي طبعتها tell() الأولى تعتمد على طول السطر الجديد على نظامك، فنظام وندوز 10 مثلًا يطبع 66 ليشير إلى أن تسلسل السطر الجديد طوله 2 بايت، لكن بما أن هذه القيمة تتوقف على نظام التشغيل ونحن نريد أن نجعل الشيفرة محمولةً قدر الإمكان؛ فقد استخدمنا tell() مرةً ثانيةً بعد قراءة سطر واحد لحساب طول كل سطر، وسترى أن مثل تلك الحيل ضرورية عند التعامل مع مشاكل المنصات المختلفة. خاتمة في نهاية هذا المقال نرجو أن تكون تعلمت ما يلي: ضرورة فتح الملفات قبل استخدامها. قراءة الملفات أو الكتابة فيها، إذ لا يمكن تنفيذ العمليتين معًا. الدالة readlines() في بايثون التي تقرأ جميع الأسطر الموجودة في ملف ما، والدالة readline() التي تقرأ سطرًا واحدًا في كل مرة، وهذا يوفر في الذاكرة. عدم الحاجة إلى استخدام أي من الدالتين السابقتين بما أن دالة open الخاصة ببايثون تعمل مع حلقات for. ضرورة غلق الملفات بعد استخدامها. ضرورة إضافة b إلى نهاية راية الوضع mode flag الخاصة بالملفات الثنائية، وتحتاج البيانات إلى تفسير بعد قراءتها، وذلك بواسطة وحدة struct عادةً. تفعّل كل من tell() وseek() الوصول شبه العشوائي pseudo-random إلى الملفات متسلسلة الوصول sequential files. ترجمة -بتصرف- للفصل الثاني عشر: Handling Files من كتاب Learning To Program لصاحبه Alan Gauld. اقرأ أيضًا المقال التالي: كيفية التعامل مع النصوص في البرمجة المقال السابق: البرمجة باستخدام الوحدات تعلم البرمجة ما هي البرمجة ومتطلبات تعلمها؟1 نقطة
-
السلام عليكم ورحمة الله تعالى وبركاته ..♥ اواجه مشكلة في فهم ال views في sql . المشكل ليس في الاستعلام نفسه وانما في المنطق ولماذا يتوجب علي استخدامها ؟ وهل تفيدني في الحماية وكيف ؟ وماهي باقي استخداماتها ؟ وشكرا لكل من افادني جزاكم الله خيرا والصلاة والسلام على حبيبنا ونبينا وقائدنا محمد صلوات ربي عليه1 نقطة
-
أريد جلب بيانات من جدولين موجودين في قاعدتي بيانات منفصلتين، هل يمكن تحقيق ذلك؟ كيق يتم ربط جدولين من قاعدتي بيانات1 نقطة
-
أريد عرض X معلومة من قاعدة البيانات في كل صفحة فكيف أستطيع التحكم بالجزء المطلوب وجلبه، أي تطبيق مبدأ skip / take1 نقطة
-
أريد شرح عن أداة puppet وكيف أستخدمها وارتباطها بمفهوم DevOps1 نقطة
-
لدي في الموقع العديد من ملفات الصور وأريد عمل تعديلات لها وتصغير حجمها وتعديلات أخرى كيف يمكن تطبيق أدوات المكتبة ImageMagick1 نقطة
-
لدي بيانات إحصائية وأريد تمثيلها بمخطط دائري لعرضها، هل هناك أداة في Matplotlib للقيام بذلك؟1 نقطة
-
كيف بدي اشترك بهاي الدورة او الاكاديمية ويصير الدفع برصيد الهاتف ا. بالدينار العراقي1 نقطة
-
أريد شرح عن أداة Docker وكيف أستخدمها وارتباطها بمفهوم DevOps1 نقطة
-
سلام عليكم .. لدي اسئله اتمنى الجواب عليه :- 1-هل الرياضيات تفيد في البرمجه ؟ 2-هل رياضيات تحل مشاكل البرمجه؟ 3-هل رياضيات لها اقسام خاصه بالبرمجه ؟ 4-هل تفيدني رياضيات ك مطور مواقع ؟ و شكراً لكمم ....1 نقطة
-
ماهو تحويل أوتسو و كيف نقوم باستخدامه لحساب قيمة العتبة للصورة الثنائية؟1 نقطة
-
الـ views أو العروض في SQL هي نوع من الجداول الافتراضية . تحتوي على صفوف وأعمدة مثلها مثل الجداول الحقيقية في SQL . بحيث يمكننا إنشاء العروض عن طريق تحديد حقول معينة من جدول واحد أو أكثر موجود في قاعدة البيانات الخاصة بنا . و لفهمها أكثر لنقم بفهم المثال التالي : ليكن لدينا جدول تفاصيل الطلاب students_details التالي : و ليكن لدينا جدول علامات الطلاب students_marks كالتالي : و لنقل أننا نريد إنشاء طريقة نقوم من خلالها بقراءة علامات الطلبة Mark و عناوينهم Address . واحدة من السبل لذلك هي في إنشاء العروض أو الـ Views .بحيث توفر تلخيصا لذلك في جدول افتراضي و لنقل أنه جدول بإسم students_extra_details . يمكننا إنشاء عرض ما باستخدام التعليمة CREATE VIEW مباشرة .بحيث يمكن إنشاء طريقة عرض إما من جدول واحد أو من عدة جداول بسياق عام كالتالي : CREATE VIEW view_name AS SELECT column1, column2..... FROM table1_name,table2_name , table3_name.... WHERE condition; أي : CREATE VIEW students_extra_details AS SELECT student_details.NAME, student_details.ADDRESS, student_marks.MARKS FROM student_details, student_marks WHERE student_details.NAME = student_marks.NAME; في ذاكرة الـ SQL قد تم إنشاء هاته الـ view كجدول افتراضي , يمكن معاملته كأي جدول SQL اخر . بشكل يبدوا كالتالي : الان لن نحتاج إلا لمعاملتها كجدول عادي تماما , فإستعلام القراءة SELECT مثلا يكون كالتالي : SELECT * FROM students_extra_details; و هكذا .. وراء ما يخفيه هذا الإستعمال المميزات و الفوائد التالية : الأمان و التغليف : بحيث يمكن إتاحة العروض للمستخدمين بينما لا يمكن الوصول إلى الجداول الأساسية بشكل مباشر . مما يعطي المستخدمين البيانات التي يحتاجون إليها فقط ، مع حماية البيانات الأخرى في نفس الجدول , لإستعمالها كشروط أو أغراض أخرى . كما أنها تعتبر طبقة تجريدية أو abstraction layer ، وهي تفعل ما تفعله أي طبقة تجريد جيدة ، بما في ذلك تغليف مخطط قاعدة البيانات وحمايتك من أية عواقب تنتج عن كون هيكلية قواعد البيانات مكشوفة . البساطة و الدلالية: يمكن استخدام العروض لإخفاء الاستعلامات المعقدة مثل إستعلامات الـ JOIN , فما الذي يبدوا أبسط برأيك , إنشاء طريقة عرض شاملة لكامل إستعمالاتك في التطبيق أم كتابة إستعلام JOIN كل مرة تحتاج القراءة من جدولين وفق شرط ما ؟ .. كما يمكن استخدامها لتوفير أسماء مستعارة بسيطة لأسماء الأعمدة لجعلها أكثر قابلية للتذكر أو دلالية ذات مغزى . مساحة تخزين بسيطة : بحيث تأخذ مساحة صغيرة جدًا للتخزين , فقاعدة البيانات تحتوي على تعريف العرض فقط ، وليس نسخة من جميع البيانات التي تقدمها و هذا شيء يقوم بإختصار الكثير . يمكنك القراءة أكثر عن العروض في سلسلة sql للمحترفين - مواضيع متفرقة في SQL .1 نقطة
-
سلام عليكم حاولت اعمل دالة تقوم بعمل insert للجدول المتصل مع db لكن عند التنفيذ node app.js لم يخرج اى نتيجة وحتى الصف لم يضاف فى الجدول المشكلة اين ؟ وهذه هى ملفات المشروع : 1- app.js var mysql = require('mysql'); var con = mysql.createConnection({ host: "localhost", user: "root", port: "4000", password: "admin", database: "javatpoint" }); // Function to insert single row values in // the database let singleRowInsert = () => { let query = `INSERT INTO employees (id,name,age,city) VALUES (?,?,?,?);`; // Value to be inserted let userName = '7'; let userAddres = 'My Addres'; let userAddre = '16'; let userAddr = 'MhAddress'; // Creating queries con.query(query, [userName, userAddres,userAddre,userAddr], (err, rows) => { if (err) throw err; console.log("Row inserted with id = " + rows.insertId); }); }; 2- index.js const express = require("express"); const database = require('./app'); const app = express(); app.listen(5000, () => { console.log(`Server is up and running on 5000 ...`); }); // Use Route Function from below Examples Here... app.get("/", (req, res) => { // Call Route Function Here... });1 نقطة
-
أنت تقوم بتنفيذ الملف app.js يوجد فيه فقط انشاء الاتصال وتعريف للتابع singleRowInsert، قم باستدعاء تلك الدالة بعد تعريفها ليتم تنفيذ استعلام الإدخال على الجدول let singleRowInsert = () => { // ... }; // تنفيذ التابع singleRowInsert()1 نقطة
-
كيفية تحويل مصفوفة الى ملف json بدون اضافة رقم الفهرس في php مثلا المصفوفة [ 0=>{ id:1, name:"khaled" }, { id:2, name:"mortada" } ] عندما اقوم بإستخدام json_encode تتحول الى ملف جيسون { [ "0":{ id:1, name:"khaled" }, "1":{ id:2, name:"mortada" } ] }1 نقطة
-
تلك المشكلة تحدث عند التﻻعب بالمصفوفة وإنتاج مصفوفة تحتاج إلى إعادة الفهرسة (re-indexing) مما يجعل الjson_encode ﻻ يعتبر أن تلك الأرقم هي فهرس للمصفوفة بل يعتبرها مفاتيح نظراً لأنها مفهرسة بشكل غير سليم, الحل أن تقوم بإعادة الفهرسة ويمكنك القيام بذلك ببساطة عبر إستخدام الدالة array_values والتي تأخذ مُعامل واحد عبارة عن المصفوفة المُراد إعادة فهرستها وتُنتج مصفوفة بدون مفاتيح بل بفهرس سليم كما في الشكل التالي $arr = array_values($arr); var_dump(json_encode($arr))1 نقطة
-
شكرا لك أخي الكريم.. قمت فهم كلامك وايضا قمت بتحويل اغلب الكود الذي ارسلته الى لغة الكوتلن مع تغيير قليل وأيضا اضافة بعض الدوال والافكار وبحمد الله تم حل مشكلتي ويعود الفضل بعد الله سبحانه وتعالى اليك جزاك الله خيرا .. سؤال اخير ماذا يجب علي ان اكتب في كود الـTimer حتى تتحدث النتيجة كل دقيقة؟1 نقطة
-
لدي استعلام SQL وفيه JOIN فهل تغيير ترتيب الجداول قبل JOIN وبعدها يغير في النتيجة؟1 نقطة
-
جلب النتيحة من قاعدة البيانات مباشرةً عبر الsql join يُعد أفضل وذلك إعتماداً على عدد من الأسباب مثل المكان الطبيعي للتعامل مع البيانات هو قواعد البيانات فﻻ يجب أن أن نجعل الخادم يقوم بتلك المهمة بدلاً عن قاعدة البيانات حتى ﻻ نخالف قاعدة المسؤلية الواحدة" Single responsibility" ويكون كل جزأ في المشروع يقوم بوظيفته يكون الأمر منطقياً أكثر عند تنفيذه بإستعﻻمة واحدة ويكون الشفرة البرمجية قابلة للقراءة بشكل أفضل يكون الأداء أفضل وأوفر للموارد حيث ﻻ تحتاج أن ترسل طلبات مختلفة إلى قاعدة البيانات كل مرة, بل تقوم بإرسال طلب واحد مما يُزيد الأداء ويوفر الموارد تقوم قاعدة البيانات بإستخدام مُحسن الإستعﻻمات(query optimizer) بتنفيذ الإستعﻻمة الواحدة بطريقة فعالة أفضل , فمثلاً عند تنفيذ جملة تقوم بجلب بيانات الموظفين في قسم معين select * from employee inner join department using ssn ستقوم قاعدة البيانات بإستخدام الفهرسة(indexing) جلب البيانات فقط التي تحتوي ع المفتاح ssn , بينما عند تنفيذ نفس الوظيفة عبر جملتين مختلفتين وربطهم بلغة الخادم(php, c#. java) ستضطر إلى جلب جميع البيانات ومن ثم فلترتها مما يعني تنفيذ عمليات أكثر يمكن أن نأخذ مثالاً أخر SELECT e.fname, e.lname FROM employee e WHERE EXISTS ( SELECT 1 FROM payment WHERE payment.emp_id = emp.id ); تلك الجملة تقوم بإرجاع بيانات الموظفين الذين لهم عمليات دفع , هنا تقوم قاعدة البيانات بتنفيذ الجملة الداخلية أولاً ومن ثم تقوم جلب البيانات التي تتطابق فقط مع الجملة الداخلية, إن قمنا بتنفيذها عبر عدة جمل وربطها بلغات البرمجة سنضطر إلى جلب البيانات كلها ومن ثم فلترتها مثل المثال السابق مما يعني عمليات أكثر وبوجهٍ عام في قواعد البيانات يُفضل أغلب الأوقات أن تقوم بتنفيذ الإستعﻻمات عبر جملة واحدة1 نقطة
-
تقوم أولا بتعريف مصفوفة لعناوين المواعيد بنفس الترتيب الذي يرجعه الصف PrayTime ويجب أن يكون تصاعديا (في الشيفرة قد يبدو الترتيب معكوسا بسبب اتجاه اللغة العربية) String[] salahNames = { "الفجر", "الصبح", "الظهر", "العصر", "المغرب", "العشاء" }; نقوم بالمرور على كافة المواعيد بالترتيب، ونقارن الوقت الحالي بتوقيت كل موعد، عند أول توقيت لا يكون قد مضى نكون حاليا عند الموعد القادم for (int i = 0; i < salahNames.length; i++) { // اسم الموعد الحالي String salahName = salahNames[i]; // توقيت الموعد الحالي String salahTimeString = times.get(i); LocalTime salahTime = LocalTime.parse(salahTimeString, DateTimeFormatter.ofPattern("hh:mm a", Locale.ENGLISH)); // التوقيت الآن LocalTime currentTime = LocalTime.now(); // اذا كان الموعد الحالي هو القادم if (salahTime.isAfter(currentTime)) { // نقوم بحساب الوقت المتبقي وننهي الحلقة ... break; } } تقوم بحساب الوقت المتبقي للموعد القادم ابتداءا من الوقت الحالي، وانشاء النص وتحديث الواجهة if (salahTime.isAfter(currentTime)) { // الوقت المتبقي Duration diff = Duration.between(salahTime, currentTime); // الساعات والدقائق long hours = diff.toHours(); long minutes = diff.minusHours(hours).toMinutes(); // بناء نص الإظهار String timeLeftToNextSalah = ""; if (hours > 0) { // اضافة الساعات فقط اذا كان التوقيت اكثر من ساعة timeLeftToNextSalah += hours + " ساعات"; timeLeftToNextSalah += " و "; } timeLeftToNextSalah += minutes + " دقيقة"; // نحدث الواجهة باسم الموعد القادم والوقت المتبقي findViewById<TextView>(R.id.NextSalahName).text = salahName; findViewById<TextView>(R.id.NextSalahTimeLeft).text = timeLeftToNextSalah; break; } يمكنك إعادة تنفيذ ما سبق والتحديث كل دقيقة عبر استخدام Timer كالتالي Timer timer = new Timer(); timer.schedule( new TimerTask() { public void run() { // إعادة الحساب وتحديث الواجهة } }, 0, 60*1000); // كل دقيقة1 نقطة
-
لا يوجد الأفضل، كل بيئة أو إطار عمل له مزاياه وتطبيقاته التي يتفوق بها، وايضا عند الحاجة يمكن فصل النظام الذي تريد تطويره الى خدمات مترابطة وكل منها تستخدم اطار عمل أو بيئة معينة NodeJS مكتبات عديدة أداء سريع في التطبيقات التي تعتمد على كميات كبيرة من الادخال والاخراج (تطبيقات الوقت الحقيقي - تطبيقات نقل الصوت والفيديو) سهولة بدء التطوير للمبرمج الخبير ب JavaScript، بما انه لديك خبرة في Node JS سيكون العمل أسهل Laravel وقت أقصر لبناء منتج أولي، مكونات ومزايا جاهزة عديدة داخلها تجعل تجربة المطور سهلة الشهرة الواسعة، أغلب المشاكل ستجد لها حلولا لاشخاص واجهوها من قبلك وكيفية حلها أو تضمينها سهولة بدء التطوير للمبرمج الخبير في PHP، يمكن الاستفادة من قراءة المقال التالي1 نقطة
-
يجب التأكد من مسار الصورة الصحيح، حيث يجب أن تكون صورة محلية local ضمن مشروع next.js أو صورة عامة global ولكن يجب أن يتم إضافة النطاق domain الخاص بالصورة في ملف next.config.js على النحو التالي: module.exports = { reactStrictMode: true, images: { domains: ['image-domain-here.com'], } } يجب أن يتم إضافة النطاق بدون بروتوكول HTTP أو HTTPS. ملاحظة: عند عمل أي تعديل على ملف next.config.js يجب أن يتم إعادة تشغيل الخادم مرة أخرى، وتتم هذه العملية تلقائيًا في النسخ الحديثة من Next.js. وإن لم تعمل معك، فيجب أن تقوم بذلك يدويًا.1 نقطة
-
يمكنك أن ترسل رسائل بإستخدام تطبيق الواتساب من خلال إستخدام العنصر a كالتالي: <a href="https://wa.me/PhoneNumber/?text=urlencodedtext"></a> فقط ضع رقم الهاتف مكان phoneNumber واكتب الرسالة في شكل URL encoded مكان urlencodedtext. يمكنك أيضُا أن تستعمل WhatsApp Business API لكي ترسل كم كبير من الرسائل بإستخدام API مخصص لذلك، كما أن هناك مقدمي خدمات chat api مدفوعة لكي ترسل رسائل من رقمك إلى رقم المستخدم، وهنا مثال بإستخدام jQuery: // URL for request POST /message var token = '83763g87x'; var instanceId = '777'; var url = `https://api.chat-api.com/instance${instanceId}/message?token=${token}`; var data = { phone: '79995253422', // Receivers phone body: 'Hello, Andrew!', // Message }; // Send a request $.ajax(url, { data : JSON.stringify(data), contentType : 'application/json', type : 'POST' }); بالتوفيق.1 نقطة
-
أي لغة من لغات تطوير الويب المعروفة ستفي بالغرض، يمكنك أن تستعمل PHP أو Python أو Ruby أو JavaScript كما تشاء ولكل منها مميزات وعيوب، لكن في النهاية سيمكنك أن تقوم بعمل منصة كشوبيفاي بالضبط بإستخدام أي من هذه اللغات ولست مضطرًا إلى إستخدام لغة معينة. لاحظ أن كل لغة من اللغات السابقة تم إستخدامها في إنشاء مواقع ضخمة للغاية، مثلًا PHP صنع بها Facebook, Wikipedia, WordPress إلخ، و Python تم إستخدامها في Instagram و Spotifyو Netflixو Pinterest، وRuby في Shopify و GitHubو Twitchو Dribbble، ولكي تتعرف أي لغة مناسبة لك أنت، عليك أن تجربهم ليس إلا، حينها سيمكنك أن تعرف أي لغة أفضل لك.1 نقطة
-
يستعرض هذا المقال الأمور الرئيسية التي كنتُ بحاجة إلى توضيحات بشأنها حتى أتمكَّن من العمل كمطور ووردبريس حر. أخبرني العديد من الأشخاص بأنَّهم يريدون البدء في مجال تطوير الووردبريس –وأغلبهم يرغبون في العمل لحسابهم الخاص كمطوِّري ووردبريس مستقلين-، ولكنَّهم لا يعلمون كيف يبدؤون. كلَّما فكَّرتُ في هذا الأمر، رأيته منطقيًا، إذ أنَّ تطوير الووردبريس مجال واسع وحدوده تتخطَّى تقنية الووردبريس (المربِكة جدًا) نفسها. في هذا المقال، سأسرد وأستعرض الأمور الجوهرية التي كنتُ بحاجة إلى اكتشافها ومعرفتها بنفسي لكي أتمكَّن من العمل كمطور ووردبريس حر ناجح، وتنقسم هذه الأمور إلى ثلاث فئات: الأمور الاستراتيجية: ما ينبغي عليك معرفته عن هذا المجال وعن الحياة نفسها لكي تنجح في العمل كمطور ووردبريس حر. الأمور العملية: التفاصيل المتعلقة بالمُعدّات والخدمات التي تحتاجها لكي تبدأ العمل بالفعل. الأمور التقنية: المواضيع التكنولوجيّة التي ينبغي عليك فهمها لكي تكون قادرًا على تقديم عمل جيِّد للعملاء الذين يستخدمون الووردبريس. ذكرتُ فيما يلي كل ما استطعت أن أذكره لمساعدتك في البدء بكل فئة من هذه الفئات، إذ تحدَّثتُ عن المسائل التي أنت حقًا بحاجة إلى أن يكون لديك حلول لها -أو على الأقل أن تكون قد فكرَّت فيها بعمق- حتى تستطيع النجاح في عملك كمطور ووردبريس حر. إحدى الأشياء التي يجدُر توضيحها هي أنَّ قسم «الأمور الاستراتيجية» قد كتبته وأنا أضع مطوِّري الووردبريس المستقلين نصب عينيّ: أي المطوِّرين أمثالي الذين يركِّزون على العمل مع عملاء، والذين يعملون لحسابهم الخاص أو يعملون كجزء من وكالات صغيرة جدًا، وهؤلاء هم الفئة الكبرى من مطوِّري الووردبريس المحترفين. هناك بالتأكيد وظائف أخرى في مجال تطوير الووردبريس إلى جانب العمل الحر! يمكنك أن تعمل لصالح وكالة كبيرة، ويمكنك أن تبيع الإضافات المدفوعة، ويمكنك أن تعمل في الدعم الفني لشركة استضافة، وغير ذلك. إذا كان لديك معرفة بسيطة جدًا بهذه الوظائف، فبرأيي أنَّه من المؤكد أنَّ قسم «الأمور التقنية» في هذا المقال سيكون ملائمًا لك مهما كانت الوظيفة التي اخترتَها في مجال تطوير الووردبريس، كما أنَّ قسم «الأمور العملية» سيكون ملائمًا إلى حدٍ ما، ولكنَّ درجة ملائمة قسم «الأمور الاستراتيجية» غير محددة. كن مطور ووردبريس حر: الأمور الاستراتيجية الأساسية التي ينبغي مراعاتها وضع دوافع وتوقعات واضحة إنَّ العمل في مجال تطوير الووردبريس -مثله مثل أي شيءٍ آخر- له إيجابيات وسلبيات، وله محاسن ومساوئ. يجب أن تكون دوافعك وتوقعاتك المتعلقة بعملك كمطور ووردبريس حر واضحة للغاية وواقعية. سأبدأ حديثي بإخبارك عن تجربتي في العمل. الأمور التي أحبُّها بشأن العمل في مجال تطوير الووردبريس باحترافية المرونة: يمكنني وضع كل ما يتعلق بعملي في حقيبة ظهر، وسيبقى هناك متسعًا كبيرًا للملابس. وبفضل هذا الأمر، تمكَّنتُ من الانتقال مع زوجتي إلى نيو أورلينزعندما أرادت ذلك، كما أنَّني أستطيع زيارة والديّ في هاواي لفترات طويلة أربع أو خمس مرَّات في السنة دون أن يؤثِّر ذلك على عملي. ولأنَّني مدير نفسي، أستطيع أخذ إجازات وقضاء أوقات في السفر بقدر ما يسمح به دخلي الخاص. شعور الإتقان: أصبحت محترفًا في تطوير الووردبريس منذ عام 2012، وأشعر الآن بأنَّني جيدٌ جدًا جدًا في عملي؛ فعندما يحتاج الناس إلى مساعدة في الجوانب التقنية المتعلقة بالووردبريس، عادةً ما أكون قادرًا على إنجازها بسرعة أكبر مما يتوقعون أو إسداء نصائح رائعة لهم تساعدهم على التقدُّم. هذا الأمر مدعاة للسرور، خصوصًا عندما تكون في صدد إصلاح مشروع ووكومرس تكلفته مائة ألف دولار قد أخفق المطوِّر السابق غير الكفء تمامًا في إنجازه، أو عندما تساهم بشكل كبير في تحديث وتحسين وجود مؤسسة -تهتم حقًا بها- على شبكة الإنترنت. إنَّ تطوير الووردبريس مهنة حقيقية، وإتقانك لها يمنحك شعورًا رائعًا. يُمكن أن يكون ممتعًا: يتضمن العمل الحر في مجال تطوير الووردبريس الكثير من التعاملات مع الناس، والكثير من عمليات حل المشكلات البسيطة أو المتوسطة، والكثير من البحث عبر الإنترنت، والكثير من الأمور التي تتطلَّب منك الإبداع. بمجرد أن تصبح خبيرًا في المجال، ستصبح عملية التطوير (وتقابلها عملية إدارة العلاقات مع العملاء) كأنَّك تقضي يومك في حل السودوكو وبناء مجسَّمات الطائرات. إنَّه ليس عملًا سيئًا. الفائدة العامة: الجميع تقريبًا يمتلكون أو يحتاجون أو يريدون موقعًا لغرضٍ أو لآخر، وغالبًا ما يكون الووردبريس هو الخيار الأمثل. لهذا، تتلاءم إمكانياتك في مجال تطوير الووردبريس بطريقة رائعة مع أي مشروع قد يقع بين يديك. الأمور التي لا أحبُّها بشأن العمل في مجال تطوير الووردبريس باحترافية قد لا تحصل على ما تسدّ به جوعك: الأجر الذي أقبضه في نهاية الشهر يكون لقاء العمل الذي أنجزتُه لأشخاص محدَّدين (الأشخاص الذين حوَّلتُهم إلى زبائن) خلال ذلك الشهر. إذا استنفدتَ كل طرق جذب العملاء المحتملين، أو إذا مررتَ بشهرٍ سيء على نحوٍ غير متوقع، فمن المحتمل جدًا ألّا تجني مالًا. بعبارة أخرى: أنت لا تملك أمانًا وظيفيًا، وكل ما تملكه هو ما توفِّره وما تعيل به نفسك. أنت عُرضَة للطلب: لا أحبِّذ -بصراحة- الأوقات التي يرن فيها الهاتف أو تصلني فيها رسالة بريد إلكتروني لأنَّه في كثير من الأحيان يتعلق الأمر بعميل لديه مشكلة مريعة (أو تبدو مريعة) يريد مني أن أحلّها، إذ يعتمد الأشخاص عليّ في ذلك. هناك طرق لإدارة التوقعات والتعامل معها بطريقة مناسبة، ولكن هذا لا يزيل التوتر الكامن في كونك مسؤولًا عن المساعدة في إيجاد الحلول لأي مشكلة قد تنشأ عن عشرات المواقع. لحسن حظي أنّني جيّد في عملي؛ فمن واقع خبرتي، يمكن أن يكون وجود أشخاص يعتمدون عليك بهذه الطريقة مزعجًا جدًا إذا لم تكن ذا معرفة بما تقوم به. من الصعب التفاوض مع العملاء حول الميزانية: بعض المطوِّرين قد لا تواجههم هذه المشكلة، ولكن طريقتي الخاصة في العمل بسيطة وغير رسمية إلى حدٍ ما -وهي تختلف كثيرًا عن طريقة الوكالات الكبيرة التي تتولّى العمل على مشاريع تبلغ تكلفتها مئات الآلاف من الدولارت ويستغرق إنجازها عدة سنوات-، إذ أميل إلى جذب أصحاب الأعمال التجارية الصغيرة الذين أُفضِّل العمل معهم على أي حال. في هذا السياق، تكون الميزانيات محدودة، وهناك حاجة دائمة إلى الشفافية. من المرهق جدًا حل المشكلات التقنية المرتبطة بالمشاريع التي تواجه مشكلات استراتيجية لا يمكنني مساعدة مالكي المواقع على التعامل معها (من الواضح أنَّهم عادةً ما يكونون مصدر هذه المشكلات)، إذ أشعر بأنَّني أساعد الناس على إنفاق أموالهم بطريقة غير عقلانية في هذه الحالة. الشعور بالصدمة: معظم عملائي لا يكونون على معرفة بي في بداية رحلتهم عبر الويب؛ بل يجدونني في منتصفها، وهم يشعرون بخيبة أمل بسبب العديد من المطوِّرين نصف المؤهلين الذين لم يكونوا على دراية بكيفية التواصل. المواقع الخاصَّة بهؤلاء العملاء تنمُّ عن الاختيارات التقنية غير الصائبة، ومن واقع ما رأيت فإنَّ معظم مواقع الووردبريس عبارة عن تجربة سيئة بالنسبة لمستخدميها النهائيين، وذلك بسبب قلة عدد "مطوِّري" الووردبريس المؤهَّلين بالفعل ولأنَّ أسوأ الأجزاء في نظام الووردبريس هي التي يتم تسويقها على النحو الأفضل، والتفكير يوميًا في هذا الأمر يبعث على الإحباط حتى لو كنت جزءًا من الحل. هذه مجرد وجهة نظري، والمغزى هو أنَّ عليك فهم ما أنت مُقبِلٌ عليه وسبب إقبالك عليه. تحدَّث إلى الأشخاص الآخرين الذين يقومون بما ترغب في القيام به، واحرص على أنَّ يكون هناك انسجام بينك وبينهم. في هذه الحالة، يمكنك العثور على الكثير من هؤلاء الأشخاص في اللقاءات التي تُعقد للحديث عن الووردبريس في مجتمعك المحلي. اعرض عليهم أن تشتري لهم وجبة غداء، وسيقبل معظمهم عرضك، كما قد يكون بعضهم -في الحقيقة- بحاجة إلى وجبة الغداء. أنصحكم أيضًا بشدة بقراءة هذا المقال الذي كتبَتْه كاري ديلز (Carrie Dils) وقد تحدَّثَتْ فيه عن مميزات أن تكون مطور ووردبريس حر، إلى جانب التحديات المصاحبة لذلك. الأمور التي قد تجعل العمل الحر في مجال تطوير الووردبريس غير مناسب لك نقطة أخيرة متعلقة بهذا الموضوع: لا أنصح أي أحد بالخوض في العمل الحر في مجال تطوير الووردبريس إذا انطبقت عليه إحدى العبارتين التاليتين أو كلتيهما: أنت لا تملك مهارات عامة قوية في الجوانب التقنية وفي حل المشكلات، وهذا يعني أنَّك لا تستطيع عمومًا التعامل مع المشاريع التقنية المعقدة (مثل مشروع jailbreak my phone) والتغلُّب على تحدياتها من خلال البحث عبر الإنترنت ومحاولة إدخال التعديلات والتحسينات عليها. تنزعج كثيرًا من خدمة العملاء، وهذا يعني أنَّك لا ترغب في التعامل مع الناس، ولا تفهم ما يريدونه، وتكره مضايقاتهم، وتكره تقديم التفسيرات، وتخوض في الجدالات بسهولة، وهكذا. إذا كنت تعاني من نقطتي الضعف السابقتين ولديك شريك يمكنه التغلُّب عليهما، فلا بأس في هذا. لكن إذا كنت تعمل لوحدك وتحاول أن تبني عملك الحر على هذا الأساس، فسوف تواجه عقبات في طريقك. المخطط الزمني والالتزام بالوقت ما هي ظروف حياتك الحالية –من حيث أوقات الفراغ ووضعك المالي- وكيف يتلاءم العمل الحر في مجال تطوير الووردبريس معها؟ هل تريد أن تتخذ من تطوير الووردبريس عملًا بدوام كامل؟ إذا كنت ستفعل ذلك، ما هو مخططك الزمني لتحقيق ذلك؟ وكيف ستشدُّ من أزر نفسك خلال عملية التحوُّل؟ تختلف الظروف من شخصٍ لآخر، لذلك لن أحاول إسداء النصائح لحالات معينة؛ بل سأذكر بعض المعلومات والحلول لتأخذها في الاعتبار مهما كانت ظروفك الحالية: ستقضي وقتًا صعبًا في سبيل الحصول على ما يكفي من الساعات مدفوعة الأجر إلى أن تؤتي الطرق التي تنتهجها لإيجاد العملاء أُكُلها، وتبدأ قائمة عملائك تمتلئ بعملاء رائعين. إذا كنت تريد أن تصبح مطور ووردبريس حر بدوام كامل، فمن المرجَّح أن يكون العائد الذي ستجنيه خلال الثلاثة أشهر الأولى على الأقل -وربما الستة أشهر- ضئيلًا، وأن تمضي سنة كاملة أو أكثر دون أن تكون واثقًا ممّا إذا كنت ستجني شهريًا ما يعادل راتب الطبقة المتوسطة. لا تستغرق الأعمال التي تقوم بها للحصول على عملاء –مثل الذهاب إلى فعاليات التشبيك، وإنشاء موقع إلكتروني لعرض نماذج أعمالك، والاستفادة من شبكة علاقاتك الحالية- 40 ساعة أسبوعيًا، إذ ينتهي بك المطاف إلى قضاء الوقت في انتظار أن يتواصل معك أحد العملاء المحتملين، أو في انتظار أن يحين موعد فعالية التشبيك الأسبوعية التالية، وما إلى ذلك. بعبارة أخرى: من الصعب جعل «عملية الحصول على عملاء» عملًا بدوام كامل إلا إذا لم تكن تمانع التسويق باستخدام أسلوب الاتصال البارد (cold calling)، أو توزيع النشرات الإعلانية الخاصة بالأعمال التجارية المحلية، وغيرها. لن تكون لك قدم ثابتة في الجوانب التقنية لمدة عام على الأقل، وهذا يعني أنَّه ستواجهك باستمرار مشكلات لا تعرف كيفية حلّها. هذه النقطة هي مجرد تنبيه لك حتى تستعد لخوض فترة صعبة وبعض اللحظات المروِّعة. (ألق نظرة على بند «من الذي سيكون طوق نجاتك» المذكور لاحقًا للتعرُّف على المزيد من الاقتراحات المتعلِّقة بهذا الأمر.) لا أعلم ما إذا كان من الأفضل مواجهة هذ الفترة من خلال العمل كمطور ووردبريس بدوام كامل أم بدوام جزئي، ولكن ربما يكون العمل بدوام كامل هو الأفضل لأنَّه لن يكون لديك خيار سوى التصدِّي للعقبات عندما تعترض طريقك. ذكرتُ هذه النقطة هنا لأنَّه ينبغي عليك أن تنظِّم أمورك المالية لفترة طويلة نسبيًا بينما تحاول التسويق لنفسك بصفتك مطور ووردبريس يتقاضى أجرًا، دون أن تكون متأكدًا ما إذا كنت ستحصل حقًا على المال. غالبًا ما يبدأ العمل الحر في مجال تطوير الووردبريس بالنمو ببطء، كغيره من الأمور الأخرى. لذا، أنصحك بأن يكون لديك قدرًا لا بأس به من الادخار الشخصي، أو أن تحافظ على التزاماتك الحالية إلى أن تصبح متأكدًا من أنَّ عملك في مجال الووردبريس سيكفيك مؤنتك. في الحقيقة، لم أفعل ذلك وقد انتهى الأمر على ما يرام، إذ أنَّ الطريقة الصعبة التي انتهجتُها كانت مفيدة جدًا، ولكنَّها لم تكن ممتعة. كيف تحدِّد تسعيرة عملك؟ أنا أُفضِّل أن يكون تسعير الأعمال في مجال تطوير الووردبريس على أساس الساعة، ما لم يكن لديك سبب قوي لاختيار أسلوب آخر. الكثير من الأشخاص لا يعجبهم التسعير على أساس الساعة، ويفضِّلون التسعير على أساس المشروع أو التسعير على أساس القيمة (value pricing)، ولكنّني شخصيًا وجدتُ أنَّ جميع الأساليب عدا التسعير على أساس الساعة من الصعب جدًا على المستقل أن يطبِّقها مع معظم العملاء. يؤدِّي التسعير على أساس المشروع إلى الخوض في عمليات طويلة لتقدير قيمة المشروع والتفاوض مع الزبائن، أما التسعير على أساس القيمة يوقعك في حبال العمل التجاري الخاص بالزبون على نطاق أوسع. لا بأس بهذه الأساليب إذا كنت ستساهم على نحو كبير لمدة سنوات في توجيه دفة العديد من الجوانب الاستراتيجية الواسعة للعمل التجاري الخاص بالعميل، ولكن إذا كانت وظيفتك مقتصرة على تقديم الحلول التقنية لجزء واحد من أجزاء العمل التجاري (هذا هو حال أغلب مشاريع العمل الحر)، فستصبح وكأنَّك سبَّاكًا يتقاضى أجره من خلال الحصول على حقوق ملكية عقارية! إرشادات عامة بشأن التسعير فيما يلي بعض الإرشادات العامة بشأن تسعير الأعمال في مجال تطوير الووردبريس على أساس الساعة (حسب ما هو متعارف عليه في الولايات المتحدة لمطوري الووردبريس المستقلين): ينبغي عليك ألا تطلب سعرًا أقل من 50$ في الساعة مقابل خدماتك. يُعَدُّ 50$ أو 60$ سعرًا متواضعًا ومناسبًا في بدايات عملك، ولكن ينبغي عليك أن تتطلَّع إلى أن يصل السعر إلى ما لا يقل عن 75$ في غضون سنة، وإلى ما لا يقل عن 100$ في غضون سنتين. ملاحظة: تختلف الأسعار من بلدٍ لآخر، وغالبًا ما تكون الأسعار في البلاد العربية أقل بكثير من الأسعار التي سبق ذكرها. ما يهم حقًا هو مدى براعتك في الأمور التي تتقاضى أجرًا على أساس الساعة للقيام بها. بالنسبة لي، أطلب إما 100$ أو 125$ مقابل الساعة. خبرتي أكبر من خبرة المطورين المبتدئين وتكلفة توظيفي أرخص بكثير من تكلفة توظيف مطور مبتدئ يطلب 50$ مقابل الساعة، إذ أنَّ هؤلاء المطورين سيكلِّفونك آلاف الدولارات بسبب حلولهم السيئة، وسيبقون عالقين في مسألة لساعات، وبعدها سيضعون الحل الخطأ. لقد تطلَّبت مني حوالي 80% من مشاريع العمل الحر التي عملتُ على إنجازها قضاء الساعات لتعديل العمل الذي قام به المطور السابق الذي لم يكون كفئًا، ومن الأمثلة على تلك المشاريع: بناء برمجي متهالك وغير متوافق مكوَّن من 50 إضافة، أو التعامل مع تركيب تكنولوجي سيء (HostGator، وقالب Divi، ومئات الإعدادات للحقول المخصصة المتطورة [AFC]، و Visual Composer)، أو أخطاء تعرقل عمل الموقع، أو مشكلات في SEO، وما إلى ذلك. ملاحظة مهمة: هذه الأسعار من وجهة نظر الكاتب وموقعه وقد لا تنطبق على العالم العربي وتكون أقل من ذلك بكثير، فأرجو أخذ ذلك بالحسبان. ارفع أسعارك دائمًا عندما ترتقي في سلَّم الثقة والكفاءة، ينبغي عليك أن ترتفع أسعارك وفقًا لذلك. لا أستطيع أن أرسم لك منحى محدَّد يوضح كيف ومتى تغيِّر أسعارك، ولكنَّني سأقول: ارفع أسعارك فحسب؛ فالعملاء لا يبالون بالقدر الذي تظنه، كما أنَّ المال الإضافي الذي ستكسبه واقعي جدًا. فيما يلي بعض المصادر الجيِّدة التي يمكن أن تساعدك في البدء في فهم الأمور الماليّة كمطور ووردبريس حر، وفي معرفة كيفية تحديد أسعارك الخاصة على أساس الساعة: حاسبة تكلفة العمل الحر على أساس الساعة تكاليف تطوير مواقع الووردبريس المخصصة مقدار الوقت الذي يستغرقه إنجاز مشاريع الووردبريس تكلفة إنشاء إضافة ووردبريس (التعامل مع أسئلة العملاء ذات النهايات المفتوحة بخصوص التكلفة) دليل جيِّد يتحدَّث عن استراتيجيات التسعير التي لا تبيع بأسعار أقل من المنافسين (على اعتبار أنَّك متعاقد) دورة تدريبية مجانية عبر البريد الإلكتروني حول التسعير للمستقلين كيفية العثور على عملاء بالنسبة لمطوِّري الووردبريس المستقلين، فإنَّ الإجابة عن سؤال «كيف أحصل على عملاء؟» هي التي تحدد ما إذا كانوا سيكسبون مالًا أم لا. لو كان لهذا السؤال إجابة سهلة، لكنتَ تعرفها بالفعل، ولكن هناك إرشادات جيِّدة تساعدك على البدء. أقترح عليك الاطلاع على هذين المقالين -هنا وهنا-، إذ يلقيان نظرة عميقة على هذا الموضوع. أضع أمامك أيضًا القواعد الرئيسية التي أظنُّها فعّالة في بداية انطلاقتك: حضور فعاليات التشبيك بين الأشخاص. استغلال شبكة علاقاتك الشخصية الحالية. التخصُّص وإقامة العلاقات مع من يعملون في مجالك. استحضار قائمة الأشخاص المرجعيين من عملائك الأوائل القلائل، وحتى من الأشخاص الذين عرفتهم من خلال وظائفك السابقة أو التدريبات أو المشاريع التطوعية، وغيرها. ملخَّص العناصر الأربعة السابقة هو: تحدَّث شخصيًا إلى أي شخص يمكنك الحديث معه داخل شبكة علاقاتك الحالية أو خارجها. قد تكون الاستراتيجيات طويلة المدى –مثل التسويق بالمحتوى والتسويق عبر وسائل التواصل الاجتماعي- ممتازة، ولكنَّها من غير المحتمل أن تكون مصدرًا للحصول على العملاء المحتملين في المدى القريب. من الذي سيكون طوق نجاتك في المواقف الصعبة دائمًا ما كان شريكي ديفيد هو سلاحي السري في مجال تطوير الووردبريس؛ فهو مطوِّر أمهر مني باستمرار ويسبقني في المجال التفني بمقدار 12 إلى 24 شهرًا. لقد تعاملتُ مع الكثير من استراتيجيات العمل وعلاقات العملاء، وأعلم -حتى هذا اليوم- أنَّ ديفيد سيكون موجودًا لينتشلني إذا ما تعرَّضت إلى مسألة تقنية صعبة (مثل أوامر Git المعقدة). بالنسبة للذين ليس لديهم شريك موهوب يعمل كمهندس برمجيات، أدرك أهمية امتلاكهم طريقة لـِ "السباحة" عوضًا عن "الغرق" عندما يواجهون موضوع تقني لا يفهمونه أثناء عملهم على مشروع لأحد العملاء. ما الذي أنصح به؟ بصراحة، لا يوجد حاليًا شيء متين وراسخ يمكن اعتباره طوق النجاة لمطور الووردبريس الحر، ولكن هذه أفضل ثلاثة اقتراحات يمكنك تطبيقها في وقتنا الحالي: اذهب إلى اللقاءات التي تُعقد للحديث عن الووردبريس في مجتمعك المحلي؛ فهذه اللقاءات تكون ممتلئة بالمطوِّرين الذين ستكون سعيدًا بمساعدتهم لك في تعلُّم أشياء لا تعرفها؛ بل حتى في تعلُّم أشياء لا تعرف أنَّك لا تعرفها. انضم إلى مجموعة IWP ومجموعة AWP على فيسبوك واستغلّهما بأريحية. حاول أن تقيم علاقة مع مطوِّر متمكِّن في مجالك، واعرض عليه أن تعطيه أجرًا على أساس الساعة مقابل أن يساعدك في استكشاف الأخطاء التقنية وإصلاحها عند الحاجة. في ماذا تتخصَّص؟ ليس من السهل أن تكون «مجرَّد مطور ووردبريس»؛ فما يقع تحت هذا المُسَّمى ضيِّق إلى حدٍ ما، كما أنَّك قد تسمع الأسئلة الآتية من العملاء: من الرائع أنَّك قمت بتثبيت الإضافة المناسبة، ولكنَّها تبدو الآن سيئة للغاية، هل يمكنك أن تجعلها أكثر أناقة وعصرية ومتناغمة مع هوية علامتنا التجارية؟ يخبروننا أنَّنا من المفترض أن يكون لدينا قسم المدونة، ولكن لا أملك أدنى فكرة عمّا أكتب فيه. أريد أن يكون موقعي الإلكتروني متوافقًا مع محركات البحث، هل تستطيع تحقيق ذلك؟ هل ينبغي علينا إنشاء نشرة بريدية؟ هل نحن بحاجة إلى أن يكون لدينا حساب إنستجرام وماذا ننشر عليه؟ متى سيبدأ الموقع الإلكتروني في تحقيق المبيعات؟ تشير كل هذه الأسئلة إلى مجموعة من المهارات التي تقع خارج حدود المهارات الأساسية الخاصة بتطوير الووردبريس، ومن المؤكَّد أنَّك ستجذب لنفسك المزيد من الانتباه في سوق العمل إذا كنت قادرًا على تقديم المساعدة في مجالات متعددة. على حد علمي، فإنَّ أفضل تخصُّص من التخصصات الواقعة ضمن الحدود التقنية لتطوير الووردبريس هو التجارة الإلكترونية، خاصةً الووكومرس. إنَّه في الوقع عالم قائم بذاته، وهناك الكثير من الأموال التي يمكن جنيها من خلاله لأنَّ العملاء أنفسهم في هذا المجال يجنون الأموال. اقتراحي الوحيد هو أن تبدأ التعامل مع العملاء الذين يستخدمون الووكومرس بتواضع؛ فالووكومرس يتطلَّب بضعة مئات من الساعات حتى تتمكَّن من فهمه جيدًا لأنَّ الزبائن سيأتونك بمختلف الحالات الفريدة، وإذا كنت تتقدَّم بغرور، فمن الممكن أن تتسبَّب في انهيار أعمال ومشاريع حقيقية، وليس مدونات مختصَّة بالسفر. المهارات التكميلية لتطوير الووردبريس أفضل ما يمكن القيام به -من وجهة نظري- هو أن تبني مجموعة مهارات خارج إطار تطوير الووردبريس، وأن تبيع خدماتك كحزمة واحدة. تشمل المسمَّيات الوظيفية الرئيسية الأخرى -غير «مطور ووردبريس»- التي يحتاجها معظم العملاء ما يلي: خبير SEO. مصمِّم ويب وجرافيك. مسوِّق إلكتروني: التسويق عبر وسائل التواصل الاجتماعي والتسويق بالمحتوى. كاتب محتوى (يتطلَّب فهمًا عميقًا لتحسين محركات البحث والتسويق بالمحتوى). إذا كنت تمتلك ذوقًا بصريًا، فمن الرائع أن تكون مصمِّمًا/مطوِّرًا. إذا كنت تجيد المهارات العامة لحل المشكلات، فمن المرجَّح أن يكون تعلُّم واحتراف SEO أقل تعقيدًا من تعلُّم تطوير الووردبريس بالنسبة لك، كما أنَّهما يشكِّلان معًا مزيجًا رائعًا. إذا كنت شخصًا اجتماعيًا، فإنَّ الكثير من العملاء لا يملكون أدنى فكرة عن كيفية التسويق لأنفسهم وهم بحاجة ماسَّة تمامًا إلى توضيحات بشأن هذا الأمر. إذا كنت تستطيع الكتابة، فهذا رائع، ولكنَّك أيضًا ستحتاج معظم الأمور المذكورة أعلاه. تحديد الأشياء غير الملموسة التي تجعلك متفرِّدًا لقد خاض العديد من الأشخاص الكثير من التجارب السيئة مع مطوِّري الووردبريس. كيف تميِّز نفسك عنهم بناءً على هذه المعلومة؟ هل أنت ودود على نحو استثنائي؟ متجاوب على نحو استثنائي؟ هل أنت شريك في الاستراتيجية الخاصَّة بالعميل (على العكس من شخص ينجز ما يطلبه الناس منه فحسب)؟ هل لديك أسلوب تسعير استثنائي يتَّسم بالوضوح والشفافية؟ أو قدرة استثنائية على التغيير والتحسين بسرعة وفاعلية؟ أو قدرة استثنائية على التكيُّف مع ميزانية ضئيلة؟ تكون الإجابات في الوضع المثالي «نعم»، ولكن ما يهم هو قضاء بعض الوقت في معرفة الأسباب التي ستجعل العملاء سعداء بتوظيفك أنت بدلًا من توظيف شخص آخر بنفس السعر لإنجاز نفس العمل. ما هي الأشياء غير الملموسة المرتبطة بطريقتك في إنجاز الأعمال بصفتك مطور ووردبريس حر والتي تجعل العمل معك هو الخيار الأمثل لعملائك المحتملين؟ عندما تكون مدركًا لهذه الأشياء غير الملموسة، وعندما تدعمها بطريقة تعاملك على الهاتف، وطريقة عرضك لإنجازاتك وشهاداتك وما إلى ذلك، سيبدأ الناس حينها في إيلاء الاهتمام لك. التعاقد مع محترفين في المجالات الأخرى في الحقيقة، لا يستطيع شخص واحد فقط أو حتى شخصان امتلاك جميع المهارات التي يحتاجها العملاء العاديون لجعل مشاريعهم ناجحة في سوق العمل، ولذلك ستحتاج إلى تكوين علاقات مع أشخاص محترفين يمتلكون المهارات التي لا تمتلكها، وستُحيل إليهم عددًا من الأعمال، والأمر الرائع أنَّهم سيُحيلون إليك أعمالًا أيضًا! خلاصة الموضوع هي أنَّ الأعمال التي قد تحتاج إلى أن تسندها للغير تتضمن الآتي: خبير SEO. مصمِّم ويب وجرافيك. مسوِّق إلكتروني: التسويق عبر وسائل التواصل الاجتماعي والتسويق بالمحتوى. كاتب محتوى (يتطلَّب فهمًا عميقًا لتحسين محركات البحث والتسويق بالمحتوى). إذا كنت لا تعلم أين تبدأ في العثور على هؤلاء الأشخاص، فاذهب إلى اللقاءات المحلية التي تُنظَّم للحديث عن المهارة التي تبحث عنها. كن مطور ووردبريس حر: الأمور العملية الأساسية التي ينبغي مراعاتها هذا القسم هو الأقل أهمية من بين الأقسام الثلاثة، وهو يتحدَّث عن الأشياء الملموسة التي ينبغي أن تقوم بها لكي تصبح جاهزًا للانطلاق في رحاب العمل الحر في مجال تطوير الووردبريس. إجمالًا، ينبغي أن يكون توجُّهك مبنيًا على السرعة والبساطة؛ افعل أبسط وأرخص الأشياء بقدر ما تستطيع لأنَّ الأمر برُمَّته مرتبط بأن تعثر على العملاء المناسبين (جانب استراتيجي) وأن تعرض عليهم القيمة أو الخدمة المناسبة (جانب استراتيجي وتقني) حتى ينجح عملك ويستمر. سنتحدَّث الآن عن التفاصيل. تسجيل عملك ليصبح رسميًا يمكنك تأجيل هذا الأمر حتى تجد نفسك جادًّا بشأنه، ولكن هناك مزايا من حيث الضرائب والالتزامات لكونك مسجَّلًا رسميًا عندما تبدأ في الحصول على عوائد حقيقية. لقد سجَّلنا أنفسنا كشركة تجارية صغيرة (مدرجة تحت تصنيف S Corp في الولايات المتحدة) من خلال شركة Rocket Lawyer (شركة LegalZoom تقدِّم خدمات مماثة)، وكانت تكلفة ذلك رخيصة نسبيًا ولم تتجاوز 500$. عمومًا، كلَّما استطعت أن تولي اهتمامًا أقل لهيكل الشركة، كان ذلك أفضل من واقع تجربتنا. بناء موقع إلكتروني لعرض نماذج أعمالك بصفتك مطور ووردبريس حر قد بدأ رحلته للتو، فسوف تحتاج إلى مراعاة المعايير الثلاثة التالية عندما تبني موقعًا إلكترونيًا تعرض فيه نماذج أعمالك: أن يبدو احترافيًا. أن يبيِّن مكانتك التي ترغب في إظهارها. أن يكون رخيص الثمن ويُبنى بسرعة. لا ينبغي عليك الاهتمام كثيرًا بتفاصيل الموقع الذي ستعرض فيه أعمالك وكأنَّه جزء مهم جدًا من عملك؛ بل يكفي أن تجعل هدفك هو أن يبدو الموقع احترافيًا وأن يعرض علامتك التجارية بطريقة مناسبة، ولا يجب أن يكون مبتكَرًا للغاية أو مبنيًا من نقطة الصفر (ربما تودُّ القيام بهذا لكي تثبت أنَّك قادرٌ على بنائه؟!) أو ما شابه ذلك. إذا كنت لا تعلم من أين تبدأ، فأقترح عليك إلقاء نظرة على متاجر القوالب المذكورة فيما بعد. لا بأس في أن تدفع بضعة مئات من الدولارات لمصمِّم جيِّد مقابل حصولك على نصائح بخصوص الشعار وتصميم الموقع إذا لم تكن متمكِّنًا في هذا المجال. لكن -إجمالًا- ينبغي أن يكون هذا المشروع رخيص الثمن وبسيطًا، وأن يكون التركيز منصبًا على المحتوى: كيف ستُظهِر مكانتك من خلاله؟ هل يبيِّن موقعك للزوَّار لماذا ينبغي عليهم أن يختاروك أنت بدلًا من اختيار غيرك بطريقة مقنعة؟ تحتاج -أيضًا- إلى أن يكون في موقعك قسم يعرض نماذج أعمالك حتى تثبت للآخرين أهليتك. إذا كنت جديدًا في عالم التطوير، ففي هذه الحالة عليك أن تكون مبدعًا؛ فمثلًا: إذا كنت قد تطوَّعت في المكتبة المحلية وأجريت بعض التحسينات على الموقع الإلكتروني الخاص بها، يمكنك أن توضِّح ذلك في معرض أعمالك. يعتبر وجود عنصر أو عنصرين في معرض أعمالك كافيًا للبدء في العمل الحر في مجال تطوير الووردبريس، إلى جانب قدرتك على أن تشير إلى خبرتك السابقة أثناء تفاعلك مع العملاء. العتاد أقصد بكلمة «عتاد» المعدَّات والأجهزة التي تحتاجها للقيام بعملك، وأهم ما يمكنني إخبارك به في هذا السياق هو أنَّ طراز العتاد لا يهم. سأذكر فيما يلي قائمة المعدَّات التي أستخدمها لتنفيذ عملي بصفتي مطور ووردبريس حر: حاسوب محمول يمكن لأي حاسوب محمول قد صُنع خلال السنوات العشر الماضية أن يؤدِّي الغرض. أنا أستخدم جهازًا يعمل بنظام ويندوز، ولكن إذا كنتَ شخصًا قابلًا للتكيُّف، فمن الأفضل لك استخدام جهاز ماك. يكره الأشخاص التقنيّون نظام ويندوز، ويفترضون أنَّك تستخدم نظام الماك عندما يكتبون شروحاتهم. يعتبر سطر الأوامر في نظام ويندوز سيئًا، ولكن لن يشكِّل هذا مشكلة حقيقية لعملك إلا إذا كنت تقضي زمنًا حقيقيًا وأنت تعمل على سطر الأوامر، وحتى لو كان الحال كذلك فهو ليس بدرجة كبيرة من السوء. هاتف لقد أضعت هاتفي القديم مؤخرًا، لذلك أحضرتُ بديلًا له من متجر وول مارت بقيمة 30$، ولكن من الضروري امتلاك هاتف في جميع الأحوال. سماعات الرأس السماعات التي تحجب الضوضاء جيِّدة حقًا، ولكن لا بأس في سماعات الأذن رخيصة الثمن إذا كانت ميزانيتك محدودة. ميكروفون أستخدم ميكروفون Blue Yeti حوالي مرتين في الشهر لتسجيل مقاطع فيديو، كما أستخدمه إذا لم يكن صوتي واضحًا أثناء إجراء المكالمات عبر برنامج Zoom أو برنامج Skype، ولكن من المؤكَّد أنَّ الميكروفون من الأجهزة التي يمكن تأجيل شرائها. البرامج العملية المطلوبة لا تساعدك هذه البرامج في تطوير الووردبريس بطريقة مباشرة، ولكنَّها مهمة لتنظيم وإنجاز عملك. برامج إدارة الوقت أنت بحاجة إلى معرفة الطريقة التي تمضي بها وقتك، وذلك لزيادة الوقت الذي تتقاضى عليه أجرًا ولتحديد مقدار المال الذي ستطلبه من زبائنك. إنَّ برنامج Toggl جيِّد لهذا الغرض. برامج إدارة الحسابات وجدول الرواتب يُعَدُّ برنامج QuickBooks Online جيّدًا لإدارة الحسابات وإعداد الفواتير، ويمكنك استخدامه أيضًا لجدول الرواتب إذا أردت. نحن نلجأ إلى شركة محاسبة قانونية محلية معتمدة، وهذا يفيدنا جدًا لأنَّها تتولّى كل أمورنا المتعلقة بالاستقطاعات والضرائب، ونحن واثقين من صحة ما تقوم به. تصل قيمة التكاليف الخاصة بنا إلى 60$ شهريًا مقابل الرواتب وحوالي 700$ سنويًا مقابل الضرائب. برامج مكالمات الفيديو إنَّ برنامج Zoom ممتاز. ينبغي أيضًا أن يكون لديك برنامج Skype، ولكن أرى أنَّه يزداد سوءًا منذ أن اشترته شركة مايكروسوفت. برامج تخزين الملفات أحبُّ استخدام دروب بوكس وجوجل درايف، والنسخة المدفوعة من دروب بوكس جديرة بالشراء إذا لم تكن تعاني من ضائقة مالية. برامج إدارة المشاريع يُعَدُّ برنامج Trello رائعًا، وهو مناسب للاستخدام الفردي، ولإدارة المشاريع مع فريق العمل، ولإدارة المشاريع الخاصة بالعملاء أيضًا. برامج الدردشة والمحادثة إذا كان لديك شركاء في العمل، فقد تحتاج إلى امتلاك حساب مجاني في برنامج Slack حتى تتعاونوا مع بعضكم بعضًا. برامج تعديل الصور بطبيعة الحال، من المهم أن يكون لديك معرفة بسيطة بكيفية تعديل الصور. يعدُّ برنامج GIMP جيّدًا جدًا ومجانيًا وهو نسخة مقلَّدة من برنامج الفوتوشوب. أنصحكم بالحصول عليه وتعلُّم أساسياته. كن مطور ووردبريس حر: الأمور التقنية الأساسية التي ينبغي مراعاتها على الأرجح أنَّك كنتَ تظنُّ أن يكون محور حديث المقال كلّه حول هذا القسم التقني، والذي ستتعرف من خلاله على المهارات البرمجية التي أنت بحاجة إلى امتلاكها حتى تبدأ في التسويق لنفسك كمطور ووردبريس حر. من المؤكَّد أنَّ هذا القسم مهم جدًا، وبدونه لن تقوم لك قائمة في العمل الحر في مجال تطوير الووردبريس. سنتناول فيما يلي بشيء من التفصيل عناصر الووردبريس التقنية الأساسية التي ينبغي أن تكون على علم بها بصفتك مطور ووردبريس حر. ما المشاريع التي تصلح الووردبريس في تطويرها؟ لماذا؟ متى تستخدمها؟ ما الذي يجعل الووردبريس مُجديًا؟ لماذا هو أفضل من Joomla ومن Drupal؟ لماذا ينبغي أن أستخدم الووردبريس في تطوير موقعي؟ أخبرني رئيسي أنَّ الووردبريس غير آمنة، فهل هذا صحيح؟ يوجد لدى موقع GoDaddy منشئ صفحات خاص به، فلماذا لا أستخدمه؟ أليس تكلفة إنشاء المواقع باستخدام Wix أرخص بكثير إذا أخذنا في الاعتبار الاستضافة وغيرها من الأمور؟ تحتاج إلى أن يكون لديك إجابات ذكية عن هذه الأسئلة، وليس ذلك لكي تخبرها لعملائك فحسب، ولكن لكي تكون أيضًا مدركًا للخدمات التي تقدِّمها في سوق العمل. إنَّ تحديد البرامج التي ستستخدمها ومعرفة طبيعة عملها -ما يمكنها القيام به وما لا يمكنها القيام به وكيف تتوافق مع البرامج الأخرى- هو من المسائل التقنية. ستقدِّم لك المقالات التالية إرشادات عامة بشأن الأسباب التي تدفعك إلى استخدام الووردبريس، وبشأن الحالات المناسبة لاستخدامها: المقال الأول: يستعرض مخطط يعطي فكرة بسيطة ومفيدة عن أنواع المشاريع التي تكون الووردبريس مناسبة لها وأنواع المشاريع التي لا تكون الووردبريس مناسبة لها. المقال الثاني: يتحدَّث فيه شريكي ديفيد عن الأسباب التي تدفعك لاستخدام الووردبريس. المقال الثالث: يقدِّم مقدمة عن Squarespace، ويبيِّن الحالات التي يكون فيها استخدام Squarespace أنسب من استخدام الووردبريس والعكس. البرامج المخصَّصة للمطورين ينطبق هنا ما ذكرناه سابقًا وهو أنَّ «طراز العتاد لا يهم»، إذ ينبغي أن تكون البرامج التي تستخدمها للتفاعل تقنيًا مع الووردبريس بسيطة جدًا. أخبرني بيبين ويليامسون (Pippin Williamson) ذات مرة بأنَّ البرامج المثبَّتة على حاسوبه المحمول بسيطة لدرجة أنَّه يستطيع إلقائه في بحيرة وأن يكون جاهزًا بعد 30 دقيقة للعمل على حاسوب جديد. أن يأتي هذا الكلام من المسؤول عن شركة تقدَّر قيمتها عدة ملايين من الدولارات وتعمل في مجال تطوير إضافات الووردبريس، فهذا يعني أنَّ مطوِّري الووردبريس المستقلين بإمكانهم أن يقوموا بالشيء ذاته. البرامج التي أحتاجها لإنجاز أي مشروع عادي هي: Sublime Text لتحرير النصوص البرمجية. FileZilla لنقل الملفات عبر بروتوكول نقل الملفات. WAMP الذي يمكن من خلاله تشغيل برامج الويب وتطويرها على شبكة محلية (أو MAMP لمستخدمي نظام الماك). متصفح ويب؛ أُفضِّل استخدام متصفح جوجل كروم وأدوات المطوِّر التي يوفرها. في الحقيقة، هذه البرامج فقط هي البرامج التي ستحتاجها للعمل على معظم المشاريع، وجميعها مجانية، ولن يستغرق معك تعلُّم أساسيات كلٍ منها أكثر من ساعة واحدة. المعرفة الأساسية باللغات التقنية اللغات الأساسية الأربعة اللازمة لتطوير الووردبريس -مرَّتبة حسب أهميتها- هي: PHP، وHTML، وCSS، وJavaScript. من الجيِّد أن يكون لديك خبرة بسيطة باللغات الثلاثة الأولى، ولكن حتى لو لم يكن لديك خبرة في لغة PHP، فإنَّه يمكنك -إلى حدٍ ما- أن تتعلَّمها من خلال تعلُّمك للنظام الأساسي الخاص بالووردبريس. لذا، إذا كنت لا تعرف استخدام لغة PHP، فأقترح عليك أن تتعلَّم PHP بينما تتعلَّم كتابة الشيفرات البرمجية في الووردبريس، لا أن تتعلَّمها على حدة، إذ أنَّ الووردبريس لا تستخدم إلا جزءًا صغيرًا من لغة PHP، وما تستخدمه في الواقع مخصَّص لها فقط بدرجة كبيرة. بعبارة مشابهة: من الأفضل لك أن تتعلَّم كيفية إنشاء أحواض السباحة بدلًا من أن تحصل على شهادة في الهندسة المعمارية بهدف أن تتمكَّن من إنشاء أحواض السباحة (إذا كان ذلك منطقيًا). إذا حاولتَ تعلُّم شروحات تطوير الووردبريس ووجدتَ نفسك تائهًا، فقد تكون بحاجة إلى علاج سريع لمواطن قصورك في أي لغة من اللغات السابق ذكرها والتي تمنعك من إحراز أي تقدُّم. نصيحتي لك هي اللجوء إلى موسوعة حسوب التي تقدِّم معلومات وافية عن كل لغة من هذه اللغات. إذا كان لديك معلومات تقنية عامة، يمكنني القول بأنَّ أسبوعًا من التعلُّم الجادّ للغات PHP و HTML و CSS كافٍ جدًا للدخول إلى صُلب الموضوع ألا وهو تعلُّم تطوير الووردبريس. أساسيات تطوير الووردبريس أعرض فيما يلي قائمة تحتوي على عدد من مفردات الووردبريس العشوائية التي تستثير ذاكرتك لكي تختبر مدى تقدُّمك في مجال تطوير الووردبريس، وينبغي أن تحفِّز كل مفردة من هذه المفردات مطوِّري الووردبريس المتمرِّسين على استحضار الكثير من الارتباطات والخبرات والذكريات والأفكار. add_action, add_filter, functions.php, stylesheet, customizer, wp_enqueue_script, wp_enqueue_style, the Loop, get_template_part, add_image_size, get_post_meta, get_the_content, get_the_ID, the_title, new WP_Query, template hierarchy, $args, foreach, is_singular, get_header, get_footer, Plugin Name: , Template: , while, wp_reset_postdata, update_option, get_option, add_shortcode, do_shortcode, get_the_terms إذا بدا لك كل ما في القائمة مألوفًا، فمن المؤكَّد أنَّك مطور ووردبريس بدرجة ما. كلَّما زاد عدد المفردات الغامضة بالنسبة لك، كان هذا مؤشِّرًا على أنَّك بحاجة إلى المزيد من الدراسة والمزيد من الخبرات حتى تصبح ضليعًا في تطوير الووردبريس. ملاحظة بشأن هذا التمرين: تتضمن القائمة السابقة بعض المفردات الأساسية التي اختيرت عشوائيًا والتي ينبغي على كل مطور ووردبريس أن يعلمها، ولا تحتوي القائمة على جميع -أو حتى معظم- المفاهيم الأساسية في مجال الووردبريس. يجب على جميع مطوِّري الووردبريس أيضًا أن يعلموا كيف يتناغم كل مفهوم من مفاهيم التطوير مع النظام التقني الكلي للووردبريس لكي يتمكَّنوا من استخدامه بالطريقة السليمة. إنَّ هذا التمرين هو مجرَّد اختبار عشوائي لتحديد مدى إلمامك ببعض المفردات الأكثر شيوعًا في مجال تطوير الووردبريس. أدوات تقنية أساسية تابعة لأطراف خارجية هذه الأدوات هي عبارة عن تقنيات الووردبريس الخارجية -مثل: القوالب، والإضافات، ومواقع الاستضافة، وغيرها- التي تؤثِّر بطريقة مباشرة على قدرتك على تقديم قيمة لعملائك. ينبغي عليك أن تحدِّد بعض الحلول التقنية التي ستلجأ إليها لكي تقدِّم المساعدة لعملائك عند الحاجة. شركة استضافة ينبغي أن تكون على علم دائم بشركة الاستضافة التي ستنصح عملاءك بالتعامل معها. أقترح أن يقع اختيارك المبدئي على شركة SiteGround (أو شركة WP Engine إذا احتاج العميل أو طلب استضافة مُدارة (managed hosting)). يمكنك معرفة المزيد من التفاصيل عن الأسباب التي جعلتنا نفضِّل هذا الخيار من خلال هذا الرابط. ينبغي أن تعلم أيضًا ما إذا كان نقل الموقع إلى استضافة أخرى يستحق العناء. بوجه عام، تكون عملية النقل ملائمة أكثر في الحالات التالية: هناك موقع واحد فقط على حساب الاستضافة. لا يزال الموقع في بداياته؛ وذلك حتى لا تضطر إلى ترحيل عشرات الرسائل الإلكترونية على سبيل المثال. المشكلات الموجودة في الاستضافة الحالية تُعيق الموقع عن النجاح؛ وليست مجرَّد مصادر إزعاج. ينبغي توجيه الانتباه للحالة الثالثة، إذ أنَّ الاستضافة البطيئة حد الإزعاج والمشكلات المرتبطة ببروتوكول SSL والدعم التقني السيئ وغيرها جميعها مصادر إزعاج رئيسية، ولكن لا تشكِّل هذه المشكلات عوائقًا استراتيجية أمام نجاح الموقع إلا في بعض الأحيان. إذا شعرت بأنَّ الاستضافة السيئة عائق استراتيجي، فاشرع في عملية النقل. أمَّا إذا كانت مجرَّد مصدر إزعاج، فتكيَّف معها. من الصعب التمييز بين الأمرين، ولكن سيزداد ذلك سهولة بمرور الزمن. منشئ النماذج (Form Builder) على الأغلب أنَّ النماذج هي أكثر الطرق شيوعًا لتفاعل المستخدم على مواقع الووردبريس، وتعتبر نماذج الاتصال (Contact forms) من الأمثلة الواضحة عليها. يمكننا إنشاء النماذج لأي غرض نريده بما في ذلك التسجيل للفعاليات أو حتى من أجل تفاعلات المستخدم المعقدة مثل التطوع لتبنِّي حيوان أليف. بالنسبة لي، أستخدم إضافة Gravity Forms لإنشاء النماذج. مع أنَّ هناك بعض الأشياء التي لا يمكنها القيام بها، إلا أنَّها خيار أولي ممتاز لإنشاء أي نموذج أحتاجه تقريبًا إلى أن يدفعني المشروع على استخدام خيار آخر. تُعَدُّ إضافة Ninja Forms وإضافة Caldera Forms من الإضافات الجيِّدة أيضًا، كما أنَّ إضافة Contact Form 7 مجانية وممتازة في إنشاء نماذج الاتصال. سأكون مرتابًا حيال استخدام أي إضافة لم أتطرَّق إلى ذكرها لإنشاء النماذج؛ فمع أنَّ هذا سيكون جائرًا بحق المشاريع الآخرى وبحق مطوِّريها، إلا أنَّ الإضافات التي ذكرتُها هي الخيارات الجيِّدة ذائعة الصيت، ومن غير المحتمل أن تحلَّ الخيارات الأخرى مشكلات لا تستطيع هذه الإضافات أن تحلَّها. منشئ الصفحات (Page Builder) يوجد في وقتنا الحالي إضافة ووردبريس جيِّدة جدًا لإنشاء الصفحات تُسمَّى Beaver Builder، وقد أحدثت تغييرًا جذريًا على الطريقة التي أعمل بها في مجال الووردبريس. من وجهة نظري، ينبغي عل كل مطور ووردبريس حر أن يحصل عليها وأن يتعلم كيفية استخدامها وأن تكون خياره الأول عندما يطلب منه العملاء إنشاء صفحة بتخطيط مخصَّص. إذا كنت ترغب في معرفة سبب تفضيلي لإضافة Beaver Builder عن برمجيات إنشاء الصفحات الرئيسية الأخرى، فقد كتبتُ مقالاً يقارن بطريقة مفصَّلة بين أربعة منها، ويمكنك الاطّلاع عليه من خلال هذا الرابط. ماذا عن استخدام Gutenberg؟ ماذا عن استخدام حلول إنشاء الصفحات التي توفِّر خدمة الاستضافة مثل Squarespace؟ دائمًا ما كنتُ متحمِّسًا لتجربة تأليف وتحرير المحتوى في الووردبريس، ولذلك كتبتُ الكثير بشأن هذا الموضوع خلال السنوات القليلة الماضية، وكتبتُ خصوصًا عن طريقة التفاعل المعقَّدة بين تقنيات معينة مثل Squarespace و Beaver Builder و Gutenberg، وألخِّص فيما يلي النقاط الرئيسية: لن تتسبَّب Gutenberg في اندثار إضافات الووردبريس مثل Beaver Builder في وقت قريب، حتى بعد صدور نسخة ووردبريس 5.0. أصبحت إضافة Beaver Builder أفضل من ذي قبل بعد صدور النسخة 2.0 منها (وهو من أفضل الإضافات لإنشاء صفحات الووردبريس من وجهة نظري). تجربة تأليف المحتوى باستخدام Squarespace أكثر روعة منها في Beaver Builder، كما يعتبر Squarespace تقنية أبسط من الووردبريس بوجه عام إذا أخذنا في الاعتبار الاستضافة وغيرها، وهو خيار جيِّد للمواقع البسيطة جدًا. أمّأ Beaver Builder فهو يوفِّر تجربة مشابهة للمشاريع التي تتطلَّب استخدام الووردبريس. ينبغي عليك أن تبتعد عن معظم إضافات الووردبريس الأخرى الخاصَّة بإنشاء الصفحات. من الصعب جدًا تطوير منشئ صفحات جيِّد للووردبريس، وقد بُنيت معظم المشاريع التي تهدف لذلك على نهج خطأ تمامًا (خاصةً اعتماد عناصر تخطيط الصفحة على الأكواد المختصرة). يعدُّ Visual Composer وDivi Builder أضخم مشروعين ولكنَّهما –أيضًا- من أسوأ المشاريع. تعدُّ إضافة Elementor من الإضافات الجيِّدة، ولكنَّني شخصيًا أُفضِّل Beaver Builder. القوالب ومتاجر القوالب من الصعب العثور على القوالب الجيِّدة، إذ أنَّ سوق القوالب يعجُّ بالقوى السوقية التي تعطي أولوية للمظاهر الفارغة على حساب محتوى القوالب وتصميمها المتقَن. إنَّ بناء موقعك الإلكتروني بالاعتماد على قالب سيئ هو أحد أسهل الطرق التي تجعل المشروع فظيعًا. من المؤكد أنَّه ينبغي عليك العثور على المتجر الذي تراه مناسبًا، ولكن أنصحك بالابتعاد عن متجر ThemeForest، وأقترح عليك متاجر القوالب الأتية: Solo Pine Elmastudio ThemeBeans Codestag قد ترغب في الاستغناء تمامًا عن القوالب التجارية نتيجة التطوُّر الكبير الذي طرأ على برامج إنشاء الصفحات. عمومًا، يُعجبني Understrap كقالب يمكن استخدامه لجميع الأغراض، وStorefront كقالب يمكن استخدامه للووكومرس، ولكن عليك أن تعلم بأنَّ قالب Understrap متقدم للغاية (يملك حوالي 8000 ملف على شكل اعتماديات وجميعها مرتبطة بمنفذات مهام [task runners] ومدراء الاعتماديات [dependency managers] وأوراق أنماط Sass المُصرَّفة وما إلى ذلك)، أمَّا قالب Storefront فيعتمد على مبدأ الخطافات (hook-based) بدرجة كبيرة. من الجيِّد أيضًا أن تتعلَّم كيفية تقييم القوالب قبل شرائها من خلال هذا الرابط. ينبغي عليك أيضًا أن تبتعد عن صنفين من القوالب وهما: القوالب القبيحة متعددة الأغراض الموجودة على متجر ThemeForest، وأي قالب يوفِّره موقع Elegant Themes بما في ذلك قالب Divi بصورة خاصة (يؤسفني قول هذا). حلول النسخ الاحتياطي وتصدير البيانات شخصيًا، لستُ مواظبًا على القيام بالنسخ الاحتياطي اليدوي كما "ينبغي" أن أكون، وذلك لأنَّ شركة SiteGround تحتفظ بنسخ احتياطية، ودائمًا ما أنقذني هذا في الحالات النادرة التي أفسدتُ فيها شيئًا. تجدر الإشارة -أيضًا- إلى نظام النسخ الاحتياطي الأوتوماتيكي الرائع الخاص بشركة WP Engine](e بسبب الخدمات التي تقدِّمها. من المؤكَّد أنَّ عملية النسخ الاحتياطي مهمة، وتعتبر إضافة BackupBuddy خيارًا جيِّدًا للقيام بها. إنَّ إضافة All-in-One WP Migration هي من حلول النسخ الاحتياطي وتصدير البيانات التي تعجبني بشدة. يمكنني الجزم بأنَّ هذه الإضافة يمكن الاعتماد عليها وهي توفِّر عليك الوقت على نحوٍ لا يُصدَّق، كما أنَّها تقدِّم حلًا كاملًا لإجراء النسخ الاحتياطي -كما هو واضح من اسمها-، إذ أنَّها تخزِّن بيانات موقعك بالكامل. الخلاصة تحدَّثنا في هذا المقال عن كيفية الاستعداد للانطلاق في العمل الحر في مجال تطوير الووردبريس، وقد تحدَّثنا عن أمور كثيرة، أليس كذلك؟ لا تُجهد نفسك، إذ أنَّك سوف تتقن هذه الأمور بمرور الزمن دون أن تضطر إلى التخطيط لجميع هذه الأمور مسبقًا. هذا المقال بمثابة الدليل الذي سيرشدك إلى "عيش حياة سعيدة". هناك الكثير من الأمور التي ينبغي التفكير فيها، ولكن لا يُشترط التفكير فيها جميعًا دفعة واحدة ولا قبل أن يحين وقتها. أتمنى أن يكون هذا المقال قد بيَّن لك الطريق الذي عليك أن تسلكه لكي تصبح مطور ووردبريس حر، وأن يكون أيضًا قد نبَّهك إلى نقاط ربما كنتَ غافلًا عنها. معظم الأمور التي ذكرتُها هي أمور تجاهلتُها حتى لم يعد أمامي خيار سوى التعامل معها، ولذلك كان الطريق الذي سلكتُه كمطور ووردبريس حر أطول وتشوبه الكثير من الصعوبات. إذا كان لديك أفكار أخرى عن كيفية الاستعداد للانطلاق في العمل الحر في مجال تطوير الووردبريس، فأخبرنا بها من خلال التعليقات. ترجمة -وبتصرف- للمقال Become a Freelance WordPress Developer: How to Make a Career of It لصاحبه Fred Meyer1 نقطة