التعليم والبحث العلمي الأدلة التقنية

محتوى تفاعلي Interactive Content مع H5P في Moodle وخارجه

كيف تبني اختباراً تفاعلياً عربياً بصيغة H5P، وترفعه إلى Moodle بدرجة في سجل الدرجات، ثم تشغل الملف نفسه في صفحة ويب عادية.

محتوى تفاعلي Interactive Content مع H5P في Moodle وخارجه

لنفرض أن معلمة في مدرستك أعدت اختباراً قصيراً ممتازاً عن أساسيات الشبكات، بأسئلة اختيار من متعدد وصح وخطأ وتصحيح فوري، ثم طلب زميلها في مدرسة أخرى نسخة منه، فإذا كان الاختبار مبنياً داخل Moodle بأسئلة Quiz فسوف تحتاج نسخة احتياطية للمقرر واستعادتها في موقع آخر بالإصدار نفسه تقريباً، وإذا كان الزميل يستخدم WordPress أو منصة أخرى فلا توجد طريقة لنقله أصلاً. وهذه هي المشكلة التي يحلها H5P، فهو صيغة مفتوحة للمحتوى التفاعلي Interactive Content، يحفظ فيها كل نشاط في ملف واحد بامتداد .h5p يحمل المحتوى ومكتبات تشغيله معاً، فيعمل الملف نفسه في Moodle وفي WordPress وفي صفحة ويب عادية. وكما ذكرنا في دليل Moodle، فالمنصة تأتي بأدوات اختبار قوية، والسؤال هنا متى تحتاج H5P بدلاً منها، وكيف يعمل فعلاً داخل Moodle وخارجه.

في هذا المقال سوف نتناول:

  • ما هو H5P، وما الذي يوجد داخل ملف .h5p، ولماذا يمكن نقله بين المنصات.
  • بناء اختبار تفاعلي عربي بثلاثة أسئلة، ورفعه إلى Moodle 5.3 في نشاط H5P، ومحاولتان حقيقيتان لطالبين.
  • العربية في H5P بصراحة: المحتوى يظهر من اليسار إلى اليمين، وكيف أصلحناه بإعداد CSS واحد.
  • تقرير المحاولات وسجل الدرجات، وما الذي تعنيه «الحصيلة» فيه.
  • تشغيل الملف نفسه خارج Moodle في صفحة ويب عادية، وقراءة عبارات xAPI التي يرسلها.

ما هو H5P؟ ومتى تختاره بدلاً من اختبار Moodle؟

H5P، واختصاراً لـ HTML5 Package، هو إطار مفتوح المصدر لإنشاء محتوى تفاعلي يعمل في المتصفح، والمحتوى فيه مبني من أنواع جاهزة Content Types مثل مجموعة الأسئلة Question Set، والفيديو التفاعلي Interactive Video الذي تتوقف فيه المحاضرة المسجلة عند سؤال، والبطاقات Flashcards، والسحب والإفلات Drag and Drop، والقائمة الكاملة في صفحة أنواع المحتوى الرسمية. وصفحة الترخيص تقول إن المشروع يستخدم رخصة MIT حيثما أمكن، مع جزء من كود مكتبة PHP برخصة GPL، وإن الفريق لا يقدم استضافة مجانية، وإنما البرنامج المجاني، والنسخة المستضافة المدفوعة هي H5P.com.

وقد يتساءل البعض: إذا كان في Moodle اختبار Quiz كامل ببنك أسئلة، فلماذا أحتاج H5P؟ والإجابة أن الأداتين لهدفين مختلفين، والجدول التالي يلخص الفرق:

الحاجةاختبار Moodle Quizنشاط H5P
اختبار رسمي بوقت محدد ومحاولة واحدةهو الأنسب، ويعمل مع Safe Exam Browserلا يناسب
بنك أسئلة واختيار عشوائي لكل طالبموجودمحدود بما في الملف
تدريب سريع داخل الدرس بتصحيح فوريممكن ولكنه ثقيل للطالبهو الأنسب
فيديو تتوقف فيه المحاضرة عند سؤاللا يوجدنوع Interactive Video
إعادة استخدام المحتوى في منصة أخرىنسخة مقرر .mbz لـ Moodle فقطملف .h5p واحد يعمل في أي منصة تدعمه

والقاعدة العملية: الاختبار الذي يدخل في الدرجة النهائية يبقى Quiz، والتدريب والمحتوى الذي تريد مشاركته بين المعلمين والمدارس يكون H5P، وهذا ما سوف نطبقه في المختبر.

ما الذي داخل ملف ‎.h5p‎؟

ملف .h5p هو ملف مضغوط Zip عادي بامتداد مختلف، وتوثيق تعريف الحزمة يحدد ما فيه، والصورة التالية تبينه من الحزمة التي بنيناها في المختبر:

مخطط ملف net-quiz.h5p: ملف مضغوط Zip فيه h5p.json وهو بطاقة الحزمة بالعنوان واللغة والمكتبة الرئيسية mainLibrary والمكتبات المطلوبة والرخصة، وcontent/content.json فيه الأسئلة والإجابات ونصوص الأزرار مع مجلد content/images، ومكتبات التشغيل H5P.QuestionSet-1.20 وH5P.MultiChoice-1.16 وH5P.TrueFalse-1.8 وH5P.Question-1.5 وفي كل مجلد library.json وملفات JavaScript وCSS، ومكتبات التحرير H5PEditor التي تلزم للتعديل فقط، وعلى اليمين المنصات التي يعمل فيها الملف نفسه: Moodle وWordPress وصفحة ويب عادية بمشغل h5p-standalone وLumi على الجهاز
الحزمة تحمل مكتباتها معها، ولذلك يعمل المحتوى في أي منصة تفهم H5P

وفيما يلي الأجزاء الثلاثة:

  • بطاقة الحزمة h5p.json: الحقول الإلزامية فيها العنوان title، واللغة language، والمكتبة الرئيسية mainLibrary، والمكتبات التي تحمل قبل التشغيل preloadedDependencies، وطريقة التضمين embedTypes، والرخصة اختيارية.
  • المحتوى content/content.json: الأسئلة والإجابات ونصوص الأزرار، أي كل ما كتبه المعلم، مع ملفات الصور والفيديو في مجلد content.
  • المكتبات Libraries: مجلد لكل مكتبة بإصدارها، مثل H5P.MultiChoice-1.16، وهي كود JavaScript وCSS الذي يرسم السؤال ويصححه. والمنصة التي فيها المكتبة نفسها بالإصدار نفسه تستخدم نسختها، والتي ليست فيها تثبتها من الحزمة.

ولهذا السبب يعمل الملف نفسه في Moodle، وفي WordPress بإضافة H5P لـ WordPress، وفي صفحة ويب عادية كما سيأتي، ويمكن للمعلم أن ينشئه ويعدله على جهازه دون منصة ببرنامج Lumi.

التجربة العملية: اختبار تفاعلي عربي داخل Moodle

بدأنا من مختبر Moodle 5.3 الذي بنيناه في دليل Moodle، بمقرر «مقدمة في الشبكات» فيه معلمة وطالبان.

نجرب العطل: مستودع H5P غير متاح

Moodle لا يأتي بأنواع المحتوى نفسها، وإنما يحملها من مستودع H5P على الإنترنت بمهمة مجدولة اسمها «Download available H5P content types from h5p.org» كما في توثيق H5P في Moodle، وتعمل مع ال Cron. ولما شغلناها يدوياً بعد التثبيت كان المخرج كما يلي:

docker exec -u www-data edu2-lms-web php /var/www/html/admin/cli/scheduled_task.php \
  --execute='\core\task\h5p_get_content_types_task'
Scheduled task failed: تنزيل أنواع محتوى H5P المتاحة من h5p.org (core\task\h5p_get_content_types_task),تم الكشف عن قيمة إجابة غير صالحة
Debug info:
تعذر الحصول على أي معلومات بشأن نوع محتوى H5P. فشل الاتصال مع مستودع H5P.

والرسالة لا تقول لماذا، لذلك طلبنا العنوان الذي يستخدمه الكود، وهو hub-api.h5p.org كما في مكتبة H5P داخل Moodle:

curl -s -X POST -d uuid=x -w ' %{http_code}\n' https://hub-api.h5p.org/v1/content-types/
Temporarily unavailable for maintenance. 503

أي أن المستودع كان في صيانة يوم التجربة، والخطأ ليس في Moodle ولا في الشبكة. والدرس هنا أن Moodle يعتمد على خدمة خارجية ليحصل على أنواع المحتوى ويحدثها، فإذا كان السيرفر في شبكة لا تصل إلى الإنترنت، أو كان المستودع متوقفاً، فلن تظهر أنواع المحتوى في محرر Moodle. والحل الذي يذكره التوثيق هو صفحة «إدارة أنواع محتوى H5P» Manage H5P content types لرفع المكتبات يدوياً، والحل الآخر الذي استخدمناه أن يحمل ملف .h5p مكتباته معه، فيثبتها Moodle عند أول عرض إذا كان من رفعه يملك صلاحية تحديث المكتبات moodle/h5p:updatelibraries مثل المدير.

بناء الحزمة

حملنا حزمة المثال الرسمية لنوع Question Set من خادم H5P، وفيها 28 مكتبة بين تشغيل وتحرير، ثم كتبنا المحتوى بأنفسنا بسكربت Node.js صغير وضغطنا الملفات في net-quiz.h5p بحجم 1959594 بايت. وهذه بطاقة الحزمة التي كتبناها:

{
  "title": "اختبار قصير: أساسيات الشبكات",
  "language": "ar",
  "mainLibrary": "H5P.QuestionSet",
  "embedTypes": [
    "iframe"
  ],
  "license": "CC BY",
  "licenseVersion": "4.0",
  "authors": [
    {
      "name": "ArabRoot",
      "role": "Author"
    }
  ],
  "defaultLanguage": "ar",
  "preloadedDependencies": [
    { "machineName": "H5P.QuestionSet", "majorVersion": "1", "minorVersion": "20" },
    { "machineName": "H5P.MultiChoice", "majorVersion": "1", "minorVersion": "16" },
    { "machineName": "H5P.TrueFalse", "majorVersion": "1", "minorVersion": "8" },
    { "machineName": "H5P.Question", "majorVersion": "1", "minorVersion": "5" },
    { "machineName": "H5P.JoubelUI", "majorVersion": "1", "minorVersion": "3" },
    { "machineName": "H5P.Transition", "majorVersion": "1", "minorVersion": "0" },
    { "machineName": "H5P.FontIcons", "majorVersion": "1", "minorVersion": "0" },
    { "machineName": "FontAwesome", "majorVersion": "4", "minorVersion": "5" },
    { "machineName": "H5P.Image", "majorVersion": "1", "minorVersion": "1" },
    { "machineName": "H5P.Video", "majorVersion": "1", "minorVersion": "6" }
  ]
}

وفي content.json ثلاثة أسئلة: اختيار من متعدد عن وظيفة DNS، واختيار من متعدد عن البروتوكول الذي يوزع عناوين IP، وسؤال صح وخطأ عن منفذ HTTPS، وهذا هو السؤال الثالث مختصراً:

{
  "library": "H5P.TrueFalse 1.8",
  "params": {
    "question": "<p>المنفذ الافتراضي لبروتوكول HTTPS هو 443.</p>",
    "correct": "true",
    "l10n": {
      "trueText": "صح",
      "falseText": "خطأ",
      "checkAnswer": "تحقق"
    }
  }
}

لاحظ أن نصوص الأزرار مثل «تحقق» و«صح» جزء من المحتوى نفسه في l10n، وليست من لغة المنصة، فالحزمة التي حفظت بأزرار إنجليزية تبقى بأزرار إنجليزية في موقع عربي حتى يترجمها أحد، وفي محرر H5P تجد هذه النصوص في قسم «النصوص والتسميات» Text overrides and translations لكل نوع.

إضافة النشاط إلى المقرر

من الواجهة تضيف نشاطاً من نوع H5P في قسم المقرر، وترفع الملف في حقل الحزمة، وتختار الدرجة وطريقة احتسابها. ونحن أضفناه بسكربت PHP بالدوال نفسها التي تستخدمها الواجهة، وهو مفيد إذا كانت لديك عشرات الحزم لعشرات المقررات:

<?php
// Adds an H5P activity with /tmp/net-quiz.h5p to course NET101, as the admin user.
define('CLI_SCRIPT', true);
require('/var/www/html/config.php');
require_once($CFG->dirroot . '/course/lib.php');
require_once($CFG->libdir . '/filelib.php');
$admin = get_admin(); \core\session\manager::set_user($admin);
$course = $DB->get_record('course', ['shortname' => 'NET101'], '*', MUST_EXIST);
$draftid = file_get_unused_draft_itemid();
$fs = get_file_storage();
$fs->create_file_from_pathname(['contextid' => context_user::instance($admin->id)->id, 'component' => 'user', 'filearea' => 'draft',
    'itemid' => $draftid, 'filepath' => '/', 'filename' => 'net-quiz.h5p'], '/tmp/net-quiz.h5p');
$m = new stdClass();
$m->modulename = 'h5pactivity'; $m->module = $DB->get_field('modules', 'id', ['name' => 'h5pactivity']);
$m->course = $course->id; $m->section = 1; $m->visible = 1;
$m->name = 'اختبار قصير تفاعلي: أساسيات الشبكات'; $m->introeditor = ['text' => '', 'format' => FORMAT_HTML, 'itemid' => file_get_unused_draft_itemid()];
$m->packagefile = $draftid; $m->displayoptions = 0;
$m->enabletracking = 1; $m->grademethod = 1; $m->reviewmode = 1;
$m->grade = 10; $m->gradecat = 0;
$m->cmidnumber = '';
$cm = create_module($m);
echo "h5pactivity cmid={$cm->coursemodule} instance={$cm->instance}\n";
docker cp net-quiz.h5p edu2-lms-web:/tmp/net-quiz.h5p
docker cp add-h5p.php edu2-lms-web:/tmp/add-h5p.php
docker exec -u www-data edu2-lms-web php /tmp/add-h5p.php
h5pactivity cmid=1 instance=1

في السكربت أعلاه لاحظ التالي:

  • enabletracking = 1 يجعل Moodle يحفظ المحاولات من عبارات xAPI التي يرسلها المحتوى، ودونه لا توجد درجة ولا تقرير.
  • grademethod = 1 يحتسب أعلى محاولة، وgrade = 10 هي الدرجة القصوى في سجل الدرجات، فالنتيجة 2 من 3 تصبح 6.67 من 10.
  • displayoptions = 0 يظهر أزرار التنزيل والتضمين وحقوق الاستعمال أسفل المحتوى، وهي الأزرار التي تجعل إعادة الاستخدام ممكنة، ويمكنك إخفاؤها إذا كان المحتوى للمقرر فقط.

وكان المقرر قد أنشئ بأداة رفع المقررات وتاريخ بدايته اليوم التالي، وهو الافتراضي، فظهرت للطالب رسالة «هذا المقرر غير متاح للطلاب حالياً» حتى غيرنا تاريخ البداية، فإذا رفعت مقررات قبل بداية الفصل فتأكد من هذا الحقل في ملف CSV.

العربية واتجاه الكتابة RTL في H5P بصراحة

فتحنا النشاط بحساب الطالب خالد، فكانت صفحة Moodle كلها من اليمين إلى اليسار، ولكن المحتوى داخل H5P كان كما يلي:

سؤال H5P داخل Moodle بالعربية ولكن باتجاه من اليسار إلى اليمين: السؤال يظهر بترتيب مختلط DNS؟ ما وظيفة خدمة، ودوائر الاختيار على يسار الإجابات، وعنوان IP في الإجابة الأولى في غير مكانه، وزر تحقق على اليسار وسهم السؤال التالي على اليمين، وفي الأسفل السؤال 1 من 3 وأزرار أعد الاستعمال وحقوق الاستعمال وتضمين
المحتوى العربي داخل H5P يعرض من اليسار إلى اليمين: لاحظ ترتيب «DNS؟» ومكان دوائر الاختيار

والسبب أن H5P يعرض المحتوى داخل iframe مستقل، وصفحة هذا ال iframe لا ترث اتجاه Moodle، فقرأنا الاتجاه المحسوب داخلها من المتصفح فكان ltr، وهو ما يخلط ترتيب الكلمات العربية مع الإنجليزية، فعلامة الاستفهام تذهب إلى غير مكانها، وتظهر «IP» في بداية السطر. وMoodle يقدم إعداداً لهذا بالضبط، وهو «Custom CSS» في إعدادات H5P، ويطبقه على كل محتوى H5P في الموقع. وبعد عدة محاولات وصلنا إلى الملف التالي، لأن تغيير الاتجاه وحده أصلح ترتيب الكلمات، ولكن دوائر الاختيار بقيت فوق النص حتى عكسنا موضعها:

.h5p-content { direction: rtl; }
.h5p-question-content, .h5p-question-introduction { text-align: right; }
.h5p-multichoice .h5p-alternative-container { text-align: right; text-indent: 0; padding: 0.25em 2.4em 0.25em 0.75em; }
.h5p-multichoice .h5p-answer .h5p-alternative-container:before { left: auto; right: 0.7em; }
.h5p-multichoice .h5p-answer-icon { left: auto; right: 0.75em; }
.h5p-joubelui-button:before { padding-right: 0; padding-left: 0.5em; }

ويمكنك أن تلصقه في إدارة الموقع ثم H5P ثم إعدادات H5P، أو أن تضبطه بسكربت، والمهم أن يعاد بناء ملف CSS بعد الحفظ، والواجهة تفعل ذلك تلقائياً، وفي السكربت نستدعي الدالة نفسها:

<?php
define('CLI_SCRIPT', true);
require('/var/www/html/config.php');
set_config('h5pcustomcss', file_get_contents('/tmp/rtl.css'), 'core_h5p');
\core_h5p\local\library\autoloader::register();
\core_h5p\file_storage::generate_custom_styles();
echo \core_h5p\file_storage::get_custom_styles()['cssversion'], "\n";
d82d3b21b08628c81eea619d997aee74

والصورة التالية للسؤال نفسه بعد الإعداد:

السؤال نفسه بعد إعداد CSS: ما وظيفة خدمة DNS؟ بترتيب صحيح ومحاذاة إلى اليمين، ودوائر الاختيار على يمين الإجابات الثلاث، وزر تحقق وسهم السؤال التالي على اليسار
بعد إعداد Custom CSS: الترتيب صحيح ودوائر الاختيار على اليمين

لاحظ أن سهم السؤال التالي ما زال يشير إلى اليمين، وأن الإعداد يغطي النوعين اللذين في الاختبار فقط، فكل نوع محتوى له CSS خاص به، وإذا استخدمت الفيديو التفاعلي أو السحب والإفلات فجربه بالعربية قبل أن تعتمده، ولا تفترض أن الإعداد أعلاه يكفي.

⚠️
الإعداد Custom CSS يطبق على كل محتوى H5P في الموقع، فإذا كان في موقعك محتوى بالإنجليزية أيضاً فسوف يظهر هو الآخر من اليمين إلى اليسار، والسبب أن الإعداد لا يعرف لغة كل حزمة، وفي هذه الحالة اجعل القاعدة خاصة بالمحتوى العربي، أو اترك الاتجاه للمحتوى نفسه بوضع dir="rtl" في نص كل سؤال.

المحاولة والدرجة

أجاب الطالب خالد عن السؤال الثالث فقط بشكل صحيح، وأجابت الطالبة ريم عن الأول والثالث بشكل صحيح وأخطأت في الثاني، فكانت شاشة النتيجة عندها كما يلي:

شاشة نتيجة H5P بالعربية: نتيجتك 2/3 مع شريط تقدم ونجمة، وزرا إعادة وعرض الحل، وأسفلها أزرار أعد الاستعمال وحقوق الاستعمال وتضمين
نتيجة الطالبة ريم: 2 من 3، وأزرار إعادة الاستخدام أسفل المحتوى

وكل إجابة ترسلها مكتبة H5P عبارة xAPI Statement إلى Moodle، وMoodle يحفظها في المحاولة، والصورة التالية تبين الطريق كله:

مخطط كيف تصل درجة الطالب من محتوى H5P إلى سجل الدرجات: الطالب يجيب في محتوى H5P داخل iframe والنتيجة 2 من 3، ثم عبارات xAPI ثلاث عبارات answered لكل سؤال بدرجته وعبارة completed بدرجة 2 من 3، ثم داخل Moodle تقرير المحاولات Attempts وسجل الدرجات Gradebook بدرجة 6.67 من 10، وخارج Moodle H5P.externalDispatcher إلى مخزن سجلات التعلم LRS، وصندوق يبين ما تحمله العبارة: verb وobject وresult.score وresult.success وresult.duration
عبارة لكل سؤال وعبارة للمجموعة كلها، وMoodle يبني المحاولة منها

وهذا تقرير المحاولات كما تراه المعلمة:

تقرير المحاولات في نشاط H5P في Moodle بالعربية: جدول فيه خالد الطالب بتاريخ الأربعاء 21 أكتوبر 2026 1:44 PM ودرجة 33% ومعاينة (1)، وريم الطالبة 1:45 PM ودرجة 67% ومعاينة (1)
تقرير المحاولات: محاولة لكل طالب بنسبته

ومعاينة محاولة ريم تعرض كل سؤال، والإجابة الصحيحة، وإجابتها:

تفاصيل المحاولة رقم 1 للطالبة ريم: تاريخ البدء 21 أكتوبر 2026 1:45 PM، والإكمال هذه المحاولة مكتملة، والمدة 17 ثانية، والحصيلة فشل، والدرجة الإجمالية 2 من أصل 3، ثم جدول لكل سؤال: سؤال DNS والإجابة الصحيحة تحويل اسم النطاق إلى عنوان IP مع علامة صح، وسؤال توزيع عناوين IP والإجابة الصحيحة DHCP وإجابة المحاولة SMTP بعلامة خطأ ودرجة 0 من 1، وسؤال منفذ HTTPS بإجابة صح ودرجة 1 من 1
تفاصيل المحاولة: الإجابة الخاطئة SMTP ظاهرة، و«الحصيلة: فشل» رغم الدرجة 2 من 3

لاحظ في الصورة الحقل «الحصيلة» Success وقيمته «فشل»، مع أن نسبة النجاح في الحزمة 50% والطالبة حصلت على 67%، وفي قاعدة البيانات كانت قيمة success في المحاولة 0. وتوثيق نشاط H5P يقول إن هذا العمود يعني أن الطالب حصل على 100%، وإنه لا علاقة له بإعداد «درجة النجاح» Grade to pass ولا بإكمال النشاط، لذلك لا تعتمد عليه في الحكم على النجاح، واعتمد على الدرجة نفسها في سجل الدرجات:

تقرير المقيم في سجل الدرجات بالعربية لمقرر مقدمة في الشبكات: عمود اختبار قصير تفاعلي أساسيات الشبكات، خالد الطالب 3.33، وريم الطالبة 6.67، وإجمالي المقرر بالقيم نفسها، والمتوسط العام 5.00
سجل الدرجات: 3.33 و6.67 من 10، أي 1 من 3 و2 من 3

الملف نفسه خارج Moodle

الآن نصل إلى سبب وجود H5P أصلاً: إعادة الاستخدام. من زر «أعد الاستعمال» Reuse أسفل المحتوى يحمل المعلم الملف، وMoodle يصدره من جديد، والفرق بين ما رفعناه وما صدره Moodle كان كما يلي:

البندالحزمة التي رفعناهاالحزمة التي صدرها Moodle
الحجم1959594 بايت1163827 بايت
عدد المكتبات2815، أي ما يستخدمه المحتوى فعلاً مع مكتبات تحريره
العنوان titleاختبار قصير: أساسيات الشبكاتQuestion Set
اللغة languagearund أي غير محددة
المحتوى والأسئلةكما هي، بالمعرفات subContentId نفسها

أي أن Moodle حذف المكتبات التي لا يحتاجها المحتوى، وهذا جيد، ولكنه فقد العنوان واللغة من بطاقة الحزمة، فإذا كانت المنصة التي تستورد الملف تعتمد على العنوان في قوائمها فسوف يظهر باسم «Question Set»، فاكتب العنوان من جديد بعد الاستيراد.

تشغيله في صفحة ويب بـ h5p-standalone

لا تحتاج منصة كاملة لعرض محتوى H5P، فمشروع h5p-standalone، برخصة MIT، مشغل يعرض الحزمة في أي صفحة ويب. فردنا الملف الذي صدره Moodle في مجلد site/quiz، ووضعنا ملفات المشغل من الحزمة [email protected] في site/h5p-player، وملف CSS السابق في site/rtl.css، ثم كتبنا الصفحة التالية:

<!doctype html>
<html lang="ar" dir="rtl">
<head>
  <meta charset="utf-8">
  <title>اختبار تفاعلي خارج Moodle</title>
  <script src="h5p-player/main.bundle.js"></script>
</head>
<body>
  <div id="h5p-container"></div>
  <pre id="xapi" dir="ltr"></pre>
  <script>
    const el = document.getElementById('h5p-container');
    const options = {
      h5pJsonPath: '/quiz',
      frameJs: '/h5p-player/frame.bundle.js',
      frameCss: '/h5p-player/styles/h5p.css',
      customCss: '/rtl.css'
    };
    new H5PStandalone.H5P(el, options).then(() => {
      H5P.externalDispatcher.on('xAPI', (event) => {
        const s = event.data.statement;
        if (s.verb.id.endsWith('/answered') || s.verb.id.endsWith('/completed')) {
          document.getElementById('xapi').textContent += JSON.stringify({ verb: s.verb.id, object: s.object.id, result: s.result }) + '\n';
        }
      });
    });
  </script>
</body>
</html>
npm pack [email protected]
docker run -d --name edu2-h5p-standalone -p 127.0.0.1:28090:80 --memory 128m \
  -v "$PWD/site":/usr/share/nginx/html:ro nginx:1.31.6-alpine
السؤال الأول من الاختبار نفسه في صفحة ويب عادية خارج Moodle: ما وظيفة خدمة DNS؟ والإجابة تحويل اسم النطاق إلى عنوان IP مظللة بالأخضر، وشريط النتيجة 1/1 بنجمة، وسهم السؤال التالي، والسؤال 1 من 3
الملف الذي صدره Moodle يعمل في صفحة HTML عادية على nginx، بالعربية ومن اليمين إلى اليسار

وأجبنا عن الأسئلة كما أجابت ريم، فطبعت الصفحة العبارات التالية:

{"verb":"http://adlnet.gov/expapi/verbs/answered","object":"http://127.0.0.1:28090/quiz?subContentId=8262cdbd-ed2e-4f89-b37e-44de1aa565f7","result":{"score":{"min":0,"max":1,"raw":1,"scaled":1},"completion":true,"success":true,"duration":"PT8.91S","response":"0"}}
{"verb":"http://adlnet.gov/expapi/verbs/answered","object":"http://127.0.0.1:28090/quiz?subContentId=22b392ca-66d2-4df7-bc91-ed8a148c4cb6","result":{"score":{"min":0,"max":1,"raw":0,"scaled":0},"completion":true,"success":false,"duration":"PT1.87S","response":"1"}}
{"verb":"http://adlnet.gov/expapi/verbs/answered","object":"http://127.0.0.1:28090/quiz?subContentId=6c7e450b-5d16-4967-90cd-b0b5dac27eb6","result":{"score":{"min":0,"max":1,"raw":1,"scaled":1},"completion":true,"success":true,"duration":"PT1.9S","response":"true"}}
{"verb":"http://adlnet.gov/expapi/verbs/completed","object":"http://127.0.0.1:28090/quiz","result":{"score":{"min":0,"max":3,"raw":2,"scaled":0.6667},"completion":true,"success":true,"duration":"PT18.69S"}}

في المخرج أعلاه لاحظ التالي:

  • كل سؤال له عبارة answered بمعرفه subContentId، وهي المعرفات نفسها التي حفظها Moodle في جدول نتائج المحاولة، وresponse هو رقم الإجابة التي اختارها الطالب، فالقيمة 1 في السؤال الثاني هي SMTP.
  • العبارة الأخيرة completed للمجموعة كلها بدرجة 2 من 3، وفيها success: true لأن نسبة النجاح في الحزمة 50%، وهذا يختلف عن «الحصيلة: فشل» التي حفظها Moodle للمحاولة نفسها، فإذا بنيت تقارير على هذا الحقل فاختبرها على المنصة التي سوف تستخدمها.
  • الصفحة لا ترسل العبارات إلى أي مكان، وإنما تطبعها، وفي الاستخدام الحقيقي ترسلها إلى مخزن سجلات تعلم LRS يدعم xAPI، كما في توثيق xAPI في H5P.
💡
ملف README في h5p-standalone يذكر الخيار user لتمرير اسم الطالب وبريده إلى عبارات xAPI، ولكن الصفحة توقفت عن عرض المحتوى عندما أضفناه بالشكل { name, mail } دون أي خطأ ظاهر، وعادت تعمل عندما حذفناه، فإذا احتجت هوية الطالب في العبارات فاختبر الخيار على نسختك أولاً.

أمان المحتوى Security

  • الحزمة كود يعمل في متصفح الطالب: مكتبات H5P ملفات JavaScript، ولهذا السبب لا يثبت Moodle مكتبات جديدة من حزمة إلا إذا رفعها من يملك صلاحية تحديث المكتبات، فلا تعط هذه الصلاحية للمعلمين، واجعل المدير يراجع الحزم التي تأتي من خارج المؤسسة.
  • الحقوق: زر «حقوق الاستعمال» يعرض الرخصة التي في بطاقة الحزمة، فاكتبها قبل المشاركة، والمحتوى المنشور على h5p.org مرخص بـ CC BY 4.0 ما لم يذكر غير ذلك بحسب صفحة الترخيص.
  • التحديث Upgrade: المكتبات لها إصدارات مستقلة عن Moodle، فإذا كان المستودع متاحاً فالمهمة المجدولة تحدث أنواع المحتوى، وتابع ذلك من صفحة إدارة أنواع المحتوى بعد كل ترقية لـ Moodle.

مشكلات شائعة وحلولها

العرضالسببالحل
«فشل الاتصال مع مستودع H5P» في المهمة المجدولةالمستودع متوقف، أو السيرفر لا يصل إلى hub-api.h5p.orgتحقق بـ curl كما فعلنا، أو ارفع المكتبات يدوياً
المحتوى العربي مختلط الترتيبال iframe باتجاه LTRإعداد Custom CSS كما في القسم السابق
المعلم يرفع حزمة فيرفضها Moodle بسبب المكتباتالمكتبات غير مثبتة، والمعلم لا يملك صلاحية تثبيتهايرفعها المدير مرة، أو تثبت المكتبات من صفحة إدارة أنواع المحتوى
لا تظهر درجة في سجل الدرجاتالتتبع غير مفعل في النشاط، أو نوع المحتوى لا يرسل درجةفعل التتبع، واستخدم نوعاً فيه أسئلة
الطالب لا يرى المقرر بعد رفعهتاريخ بداية المقرر في المستقبلاضبط startdate في ملف CSV أو في إعدادات المقرر

تنظيف المختبر

docker rm -f edu2-h5p-standalone
docker compose down -v

تدريب عملي

  • أضف إلى الحزمة سؤالاً رابعاً من نوع صح وخطأ في content.json، وارفعها من جديد، وتأكد أن المحاولة الجديدة أصبحت من 4.
  • غير passPercentage في الحزمة إلى 100، وأجب عن الأسئلة كلها صحيحة، ثم قارن «الحصيلة» في Moodle بقيمة success في الصفحة المستقلة.

الخلاصة

وصلنا لنهاية الموضوع، وأهم ما فيه:

  • H5P صيغة مفتوحة للمحتوى التفاعلي، والملف .h5p ملف Zip فيه بطاقة الحزمة والمحتوى والمكتبات معاً، ولذلك ينتقل بين المنصات.
  • الاختبار الرسمي يبقى Quiz في Moodle، وH5P للتدريب والمحتوى الذي تريد مشاركته.
  • Moodle يحمل أنواع المحتوى من مستودع خارجي، فإذا كان المستودع متوقفاً فالحزمة التي تحمل مكتباتها يرفعها المدير.
  • المحتوى العربي يعرض LTR داخل ال iframe، وإعداد Custom CSS يصلح الأنواع التي تختبرها فقط.
  • الدرجة تصل إلى سجل الدرجات من عبارات xAPI، و«الحصيلة» في Moodle تعني 100% فقط، فلا تحكم بها على النجاح.
  • الملف الذي يصدره Moodle يعمل في صفحة ويب عادية بـ h5p-standalone، ولكنه يفقد العنوان واللغة من بطاقته.

سجل التحديثات

  • أكتوبر 2026: كتابة المقال وتجربته على Moodle 5.3.0 بمكتبة H5P 1.28، ونوع H5P.QuestionSet 1.20، والمشغل h5p-standalone 3.8.2.
Could not load content
نشرة عرب رووت | ArabRoot

معرفة تستحق مكاناً في بريدك.

مقالات مختارة وأدوات مفيدة وأفكار لمشروعك القادم، في رسالة واحدة كل أسبوع.

يمكنك إلغاء الاشتراك متى شئت. الخصوصية

تم استلام طلبك. افتح بريدك واضغط رابط التأكيد لإتمام الاشتراك.