EST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function get_items( $request ) { $user = $this->get_user( $request ); if ( is_wp_error( $user ) ) { return $user; } $passwords = WP_Application_Passwords::get_user_application_passwords( $user->ID ); $response = array(); foreach ( $passwords as $password ) { $response[] = $this->prepare_response_for_collection( $this->prepare_item_for_response( $password, $request ) ); } return new WP_REST_Response( $response ); } /** * Checks if a given request has access to get a specific application password. * * @since 5.6.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has read access for the item, WP_Error object otherwise. */ public function get_item_permissions_check( $request ) { $user = $this->get_user( $request ); if ( is_wp_error( $user ) ) { return $user; } if ( ! current_user_can( 'read_app_password', $user->ID, $request['uuid'] ) ) { return new WP_Error( 'rest_cannot_read_application_password', __( 'Sorry, you are not allowed to read this application password.' ), array( 'status' => rest_authorization_required_code() ) ); } return true; } /** * Retrieves one application password from the collection. * * @since 5.6.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function get_item( $request ) { $password = $this->get_application_password( $request ); if ( is_wp_error( $password ) ) { return $password; } return $this->prepare_item_for_response( $password, $request ); } /** * Checks if a given request has access to create application passwords. * * @since 5.6.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has access to create items, WP_Error object otherwise. */ public function create_item_permissions_check( $request ) { $user = $this->get_user( $request ); if ( is_wp_error( $user ) ) { return $user; } if ( ! current_user_can( 'create_app_password', $user->ID ) ) { return new WP_Error( 'rest_cannot_create_application_passwords', __( 'Sorry, you are not allowed to create application passwords for this user.' ), array( 'status' => rest_authorization_required_code() ) ); } return true; } /** * Creates an application password. * * @since 5.6.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function create_item( $request ) { $user = $this->get_user( $request ); if ( is_wp_error( $user ) ) { return $user; } $prepared = $this->prepare_item_for_database( $request ); if ( is_wp_error( $prepared ) ) { return $prepared; } $created = WP_Application_Passwords::create_new_application_password( $user->ID, wp_slash( (array) $prepared ) ); if ( is_wp_error( $created ) ) { return $created; } $password = $created[0]; $item = WP_Application_Passwords::get_user_application_password( $user->ID, $created[1]['uuid'] ); $item['new_password'] = WP_Application_Passwords::chunk_password( $password ); $fields_update = $this->update_additional_fields_for_object( $item, $request ); if ( is_wp_error( $fields_update ) ) { return $fields_update; } /** * Fires after a single application password is completely created or updated via the REST API. * * @since 5.6.0 * * @param array $item Inserted or updated password item. * @param WP_REST_Request $request Request object. * @param bool $creating True when creating an application password, false when updating. */ do_action( 'rest_after_insert_application_password', $item, $request, true ); $request->set_param( 'context', 'edit' ); $response = $this->prepare_item_for_response( $item, $request ); $response->set_status( 201 ); $response->header( 'Location', $response->get_links()['self'][0]['href'] ); return $response; } /** * Checks if a given request has access to update application passwords. * * @since 5.6.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has access to create items, WP_Error object otherwise. */ public function update_item_permissions_check( $request ) { $user = $this->get_user( $request ); if ( is_wp_error( $user ) ) { return $user; } if ( ! current_user_can( 'edit_app_password', $user->ID, $request['uuid'] ) ) { return new WP_Error( 'rest_cannot_edit_application_password', __( 'Sorry, you are not allowed to edit this application password.' ), array( 'status' => rest_authorization_required_code() ) ); } return true; } /** * Updates an application password. * * @since 5.6.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function update_item( $request ) { $user = $this->get_user( $request ); if ( is_wp_error( $user ) ) { return $user; } $item = $this->get_application_password( $request ); if ( is_wp_error( $item ) ) { return $item; } $prepared = $this->prepare_item_for_database( $request ); if ( is_wp_error( $prepared ) ) { return $prepared; } $saved = WP_Application_Passwords::update_application_password( $user->ID, $item['uuid'], wp_slash( (array) $prepared ) ); if ( is_wp_error( $saved ) ) { return $saved; } $fields_update = $this->update_additional_fields_for_object( $item, $request ); if ( is_wp_error( $fields_update ) ) { return $fields_update; } $item = WP_Application_Passwords::get_user_application_password( $user->ID, $item['uuid'] ); /** This action is documented in wp-includes/rest-api/endpoints/class-wp-rest-application-passwords-controller.php */ do_action( 'rest_after_insert_application_password', $item, $request, false ); $request->set_param( 'context', 'edit' ); return $this->prepare_item_for_response( $item, $request ); } /** * Checks if a given request has access to delete all application passwords for a user. * * @since 5.6.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has access to delete the item, WP_Error object otherwise. */ public function delete_items_permissions_check( $request ) { $user = $this->get_user( $request ); if ( is_wp_error( $user ) ) { return $user; } if ( ! current_user_can( 'delete_app_passwords', $user->ID ) ) { return new WP_Error( 'rest_cannot_delete_application_passwords', __( 'Sorry, you are not allowed to delete application passwords for this user.' ), array( 'status' => rest_authorization_required_code() ) ); } return true; } /** * Deletes all application passwords for a user. * * @since 5.6.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function delete_items( $request ) { $user = $this->get_user( $request ); if ( is_wp_error( $user ) ) { return $user; } $deleted = WP_Application_Passwords::delete_all_application_passwords( $user->ID ); if ( is_wp_error( $deleted ) ) { return $deleted; } return new WP_REST_Response( array( 'deleted' => true, 'count' => $deleted, ) ); } /** * Checks if a given request has access to delete a specific application password for a user. * * @since 5.6.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has access to delete the item, WP_Error object otherwise. */ public function delete_item_permissions_check( $request ) { $user = $this->get_user( $request ); if ( is_wp_error( $user ) ) { return $user; } if ( ! current_user_can( 'delete_app_password', $user->ID, $request['uuid'] ) ) { return new WP_Error( 'rest_cannot_delete_application_password', __( 'Sorry, you are not allowed to delete this application password.' ), array( 'status' => rest_authorization_required_code() ) ); } return true; } /** * Deletes an application password for a user. * * @since 5.6.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function delete_item( $request ) { $user = $this->get_user( $request ); if ( is_wp_error( $user ) ) { return $user; } $password = $this->get_application_password( $request ); if ( is_wp_error( $password ) ) { return $password; } $request->set_param( 'context', 'edit' ); $previous = $this->prepare_item_for_response( $password, $request ); $deleted = WP_Application_Passwords::delete_application_password( $user->ID, $password['uuid'] ); if ( is_wp_error( $deleted ) ) { return $deleted; } return new WP_REST_Response( array( 'deleted' => true, 'previous' => $previous->get_data(), ) ); } /** * Checks if a given request has access to get the currently used application password for a user. * * @since 5.7.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has read access for the item, WP_Error object otherwise. */ public function get_current_item_permissions_check( $request ) { $user = $this->get_user( $request ); if ( is_wp_error( $user ) ) { return $user; } if ( get_current_user_id() !== $user->ID ) { return new WP_Error( 'rest_cannot_introspect_app_password_for_non_authenticated_user', __( 'The authenticated application password can only be introspected for the current user.' ), array( 'status' => rest_authorization_required_code() ) ); } return true; } /** * Retrieves the application password being currently used for authentication of a user. * * @since 5.7.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function get_current_item( $request ) { $user = $this->get_user( $request ); if ( is_wp_error( $user ) ) { return $user; } $uuid = rest_get_authenticated_app_password(); if ( ! $uuid ) { return new WP_Error( 'rest_no_authenticated_app_password', __( 'Cannot introspect application password.' ), array( 'status' => 404 ) ); } $password = WP_Application_Passwords::get_user_application_password( $user->ID, $uuid ); if ( ! $password ) { return new WP_Error( 'rest_application_password_not_found', __( 'Application password not found.' ), array( 'status' => 500 ) ); } return $this->prepare_item_for_response( $password, $request ); } /** * Performs a permissions check for the request. * * @since 5.6.0 * @deprecated 5.7.0 Use `edit_user` directly or one of the specific meta capabilities introduced in 5.7.0. * * @param WP_REST_Request $request * @return true|WP_Error */ protected function do_permissions_check( $request ) { _deprecated_function( __METHOD__, '5.7.0' ); $user = $this->get_user( $request ); if ( is_wp_error( $user ) ) { return $user; } if ( ! current_user_can( 'edit_user', $user->ID ) ) { return new WP_Error( 'rest_cannot_manage_application_passwords', __( 'Sorry, you are not allowed to manage application passwords for this user.' ), array( 'status' => rest_authorization_required_code() ) ); } return true; } /** * Prepares an application password for a create or update operation. * * @since 5.6.0 * * @param WP_REST_Request $request Request object. * @return object|WP_Error The prepared item, or WP_Error object on failure. */ protected function prepare_item_for_database( $request ) { $prepared = (object) array( 'name' => $request['name'], ); if ( $request['app_id'] && ! $request['uuid'] ) { $prepared->app_id = $request['app_id']; } /** * Filters an application password before it is inserted via the REST API. * * @since 5.6.0 * * @param stdClass $prepared An object representing a single application password prepared for inserting or updating the database. * @param WP_REST_Request $request Request object. */ return apply_filters( 'rest_pre_insert_application_password', $prepared, $request ); } /** * Prepares the application password for the REST response. * * @since 5.6.0 * * @param array $item WordPress representation of the item. * @param WP_REST_Request $request Request object. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function prepare_item_for_response( $item, $request ) { $user = $this->get_user( $request ); if ( is_wp_error( $user ) ) { return $user; } $fields = $this->get_fields_for_response( $request ); $prepared = array( 'uuid' => $item['uuid'], 'app_id' => empty( $item['app_id'] ) ? '' : $item['app_id'], 'name' => $item['name'], 'created' => gmdate( 'Y-m-d\TH:i:s', $item['created'] ), 'last_used' => $item['last_used'] ? gmdate( 'Y-m-d\TH:i:s', $item['last_used'] ) : null, 'last_ip' => $item['last_ip'] ? $item['last_ip'] : null, ); if ( isset( $item['new_password'] ) ) { $prepared['password'] = $item['new_password']; } $prepared = $this->add_additional_fields_to_object( $prepared, $request ); $prepared = $this->filter_response_by_context( $prepared, $request['context'] ); $response = new WP_REST_Response( $prepared ); if ( rest_is_field_included( '_links', $fields ) || rest_is_field_included( '_embedded', $fields ) ) { $response->add_links( $this->prepare_links( $user, $item ) ); } /** * Filters the REST API response for an application password. * * @since 5.6.0 * * @param WP_REST_Response $response The response object. * @param array $item The application password array. * @param WP_REST_Request $request The request object. */ return apply_filters( 'rest_prepare_application_password', $response, $item, $request ); } /** * Prepares links for the request. * * @since 5.6.0 * * @param WP_User $user The requested user. * @param array $item The application password. * @return array The list of links. */ protected function prepare_links( WP_User $user, $item ) { return array( 'self' => array( 'href' => rest_url( sprintf( '%s/users/%d/application-passwords/%s', $this->namespace, $user->ID, $item['uuid'] ) ), ), ); } /** * Gets the requested user. * * @since 5.6.0 * * @param WP_REST_Request $request The request object. * @return WP_User|WP_Error The WordPress user associated with the request, or a WP_Error if none found. */ protected function get_user( $request ) { if ( ! wp_is_application_passwords_available() ) { return new WP_Error( 'application_passwords_disabled', __( 'Application passwords are not available.' ), array( 'status' => 501 ) ); } $error = new WP_Error( 'rest_user_invalid_id', __( 'Invalid user ID.' ), array( 'status' => 404 ) ); $id = $request['user_id']; if ( 'me' === $id ) { if ( ! is_user_logged_in() ) { return new WP_Error( 'rest_not_logged_in', __( 'You are not currently logged in.' ), array( 'status' => 401 ) ); } $user = wp_get_current_user(); } else { $id = (int) $id; if ( $id <= 0 ) { return $error; } $user = get_userdata( $id ); } if ( empty( $user ) || ! $user->exists() ) { return $error; } if ( is_multisite() && ! user_can( $user->ID, 'manage_sites' ) && ! is_user_member_of_blog( $user->ID ) ) { return $error; } if ( ! wp_is_application_passwords_available_for_user( $user ) ) { return new WP_Error( 'application_passwords_disabled_for_user', __( 'Application passwords are not available for your account. Please contact the site administrator for assistance.' ), array( 'status' => 501 ) ); } return $user; } /** * Gets the requested application password for a user. * * @since 5.6.0 * * @param WP_REST_Request $request The request object. * @return array|WP_Error The application password details if found, a WP_Error otherwise. */ protected function get_application_password( $request ) { $user = $this->get_user( $request ); if ( is_wp_error( $user ) ) { return $user; } $password = WP_Application_Passwords::get_user_application_password( $user->ID, $request['uuid'] ); if ( ! $password ) { return new WP_Error( 'rest_application_password_not_found', __( 'Application password not found.' ), array( 'status' => 404 ) ); } return $password; } /** * Retrieves the query params for the collections. * * @since 5.6.0 * * @return array Query parameters for the collection. */ public function get_collection_params() { return array( 'context' => $this->get_context_param( array( 'default' => 'view' ) ), ); } /** * Retrieves the application password's schema, conforming to JSON Schema. * * @since 5.6.0 * * @return array Item schema data. */ public function get_item_schema() { if ( $this->schema ) { return $this->add_additional_fields_schema( $this->schema ); } $this->schema = array( '$schema' => 'http://json-schema.org/draft-04/schema#', 'title' => 'application-password', 'type' => 'object', 'properties' => array( 'uuid' => array( 'description' => __( 'The unique identifier for the application password.' ), 'type' => 'string', 'format' => 'uuid', 'context' => array( 'view', 'edit', 'embed' ), 'readonly' => true, ), 'app_id' => array( 'description' => __( 'A UUID provided by the application to uniquely identify it. It is recommended to use an UUID v5 with the URL or DNS namespace.' ), 'type' => 'string', 'format' => 'uuid', 'context' => array( 'view', 'edit', 'embed' ), ), 'name' => array( 'description' => __( 'The name of the application password.' ), 'type' => 'string', 'required' => true, 'context' => array( 'view', 'edit', 'embed' ), 'minLength' => 1, 'pattern' => '.*\S.*', ), 'password' => array( 'description' => __( 'The generated password. Only available after adding an application.' ), 'type' => 'string', 'context' => array( 'edit' ), 'readonly' => true, ), 'created' => array( 'description' => __( 'The GMT date the application password was created.' ), 'type' => 'string', 'format' => 'date-time', 'context' => array( 'view', 'edit' ), 'readonly' => true, ), 'last_used' => array( 'description' => __( 'The GMT date the application password was last used.' ), 'type' => array( 'string', 'null' ), 'format' => 'date-time', 'context' => array( 'view', 'edit' ), 'readonly' => true, ), 'last_ip' => array( 'description' => __( 'The IP address the application password was last used by.' ), 'type' => array( 'string', 'null' ), 'format' => 'ip', 'context' => array( 'view', 'edit' ), 'readonly' => true, ), ), ); return $this->add_additional_fields_schema( $this->schema ); } } ng $url, bool $enabled = true ): bool { $url = $this->prepare_url_for_upsert( $url ); $existing_path = $this->get_by_url( $url ); // No need to go any further if the URL is already listed and nothing has changed. if ( $existing_path && $existing_path->get_url() === $url && $enabled === $existing_path->is_enabled() ) { return true; } global $wpdb; $fields = array( 'url' => $url, 'enabled' => (int) $enabled, ); if ( false === $wpdb->update( $this->get_table(), $fields, array( 'url_id' => $id ) ) ) { throw new ApprovedDirectoriesException( __( 'URL could not be updated (probable database error).', 'woocommerce' ), ApprovedDirectoriesException::DB_ERROR ); } return true; } /** * Indicates if the specified URL is already an approved directory. * * @param string $url The URL to check. * * @return bool */ public function approved_directory_exists( string $url ): bool { return (bool) $this->get_by_url( $url ); } /** * Returns the path identified by $id, or false if it does not exist. * * @param int $id The ID of the rule we are looking for. * * @return StoredUrl|false */ public function get_by_id( int $id ) { global $wpdb; $table = $this->get_table(); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared $result = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$table} WHERE url_id = %d", array( $id ) ) ); if ( ! $result ) { return false; } return new StoredUrl( $result->url_id, $result->url, $result->enabled ); } /** * Returns the path identified by $url, or false if it does not exist. * * @param string $url The URL of the rule we are looking for. * * @return StoredUrl|false */ public function get_by_url( string $url ) { global $wpdb; $table = $this->get_table(); $url = trailingslashit( $url ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared $result = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$table} WHERE url = %s", array( $url ) ) ); if ( ! $result ) { return false; } return new StoredUrl( $result->url_id, $result->url, $result->enabled ); } /** * Indicates if the URL is within an approved directory. The approved directory must be enabled * (it is possible for individual approved directories to be disabled). * * For instance, for 'https://storage.king/12345/ebook.pdf' to be valid then 'https://storage.king/12345' * would need to be within our register. * * If the provided URL is a filepath it can be passed in without the 'file://' scheme. * * @throws URLException If the provided URL is badly formed. * * @param string $download_url The URL to check. * * @return bool */ public function is_valid_path( string $download_url ): bool { global $wpdb; $parent_directories = array(); foreach ( ( new URL( $this->normalize_url( $download_url ) ) )->get_all_parent_urls() as $parent ) { $parent_directories[] = "'" . esc_sql( $parent ) . "'"; } if ( empty( $parent_directories ) ) { return false; } $parent_directories = join( ',', $parent_directories ); $table = $this->get_table(); // Look for a rule that matches the start of the download URL being tested. Since rules describe parent // directories, we also ensure it ends with a trailing slash. // // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared $matches = (int) $wpdb->get_var( " SELECT COUNT(*) FROM {$table} WHERE enabled = 1 AND url IN ( {$parent_directories} ) " ); // phpcs:enable return $matches > 0; } /** * Used when a URL string is prepared before potentially adding it to the database. * * It will be normalized and trailing-slashed; a length check will also be performed. * * @throws ApprovedDirectoriesException If the operation could not be performed. * @throws URLException If the URL was invalid. * * @param string $url The string URL to be normalized and trailing-slashed. * * @return string */ private function prepare_url_for_upsert( string $url ): string { $url = trailingslashit( $this->normalize_url( $url ) ); if ( mb_strlen( $url ) > 256 ) { throw new ApprovedDirectoriesException( __( 'Approved directory URLs cannot be longer than 256 characters.', 'woocommerce' ), ApprovedDirectoriesException::INVALID_URL ); } return $url; } /** * Normalizes the provided URL, by trimming whitespace per normal PHP conventions * and removing any trailing slashes. If it lacks a scheme, the file scheme is * assumed and prepended. * * @throws URLException If the URL is badly formed. * * @param string $url The URL to be normalized. * * @return string */ private function normalize_url( string $url ): string { $url = untrailingslashit( trim( $url ) ); return ( new URL( $url ) )->get_url(); } /** * Lists currently approved directories. * * Returned array will have the following structure: * * [ * 'total_urls' => 12345, * 'total_pages' => 123, * 'urls' => [], # StoredUrl[] * ] * * @param array $args { * Controls pagination and ordering. * * @type null|bool $enabled Controls if only enabled (true), disabled (false) or all rules (null) should be listed. * @type string $order Ordering ('ASC' for ascending, 'DESC' for descending). * @type string $order_by Field to order by (one of 'url_id' or 'url'). * @type int $page The page of results to retrieve. * @type int $per_page The number of results to retrieve per page. * @type string $search Term to search for. * } * * @return array */ public function list( array $args ): array { global $wpdb; $args = array_merge( array( 'enabled' => null, 'order' => 'ASC', 'order_by' => 'url', 'page' => 1, 'per_page' => 20, 'search' => '', ), $args ); $table = $this->get_table(); $paths = array(); $order = in_array( $args['order'], array( 'ASC', 'DESC' ), true ) ? $args['order'] : 'ASC'; $order_by = in_array( $args['order_by'], array( 'url_id', 'url' ), true ) ? $args['order_by'] : 'url'; $page = absint( $args['page'] ); $per_page = absint( $args['per_page'] ); $enabled = is_bool( $args['enabled'] ) ? $args['enabled'] : null; $search = '%' . $wpdb->esc_like( sanitize_text_field( $args['search'] ) ) . '%'; if ( $page < 1 ) { $page = 1; } if ( $per_page < 1 ) { $per_page = 1; } $where = array(); $where_sql = ''; if ( ! empty( $search ) ) { $where[] = $wpdb->prepare( 'url LIKE %s', $search ); } if ( is_bool( $enabled ) ) { $where[] = 'enabled = ' . (int) $enabled; } if ( ! empty( $where ) ) { $where_sql = 'WHERE ' . join( ' AND ', $where ); } // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared $results = $wpdb->get_results( $wpdb->prepare( " SELECT url_id, url, enabled FROM {$table} {$where_sql} ORDER BY {$order_by} {$order} LIMIT %d, %d ", ( $page - 1 ) * $per_page, $per_page ) ); $total_rows = (int) $wpdb->get_var( "SELECT COUNT( * ) FROM {$table} {$where_sql}" ); // phpcs:enable foreach ( $results as $single_result ) { $paths[] = new StoredUrl( $single_result->url_id, $single_result->url, $single_result->enabled ); } return array( 'total_urls' => $total_rows, 'total_pages' => (int) ceil( $total_rows / $per_page ), 'approved_directories' => $paths, ); } /** * Delete the approved directory identitied by the supplied ID. * * @param int $id The ID of the rule to be deleted. * * @return bool */ public function delete_by_id( int $id ): bool { global $wpdb; $table = $this->get_table(); return (bool) $wpdb->delete( $table, array( 'url_id' => $id ) ); } /** * Delete the entirev approved directory list. * * @return bool */ public function delete_all(): bool { global $wpdb; $table = $this->get_table(); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared return (bool) $wpdb->query( "DELETE FROM $table" ); } /** * Enable the approved directory identitied by the supplied ID. * * @param int $id The ID of the rule to be deleted. * * @return bool */ public function enable_by_id( int $id ): bool { global $wpdb; $table = $this->get_table(); return (bool) $wpdb->update( $table, array( 'enabled' => 1 ), array( 'url_id' => $id ) ); } /** * Disable the approved directory identitied by the supplied ID. * * @param int $id The ID of the rule to be deleted. * * @return bool */ public function disable_by_id( int $id ): bool { global $wpdb; $table = $this->get_table(); return (bool) $wpdb->update( $table, array( 'enabled' => 0 ), array( 'url_id' => $id ) ); } /** * Enables all Approved Download Directory rules in a single operation. * * @return bool */ public function enable_all(): bool { global $wpdb; $table = $this->get_table(); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared return (bool) $wpdb->query( "UPDATE {$table} SET enabled = 1" ); } /** * Disables all Approved Download Directory rules in a single operation. * * @return bool */ public function disable_all(): bool { global $wpdb; $table = $this->get_table(); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared return (bool) $wpdb->query( "UPDATE {$table} SET enabled = 0" ); } /** * Indicates the number of approved directories that are enabled (or disabled, if optional * param $enabled is set to false). * * @param bool $enabled Controls whether enabled or disabled directory rules are counted. * * @return int */ public function count( bool $enabled = true ): int { global $wpdb; $table = $this->get_table(); return (int) $wpdb->get_var( $wpdb->prepare( // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared "SELECT COUNT(*) FROM {$table} WHERE enabled = %d", $enabled ? 1 : 0 ) ); } }