icons = $icons; } public function register(): void { add_action('admin_menu', [$this, 'menu'], 20); add_action('admin_enqueue_scripts', [$this, 'assets']); add_action('admin_post_' . self::ACTION_IMPORT, [$this, 'import']); add_action('admin_post_' . self::ACTION_DELETE, [$this, 'delete']); } public static function url(array $args = []): string { return add_query_arg(['page' => self::SLUG] + $args, admin_url('admin.php')); } public function menu(): void { $this->hook = (string) add_submenu_page('zadex', __('Custom Icons', 'zadex'), __('Custom Icons', 'zadex'), IconSets::CAPABILITY, self::SLUG, [$this, 'render']); } public function assets(string $hook): void { if ($hook !== $this->hook) { return; } foreach ($this->icons->all() as $set) { wp_enqueue_style(IconSets::handle((string) $set['slug']), $this->icons->style_url($set), [], (string) ($set['version'] ?? ZADEX_VERSION)); } } /** @return string|\WP_Error path of the uploaded zip */ public static function validate_upload($file) { if (!is_array($file) || !isset($file['tmp_name'], $file['name'], $file['error']) || (int) $file['error'] !== 0) { return new \WP_Error('zadex_no_file', __('Choose an icon set (.zip) to upload.', 'zadex')); } if (strtolower(pathinfo((string) $file['name'], PATHINFO_EXTENSION)) !== 'zip') { return new \WP_Error('zadex_bad_type', __('Icon sets are uploaded as a .zip file.', 'zadex')); } $size = (int) ($file['size'] ?? 0); $tmp = (string) $file['tmp_name']; if ($size <= 0 || $size > self::MAX_UPLOAD || !is_file($tmp) || (function_exists('is_uploaded_file') && !is_uploaded_file($tmp))) { return new \WP_Error('zadex_bad_type', __('The file is empty or too large.', 'zadex')); } return $tmp; } /** admin-post.php: import an icon-set zip (capability + nonce first, then the sanitized upload entry). */ public function import(): void { if (!current_user_can(IconSets::CAPABILITY)) { wp_die(esc_html__('You are not allowed to manage icon sets.', 'zadex'), 403); } check_admin_referer(self::ACTION_IMPORT); $label = isset($_POST['label']) ? sanitize_text_field(wp_unslash($_POST['label'])) : ''; $tmp = self::validate_upload(UploadedFile::from_request('icon_zip', self::ACTION_IMPORT)); $result = is_wp_error($tmp) ? $tmp : $this->icons->import($tmp, $label); if (is_wp_error($result)) { Notices::add(self::SLUG, $result->get_error_message(), 'error', 'icons-error'); } else { Notices::add(self::SLUG, __('Icon set imported. It is now available in the icon picker of the Zadex editor.', 'zadex'), 'success', 'icons-imported'); } wp_safe_redirect(self::url()); exit; } /** admin-post.php: delete an icon set. */ public function delete(): void { if (!current_user_can(IconSets::CAPABILITY)) { wp_die(esc_html__('You are not allowed to manage icon sets.', 'zadex'), 403); } check_admin_referer(self::ACTION_DELETE); $this->icons->delete(isset($_GET['set']) ? sanitize_key(wp_unslash($_GET['set'])) : ''); Notices::add(self::SLUG, __('Icon set deleted.', 'zadex')); wp_safe_redirect(self::url()); exit; } public function render(): void { if (!current_user_can(IconSets::CAPABILITY)) { return; } $sets = $this->icons->all(); ?>