false, 'type' => false, 'proper_filename' => false]; public static function manifest(): Manifest { return new Manifest( Manifest::DESIGN, calls: [ new Call(FontsUtility::class . '::mime_types_font', 0), new Call(HooksRegistration::class . '::check_filetype_and_ext_font', 3), new Call(FontsUtility::class . '::font_add', 4), new Call(FontsUtility::class . '::font_remove', 1), ], constants: [FontsUtility::class . '::FONT_NAME_MAX_LENGTH'], // Read before font_add(): a corrupt list would make Divi lose the files it moved. keys: ['et_uploaded_fonts'], mirrors: [ new Mirror( 'font-install', 'includes/builder-5/server/VisualBuilder/AiAgent/AiAgentImageUtility.php', 'install_to_custom_fonts', 'AiAgentImageUtility', 'Aufrufkonvention von font_add() mit serverseitiger Temp-Datei (check_filetype_and_ext_font ' . 'vorab, wp_tempnam, action wp_handle_upload_rest)' ), ], features: [DiviFeature::FontUpload] ); } /** @return list FORMATS that Divi's font MIME list knows too. */ public function formats(): array { return array_values(array_intersect(self::FORMATS, array_keys(FontsUtility::mime_types_font()))); } /** Divi's bound for a font name (FontNameRules::check() takes it). */ public function nameMaxLength(): int { return (int) FontsUtility::FONT_NAME_MAX_LENGTH; } /** Whether Divi's content check (finfo) takes $path as a font of $filename's extension. */ public function accepts(string $path, string $filename): bool { return $this->mimeOf($path, $filename) !== null; } /** * @param array $files Extension => temp file path (deleted or moved by WordPress). * @return list The extensions Divi stored – fewer than $files on a partial success. * @throws DiviLocked When font-upload is not released – before anything is written. * @throws RuntimeException When Divi's font list is corrupt or Divi refuses a file or the whole font; nothing is stored then. */ public function install(string $name, array $files, string $weights, string $family): array { ReleaseGate::assertFeature(DiviFeature::FontUpload); if (! is_array(get_option('et_uploaded_fonts', []))) { throw new RuntimeException( 'Divis Schriftenliste (et_uploaded_fonts) ist beschädigt; nichts wurde gespeichert. ' . 'Die Option in Divi bzw. der Datenbank prüfen.' ); } $uploads = []; foreach ($files as $extension => $path) { $filename = sanitize_file_name($name . '.' . $extension); $mime = $this->mimeOf($path, $filename); if ($mime === null) { throw new RuntimeException(sprintf("font file %s refused by Divi's type check", $extension)); } clearstatcache(true, $path); $uploads[$extension] = [ 'name' => $filename, 'type' => $mime, 'tmp_name' => $path, 'error' => 0, 'size' => (int) filesize($path), ]; } $result = FontsUtility::font_add( $uploads, $name, ['font_weights' => $weights, 'generic_family' => $family], ['action' => 'wp_handle_upload_rest'] ); if (is_wp_error($result)) { throw new RuntimeException('font_add refused: ' . $result->get_error_message()); } $stored = is_array($result) ? ($result['updated_fonts'][$name]['font_file'] ?? null) : null; return is_array($stored) ? array_map('strval', array_keys($stored)) : []; } /** @throws RuntimeException When Divi does not remove the font (e.g. it does not exist). */ public function remove(string $name): void { $result = FontsUtility::font_remove($name); if (is_wp_error($result)) { throw new RuntimeException('font_remove refused: ' . $result->get_error_message()); } } /** The MIME type Divi detected, or null when it refuses the content or names another extension. */ private function mimeOf(string $path, string $filename): ?string { $checked = HooksRegistration::check_filetype_and_ext_font(self::UNCHECKED, $path, $filename); $extension = strtolower((string) ($checked['ext'] ?? '')); $type = (string) ($checked['type'] ?? ''); return $type !== '' && $extension !== '' && $extension === strtolower(pathinfo($filename, PATHINFO_EXTENSION)) ? $type : null; } }