اذهب إلى المحتوى

إسلام عبدالعزيز

الأعضاء
  • المساهمات

    93
  • تاريخ الانضمام

  • تاريخ آخر زيارة

  • عدد الأيام التي تصدر بها

    1

كل منشورات العضو إسلام عبدالعزيز

  1. هذا ما يدعى بالـ Strict Mode في React. اذا قمت بالنظر الى شجرة المكونات، ستجد ان هناك مكون بالشكل التالي: function ExampleApplication() { return ( <React.StrictMode> <div> <SomeComponent /> </div> </React.StrictMode> ); } يساعد الـ Strict Mode في: تحديد المكونات ذات دورات الحياة غير الآمنة الكشف عن الآثار الجانبية غير المتوقعة الكشف عن API قديم مثل Context الحل الأول هو ان تقوم بتعديل التطبيق بالتحديثات التي يتطلبها Strict Mode، او يمكنك حذفه واستخدام React.Fragment مكانه: function ExampleApplication() { return ( <React.Fragment> <div> <SomeComponent /> </div> </React.Fragment> ); }
  2. عند استخدام JSX، فعليك الانتابه ان المكون يجب ان يكون عبارة عن دالة. يريد React دائماً ان يحصل على المكونات في دالة او class، على حسب الاصدار الذي تستعمله. في الدالة withState، الراجع منها ليس دالة، بل انه كائن (object). كيف هذا؟ عند كتابة المكون في شكل JSX، يقوم Babel (المترجم) بعمل نداء لهذا المكون. على سبيل المثال، اذا قمت بكتابة الدالة الآتيه: function Button({ title }) {} // عندما نستخدم المكون كـ JSX // <Button title="Save" /> // هذا يساوي الآتي // Button({ title: "Save" }) لذلك، بداخل الدالة withState، يجب ان يكون الراجع منها دالة، وهذه الدالة يكون الراجع منها هو المكون نفسه. فسيكون الحل هكذا: const withState = state => Component => { return () => <Component {...state} />; }; او يمكن كتابة الدالة بدون الـ Arrow Functions هكذا: const withState = state => Component => { return function () { return <Component {...state} />; } };
  3. أحد الخصائص المتاحة لـ View هي onLayout. يتم استدعاء onLayout عند إجراء تغييرات في الـ layout للعنصر. يمكنك الحصول على العرض والطول والمحور للعنصر في شكل X & Y. تعمل الخاصية بالشكل الآتي: function Feed() { const onLayoutChange = event => { const { x, y, width, height } = event.nativeEvent.layout; }; return ( <View onLayout={onLayoutChange}> <Profile /> <Sidebar /> </View> ); }
  4. عند استخدام deleteAsync، يجب عليك معرفة ان هذه الدالة ستظهر خطأ إذا لم يكن هناك ملف أو مجلد في الـ URI الذي تقوم بالعمليات عليه. لذلك، يمكنك استخدام idempotent في اعدادات الدالة هكذا: static async flush() { await FileSystem.deleteAsync(__BASE_DIR__, { idempotent: true }); await FileSystem.makeDirectoryAsync(__BASE_DIR__); }
  5. إذا نسيت إضافة الدالة maybeCompleteAuthSession من حزمة WebBrowser، فلن يتم إغلاق النافذة المنبثقة. يجب استدعاء الدالة في الصفحة التي تعيد النافذة التوجيه إليها. import * as React from 'react'; import { Button, Text, View } from 'react-native'; import * as AuthSession from 'expo-auth-session'; import * as WebBrowser from 'expo-web-browser'; WebBrowser.maybeCompleteAuthSession(); أيضاً، ضع في الاعتبار ان الـ pop-up ستعمل بشكل طبيعي في الموبايل بدون استعمال maybeCompleteAuthSession.
  6. يمكنك استخدام Redux مع React-Redux بهذا الشكل البسيط: import React from 'react'; import { Provider, connect } from 'react-redux'; import { createStore } from 'redux'; // هذا الكائن يحتوي على الحالة المبدئية للتطبيق const initialState = { color: 'red', theme: 'dark', activeRoute: '/home' }; // نستخدم هذه الدالة لعمل تعديلات على الحالة // لتبسيط المثال، سنقوم فقط بقراءة اللون // لذا سنكتفي بارجاع الحالة كاملة function reducer(state = initialState, action) { return state; } // هنا نربط الـ state مع reducer const store = createStore(reducer); // فلنفترض ان هذا المكون يريد الحصول على قيمة اللون // اذا قمنا باستخدامة هكذا، لن نحصل على اللوت في الحالة الأساسية // علينا اولاً ان نربطه بالحالة عن طريق connect function Component({ color, children }) { return ( <div>The color is: {color}</div> ); } // أولاً // سنكتب دالة get بسيطة // تأخذ الدالة كائن الحالة وتعيد لنا اللون function getColor(state) { return { color: state.color }; } // ثانياً // الآن سنقوم بربط الحالة مع المكون مع الدالة التي // تعيد لنا اللون هكذا const ConnectedComponent = connect(getColor)(Component); // الآن أصبح ConnectedComponent قادراً على الحصول على اللون function App() { return ( <div> <ConnectedComponent /> </div> ); } ReactDOM.render( <Provider store={store}> <App /> </Provider> );
  7. في لغة الجافاسكريبت، كل دالة لها context او سياق لتعمل فيه. لو قمنا بكتابة دالة عادية خارج React، وقمنا بعمل log للـ this، ستجد انها تشير الى النطاق/السياق العام (Window for Browsers & Global for Node). عندما نكتب مكون في React، نريد دائماً ان نشير للاحداث ان تعمل على المكون نفسه، وليس السياق العام. ولكن ما يحدث هو ما شرحته من قبل، حيث ان الـ methods بداخل المكون لا تأخذ سياقه. لهذا السبب، تقدم جافاسكريبت bind وهي دالة تستخدم لتغيير السياق العام لدالة معينة. انظر للمثال التالي: // السياق هنا هو window function logThis() { console.log(this); } logThis(); // => Window {} const car = { color: 'red', speed: 260 }; // الآن سنحول السياق الى كائن السيارة ونضعه في دالة جديدة const logThisCar = logThis.bind(car); logThisCar(); // => {color: "red", speed: 260} لذا، لربط اي دالة بمكون الـ React قم باستخدام bind بداخل الـ constructor هكذا: constructor(props) { super(props); this.state = {code: ''}; // هنا this.login = this.login.bind(this); }
  8. تستخدم الدالة lockAsync لعمل lock على الشاشة بحيث لا يستطيع المستخدم دوران الفيديو. على الجانب الآخر، تستخدم unlockAsync لفك هذا القفل. في الكود المرفق، إذا أردت أن ترجع الشاشة مرة أخرى إلى الوضعية الإفتراضية، عليك استخدام lockAsync ايضاً، ولكن مع اعطائها الوضعية الجديدة (Portrait على سبيل المثال). if (fullscreenUpdate === Video.FULLSCREEN_UPDATE_PLAYER_DID_PRESENT) { await ScreenOrientation.lockAsync(ScreenOrientation.OrientationLock.LANDSCAPE); } else { // لاحظ استخدام lockAsync مرة اخرى ولكن مع الوضعية الجديدة await ScreenOrientation.lockAsync(ScreenOrientation.OrientationLock.PORTRAIT_UP); } return true;
  9. في الـ Generator Functions، أي expression على يمين yield يتم حسابه ثم يتم تسليم النتيجة للمتصل. في السطر الثاني، سيقوم التأثير all بحساب حالة الـ mode والـ theme، ولكن يجب استخدام yield قبلها هكذا: export function* appOnLoad() { const { mode, theme } = yield all({ ... }); } يمكنك التفكير في التأثيرات كتعليمات للـ middleware لإجراء بعض العمليات (مثلاً، عمل dispatch asynchronous).
  10. يوفر ووردبريس واجهة برمجية من خلال JavaScript لتمكين إضافة اللوحات إلى الشريط الجانبي. يعد تسجيل مكون إضافي للشريط الجانبي سهلاً عن طريق استخدام الدالة registerPlugin المضمنة داخل ووردبريس كما يلي: import { PluginSidebar, PluginSidebarMoreMenuItem } from '@wordpress/edit-post'; import { registerPlugin } from '@wordpress/plugins'; import { more } from '@wordpress/icons'; const Component = () => ( <> <PluginSidebarMoreMenuItem target="sidebar-name" >My Sidebar</PluginSidebarMoreMenuItem> <PluginSidebar name="sidebar-name" title="My Sidebar" >Content of the sidebar</PluginSidebar> </> ); registerPlugin( 'plugin-name', { icon: more, render: Component, scope: 'my-page', } ); ستلاحظ أننا نستخدم صيغة JSX. هذا لأن حزم ووردبريس عبارة عن غلاف حول React. قبل التشغيل، نحتاج إلى تثبيت الحزم المطلوبة باستخدام: npm install @wordpress/plugins --save يمكنك الآن إنشاء الكود الخاص بك على غرار إنشاء تطبيق React باستخدام: npm run build سيكون الرمز المترجم جاهزًا. انقله إلى مجلد الأصول في مجلد WordPress الخاص بك. في الخطوة الأخيرة، نحتاج إلى تضمين هذا الرمز في صفحة المحرر. استخدم الإجراء "enqueue_block_editor_assets" هكذا: <?php add_action( 'enqueue_block_editor_assets', 'x_editor_assets' ); function x_editor_assets() { wp_enqueue_script( 'x-editor-script', plugins_url( '/assets/js/build.js', __FILE__ ) ); } الآن لديك لوحة الشريط الجانبي المخصصة الخاصة بك. يمكنك إضافة ما تريد داخل اللوحة. في حالتك، أضف حقل إدخال للون داخل مكون "PluginSidebar" بالشكل التالي: <PluginSidebar> <PanelBody> <TextControl label="First Color" /> <TextControl label="Second Color" /> </PanelBody> </PluginSidebar> الآن لديك القدرة على تحديد لونين للتدرج اللوني الخاص بك. باستخدام خدمات WordPress REST، يمكنك إرسال هذه القيم إلى قاعدة البيانات الخاصة بك كقيم Meta للصورة. وبعد ذلك يمكنك تحميل هذه الألوان على الواجهة الأمامية وتطبيق اللونين باستخدام CSS. يتضمن WordPress أيضًا على حزمة لطلبات AJAX للتواصل باستخدام REST: npm install @wordpress/data --save npm install @wordpress/compose --save import { withDispatch, withSelect } from '@wordpress/data'; const SidebarMeta = compose( // نستخدم "withSelect" لقراءة القيم من قاعدة البيانات withSelect(select => ({ // قيمة اللون هنا value: select('core/editor').getEditedPostAttribute('meta')['color_meta_key'] })), // نستخدم "withDispatch" لكتابة القيم إلى قاعدة البيانات withDispatch(dispatch => ({ write: color => { dispatch('core/editor').editPost({ meta: { 'color_meta_key': color } }); } })) );
  11. دعنا نأخذ هذه الدالة قطعة بقطعة ونشرح ماذا يحدث بها. تحتوي مكتبة RxJS على ثلاثة مفاهيم رئيسية: الملاحظ (Observable) وهو المكون الأساسي في المكتبة الذي تتعامل معه العمليات والملاحظين. العمليات (operators) مثل switchMap و map. الاشتراكات (Subscriptions) الملاحظ هو كائن يمكن للملاحظين عمل اشتراك له، ورؤية القيم التي بداخله. اكثر شئ مهم عند استخدام RxJS هو التحكم في حركة القيمة بداخل العمليات بشكلٍ صحيح حتى لا يحدث خلل في النتيجة. لهذا السبب، تأتي المكتبة بالكثير من العمليات لتوفير كل شئ تحتاجه. مثال بسيط: // قم بصناعة ملاحَظ const color = new rxjs.Subject('Red'); // ملاحِظ function logColorName(color) { console.log(`The color has changed to: ${color}.`); } // قم بربط الملاحِظ بداخل الملاحَظ color.subscribe(logColorName); // الآن عند تغير قيمة اللون ستقوم الدالة بالعمل color.next('Green'); // => 'The color has changed to: Green' او مثلاً يمكننا عمل subscribe لحدث الضغط على الشاشة، ولكن عليك استخدام pipe او الانبوب، وهو عبارة عن انبوب تمرر به كل العمليات التي ستقوم بعمل شئ معين على القيمة. هنا مثلاً سنقوم بعمل map على الـ event ونأخذ الـ X axis. const clicks = fromEvent(window, 'click'); // سنقوم بجمع كل الاماكن التي يتم الضغط عليها على الشاشة const positions = clicks.pipe(map(event => { return event.clientX; })); // قم بطباعة الاماكن positions.subscribe(console.log); لاحظ ان map تقوم بعمل نفس الشئ في Array.prototype.map فهي تقوم بعمل Loop على كل القيم، ولكن switchMap ستقوم بارجاع احدث قيمة فقط، وتقوم بالتمرير للملاحظ القادم لنستطيع عمل اشتراك او تحويله لـ Promise عن طريق toPromise مثلاً. لذلك يجب استخدام switchMap بهذا الشكل: const getProfile = (actions) => ( actions.pipe( // لاحظ هنا اننا نقوم بارجاع القيمة، وليس فقط مناداة الدالة switchMap(() => APIService.getProfile().pipe( map(res => getProfileSuccess(res)) )) ) )
  12. هنا يتم استخدام مكتبة Ramda والتي تعمل على توفير Functional Programming. الدالة R.cond تقوم بعمل if condition عادية وتتحقق من المصفوفات المعطاه حتى تصل الى قيمة تكون true. على سبيل المثال: const colorIfCond = R.cond([ [R.prop('red'), () => console.log('لدينا اللون الاحمر')], [R.prop('green'), () => console.log('لدينا اللون الاخضر')], [R.T, () => console.log('ليس لدينا اي لون')] ]); colorIfCond(); // 'ليس لدينا اي لون' colorIfCond({ red: true }); // 'لدينا اللون الاحمر' colorIfCond({ green: true }); // 'لدينا اللون الاخضر' // بدون Ramda سيكون بالشكل التالي function colorIfCond(obj = {}) { if (Object.hasOwnProperty.call(obj, 'red')) { console.log('لدينا اللون الاحمر'); return; } if (Object.hasOwnProperty.call(obj, 'green')) { console.log('لدينا اللون الاخضر'); return; } console.log('ليس لدينا اي لون'); return; } R.T هي دالة سوف تقوم بارجاع true دائماً للتاكد من ان الـ condition سوف تقوم بعمل console.log دائماً حتى لو لم يكن هناك اي لون. لو اردت كتابة الكود التالي بـ React سيكون: const Container = (props) => { if (props.loading) { return <Loading />; } if (props.posts && props.posts.length == 0) { return <NoNewPosts />; } return <Feed />; }
  13. تتكون حلقة الـ Redux Saga من الـ JavaScript Generators. كما تعلم، فعند إنشاء، على سبيل المثال، ساجا للـ Auth بالشكل التالي لعمل تسجيل خروج للمستخدم: function* requestLogout() { const isLogged = yield select(authSelectors.isLogged); if (isLogged) { yield call(authModels.logout); } yield put(authActions.logout()); } ستلاحظ أن كل شئ يتم تمريره ياستخدام الـ Effects مثل call و put مع الـ generators عن طريق yield. بكل بساطة، القيم العائدة من الـ yields هي نوع من التعليمات في شكل كائنات (object) ليستطيع Redux Saga تمريرها للـ saga التالية. لذا، عند عمل الـ root saga للتطبيق، يحب أولاً تحويل الدالة الى generator واستخدام التأثير all: function* rootSagas() { yield all([...authSagas, ...notificationSagas]); }
  14. إضافةً لإجابات المدربين، وائل وصلاح، يمكنك أيضاً وضع الجافاسكربت في ملف منفصل، وعمل الدالة التالية بداخل PHP لإستخدامها بداخل ملف الـ PHP. <?php function enqueue_script( $src ) { return '<script src="' . $src . '"></script>'; } echo '<div class="dropdown"> <button onClick="myFunction()" class="dropbtn">Dropdown</button> <div id="myDropdown" class="dropdown-content"> <a href="#home">Home</a> <a href="#about">About</a> <a href="#contact">Contact</a> </div> </div>'; echo enqueue_script( "./index.js" );
  15. يمكنك إستخدام Mock Service لعمل ما تريد بالعديد من الطرق. يمكنك إستخدام مكتبة Mirage وهي مكتبة للـ testing ويوجد بها module جاهز لصنع خادم غير حقيقي (Fake Server). أيضاً، يمكنك كتابة دالة والاستفادة من setTimeout والـ Promise API لتأخير الرد ليكون شبيه للخادم. أولاً: عن طريق Mirage: npm install --save-dev miragejs تأكد أنك تقوم بتحميل المكتبة كـ Development Dependency عن طريق --save-dev لتكون في جزء التطوير فقط. import { createServer } from 'miragejs'; // تأكد من هذا الشرط حتى لا يتم إنشاء خادم جديد مع كل دورة if (window.server) { server.shutdown(); } // إصنع الخادم window.server = createServer({ // قم بتعريف المسارات routes() { this.get('/api/questions', () => { return { questions: [ { id: 0, title: 'My question!', answer: 'Some answer.' } ] } }) } }); ثانياً: عن طريق دوال خاصة. يمكنك كتابة الدالة التالية وسوف تعمل أيضاً: // لتكون عملية إنشاء الدوال سهلة، سنقوم بإستخدام // نوع من الدوال يسمى الـ // Factory Functions // عبارة عن دالة نستخدمها لانشاء دوال آخرى function createFakeAPI({ data, after }) { return () => { return new Promise(resolve => setTimeout( () => resolve(data), after * 1000 )); } } const fakeQuestions = [{ id: 0, title: 'My question!' }]; // الآن يمكننا الاستخدام هكذا // تعني after ان الرد سيأتي بعد 4 ثواني const getQuestions = createFakeAPI({ data: fakeQuestions, after: 4 }); // سنستخدمها هكذا بداخل // useEffect getQuestions() .then(questions => setQuestions(questions)); أو، يمكنك استخدامها بداخل الـ Data Structure الذي تريده. const routes = { '/api/questions': createFakeAPI({ data: fakeQuestions, after: 5 }); }; function fakeFetch(route) { return routes[route](); } fakeFetch('/api/questions') .then(questions => console.log(questions));
  16. يمكنك إستخدام عمليات التخزين المؤقت (caching) عن طريق: قم بتنزيل الصورة وحفظها محليًا باستخدام React Native Fetch Blob. قم بحفظ الصور عن طريق كائن (object)، حيث أن تكون المفاتيح (object keys) هي الـ ID للصورة، وتكون القيم (object values) هي العنوان المحلي للصورة على الجهاز، وليس الـ URL الذي قمت بتحميل الصورة منه. مثال بداخل المكون (component): RNFetchBlob .config({ // قم باستخدام خاصية التخزين المؤقت fileCache : true, }) .fetch('GET', 'http://www.example.com/photo.png', {}) .then((res) => { // سيكون الملف جاهزاً const file = res.path(); })
  17. إذا قمت بعرض الملف config/websockets.php في الكود المصدري لـ Laravel WebSockets، ستجد أن الـ default port او المنفذ الافتراضي للمكتبة هو 6001. <?php return [ 'dashboard' => [ 'port' => env('LARAVEL_WEBSOCKETS_PORT', 6001), وحدد استثناء وقت التشغيل أن هذا المنفذ قيد الاستخدام بالفعل. كل ما عليك فعله هو إما معرفة ما يتم تشغيله على المنفذ 6001 وإيقافه، أو تغيير المنفذ لخادم WebSocket الخاص بك إلى أي منفذ آخر ليس قيد التشغيل. إذا كنت تريد التحقق مما يتم تشغيله على المنفذ 6001 الذي يحظر تشغيلك على Linux، فيمكنك القيام بما يلي: # يمكنك تغيير 6001 بأي رقم منفذ للتحقق من المضيف الذي يستخدمه sudo lsof -i:6001 أو قم بتشغيل الخادم الخاص بك على منفذ مختلف باستخدام: php artisan websockets:serve --port=3030
  18. الجواب البسيط هو أنك تحتاج إلى اعتراض طلباتك (request interception) باستخدام برمجية وسيطة (middleware) وتعيين الـ CORS بشكل صحيح. ولكن دعني أشرح لك ما هو CORS و Access-Control-Allow-Origin. لأسباب تتعلق بالسلامة، يجب تشغيل تطبيقات الويب في بيئات منعزلة، ما لم ينص على خلاف ذلك. ببساطة، يجب بدء الاتصال بطلب (request)، وسيحتاج هذا الطلب في النهاية إلى استجابة (response). هذه هي الطريقة التي يعمل بها الاتصال في HTTP (المتصفحات). تتم هذه الاتصالات لمشاركة الموارد (على سبيل المثال، ملف JavaScript أو استجابات HTML أو JSON). مثال بسيط: يريد المستخدم تحميل شيء ما على origin A، والذي يتطلب الوصول إلى البيانات من origin B. يعالج الخادم الطلب ويرسل بعض العناوين (headers) (بما في ذلك Access-Control-Allow-Origin التي تحتوي على المواقع آمنة). يحصل المتصفح على الاستجابة ويقرر ما إذا كان سيمنح المستخدم حق الوصول إلى البيانات أم لا. فمثلاً، إذا كانت لديك endpoint على الخادم الخاص بك، وتريد أن يصل الجميع إليها، فسيتعين عليك تعيين Access-Control-Allow-Origin للقيمة "*". مثال من العالم الحقيقي، إذا كنا نكتب بيانات حساسة لمعالجة تطبيق (على سبيل المثال، تطبيق مصرفي) وأردنا تقديم الـ Front-End والـ Back-End من نقاط نهاية مختلفة (endpoints) وأردنا السماح للـ Front-End فقط بقراءة البيانات، فسيتعين علينا إدراجها في القائمة البيضاء عن طريق Access-Control-Allow-Origin. لذلك، إذا كان الـ Front-End عرضة للهجمات، فسيكون من المستحيل على شخص ما قراءة البيانات من الـ Back-End وتمريرها إلى خادم آخر.
  19. يوجد العديد من الطرق لتنفيذ علامة التخفيض في ووكوميرس. يقدم ووكوميرس filters وactions للتحكم في الـ markup أو شكل الصفحة في العموم، مثل ووردبريس. بجانب العديد من الإضافات (plugins) لتسهيل هذا الموضوع، إذا كنت لا تريد التعامل مع كود PHP. أولاً، يمكنك استخدام YITH WOOCOMMERCE BADGE MANAGEMENT وهو من أفضل الإضافات لهذه المهمة. فيمكنك التحكم في شكل ومكان ومحتوى العلامة التي ستضعها على المنتج. ثانياً، عن طريق الميزات التي يقدمها ووكوميرس وووردبريس، يمكنك عمل هذه الخاصية بالعديد من الطرق. فمثلاً، يمكنك ان تصنع Post Type جديد للـ badges عن طريق: <?php // قم بعمل نوع منشور جديد بالخصائص التي تحتاجها register_post_type( 'wpwc-badge', array( // قم بإختيار الميزات التي تحتاجها للمنشور ) ); add_action( 'init', 'wpwc_register_badges_post_type' ); ومن ثم، يمكنك عمل template او shortcode وربطه بداخل صفحة عرض المنتجات بكل سهولة. فسيكون لديك تحكم كامل في خصائص العلامة: <?php // [wpwc-badge] function wpwc_badge_shortcode( $atts ) { // قم بكتابة العلامة بالشكل الذي تريده } add_shortcode( 'wpwc-badge', 'wpwc_badge_shortcode' );
  20. توجد مكتبة جيدة جدًا تسمى botman تتيح لك إنشاء روبوت محادثة بلغة PHP، وهي لا تعتمد على إطار عمل معين. تتيح لك المكتبة بناء روبوت لـ Slack و Telegram و Facebook و WeChat. تعمل المكتبة بالشكل التالي: <?php $botman->hears('كيف الحال؟', function (BotMan $bot) { $bot->reply('أنا بخير'); });
  21. هذه ملفات أساسية في شفرة مصدر WordPress الأصلية. يتم استخدامها في النماذج (forms) لتقديم طلبات نشر (POST requests) مصدق عليها (authenticated). إذا كنت تقوم بإنشاء Theme أو Plugin، فستحتاج بالتأكيد إلى حفظ شيء ما على الخادم. يجب أن تتم عمليات الكتابة هذه بأمان باستخدام admin-post.php و admin-ajax.php. عند إجراء طلب نشر إلى خادم، يمكن أن يؤدي الطلب إلى إعادة تحميل الصفحة، أو يمكنك البقاء على نفس الصفحة، والحصول على ردك باستخدام JavaScript. لبدء تنفيذ طلب نشر أساسي، أنشئ نموذجًا باستخدام HTML، وعيِّن الـ action attribute على النحو التالي: <form method="post" action="<?php echo admin_url( 'admin-post.php' ); ?>"> <input type="text" name="theme_color" id="theme_color" required /> <button type="submit" class="button-primary">Save</button> </form> <?php add_action( 'admin_post_theme_color', 'wp_theme_color' ); function wp_theme_color() { // سيكون متاحاً لك هنا كل المعلومات من النموذج // مثلاً: يمكنك الحصول على لون الثيم وعرضه للمستخدم $theme_color = $_REQUEST['theme_color']; } بالنسبة إلى admin-ajax.php، أو طلبات الـ AJAX عموماً، فيجب عليك استخدام JavaScript + jQuery. الفكرة نفسها هي admin-post.php، ولكن مع بعض التغيرات البسيطة وهي أننا لا نريد عمل reload للصفحة عند عمل submit لنموذج الـ HTML. أولاً، يجب عليك عمل تسجيل ملف الـ JavaScript الذي سيحتوي على كود الـ AJAX. <?php add_action( 'admin_enqueue_scripts', 'mywp_enqueue_scripts' ); function mywp_enqueue_scripts() { wp_enqueue_script( // هذا هو اسم الملف لنتمكن من ادخاله في الصفحات 'my-ajax-script', // هذا هو مكان الملف بداخل مجلد البلجن plugins_url( '/js/query.js' ), // هنا نحن نطلب من ووردبريس ان يقوم بتحميل مكتبة // jQuery قبل الملف array( 'jquery' ) ); // تحميل متغيرات بداخل الجافاسكريبت wp_localize_script( // هذا اسم الملف الذي قمنا بتسجيلة فوق 'my-ajax-script', // ذلك سيكون الكائن الذي سيحتوي على المتغيرات 'ajax_object', array( // Access like: ajax_object.ajax_url 'ajax_url' => admin_url( 'admin-ajax.php' ), // Access like: ajax_object.theme_color 'theme_color' => 'Red' ) ); } وطبعاً، لا تنسى أن تمنع السلوك الإفتراضي للنموذج من داخل ملف الجافاسكريبت. ستؤدي جميع نماذج HTML إلى إعادة تحميل الصفحة ما لم يتم منعها على النحو التالي: // File: query.js (function( $ ) { $( '#form' ).submit( function(event) { // إمنع النموذج من القيام بعمل إعادة تحميل للصفحة event.preventDefault(); // // أكتب باقي الكود هنا // } ); })( jQuery );
  22. يسمى محرر ووردبريس الإفتراضي "غوتنبرغ" أو "Gutenberg". غوتنبرغ ليس محرر نصوص بسيط. في الواقع، يمكنك استخدامه لبناء صفحة كاملة دون كتابة أي كود عن طريق استخدام الـ blocks. يتكون المحرر من ثلاثة أجزاء رئيسية: شاشة الـ blocks وتحتوي على كل الـ blocks المتاح لك استخدامها شاشة التحرير، وهي المنطقة التي تضع وترتب فيها الـ blocks إعدادات الشريط الجانبي، وتحتوي على إعدادات إضافية يمكنك عملها لكل block موجود في المحرر يمنحك غوتنبرغ القدرة على إضافة ميزات إضافية إلى المحرر الخاص بك عن طريق المكونات الإضافية (plugins). الـ plugin هو كود يتم إضافته إلى ووردبريس ليوفر له قدرات جديدة. على سبيل المثال، يمكنك استخدام plugin لإنشاء block جديد يسمح للمحررين بإضافة قائمة إلى أي منشور بكل سهولة. لإضافة ميزات للمحرر عن طريق استخدام plugin، يمكنك ان تستعمل الدالة register_block_type_from_metadata هكذا: <?php function create_block_gutenpride_block_init() { register_block_type_from_metadata( __DIR__ ); } add_action( 'init', 'create_block_gutenpride_block_init' ); ستقوم هذه الدالة بالبحث عن ملف block.json الذي عليك وضعه في مجلد الـ plugin، وبداخله يمكنك وضع تعريفات الـ blocks الجديدة. يوجد الكثير من المدخلات عند تعريف كل block. فيمكنك التحكم في شكله، وطوله، وعدد الأعمدة التي سيستخدمها في الصفحة، والكثير عن طريق ملفات الـ CSS والـ PHP. مثال: { "apiVersion": 2, "name": "post-comments-block", "category": "design", "attributes": { "textAlign": { "type": "string" } }, "usesContext": [ "postId", "postType" ], "supports": { "html": false, "align": [ "wide", "full" ], "fontSize": true, "color": { "gradients": true, "link": true }, "lineHeight": true } }
  23. دعني أعطيك مقدمة بسيطة لفهم طريقة عمل الحزم عامةً. عند العمل مع مدير حزم، مثل npm، عليك أن تضع في اعتبارك أن الحزم التي تقوم بتثبيتها لها أنواع. افتراضيًا، يتم تثبيت الحزم بعلامة --save. تعني هذه العلامة أنه سيتم تثبيت الحزمة التالية عندما يقوم شخص ما بتشغيل npm install. على الجانب الآخر، يوجد إختيار save-dev--. إذا قمت بإستخدام هذا الشعار عند عمل install لحزمة معينة، سيتم وضعها في قائمة "حزم التطوير" أو الـ Development Dependencies. تحتوي هذه القائمة على الحزم التي يحتاجها المطور في مرحلة تطوير البرنامج فقط وليس في مرحلة الـ build الذي سيعمل بداخل المتصفح أو الخادم. عند تطوير أي تطبيق، ستجد أنه يمكنك عمل بيئات متعددة للتطوير. البيئات الأكثر شيوعًا هي بيئة الإنتاج (production) وبيئة التطوير (development). يمكنك استخدام الحزم المثبتة بشروط وفقًا للبيئة المستهدفه عن طريق متغيرات البيئة (environment variables): // يحتوي هذا المتغير على إسم بيئة العمل process.env.NODE_ENV على سبيل المثال، لو أردنا إستخدام حزمة XYZ لو لم تكن بيئة العمل هي الـ production، سنقوم بكتابة: if (process.env.NODE_ENV !== 'production') { require('XYZ').abc(); // import أو يمكنك إستخدام } وفي النهاية، عند تشغيل التطبيق يمكنك أن تكتب run scripts بداخل ملف الـ package.json لعمل تشغيل بطرق مختلفة على حسب بيئة العمل. مثلا، لدى Node.js مكتبة Nodemon التي تعمل على عمل restart للـ server عندما تقوم بعمل تغيير في أي ملف بدلاً من أن تقوم بذلك يدوياً. فبالتأكيد، مكتبة مثل Nodemon مكانها الوحيد في بيئة التطوير، لذا يمكننا كتابة الـ scripts التالية: // package.json { "scripts": { "start": "node index.js", "dev": "nodemon index.js" } } طريقة الإستخدام: npm run start أو // التطوير npm run dev
  24. يوجد لدى "فوري" دليل المطورين وهو سهل الإستخدام. بالنسبة إلى "فودافون كاش"، فيمكنك أن تستعمل بوابة الدفع نفسها "فوري"، أو يوجد أيضاً خدمة Bee.
  25. إضافةً إلى ما قاله المدرب عبدالله، بالنسبة إلي، أجد دائماً أن الحصول على نسخة ورقية أو مطبوعة من الكتاب تكون مفيدة في الكتب التي بها علم قيم على المدى البعيد. بمعنى آخر، الكتب التي تتحدث عن الخوارزميات والـ Data Structures والـ Software Architecture والـ Object Oriented والـ Clean Code أو أي علم يكون مفيد على المدى الطويل ولن تنتهي صلاحيته قريباً. على الجانب الآخر، لا تحصل على النسخة الورقية من كتاب يتحدث عن Laravel النسخة السابعة مثلاً. لأنه، في وقت قصير، ستصبح النسخة السابعة قديمة، وسيصبح الكتاب دون أي فائدة، وسوف تملأ مكتبتك بالكتب القديمة، وستجد نفسك تحاول التخلص منه في أسرع وقت ممكن. في هذه الحالة، تكون النسخة الـ PDF هي الحل الأمثل.
×
×
  • أضف...