settings = $settings; $this->editor = $editor; } private function editor(): EditorLoader { if ($this->editor === null) { $this->editor = Plugin::instance()->editor; } return $this->editor; } public function register(): void { add_action('admin_menu', [$this, 'menu']); add_action('admin_post_' . self::NONCE_ACTION, [$this, 'save_settings']); add_action('add_meta_boxes', [$this, 'meta_box']); add_filter('post_row_actions', [$this, 'row_action'], 10, 2); add_filter('page_row_actions', [$this, 'row_action'], 10, 2); add_action('enqueue_block_editor_assets', [$this, 'block_editor_assets']); add_action('edit_form_after_title', [$this, 'classic_editor_button']); add_action('admin_enqueue_scripts', [$this, 'enqueue_admin_assets']); } /** Delete-confirmation helper (`data-zadex-confirm` links), only on Zadex's own admin screens. */ public function enqueue_admin_assets(string $hook): void { $page = isset($_GET['page']) ? sanitize_key(wp_unslash($_GET['page'])) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only screen routing, no state change. if ($page !== 'zadex' && strpos($page, 'zadex-') !== 0) { return; } wp_enqueue_script('zadex-admin-confirm', ZADEX_URL . 'includes/Admin/assets/confirm.js', [], ZADEX_VERSION, true); } public function menu(): void { // Other screens add their markers to the menu title (Submissions: the unread count bubble, escaped there). $menu_title = (string) apply_filters('zadex/admin/menu_title', esc_html__('Zadex', 'zadex')); add_menu_page( __('Zadex', 'zadex'), $menu_title, 'manage_options', 'zadex', [$this, 'settings_page'], 'dashicons-layout', 58 ); // Explicit first submenu item, so WordPress does not copy the top-level title (with its bubble) into it. add_submenu_page('zadex', __('Zadex', 'zadex'), esc_html__('Zadex', 'zadex'), 'manage_options', 'zadex', [$this, 'settings_page']); } /** Post being edited on post.php / post-new.php (the global post WordPress sets up there; 0 when unknown). */ private function current_post_id(): int { $post = function_exists('get_post') ? get_post() : null; return $post instanceof \WP_Post && $post->ID ? (int) $post->ID : 0; } /** Data handed to includes/Admin/assets/gutenberg-button.js. */ public function admin_config(int $post_id): array { return [ 'postId' => $post_id, 'editUrl' => $this->editor()->edit_url($post_id), 'label' => __('Edit with Zadex', 'zadex'), 'isBuilder' => Document::is_builder($post_id), 'builtNotice' => self::built_notice(), ]; } /** Block editor: a real registered script (no inline JS) adds the toolbar button. */ public function block_editor_assets(): void { $post_id = $this->current_post_id(); if (!$post_id || !$this->editor()->can_edit($post_id)) { return; } wp_register_script( self::SCRIPT_HANDLE, ZADEX_URL . 'includes/Admin/assets/gutenberg-button.js', ['wp-plugins', 'wp-edit-post', 'wp-editor', 'wp-element', 'wp-data', 'wp-notices'], ZADEX_VERSION, true ); wp_localize_script(self::SCRIPT_HANDLE, 'zadexAdmin', $this->admin_config($post_id)); wp_enqueue_script(self::SCRIPT_HANDLE); } /** Classic editor: prominent button right under the title field. */ public function classic_editor_button(\WP_Post $post): void { if (!$this->editor()->can_edit((int) $post->ID)) { return; } if (function_exists('use_block_editor_for_post') && use_block_editor_for_post($post)) { return; } $built = Document::is_builder((int) $post->ID); echo '
' . esc_html(self::built_notice()) . '
' . esc_html__('Design this content visually.', 'zadex') . '
'; } echo '' . esc_html__('Edit with Zadex', 'zadex') . ''; } public function row_action(array $actions, \WP_Post $post): array { $editor = $this->editor(); if ($editor->can_edit((int) $post->ID)) { $actions['zadex'] = '' . esc_html__('Edit with Zadex', 'zadex') . ''; } return $actions; } public function settings_page(): void { if (!current_user_can('manage_options')) { return; } $breakpoints = $this->settings->breakpoints(); $enabled_types = $this->settings->post_types(); $post_types = get_post_types(['public' => true], 'objects'); unset($post_types['attachment']); ?>