WP_REST_Server::READABLE, 'callback' => [ $this, 'index' ], 'permission_callback' => $auth, ] ); register_rest_route( $ns, '/404s/bulk', [ 'methods' => WP_REST_Server::CREATABLE, 'callback' => [ $this, 'bulk' ], 'permission_callback' => $auth, ] ); register_rest_route( $ns, '/404s/clear', [ 'methods' => WP_REST_Server::CREATABLE, 'callback' => [ $this, 'clear' ], 'permission_callback' => $auth, ] ); register_rest_route( $ns, '/404s/restore', [ 'methods' => WP_REST_Server::CREATABLE, 'callback' => [ $this, 'restore' ], 'permission_callback' => $auth, ] ); register_rest_route( $ns, '/404s/suggestions', [ 'methods' => WP_REST_Server::CREATABLE, 'callback' => [ $this, 'suggest' ], 'permission_callback' => $auth, ] ); } public function index( WP_REST_Request $request ): WP_REST_Response { $result = $this->log->find( [ 'search' => (string) $request->get_param( 'search' ), 'view' => (string) ( $request->get_param( 'view' ) ?? 'active' ), 'orderby' => (string) ( $request->get_param( 'orderby' ) ?? 'hits' ), 'order' => (string) ( $request->get_param( 'order' ) ?? 'desc' ), 'page' => (int) ( $request->get_param( 'page' ) ?? 1 ), 'per_page' => (int) ( $request->get_param( 'per_page' ) ?? 25 ), ] ); // Opening the list counts as having seen what is in it, so the menu bubble goes. if ( $request->get_param( 'mark_seen' ) ) { update_user_meta( get_current_user_id(), AdminModule::SEEN_META, current_time( 'mysql', true ) ); } return new WP_REST_Response( [ 'items' => $result['items'], 'total' => $result['total'], 'counts' => $this->log->counts(), ] ); } public function bulk( WP_REST_Request $request ): WP_REST_Response|WP_Error { $ids = RestModule::ids( $request->get_param( 'ids' ) ); $action = (string) $request->get_param( 'action' ); if ( [] === $ids ) { return new WP_Error( 'codebold_nothing', __( 'Select at least one address first.', 'codebold-redirects' ), [ 'status' => 400 ] ); } // What a delete removes is handed back, so the screen can offer to undo it. $deleted = 'delete' === $action ? $this->log->many( $ids ) : []; $count = match ( $action ) { 'ignore' => $this->log->set_ignored( $ids, true ), 'unignore' => $this->log->set_ignored( $ids, false ), 'delete' => $this->log->delete( $ids ), default => null, }; if ( null === $count ) { return new WP_Error( 'codebold_bad_action', __( 'Unknown bulk action.', 'codebold-redirects' ), [ 'status' => 400 ] ); } return new WP_REST_Response( [ 'count' => $count, 'deleted' => $deleted, 'counts' => $this->log->counts() ] ); } /** * Undo: put back rows that a delete or a one-click fix took out. */ public function restore( WP_REST_Request $request ): WP_REST_Response { $rows = $request->get_param( 'rows' ); $count = $this->log->restore( is_array( $rows ) ? array_values( array_slice( $rows, 0, 1000 ) ) : [] ); return new WP_REST_Response( [ 'restored' => $count, 'counts' => $this->log->counts() ] ); } public function clear( WP_REST_Request $request ): WP_REST_Response { $count = $this->log->clear( (bool) $request->get_param( 'include_ignored' ) ); return new WP_REST_Response( [ 'count' => $count, 'counts' => $this->log->counts() ] ); } /** * Suggestions for a page of rows, fetched after the list has drawn so the list itself * appears at once. */ public function suggest( WP_REST_Request $request ): WP_REST_Response { $out = []; foreach ( $this->log->many( array_slice( RestModule::ids( $request->get_param( 'ids' ) ), 0, 100 ) ) as $row ) { $out[ (string) $row['id'] ] = $this->suggestions->for_path( (string) $row['url'] ); } // Or by address — for the add form, which offers likely destinations for whatever // old address has been typed, whether or not it was ever recorded as a 404. foreach ( array_slice( (array) $request->get_param( 'urls' ), 0, 10 ) as $url ) { $url = sanitize_text_field( (string) $url ); if ( '' !== $url ) { $out[ $url ] = $this->suggestions->for_path( $url ); } } return new WP_REST_Response( [ 'suggestions' => (object) $out ] ); } }