input( 'action', 'get', 'list' ); switch ( $action ) { case 'edit': case 'create': self::renderForm(); break; default: self::renderList(); break; } } /** * Render the Ad Spaces list page with pagination and filters. * * @return void */ private static function renderList() { $request = static::request(); // phpcs:disable WordPress.Security.NonceVerification.Recommended // These are read-only filter/pagination params for an admin list page. // No state is mutated. Pattern mirrors WordPress core WP_List_Table behaviour. $page = max( 1, (int) $request->input( 'page_no', 'get', 1 ) ); $search_input = $request->input( 'search', 'get', '' ); if ( '' === $search_input ) { $search_input = $request->input( 's', 'get', '' ); } $current_search = trim( sanitize_text_field( wp_unslash( $search_input ) ) ); $current_status = sanitize_text_field( wp_unslash( $request->input( 'status', 'get', '' ) ) ); $filters = array(); if ( '' !== $current_search ) { $filters['search'] = $current_search; } if ( '' !== $current_status ) { $filters['status'] = $current_status; } $data = AdSpaces::withCampaignAdsPaginated( $page, 10, $filters ); // Smart pagination clamping: redirect if page is beyond last_page after items are deleted $last_page = (int) ( $data['total_pages'] ?? 1 ); if ( $page > $last_page && $last_page >= 1 && (int) ( $data['total'] ?? 0 ) > 0 ) { // phpcs:disable WordPress.Security.NonceVerification.Recommended $redirect_args = array( 'page' => sanitize_key( wp_unslash( $_GET['page'] ?? 'adfuz-spaces' ) ), 'page_no' => $last_page, ); // phpcs:enable WordPress.Security.NonceVerification.Recommended if ( ! empty( $filters['status'] ) ) { $redirect_args['status'] = $filters['status']; } if ( ! empty( $filters['search'] ) ) { $redirect_args['search'] = $filters['search']; } wp_safe_redirect( add_query_arg( $redirect_args, admin_url( 'admin.php' ) ) ); exit; } $data['current_search'] = $current_search; $data['current_status'] = $current_status; Template::load( 'admin/adz-space/index', $data ); } private static function renderForm() { $adSpaceID = (int) static::request()->input( 'ad_space_id', 'get' ); $adSpace = $adSpaceID ? DB::get( TableName::ADFUZ_AD_SPACES() )->find( $adSpaceID ) : array(); $campaigns = $adSpaceID ? Campaigns::withAdsBySpace( $adSpaceID ) : array(); $ads = DB::get( TableName::ADFUZ_ADS() ) ->where( 'status', 'active' ) ->select( array( 'id', 'title' ) ) ->orderBy( 'title' ) ->toArray(); Template::load( 'admin/adz-space/form', array( 'ad_space' => $adSpace ?? array(), 'campaigns' => $campaigns, 'ads' => $ads, ) ); } private static function viewAdd() { Template::load( 'admin/adz-space/space', array() ); } protected static function extraResponseData( int $id, array $data ): array { return array( 'redirect_url' => add_query_arg( array( 'action' => 'edit', 'ad_space_id' => $id, 'tab' => 'campaigns', ), Common::menu_page_url( 'adfuz-spaces' ) ), ); } public static function status( $name = false ) { $status = array( 'draft' => 'Draft', 'active' => 'Active', 'inactive' => 'In Active', ); return false !== $name ? $status[ $name ] : $status; } public static function save(): void { Common::checkCapability( static::getCapabilities() ); Common::verifyNonce(); $request = static::request(); $id = (int) $request->input( 'id', 'post', 0 ); // Error redirect: back to edit or create URL. $form_url = $id ? Url::adSpaceEdit( $id ) : Url::adSpaceNew(); $record_id = static::persistForm( $form_url ); static::redirectWithSuccess( __( 'AdSpace saved successfully.', 'ad-fuz' ), Url::adSpaceEdit( $record_id ) ); } public static function checkAvailability(): void { $ad_space_id = (int) static::request()->input( 'ad_space_id' ); if ( ! $ad_space_id ) { wp_send_json_error( array( 'message' => __( 'Invalid Ad Space ID.', 'ad-fuz' ), ), 400 ); return; } $result = AdSpaces::checkAvailability( $ad_space_id ); if ( ! empty( $result['not_found'] ) ) { wp_send_json_error( array( 'message' => __( 'Ad Space not found.', 'ad-fuz' ), ), 404 ); return; } if ( $result['is_full'] ) { wp_send_json_error( array( 'message' => sprintf( /* translators: %1$d = assigned count, %2$d = availability limit */ __( 'This Ad Space has reached its availability limit (%1$d/%2$d ads assigned).', 'ad-fuz' ), $result['assigned_count'], $result['availability'] ), 'assigned_count' => $result['assigned_count'], 'availability' => $result['availability'], ) ); return; } wp_send_json_success( array( 'message' => __( 'Ad Space is available.', 'ad-fuz' ), 'assigned_count' => $result['assigned_count'], 'availability' => $result['availability'], ) ); } public static function unlink(): void { Common::checkCapability( static::getCapabilities() ); Common::verifyNonce(); $campaign_id = static::request()->input( 'campaign_id', 'post', 0, 'absint' ); $ad_space_id = static::request()->input( 'ad_space_id', 'post', 0, 'absint' ); if ( ! $campaign_id || ! $ad_space_id ) { wp_send_json_error( array( 'message' => 'Invalid campaign or ad space.' ) ); } $deleted = DB::get( TableName::ADFUZ_CAMPAIGN_AD_SPACES() ) ->where( 'campaign_id', $campaign_id ) ->where( 'ad_space_id', $ad_space_id ) ->delete(); if ( $deleted ) { wp_send_json_success( array( 'message' => 'Campaign unlinked successfully.' ) ); } else { wp_send_json_error( array( 'message' => 'Failed to unlink. Record not found.' ) ); } } protected static function afterDelete( int $recordId ): void { DB::get( TableName::ADFUZ_CAMPAIGN_AD_SPACES() ) ->where( 'ad_space_id', $recordId ) ->delete(); do_action( 'adfuz/adspace/after_delete', $recordId ); } protected static function afterSave( int $recordId, array $cleanData ): void { $campaign_ids = static::request()->input( 'campaign_ids', 'post', array(), static fn( $value ) => is_array( $value ) ? array_filter( array_map( 'absint', $value ) ) : array() ); DB::get( TableName::ADFUZ_CAMPAIGN_AD_SPACES() ) ->where( 'ad_space_id', $recordId ) ->delete(); if ( empty( $campaign_ids ) ) { return; } // Re-insert with display_order. foreach ( array_values( $campaign_ids ) as $order => $campaign_id ) { DB::get( TableName::ADFUZ_CAMPAIGN_AD_SPACES() )->insert( array( 'campaign_id' => $campaign_id, 'ad_space_id' => $recordId, 'display_order' => $order, 'status' => 'active', ) ); } } }