get_per_page($request); $page = $this->get_page($request); $offset = ($page - 1) * $per_page; $exclude = $this->get_id_list_param($request, 'exclude'); $count_args = [ 'taxonomy' => 'product_cat', 'hide_empty' => false, ]; if (!empty($exclude)) { // phpcs:ignore WordPressVIPMinimum.Performance.WPQueryParams.PostNotIn_exclude -- Optional client-driven term exclusion for catalog sync. $count_args['exclude'] = $exclude; } $total = (int) wp_count_terms($count_args); if (is_wp_error($total)) { return $total; } $term_args = [ 'taxonomy' => 'product_cat', 'hide_empty' => false, 'number' => $per_page, 'offset' => $offset, 'orderby' => 'term_id', 'order' => 'DESC', ]; if (!empty($exclude)) { // phpcs:ignore WordPressVIPMinimum.Performance.WPQueryParams.PostNotIn_exclude -- Optional client-driven term exclusion for catalog sync. $term_args['exclude'] = $exclude; } $terms = get_terms($term_args); if (is_wp_error($terms)) { return $terms; } $controller = new Twokcs_REST_Categories_Controller(); $items = []; foreach ($terms as $term) { $items[] = $controller->prepare_item_for_response($term, $request)->get_data(); } return $this->build_response('results', $items, $total, $per_page, $request); } /** * Export paginated product attributes. * * @param WP_REST_Request $request Request object. * @return WP_REST_Response|WP_Error */ public function export_attributes(WP_REST_Request $request) { $per_page = $this->get_per_page($request); $page = $this->get_page($request); $offset = ($page - 1) * $per_page; $exclude = $this->get_id_list_param($request, 'exclude'); $attributes = wc_get_attribute_taxonomies(); if (!empty($exclude)) { $attributes = array_values(array_filter($attributes, function ($attribute) use ($exclude) { return !in_array((int) $attribute->attribute_id, $exclude, true); })); } $total = count($attributes); $slice = array_slice($attributes, $offset, $per_page); $controller = new Twokcs_REST_Attributes_Controller(); $items = []; foreach ($slice as $attribute) { $items[] = $controller->prepare_item_for_response($attribute, $request)->get_data(); } return $this->build_response('results', $items, $total, $per_page, $request); } /** * Export paginated attribute terms. * * @param WP_REST_Request $request Request object. * @return WP_REST_Response|WP_Error */ public function export_attribute_terms(WP_REST_Request $request) { $per_page = $this->get_per_page($request); $page = $this->get_page($request); $offset = ($page - 1) * $per_page; $attribute_id = (int) $request->get_param('attribute_id'); $taxonomy_map = $this->get_attribute_taxonomy_map(); if ($attribute_id > 0) { if (!isset($taxonomy_map[$attribute_id])) { return new WP_Error( 'twokcs_invalid_attribute', __('Invalid attribute ID.', '2khat-catalog-sync'), ['status' => 400] ); } $taxonomy_map = [$attribute_id => $taxonomy_map[$attribute_id]]; } $taxonomies = array_values($taxonomy_map); if (empty($taxonomies)) { return $this->build_response('attribute_terms', [], 0, $per_page, $request); } $exclude = $this->get_id_list_param($request, 'exclude'); $count_args = [ 'taxonomy' => $taxonomies, 'hide_empty' => false, ]; if (!empty($exclude)) { // phpcs:ignore WordPressVIPMinimum.Performance.WPQueryParams.PostNotIn_exclude -- Optional client-driven term exclusion for catalog sync. $count_args['exclude'] = $exclude; } $total = (int) wp_count_terms($count_args); if (is_wp_error($total)) { return $total; } $term_args = [ 'taxonomy' => $taxonomies, 'hide_empty' => false, 'number' => $per_page, 'offset' => $offset, 'orderby' => 'term_id', 'order' => 'DESC', ]; if (!empty($exclude)) { // phpcs:ignore WordPressVIPMinimum.Performance.WPQueryParams.PostNotIn_exclude -- Optional client-driven term exclusion for catalog sync. $term_args['exclude'] = $exclude; } $terms = get_terms($term_args); if (is_wp_error($terms)) { return $terms; } $taxonomy_to_attribute = array_flip($taxonomy_map); $controller = new Twokcs_REST_Attribute_Terms_Controller(); $items = []; foreach ($terms as $term) { $term_attribute_id = $taxonomy_to_attribute[$term->taxonomy] ?? 0; $request->set_param('attribute_id', $term_attribute_id); $item_data = $controller->prepare_item_for_response($term, $request)->get_data(); $item_data['attribute_id'] = $term_attribute_id; $items[] = $item_data; } return $this->build_response('results', $items, $total, $per_page, $request); } /** * Map attribute IDs to their taxonomy names. * * @return array */ private function get_attribute_taxonomy_map() { $map = []; foreach (wc_get_attribute_taxonomies() as $attribute) { $map[(int) $attribute->attribute_id] = wc_attribute_taxonomy_name($attribute->attribute_name); } return $map; } /** * @param string $key Response collection key. * @param array $items Prepared items. * @param int $total Total item count. * @param int $per_page Items per page. * @param WP_REST_Request $request Request object. * @return WP_REST_Response */ private function build_response($key, array $items, $total, $per_page, WP_REST_Request $request) { $data = [ 'count' => (int) $total, 'max_pages' => $total > 0 ? (int) ceil($total / $per_page) : 0, $key => $items, ]; if ($this->is_debug_enabled($request)) { $this->append_debug_data($data); } return new WP_REST_Response($data, 200); } /** * Append read-only SQL debug stats when debug mode is enabled. * * @param array $data Response data array. */ private function append_debug_data(array &$data) { global $wpdb; $data['debug'] = ['num_queries' => $wpdb->num_queries]; if (defined('SAVEQUERIES') && SAVEQUERIES && !empty($wpdb->queries)) { $data['debug']['queries'] = $wpdb->queries; } } /** * Parse a comma-separated or array request param into a list of positive integers. * * @param WP_REST_Request $request Request object. * @param string $name Parameter name. * @return int[] */ private function get_id_list_param(WP_REST_Request $request, $name) { $value = $request->get_param($name); if (empty($value)) { return []; } if (!is_array($value)) { $value = explode(',', (string) $value); } $ids = array_map('intval', $value); return array_values(array_filter($ids, function ($id) { return $id > 0; })); } /** * @param WP_REST_Request $request Request object. * @return int */ private function get_per_page(WP_REST_Request $request) { $per_page = (int) $request->get_param('per_page'); if ($per_page < 1) { $per_page = Twokcs_Constants::DEFAULT_PER_PAGE; } return min($per_page, Twokcs_Constants::MAX_PER_PAGE); } /** * @param WP_REST_Request $request Request object. * @return int */ private function get_page(WP_REST_Request $request) { $page = (int) $request->get_param('page'); return max($page, 1); } /** * @param WP_REST_Request $request Request object. * @return bool */ private function is_debug_enabled(WP_REST_Request $request) { if (!(bool) $request->get_param('debug')) { return false; } if (apply_filters('twokcs_allow_debug', false)) { return true; } return defined('WP_DEBUG') && WP_DEBUG && defined('TWOKCS_DEBUG') && TWOKCS_DEBUG; } }