Файловый менеджер - Редактировать - /home/harasnat/www/horse/wp-content/plugins/google-listings-and-ads/src/Integration/WPCOMProxy.php
Назад
<?php declare( strict_types=1 ); namespace Automattic\WooCommerce\GoogleListingsAndAds\Integration; use Automattic\WooCommerce\GoogleListingsAndAds\DB\Query\ShippingRateQuery; use Automattic\WooCommerce\GoogleListingsAndAds\DB\Query\ShippingTimeQuery; use Automattic\WooCommerce\GoogleListingsAndAds\Infrastructure\Registerable; use Automattic\WooCommerce\GoogleListingsAndAds\Infrastructure\Service; use Automattic\WooCommerce\GoogleListingsAndAds\Internal\ContainerAwareTrait; use Automattic\WooCommerce\GoogleListingsAndAds\Internal\Interfaces\ContainerAwareInterface; use Automattic\WooCommerce\GoogleListingsAndAds\Value\ChannelVisibility; use Automattic\WooCommerce\GoogleListingsAndAds\MerchantCenter\MerchantCenterService; use Automattic\WooCommerce\GoogleListingsAndAds\Options\OptionsAwareTrait; use Automattic\WooCommerce\GoogleListingsAndAds\Options\OptionsInterface; use Automattic\WooCommerce\GoogleListingsAndAds\Options\OptionsAwareInterface; use Automattic\WooCommerce\GoogleListingsAndAds\PluginHelper; use Automattic\WooCommerce\GoogleListingsAndAds\Product\Attributes\AttributeManager; use Automattic\WooCommerce\GoogleListingsAndAds\Product\ProductRepository; use WC_Product; use WP_REST_Response; use WP_REST_Request; defined( 'ABSPATH' ) || exit; /** * Class WPCOMProxy * * Prepares and filters data pulled by WPCOM proxy based on the `gla_syncable` query parameter. * * The `gla_syncable` parameter indicates that the request originates from the WPCOM proxy. * It's not intended to provide security, as it does not expose any data * that should be hidden from REST API users. * * Its primary purpose is to prevent global endpoints from being cluttered with additional data * and to conceal undocumented implementation details of the integration between the G4W plugin and WPCOM proxy. * * ContainerAware used to access: * - AttributeManager * - MerchantCenterService * - ProductRepository * - ShippingRateQuery * - ShippingTimeQuery * * @since 2.8.0 * * @package Automattic\WooCommerce\GoogleListingsAndAds\Integration */ class WPCOMProxy implements Service, Registerable, ContainerAwareInterface, OptionsAwareInterface { use ContainerAwareTrait; use OptionsAwareTrait; use PluginHelper; /** * The protected resources. Only items with visibility set to sync-and-show will be returned. */ protected const PROTECTED_RESOURCES = [ 'products', 'coupons', ]; /** * The settings group for the REST API. * * @var string */ protected const SETTINGS_GROUP = 'google-for-woocommerce'; /** * The meta key used to filter the items. * * @var string */ public const KEY_VISIBILITY = '_wc_gla_visibility'; /** * Get the post types to be filtered. * * @return array */ private function get_post_types_to_filter() { /** @var ProductRepository $product_repository */ $product_repository = $this->container->get( ProductRepository::class ); return [ 'product' => [ 'meta_query' => $product_repository->get_sync_ready_products_meta_query( true ), ], 'shop_coupon' => [ 'meta_query' => [ [ 'key' => self::KEY_VISIBILITY, 'value' => ChannelVisibility::SYNC_AND_SHOW, 'compare' => '=', ], [ 'key' => 'customer_email', 'compare' => 'NOT EXISTS', ], ], ], 'product_variation' => [ 'meta_query' => null, ], ]; } /** * Register all filters. */ public function register(): void { // Allow to filter by gla_syncable. add_filter( 'woocommerce_rest_query_vars', function ( $valid_vars ) { $valid_vars[] = 'gla_syncable'; return $valid_vars; } ); $this->register_callbacks(); $this->add_g4w_settings(); foreach ( array_keys( $this->get_post_types_to_filter() ) as $object_type ) { $this->register_object_types_filter( $object_type ); } } /** * Register the filters for a specific object type. * * @param string $object_type The object type. */ protected function register_object_types_filter( string $object_type ): void { add_filter( 'woocommerce_rest_prepare_' . $object_type . '_object', [ $this, 'filter_response_by_syncable_item' ], PHP_INT_MAX, // Run this filter last to override any other response. 3 ); add_filter( 'woocommerce_rest_prepare_' . $object_type . '_object', [ $this, 'prepare_response' ], PHP_INT_MAX - 1, 3 ); add_filter( 'woocommerce_rest_' . $object_type . '_object_query', [ $this, 'filter_by_metaquery' ], 10, 2 ); } /** * Register the `rest_request_after_callbacks`, to prepare shipping methods. */ protected function register_callbacks() { add_filter( 'rest_request_after_callbacks', /** * Set data for settings & prepare data for shipping methods. * * @param WP_REST_Response|WP_HTTP_Response|WP_Error|mixed $response The response object. * @param mixed $handler The handler. * @param WP_REST_Request $request The request object. */ function ( $response, $handler, $request ) { if ( ! $this->is_gla_request( $request ) || ! $response instanceof WP_REST_Response ) { return $response; } if ( $request->get_route() === '/wc/v3/settings/' . self::SETTINGS_GROUP ) { /** @var MerchantCenterService $merchant_center */ $merchant_center_service = $this->container->get( MerchantCenterService::class ); /** @var ShippingRateQuery $shipping_rate_query */ $shipping_rate_query = $this->container->get( ShippingRateQuery::class ); /** @var ShippingTimeQuery $shipping_time_query */ $shipping_time_query = $this->container->get( ShippingTimeQuery::class ); $merchant_center = $merchant_center_service->is_connected() ? $this->options->get( OptionsInterface::MERCHANT_CENTER, null ) : null; $data = $response->get_data(); $data[] = [ 'id' => 'gla_plugin_version', 'label' => 'Google for WooCommerce: Current plugin version', 'value' => $this->get_version(), ]; $data[] = [ 'id' => 'gla_google_connected', 'label' => 'Google for WooCommerce: Is Google account connected?', 'value' => $merchant_center_service->is_google_connected(), ]; $data[] = [ 'id' => 'gla_language', 'label' => 'Google for WooCommerce: Store language', 'value' => get_locale(), ]; $data[] = [ 'id' => 'gla_merchant_center', 'label' => 'Google for WooCommerce: Merchant Center settings', 'value' => $merchant_center, ]; $data[] = [ 'id' => 'gla_shipping_rates', 'label' => 'Google for WooCommerce: Shipping Rates', 'value' => (object) $shipping_rate_query->get_all_shipping_rates(), ]; $data[] = [ 'id' => 'gla_shipping_times', 'label' => 'Google for WooCommerce: Shipping Times', 'value' => (object) $shipping_time_query->get_all_shipping_times(), ]; $data[] = [ 'id' => 'gla_target_audience', 'label' => 'Google for WooCommerce: Target Audience', 'value' => $this->options->get( OptionsInterface::TARGET_AUDIENCE, null ), ]; $response->set_data( array_values( $data ) ); } $response->set_data( $this->prepare_data( $response->get_data(), $request ) ); return $response; }, 10, 3 ); } /** * Add the Google for WooCommerce settings to the WooCommerce REST API. * * @return void */ protected function add_g4w_settings() { add_filter( 'woocommerce_settings_groups', function ( $locations ) { $locations[] = [ 'id' => self::SETTINGS_GROUP, 'label' => 'Google for WooCommerce', 'description' => 'Settings of the Google for WooCommerce plugin.', ]; return $locations; } ); // Hack to make the settings group show up in the response. add_filter( 'woocommerce_settings-' . self::SETTINGS_GROUP, function ( $data ) { /* * We need to add non-empty return value in the filter, to be able to pass the valid group check. * We provide invalid 'type', so the entry will be ignored * in the response by `WC_REST_Setting_Options_V2_Controller::get_items` */ $data[] = [ 'id' => 'gla_settings_placeholder', 'option_key' => 'gla_settings_placeholder', 'type' => '_invalid_type_', ]; /* * This way `rest_request_after_callbacks` will get an empty data set * and could provide complete option- and non-option related settings. */ return $data; } ); } /** * Prepares the data converting the empty arrays in objects for consistency. * * @param array $data The response data to parse * @param WP_REST_Request $request The request object. * @return mixed */ public function prepare_data( $data, $request ) { if ( ! is_array( $data ) ) { return $data; } if ( preg_match( '/^\/wc\/v3\/shipping\/zones\/\d+\/methods/', $request->get_route() ) ) { foreach ( $data as $key => $value ) { if ( isset( $value['settings'] ) && empty( $value['settings'] ) ) { $data[ $key ]['settings'] = (object) $value['settings']; } } } return $data; } /** * Whether the request is coming from the WPCOM proxy. * * @param WP_REST_Request $request The request object. * * @return bool */ protected function is_gla_request( WP_REST_Request $request ): bool { // WPCOM proxy will set the gla_syncable to 1 if the request is coming from the proxy and it is the Google App. return $request->get_param( 'gla_syncable' ) === '1'; } /** * Get route pieces: resource and id, if present. * * @param WP_REST_Request $request The request object. * * @return array The route pieces. */ protected function get_route_pieces( WP_REST_Request $request ): array { $route = $request->get_route(); $pattern = '/(?P<resource>[\w]+)(?:\/(?P<id>[\d]+))?$/'; preg_match( $pattern, $route, $matches ); return $matches; } /** * Filter response by syncable item. * * @param WP_REST_Response $response The response object. * @param mixed $item The item. * @param WP_REST_Request $request The request object. * * @return WP_REST_Response The response object updated. */ public function filter_response_by_syncable_item( $response, $item, WP_REST_Request $request ): WP_REST_Response { if ( ! $this->is_gla_request( $request ) ) { return $response; } $pieces = $this->get_route_pieces( $request ); if ( ! isset( $pieces['id'] ) || ! isset( $pieces['resource'] ) || ! in_array( $pieces['resource'], self::PROTECTED_RESOURCES, true ) ) { return $response; } // Product is opt-out but coupon is opt-in $is_syncable = $pieces['resource'] === 'products'; $meta_data = $response->get_data()['meta_data'] ?? []; foreach ( $meta_data as $meta ) { if ( $meta->key === self::KEY_VISIBILITY ) { $is_syncable = $meta->value === ChannelVisibility::SYNC_AND_SHOW; break; } } if ( $is_syncable ) { return $response; } return new WP_REST_Response( [ 'code' => 'gla_rest_item_no_syncable', 'message' => 'Item not syncable', 'data' => [ 'status' => '403', ], ], 403 ); } /** * Query items with specific args for example where _wc_gla_visibility is set to sync-and-show. * * @param array $args The query args. * @param WP_REST_Request $request The request object. * * @return array The query args updated. * */ public function filter_by_metaquery( array $args, WP_REST_Request $request ): array { if ( ! $this->is_gla_request( $request ) ) { return $args; } $post_type = $args['post_type']; $post_type_filters = $this->get_post_types_to_filter()[ $post_type ]; if ( ! isset( $post_type_filters['meta_query'] ) || ! is_array( $post_type_filters['meta_query'] ) ) { return $args; } $meta_query = $post_type_filters['meta_query']; if ( empty( $args['meta_query'] ) ) { $args['meta_query'] = $meta_query; } else { array_push( $args['meta_query'], $meta_query ); } return $args; } /** * Prepares the response when the request is coming from the WPCOM proxy: * * Filter all the private metadata and returns only the public metadata and those prefixed with _wc_gla * For WooCommerce products, it will add the attribute mapping values. * * @param WP_REST_Response $response The response object. * @param mixed $item The item. * @param WP_REST_Request $request The request object. * * @return WP_REST_Response The response object updated. */ public function prepare_response( WP_REST_Response $response, $item, WP_REST_Request $request ): WP_REST_Response { if ( ! $this->is_gla_request( $request ) ) { return $response; } $data = $response->get_data(); $resource = $this->get_route_pieces( $request )['resource'] ?? null; if ( $item instanceof WC_Product && ( $resource === 'products' || $resource === 'variations' ) ) { /** @var AttributeManager $attribute_manager */ $attribute_manager = $this->container->get( AttributeManager::class ); $attr = $attribute_manager->get_all_aggregated_values( $item ); // In case of empty array, convert to object to keep the response consistent. $data['gla_attributes'] = (object) $attr; // Force types and prevent user type change for fields as Google has strict type requirements. $data['price'] = strval( $data['price'] ?? null ); $data['regular_price'] = strval( $data['regular_price'] ?? null ); $data['sale_price'] = strval( $data['sale_price'] ?? null ); } foreach ( $data['meta_data'] ?? [] as $key => $meta ) { if ( str_starts_with( $meta->key, '_' ) && ! str_starts_with( $meta->key, '_wc_gla' ) ) { unset( $data['meta_data'][ $key ] ); } } $data['meta_data'] = array_values( $data['meta_data'] ); $response->set_data( $data ); return $response; } }
| ver. 1.4 |
Github
|
.
| PHP 8.1.33 | Генерация страницы: 0 |
proxy
|
phpinfo
|
Настройка