Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

H5P Editor Laravel Package

h5p/h5p-editor

A general PHP library for implementing the H5P editor in most PHP projects. It provides the editor assets and backend needed to create and modify H5P content, with SCSS sources and Compass build instructions for customizing styles.

View on GitHub
Deep Wiki
Context7

Getting Started

h5p/h5p-editor (repo: h5p/h5p-editor-php-library) is not a Laravel package. There is no service provider, no config file, no publishable migrations. It is the framework-agnostic PHP backend + JS UI for the H5P authoring experience: it emits the editor HTML, resolves library dependencies, and exposes a set of AJAX endpoints (libraries, content-type-cache, translations, files, save, …). Your job is to wire it into Laravel.

You need three pieces stacked together:

Piece Package Role
Core h5p/h5p-core (h5p-php-library) Content rendering, library semantics, upgrade scripts
Editor h5p/h5p-editor Authoring UI, AJAX endpoints, content-type cache
Your code — H5peditorStorage + H5PEditorAjaxInterface implementations, routes

Minimal steps

  1. composer require h5p/h5p-core h5p/h5p-editor.
  2. Copy the editor library's public assets (h5peditor.js, styles/, language/, scripts/) into public/vendor/h5p-editor (or symlink). The editor will 404 silently if the base path is wrong.
  3. Implement the two interfaces you must own:
    • H5peditorStorage — library persistence and language loading.
    • H5PEditorAjaxInterface — content-type cache, translations, recently-used libraries.
  4. Bootstrap the singleton once in a service provider:
$core = new \H5PCore($storage, storage_path('h5p'), url('h5p'), 'en', true);
$editor = \H5PEditor::getInstance();
$editor->setStorage($editorStorage);
$editor->setAjax($ajaxImpl);
$editor->setFileStorage(storage_path('h5p/content'));
$editor->setCore($core);
  1. Two routes minimum: a page route that renders the editor, and an AJAX route that dispatches H5PEditorAjax::action($action, $_POST, $_GET).

Where to look first: h5peditor-storage.interface.php and h5peditor-ajax.interface.php. Those two files are the entire integration contract. Read them before touching anything else — every other class is either shipped assets or something H5PEditor::getEditor() calls on your behalf.

First use case: let an admin create an "Interactive Video" or "Course Presentation". On save you get a JSON params blob plus a main_library_id/main_library_version pair; that pair plus params is what H5PCore needs to render the finished content later. If you only get the create flow working end-to-end, you've already validated the storage layer, the cache, the file upload path, and the dependency resolver.

Implementation Patterns

Interface implementations backed by Eloquent. The natural mapping:

Interface method Table
saveLibrary / loadLibrary / getLibrary h5p_libraries
getLibraries h5p_libraries (filtered by runnable, content_type)
loadContent / saveContent h5p_contents
getLanguage / getAvailableLanguages h5p_libraries_languages
deleteLibraryUsage h5p_libraries_library_dependencies

Keep the interface signatures exact — H5P passes objects ($library, $content) with public properties, not arrays. Returning a wrong shape produces the classic "Unable to find library" error far downstream.

Editor page. H5PEditor::getInstance()->getEditor($contentId, $contentType, $params, $language) returns a string of HTML + inline <script>. Drop it into an unescaped Blade slot:

<div id="h5p-editor">{!! $editorHtml !!}</div>

Do not wrap it in your own layout's JS bundle ordering — the editor expects its scripts to run last and will attach to #h5p-editor.

Route grouping. Put the authoring routes behind auth + a policy/gate, and deliberately exclude the AJAX route from the web middleware group. The H5P AJAX endpoints are designed to echo JSON and exit; CSRF middleware and session cookie churn fight with that. A thin controller is fine:

Route::post('/h5p/ajax', fn () => app(\H5PEditorAjax::class)->action(
    request('action'), request()->all(), request()->query()
))->withoutMiddleware(['web']);

If you must keep web (you usually must, for session-based auth inside the editor), send X-CSRF-TOKEN from the editor and add the route to VerifyCsrfToken::$except.

Content-type cache as a scheduled job. getContentTypeCache() hits the H5P hub over the network. Never call it live in a request path. Store the result in a h5p_content_type_cache table, refresh via php artisan h5p:refresh-cache on a schedule, and serve from the DB in H5PEditorAjaxInterface::getContentTypeCache().

File uploads. H5peditorFile writes to the directory you gave setFileStorage(). It bypasses Laravel's Storage facade entirely — handle permissions and cleanup yourself, and reconcile filenames into your own media table if you need to track ownership.

Save flow. After H5PEditorAjax::save, persist params and the resolved main_library_id / main_library_version. On re-edit, upgrade dependencies first:

$upgradeScript = \H5PCore::getUpgradeScript($currentLib, $targetLib);

Then hand the migrated params to the editor. Skipping this gives you editable-but-broken content after any library update.

Import/export. H5PEditor::exportContent() and the .h5p upload path are the easiest way to seed a fresh environment with content types — far faster than clicking through the hub installer.

Gotchas and Tips

  • Assets are the #1 failure mode. A blank editor canvas with no console errors is almost always a wrong base path or a missing language/en.json. Check the Network tab for h5peditor.js and semantics.json 404s first.
  • The SCSS/Compass instructions in the README are a trap. Compass is unmaintained and does not work on modern Ruby. Only touch it if you are forking the editor CSS; otherwise use the pre-built CSS from the release tarball.
  • Errors return HTTP 200. H5P reports failures as {"success": false, "message": "..."}. Your generic exception handler will never see them. Log inside your interface implementations, and watch the response body during debugging.
  • H5PEditor::getInstance() is a process-wide singleton. Configure it in a service provider's register(), not per-request in a controller, or you will get "already initialized" behaviour and stale core references under Octane. Bind it as a singleton and resolve it lazily.
  • Library version explosion. Every imported .h5p adds rows to h5p_libraries keyed by (machine_name, major, minor, patch). Dependency errors are usually a missing patch row, not a missing library — check h5p_libraries_library_dependencies before assuming a corrupted install.
  • Don't upgrade h5p/h5p-core and h5p/h5p-editor independently. They share the semantics/dependency format. Pin them to compatible ranges in composer.json and test the editor after every bump.
  • Extension points are the interfaces, not hooks. There is no Drupal-style hook_h5p_alter_* here. Customize behaviour by decorating H5peditorStorage — getLibraries() with $type filters what appears in the type picker, and alterLibraryFiles()-equivalent logic belongs in your own wrapper around getAssets().
  • Development mode for source-mapped, unminified assets: run with H5PDevelopment::MODE_DEV and APP_DEBUG=true when chasing editor-side JS errors; switch off in production or you ship unminified bundles.
  • Maturity reality check: 82 stars, 0 dependents, README-only docs. Budget for reading the library source when integrating, and expect to write and own the entire Laravel adapter layer — the "library that is supposed to be used in most PHP implementations of H5P" deliberately leaves that work to you.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator
equipc/laravel-email-database-log
adedsec/nova-translated-labels
wazza/laravel-db-encryption
hokny/laravel-generator
vonsogt/backup
jengo/queues
jeremykenedy/laravel-observability
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums