Browse Source

changes to import all the latest h5p css not just the missing files

main
Paul Pound 3 weeks ago
parent
commit
7c502dc094
  1. 169
      h5p-core-fonts-fix.php

169
h5p-core-fonts-fix.php

@ -1,45 +1,170 @@
<?php
/**
* Plugin Name: H5P core fonts fix
* Description: Re-adds styles/h5p-fonts.css to H5PCore::$styles, which Pressbooks' vendored h5p-core 1.27 omits.
* Plugin Name: H5P core version reconciliation
* Description: Reconciles H5PCore's static properties with the h5p-php-library actually installed, which Pressbooks' vendored h5p-core 1.27 misreports.
*
* Pressbooks pins h5p/h5p-core 1.27.0 and requires it eagerly through Composer's
* autoload_files.php, so it defines H5PCore before the H5P plugin's lazy autoloader
* (h5p/autoloader.php) ever gets a chance to. H5PCore::$styles is therefore always the
* 1.27 list, while H5P_Plugin::add_core_assets() resolves those filenames against the
* H5P plugin's own h5p-php-library (1.28+), where the icon @font-face was moved out of
* h5p.css into h5p-fonts.css.
* Pressbooks pins h5p/h5p-core 1.27.0, and that package declares its classes under
* Composer's autoload.files, so h5p.classes.php is eagerly required when Pressbooks'
* autoloader boots. The H5P WordPress plugin registers the same classes through a lazy
* spl_autoload_register classmap (h5p/autoloader.php) and never requires the file
* directly. Eager autoload wins, the plugin's autoloader never fires, and no redeclare
* fatal occurs — so H5PCore silently describes 1.27 while the library actually installed,
* executed and served to browsers is the H5P plugin's 1.28 at a different path.
*
* Net effect: h5p-fonts.css never makes it into H5PIntegration.core.styles, so the
* document.write()n content iframe has no 'h5p' icon font and the action bar renders
* Reuse/Embed/Rights of use with tofu boxes instead of icons (and the H5P logo link,
* being icon-only, disappears entirely).
* Two symptoms follow, both fixed here by reconciling the statics with what is on disk:
*
* 1. $styles omits three stylesheets 1.28 ships. add_core_assets() resolves the 1.27 list
* against plugins_url('h5p/h5p-php-library'), so the content iframe is built without
* the icon @font-face (action bar renders as tofu) and without the theme layer that
* 1.28-era libraries depend on (content collapses — see PB_H5P_RESTORE_STYLES).
*
* 2. $coreApi reports 1.27. H5PValidator::isValidH5pData() compares an imported package's
* declared coreApi against it, so importing an .h5p archive containing a library that
* requires 1.28 fails with "requires a newer version of the H5P plugin ... currently
* running version 1.27". Authoring new content is unaffected, because the editor never
* runs the package validator.
*
* Reporting the shipped values is accurate, not a workaround: coreApi describes the
* client-side H5P core JS, and the JS actually served is the shipped one. The PHP delta
* between 1.27 and 1.28 is confined to Hub endpoints and one sanitization fix, with no
* change to content validation or storage.
*
* Remove this once Pressbooks' vendored h5p-core catches up with the H5P plugin's
* h5p-php-library.
* h5p-php-library. Removing the file is a complete rollback: nothing here is persisted
* beyond a cache of values read from disk.
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Stylesheets 1.28 ships that 1.27's $styles omits, used as a fallback if the shipped
* $styles array can't be parsed.
*
* h5p-fonts.css carries the icon @font-face. The other two carry H5P's 1.28 theme layer:
* h5p-theme-variables.css defines ~82 --h5p-theme-* custom properties, and h5p-theme.css
* consumes them. Libraries built against 1.28 — H5P.Components, and current builds of the
* shared H5P.Question / H5P.JoubelUI / H5P.DragText — reference those variables heavily,
* and without the definitions every reference resolves to an empty string and the content
* collapses. Importing any recent .h5p package upgrades those shared libraries site-wide,
* so this is not opt-in.
*
* Restoring all three is safe for older content: h5p-theme.css is scoped entirely to
* .h5p-theme / .h5p-content:has(.h5p-theme), which only 1.28-era libraries apply to
* themselves, and h5p-theme-variables.css just declares custom properties on :root and
* .h5peditor. Neither affects a library that does not reference them.
*/
const PB_H5P_RESTORE_STYLES = [
'styles/h5p-fonts.css',
'styles/h5p-theme.css',
'styles/h5p-theme-variables.css',
];
/**
* Read the coreApi version and core stylesheet list declared by the h5p-php-library on
* disk.
*
* Parsed rather than hardcoded so this keeps telling the truth across H5P plugin updates,
* and so the stylesheet list keeps upstream's ordering by construction. Cached against the
* file's mtime. Either value may come back null, in which case callers fall back.
*
* @param string $classes_file Absolute path to the shipped h5p.classes.php.
* @return array{coreApi:?array,styles:?array}
*/
function pb_h5p_shipped_core_values( $classes_file ) {
$mtime = @filemtime( $classes_file );
$cached = get_site_transient( 'pb_h5p_shipped_core_values' );
if ( is_array( $cached ) && isset( $cached['mtime'] ) && $cached['mtime'] === $mtime ) {
return $cached['values'];
}
$source = @file_get_contents( $classes_file );
$values = [ 'coreApi' => null, 'styles' => null ];
if ( $source ) {
if ( preg_match(
'/public\s+static\s+\$coreApi\s*=\s*(?:array\s*\(|\[)\s*'
. "'majorVersion'\s*=>\s*(\d+)\s*,\s*'minorVersion'\s*=>\s*(\d+)/",
$source,
$m
) ) {
$values['coreApi'] = [
'majorVersion' => (int) $m[1],
'minorVersion' => (int) $m[2],
];
}
if ( preg_match( '/public\s+static\s+\$styles\s*=\s*(?:array\s*\(|\[)(.*?)(?:\)|\])\s*;/s', $source, $m )
&& preg_match_all( "/'([^']+\.css)'/", $m[1], $found )
) {
$values['styles'] = $found[1];
}
}
set_site_transient(
'pb_h5p_shipped_core_values',
[ 'mtime' => $mtime, 'values' => $values ],
DAY_IN_SECONDS
);
return $values;
}
add_action( 'plugins_loaded', function () {
if ( ! class_exists( 'H5PCore' ) ) {
return;
}
// add_core_assets() resolves these against plugins_url('h5p/h5p-php-library').
$library_dir = WP_PLUGIN_DIR . '/h5p/h5p-php-library/';
// add_core_assets() resolves style paths against plugins_url('h5p/h5p-php-library').
$library_dir = WP_PLUGIN_DIR . '/h5p/h5p-php-library/';
$classes_file = $library_dir . 'h5p.classes.php';
$missing = [];
foreach ( [ 'styles/h5p-fonts.css' ] as $style ) {
if ( ! in_array( $style, H5PCore::$styles, true ) && file_exists( $library_dir . $style ) ) {
$missing[] = $style;
if ( ! is_readable( $classes_file ) ) {
return;
}
$shipped = pb_h5p_shipped_core_values( $classes_file );
$loaded = H5PCore::$styles;
// 1. Adopt the shipped stylesheet list, which preserves upstream's ordering — the
// theme layer has to load after h5p.css to override it. Only files actually
// present are included, and anything the loaded list has that the shipped one
// doesn't is kept, so this can only ever add.
if ( $shipped['styles'] ) {
$styles = array_values( array_filter(
$shipped['styles'],
function ( $style ) use ( $library_dir ) {
return file_exists( $library_dir . $style );
}
) );
H5PCore::$styles = array_merge( $styles, array_values( array_diff( $loaded, $styles ) ) );
} else {
// Fallback: prepend whichever known-missing sheets are present.
$missing = array_values( array_filter(
PB_H5P_RESTORE_STYLES,
function ( $style ) use ( $library_dir, $loaded ) {
return ! in_array( $style, $loaded, true ) && file_exists( $library_dir . $style );
}
) );
if ( $missing ) {
H5PCore::$styles = array_merge( $missing, $loaded );
}
}
if ( $missing ) {
// Prepend, mirroring upstream ordering.
H5PCore::$styles = array_merge( $missing, H5PCore::$styles );
// 2. Report the coreApi the shipped library actually implements. Only ever raised,
// so a future vendor copy that overtakes the H5P plugin is left untouched.
if ( ! $shipped['coreApi'] ) {
return;
}
$current = H5PCore::$coreApi;
$is_newer = $shipped['coreApi']['majorVersion'] > $current['majorVersion']
|| ( $shipped['coreApi']['majorVersion'] === $current['majorVersion']
&& $shipped['coreApi']['minorVersion'] > $current['minorVersion'] );
if ( $is_newer ) {
H5PCore::$coreApi = $shipped['coreApi'];
}
}, 100 );

Loading…
Cancel
Save