register(); } /** * Adds the top-level menu and submenu pages to wp-admin. * * @since 1.0.0 * @return void */ public function add_menus(): void { add_menu_page( __( 'BreznFlow', 'breznflow' ), __( 'BreznFlow', 'breznflow' ), 'edit_posts', 'breznflow', array( $this, 'render_dashboard' ), 'dashicons-networking', 30 ); add_submenu_page( 'breznflow', __( 'All Workflows', 'breznflow' ), __( 'All Workflows', 'breznflow' ), 'edit_posts', 'breznflow', array( $this, 'render_dashboard' ) ); add_submenu_page( 'breznflow', __( 'Add Workflow', 'breznflow' ), __( 'Add Workflow', 'breznflow' ), 'edit_posts', 'breznflow-add', array( $this, 'render_wizard' ) ); add_submenu_page( 'breznflow', __( 'Themes', 'breznflow' ), __( 'Themes', 'breznflow' ), 'manage_options', 'breznflow-themes', array( $this, 'render_themes' ) ); add_submenu_page( 'breznflow', __( 'Settings', 'breznflow' ), __( 'Settings', 'breznflow' ), 'manage_options', 'breznflow-settings', array( $this, 'render_settings' ) ); } /** * Handles single and bulk delete actions early (admin_init), * before any output is sent — so wp_safe_redirect() works correctly. */ public function handle_delete_action(): void { // Only act on our page. if ( ! isset( $_GET['page'] ) || 'breznflow' !== $_GET['page'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended return; } $action = isset( $_GET['action'] ) ? sanitize_key( $_GET['action'] ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended // ── Single-row delete ───────────────────────────────────────────────── if ( 'delete' === $action && isset( $_GET['post'] ) && ! isset( $_GET['workflow'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended $post_id = (int) sanitize_text_field( wp_unslash( $_GET['post'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended if ( $post_id > 0 && check_admin_referer( 'breznflow_delete_' . $post_id ) && current_user_can( 'delete_post', $post_id ) ) { wp_trash_post( $post_id ); wp_safe_redirect( add_query_arg( array( 'page' => 'breznflow', 'deleted' => '1', ), admin_url( 'admin.php' ) ) ); exit; } } // ── Bulk delete ─────────────────────────────────────────────────────── // WP_List_Table sends action2 when the bottom select is used. $bulk = $action; if ( 'delete' !== $bulk && isset( $_GET['action2'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended $bulk = sanitize_key( $_GET['action2'] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended } if ( 'delete' === $bulk && isset( $_GET['workflow'] ) && is_array( $_GET['workflow'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended check_admin_referer( 'bulk-workflows' ); $count = 0; $raw_workflows = array_map( 'absint', wp_unslash( $_GET['workflow'] ) ); foreach ( $raw_workflows as $pid ) { if ( $pid > 0 && current_user_can( 'delete_post', $pid ) ) { wp_trash_post( $pid ); ++$count; } } wp_safe_redirect( add_query_arg( array( 'page' => 'breznflow', 'deleted' => $count, ), admin_url( 'admin.php' ) ) ); exit; } } /** * Renders the workflow list dashboard page. * * @since 1.0.0 * @return void */ public function render_dashboard(): void { require_once BREZNFLOW_DIR . 'includes/Admin/WorkflowListTable.php'; $table = new WorkflowListTable(); $table->prepare_items(); require BREZNFLOW_DIR . 'includes/Admin/views/list.php'; } /** * Renders the add-workflow wizard page for the current step. * * @since 1.0.0 * @return void */ public function render_wizard(): void { $step = isset( $_GET['step'] ) ? (int) $_GET['step'] : 1; // phpcs:ignore WordPress.Security.NonceVerification.Recommended switch ( $step ) { case 2: require BREZNFLOW_DIR . 'includes/Admin/views/wizard-step-2.php'; break; case 3: require BREZNFLOW_DIR . 'includes/Admin/views/wizard-step-3.php'; break; default: require BREZNFLOW_DIR . 'includes/Admin/views/wizard-step-1.php'; break; } } /** * Renders the themes management page. * * @since 1.0.0 * @return void */ public function render_themes(): void { require_once BREZNFLOW_DIR . 'includes/Admin/ThemesPage.php'; ( new ThemesPage() )->render(); } /** * Renders the plugin settings page. * * @since 1.0.0 * @return void */ public function render_settings(): void { require BREZNFLOW_DIR . 'includes/Admin/views/settings.php'; } }