From e13fb5e61f55ef4cee3e78909b83c123b5a4e579 Mon Sep 17 00:00:00 2001 From: Timi Wahalahti Date: Mon, 20 May 2024 23:36:36 +0300 Subject: [PATCH] Changes to WordCamp and Meetup REST API endpoints (#926) * List meetups on their REST API base and hide all meetups without public post status * Prevent getting non-public WordCamp data from REST API --- .../class-wp-rest-meetups-controller.php | 90 +++++++++++++++++++ .../wcpt/wcpt-meetup/meetup-loader.php | 63 +++++++++---- .../class-wp-rest-wordcamps-controller.php | 26 ++++++ 3 files changed, 161 insertions(+), 18 deletions(-) create mode 100644 public_html/wp-content/plugins/wcpt/wcpt-meetup/class-wp-rest-meetups-controller.php diff --git a/public_html/wp-content/plugins/wcpt/wcpt-meetup/class-wp-rest-meetups-controller.php b/public_html/wp-content/plugins/wcpt/wcpt-meetup/class-wp-rest-meetups-controller.php new file mode 100644 index 000000000..169813415 --- /dev/null +++ b/public_html/wp-content/plugins/wcpt/wcpt-meetup/class-wp-rest-meetups-controller.php @@ -0,0 +1,90 @@ +add_additional_fields_schema( $schema ); + } + + /** + * Sanitizes and validates the list of post statuses, including whether the + * user can query private statuses. + * + * Based on the method in WP_REST_Posts_Controller, but takes into account that + * there are multiple public statuses for the Meetup CPT. + * + * @access public + * + * @param string|array $statuses One or more post statuses. + * @param WP_REST_Request $request Full details about the request. + * @param string $parameter Additional parameter to pass to validation. + * @return array|WP_Error A list of valid statuses, otherwise WP_Error object. + */ + public function sanitize_post_statuses( $statuses, $request, $parameter ) { + $statuses = wp_parse_slug_list( $statuses ); + + $public_statuses = Meetup_Loader::get_public_post_statuses(); + + foreach ( $statuses as $status ) { + if ( in_array( $status, $public_statuses ) ) { + continue; + } + + $post_type_obj = get_post_type_object( $this->post_type ); + + if ( current_user_can( $post_type_obj->cap->edit_posts ) ) { + $result = rest_validate_request_arg( $status, $request, $parameter ); + if ( is_wp_error( $result ) ) { + return $result; + } + } else { + return new WP_Error( 'rest_forbidden_status', __( 'Status is forbidden.' ), array( 'status' => rest_authorization_required_code() ) ); + } + } + + return $statuses; + } + + /** + * Checks if user can read the Meetup post. + * + * First make our custom check against public Meetup statuses and + * after that fallback to default WP_REST_Posts_Controller for assurance. + * + * @access public + * + * @param object $post Post object. + * @return bool Whether the post can be read. + */ + public function check_read_permission( $post ) { + $public_statuses = Meetup_Loader::get_public_post_statuses(); + + // If post status is not listed as public, it cannot be read. + if ( ! in_array( $post->post_status, $public_statuses ) ) { + return false; + } + + // Fallback to default read permission check. + return WP_REST_Posts_Controller::check_read_permission( $post ); + } +} diff --git a/public_html/wp-content/plugins/wcpt/wcpt-meetup/meetup-loader.php b/public_html/wp-content/plugins/wcpt/wcpt-meetup/meetup-loader.php index f5cfa62fc..5a71d3d5d 100644 --- a/public_html/wp-content/plugins/wcpt/wcpt-meetup/meetup-loader.php +++ b/public_html/wp-content/plugins/wcpt/wcpt-meetup/meetup-loader.php @@ -25,6 +25,7 @@ public function __construct() { parent::__construct(); add_action( 'init', array( $this, 'register_meetup_taxonomy' ) ); add_action( 'set_object_terms', array( $this, 'log_meetup_tags' ), 10, 6 ); + add_filter( 'rest_wp_meetup_collection_params', array( $this, 'set_rest_post_status_default' ) ); } /** @@ -53,16 +54,19 @@ public function log_meetup_tags( $event_id, $terms, $tt_ids, $taxonomy, $append, 'object_ids' => $event_id, 'term_taxonomy_id' => $tt_added_ids, 'fields' => 'names', - ) - ); + ) ); $added_terms = $added_terms_query->get_terms(); - add_post_meta( $event_id, '_tags_log', array( - 'timestamp' => time(), - 'user_id' => get_current_user_id(), - 'message' => 'Tags added: ' . join( ', ', $added_terms ), - ) ); + add_post_meta( + $event_id, + '_tags_log', + array( + 'timestamp' => time(), + 'user_id' => get_current_user_id(), + 'message' => 'Tags added: ' . join( ', ', $added_terms ), + ) + ); } if ( count( $tt_removed_ids ) > 0 ) { @@ -71,14 +75,17 @@ public function log_meetup_tags( $event_id, $terms, $tt_ids, $taxonomy, $append, 'term_taxonomy_id' => $tt_removed_ids, 'fields' => 'names', 'hide_empty' => false, - ) - ) )->get_terms(); - - add_post_meta( $event_id, '_tags_log', array( - 'timestamp' => time(), - 'user_id' => get_current_user_id(), - 'message' => 'Tags removed: ' . join( ', ', $removed_terms ), - ) ); + ) ) )->get_terms(); + + add_post_meta( + $event_id, + '_tags_log', + array( + 'timestamp' => time(), + 'user_id' => get_current_user_id(), + 'message' => 'Tags removed: ' . join( ', ', $removed_terms ), + ) + ); } } @@ -111,13 +118,14 @@ public function register_meetup_taxonomy() { * Include files specific for meetup event */ public function includes() { + require_once WCPT_DIR . 'wcpt-meetup/class-wp-rest-meetups-controller.php'; } /** * Register meetup custom post type */ public function register_post_types() { - // Meetup post type labels + // Meetup post type labels. $wcpt_labels = array( 'name' => __( 'Meetups', 'wordcamporg' ), 'singular_name' => __( 'Meetup', 'wordcamporg' ), @@ -147,9 +155,10 @@ public function register_post_types() { 'author', ); - // Register WordCamp post type + // Register meetup post type. register_post_type( - Meetup_Application::POST_TYPE, array( + Meetup_Application::POST_TYPE, + array( 'labels' => $wcpt_labels, 'rewrite' => $wcpt_rewrite, 'supports' => $wcpt_supports, @@ -177,6 +186,7 @@ public function register_post_types() { 'menu_icon' => 'dashicons-wordpress', 'show_in_rest' => true, 'rest_base' => 'meetups', + 'rest_controller_class' => 'WordCamp_REST_Meetups_Controller', ) ); } @@ -199,6 +209,23 @@ public static function get_public_post_statuses() { return Meetup_Application::get_public_post_statuses(); } + /** + * Change the default status used for the Meetup CPT in the v2 REST API. + * + * @hooked filter rest_wp_meetup_collection_params + * + * @param array $query_params + * + * @return array + */ + public function set_rest_post_status_default( $query_params ) { + if ( isset( $query_params['status'] ) ) { + $query_params['status']['default'] = self::get_public_post_statuses(); + } + + return $query_params; + } + } endif; diff --git a/public_html/wp-content/plugins/wcpt/wcpt-wordcamp/class-wp-rest-wordcamps-controller.php b/public_html/wp-content/plugins/wcpt/wcpt-wordcamp/class-wp-rest-wordcamps-controller.php index f3cbb3d2e..518756ec1 100644 --- a/public_html/wp-content/plugins/wcpt/wcpt-wordcamp/class-wp-rest-wordcamps-controller.php +++ b/public_html/wp-content/plugins/wcpt/wcpt-wordcamp/class-wp-rest-wordcamps-controller.php @@ -81,4 +81,30 @@ public function sanitize_post_statuses( $statuses, $request, $parameter ) { return $statuses; } + + /** + * Checks if user can read the WordCamp post. + * + * First make our custom check against public WordCamp statuses and + * after that fallback to default WP_REST_Posts_Controller for assurance. + * + * @access public + * + * @param object $post Post object. + * @return bool Whether the post can be read. + */ + public function check_read_permission( $post ) { + $public_statuses = WordCamp_Loader::get_public_post_statuses(); + + // Camps that are scheduled and then cancelled should still be available (though not included by default). + $public_statuses[] = 'wcpt-cancelled'; + + // If post status is not listed as public, it cannot be read. + if ( ! in_array( $post->post_status, $public_statuses ) ) { + return false; + } + + // Fallback to default read permission check. + return WP_REST_Posts_Controller::check_read_permission( $post ); + } }