PluginProbe ʕ •ᴥ•ʔ
WooCommerce / 10.8.1
WooCommerce v10.8.1
10.8.1 10.8.0 10.8.0-rc.1 10.8.0-beta.2 10.8.0-beta.1 7.8.0-beta.1 7.8.0-beta.2 7.8.0-rc.1 7.8.0-rc.2 7.8.1 7.8.2 7.8.3 7.8.4 7.9.0 7.9.0-beta.1 7.9.0-beta.2 7.9.0-rc.2 7.9.0-rc.3 7.9.1 7.9.2 8.0.0 8.0.0-beta.1 8.0.0-beta.2 8.0.0-rc.1 8.0.0-rc.2 8.0.1 8.0.2 8.0.3 8.0.4 8.0.5 8.1.0 8.1.0-beta.1 8.1.0-rc.1 8.1.0-rc.2 8.1.1 8.1.2 8.1.3 8.1.4 8.2.0 8.2.0-beta.1 8.2.0-rc.1 8.2.0-rc.2 8.2.1 8.2.2 8.2.3 8.2.4 8.2.5 8.3.0 8.3.0-beta.1 8.3.0-rc.1 8.3.0-rc.2 8.3.1 8.3.2 8.3.3 8.3.4 8.4.0 8.4.0-beta.1 8.4.0-rc.1 8.4.1 8.4.2 8.4.3 8.5.0 8.5.0-beta.1 8.5.0-rc.1 8.5.1 8.5.2 8.5.3 8.5.4 8.5.5 8.6.0 8.6.0-beta.1 8.6.0-rc.1 8.6.1 8.6.2 8.6.3 8.6.4 8.7.0 8.7.0-beta.1 8.7.0-beta.2 8.7.0-rc.1 8.7.1 8.7.2 8.7.3 8.8.0 8.8.0-beta.1 8.8.0-rc.1 8.8.1 8.8.2 8.8.3 8.8.4 8.8.5 8.8.6 8.8.7 8.9.0 8.9.0-beta.1 8.9.0-rc.1 8.9.1 8.9.2 8.9.3 8.9.4 8.9.5 9.0.0 9.0.0-beta.1 9.0.0-beta.2 9.0.0-rc.1 9.0.1 9.0.2 9.0.3 9.0.4 9.1.0 9.1.0-beta.1 9.1.0-rc.1 9.1.1 9.1.2 9.1.3 9.1.4 9.1.5 9.1.6 9.2.0 9.2.0-beta.1 9.2.0-rc.1 9.2.1 9.2.2 9.2.3 9.2.4 9.2.5 9.3.0 9.3.0-beta.1 9.3.0-rc.1 9.3.1 9.3.2 9.3.3 9.3.4 9.3.5 9.3.6 9.4.0 9.4.0-beta.1 9.4.0-beta.2 9.4.0-rc.1 9.4.0-rc.2 9.4.0-rc.3 9.4.0-rc.4 9.4.1 9.4.2 9.4.3 9.4.4 9.4.5 9.5.0 9.5.0-beta.1 9.5.0-beta.2 9.5.0-rc.1 9.5.1 9.5.2 9.5.3 9.5.4 9.6.0 9.6.0-beta.1 9.6.0-beta.2 9.6.0-rc.1 9.6.1 9.6.2 9.6.3 9.6.4 9.7.0 9.7.0-beta.1 9.7.0-rc.1 9.7.1 9.7.2 9.7.3 9.8.0 9.8.0-beta.1 9.8.0-rc.1 9.8.1 9.8.2 9.8.3 9.8.4 9.8.5 9.8.6 9.8.7 9.9.0 9.9.0-beta.1 9.9.0-rc.1 9.9.1 9.9.2 9.9.3 9.9.4 9.9.5 9.9.6 9.9.7 3.7.3 7.1.2 3.8.0 7.2.0 3.8.0-beta.1 7.2.0-beta.1 3.8.0-rc.1 7.2.0-beta.2 3.8.0-rc.2 7.2.0-rc.1 3.8.1 7.2.0-rc.2 3.8.2 7.2.1 3.8.3 7.2.2 3.9.0 7.2.3 3.9.0-beta.1 7.2.4 3.9.0-beta.2 7.3.0 3.9.0-rc.1 7.3.0-beta.1 3.9.0-rc.2 7.3.0-beta.2 3.9.0-rc.3 7.3.0-rc.1 3.9.0-rc.4 7.3.0-rc.2 3.9.1 7.3.1 3.9.2 7.4.0 3.9.3 7.4.0-beta.1 3.9.4 7.4.0-beta.2 3.9.5 7.4.0-rc.1 4.0.0 7.4.0-rc.2 4.0.0-beta.1 7.4.1 4.0.0-rc.1 7.4.2 4.0.0-rc.2 7.5.0 4.0.1 7.5.0-beta.1 4.0.2 7.5.0-beta.2 4.0.3 7.5.0-rc.1 4.0.4 7.5.1 4.1.0 7.5.2 4.1.0-beta.1 7.6.0 4.1.0-beta.2 7.6.0-beta.1 4.1.0-rc.1 7.6.0-beta.2 4.1.0-rc.2 7.6.0-rc.1 4.1.1 7.6.0-rc.2 4.1.2 7.6.0-rc.3 4.1.3 7.6.1 4.1.4 7.6.2 4.2.0 7.7.0 4.2.0-RC.1 7.7.0-beta.1 4.2.0-RC.2 7.7.0-beta.2 4.2.0-beta.1 7.7.0-rc.1 4.2.1 7.7.1 4.2.2 7.7.2 4.2.3 7.7.3 4.2.4 7.8.0 4.2.5 4.3.0 4.3.0-beta.1 4.3.0-rc.1 4.3.0-rc.2 4.3.0-rc.3 4.3.1 4.3.2 4.3.3 4.3.4 4.3.5 4.3.6 4.4.0 4.4.0-beta.1 4.4.0-rc.1 4.4.1 4.4.2 4.4.3 4.4.4 4.5.0 4.5.0-beta.1 4.5.0-rc.1 4.5.0-rc.3 4.5.1 4.5.2 4.5.3 4.5.4 4.5.5 4.6.0 4.6.0-beta.1 4.6.0-rc.1 4.6.1 4.6.2 4.6.3 4.6.4 4.6.5 4.7.0 4.7.0-beta.1 4.7.0-beta.2 4.7.0-rc.1 4.7.1 4.7.1-beta.1 4.7.2 4.7.3 4.7.4 4.8.0 4.8.0-beta.1 4.8.0-rc.1 4.8.0-rc.2 4.8.1 4.8.2 4.8.3 4.9.0 4.9.0-beta.1 4.9.0-rc.1 4.9.0-rc.2 4.9.1 4.9.2 4.9.3 4.9.4 4.9.5 5.0.0 5.0.0-beta.1 5.0.0-beta.2 5.0.0-rc.1 5.0.0-rc.2 5.0.0-rc.3 5.0.1 5.0.2 5.0.3 5.1.0 5.1.0-beta.1 5.1.0-rc.1 trunk 5.1.1 10.0.0 5.1.2 10.0.0-rc.1 5.1.3 10.0.0-rc.2 5.2.0 10.0.1 5.2.0-beta.1 10.0.2 5.2.0-rc.1 10.0.3 5.2.0-rc.2 10.0.4 5.2.1 10.0.5 5.2.2 10.0.6 5.2.3 10.1.0 5.2.4 10.1.0-rc.1 5.2.5 10.1.0-rc.2 5.3.0 10.1.0-rc.3 5.3.0-beta.1 10.1.0-rc.4 5.3.0-rc.1 10.1.1 5.3.0-rc.2 10.1.2 5.3.1 10.1.3 5.3.2 10.1.4 5.3.3 10.2.0 5.4.0 10.2.0-beta.1 5.4.0-beta.1 10.2.0-beta.2 5.4.0-rc.1 10.2.0-rc.1 5.4.1 10.2.1 5.4.2 10.2.2 5.4.3 10.2.3 5.4.4 10.2.4 5.4.5 10.3.0 5.5.0 10.3.0-beta.1 5.5.0-beta.1 10.3.0-beta.2 5.5.0-rc.1 10.3.0-rc.1 5.5.0-rc.2 10.3.0-rc.2 5.5.1 10.3.1 5.5.2 10.3.2 5.5.3 10.3.3 5.5.4 10.3.4 5.5.5 10.3.5 5.6.0 10.3.6 5.6.0-beta.1 10.3.7 5.6.0-rc.1 10.3.8 5.6.0-rc.2 10.4.0 5.6.1 10.4.0-beta.1 5.6.2 10.4.0-beta.2 5.6.3 10.4.0-rc.1 5.7.0 10.4.1 5.7.0-beta.1 10.4.2 5.7.0-rc.1 10.4.3 5.7.1 10.4.4 5.7.2 10.5.0 5.7.3 10.5.0-beta.1 5.8.0 10.5.0-beta.2 5.8.0-beta.1 10.5.0-rc.1 5.8.0-beta.2 10.5.0-rc.2 5.8.0-rc.1 10.5.0-rc.3 5.8.1 10.5.1 5.8.2 10.5.2 5.9.0 10.5.3 5.9.0-beta.1 10.6.0 5.9.0-rc.1 10.6.0-beta.1 5.9.0-rc.2 10.6.0-beta.2 5.9.1 10.6.0-rc.1 5.9.2 10.6.1 6.0.0 10.6.2 6.0.0-beta.1 10.7.0 6.0.0-rc.1 10.7.0-beta.1 6.0.1 10.7.0-beta.2 6.0.2 10.7.0-rc.1 6.1.0 3.0.0 6.1.0-beta.1 3.0.1 6.1.0-rc.1 3.0.2 6.1.0-rc.2 3.0.3 6.1.1 3.0.4 6.1.2 3.0.5 6.1.3 3.0.6 6.2.0 3.0.7 6.2.0-beta.1 3.0.8 6.2.0-rc.1 3.0.9 6.2.0-rc.2 3.1.0 6.2.1 3.1.1 6.2.2 3.1.2 6.2.3 3.2.0 6.3.0 3.2.1 6.3.0-beta.1 3.2.2 6.3.0-rc.1 3.2.3 6.3.0-rc.2 3.2.4 6.3.1 3.2.5 6.3.2 3.2.6 6.4.0 3.3.0 6.4.0-beta.1 3.3.1 6.4.0-rc.1 3.3.2 6.4.1 3.3.2-rc.1 6.4.2 3.3.3 6.5.0 3.3.4 6.5.0-beta.1 3.3.5 6.5.0-rc.1 3.3.6 6.5.0-rc.2 3.4.0 6.5.1 3.4.0-beta.1 6.5.2 3.4.0-rc.2 6.6.0 3.4.1 6.6.0-beta.1 3.4.2 6.6.0-rc.1 3.4.3 6.6.0-rc.2 3.4.4 6.6.1 3.4.5 6.6.2 3.4.6 6.7.0 3.4.7 6.7.0-beta.1 3.4.8 6.7.0-beta.2 3.5.0 6.7.0-rc.1 3.5.0-beta.1 6.7.1 3.5.0-rc.1 6.8.0 3.5.0-rc.2 6.8.0-beta.1 3.5.1 6.8.0-beta.2 3.5.10 6.8.0-rc.1 3.5.2 6.8.1 3.5.3 6.8.2 3.5.4 6.8.3 3.5.5 6.9.0 3.5.6 6.9.0-beta.1 3.5.7 6.9.0-beta.2 3.5.8 6.9.0-rc.1 3.5.9 6.9.1 3.6.0 6.9.2 3.6.0-beta.1 6.9.3 3.6.0-rc.1 6.9.4 3.6.0-rc.2 6.9.5 3.6.0-rc.3 7.0.0 3.6.1 7.0.0-beta.1 3.6.2 7.0.0-beta.2 3.6.3 7.0.0-beta.3 3.6.4 7.0.0-rc.1 3.6.5 7.0.0-rc.2 3.6.6 7.0.1 3.6.7 7.0.2 3.7.0 7.1.0 3.7.0-beta.1 7.1.0-beta.1 3.7.0-rc.1 7.1.0-beta.2 3.7.0-rc.2 7.1.0-rc.1 3.7.1 7.1.0-rc.2 3.7.2 7.1.1
woocommerce / includes / admin / class-wc-admin-addons.php
woocommerce / includes / admin Last commit date
helper 4 weeks ago importers 1 year ago list-tables 4 months ago marketplace-suggestions 10 months ago meta-boxes 4 weeks ago notes 4 weeks ago plugin-updates 2 years ago reports 2 months ago settings 1 week ago views 2 months ago class-wc-admin-addons.php 7 months ago class-wc-admin-api-keys-table-list.php 2 years ago class-wc-admin-api-keys.php 10 months ago class-wc-admin-assets.php 4 weeks ago class-wc-admin-attributes.php 3 years ago class-wc-admin-brands.php 3 months ago class-wc-admin-customize.php 5 years ago class-wc-admin-dashboard-setup.php 10 months ago class-wc-admin-dashboard.php 3 months ago class-wc-admin-duplicate-product.php 4 months ago class-wc-admin-exporters.php 1 year ago class-wc-admin-help.php 2 years ago class-wc-admin-importers.php 10 months ago class-wc-admin-log-table-list.php 3 months ago class-wc-admin-marketplace-promotions.php 3 months ago class-wc-admin-menus.php 3 months ago class-wc-admin-meta-boxes.php 1 year ago class-wc-admin-notices.php 4 weeks ago class-wc-admin-permalink-settings.php 5 years ago class-wc-admin-pointers.php 3 years ago class-wc-admin-post-types.php 1 year ago class-wc-admin-profile.php 1 year ago class-wc-admin-reports.php 3 months ago class-wc-admin-settings.php 2 months ago class-wc-admin-setup-wizard.php 3 months ago class-wc-admin-status.php 1 year ago class-wc-admin-taxonomies.php 6 months ago class-wc-admin-upload-downloadable-product.php 2 years ago class-wc-admin-webhooks-table-list.php 1 year ago class-wc-admin-webhooks.php 10 months ago class-wc-admin.php 2 months ago wc-admin-functions.php 6 months ago wc-meta-box-functions.php 1 year ago woocommerce-legacy-reports.php 1 year ago
class-wc-admin-addons.php
421 lines
1 <?php
2 /**
3 * Addons Page
4 *
5 * @package WooCommerce\Admin
6 * @version 2.5.0
7 */
8
9 use Automattic\Jetpack\Constants;
10 use Automattic\WooCommerce\Admin\RemoteInboxNotifications as PromotionRuleEngine;
11 use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\RuleEvaluator;
12
13 if ( ! defined( 'ABSPATH' ) ) {
14 exit;
15 }
16
17 /**
18 * WC_Admin_Addons Class.
19 */
20 class WC_Admin_Addons {
21
22 /**
23 * Fetch featured products from WCCOM's the Featured 3.0 Endpoint and cache the data for a day.
24 *
25 * @return array|WP_Error
26 */
27 public static function fetch_featured() {
28 $transient_name = 'wc_addons_featured';
29 // Important: WCCOM Extensions API v4.0 is used.
30 $url = 'https://woocommerce.com/wp-json/wccom-extensions/4.0/featured';
31 $locale = get_user_locale();
32 $featured = self::get_locale_data_from_transient( $transient_name, $locale );
33
34 if ( false === $featured ) {
35 $fetch_options = array(
36 'auth' => true,
37 'locale' => true,
38 'country' => true,
39 );
40 $raw_featured = self::fetch( $url, $fetch_options );
41
42 $featured = self::process_api_response( $raw_featured, 'featured' );
43
44 if ( ! is_wp_error( $featured ) && $featured ) {
45 self::set_locale_data_in_transient( $transient_name, $featured, $locale, DAY_IN_SECONDS );
46 }
47 }
48
49 return $featured;
50 }
51
52 /**
53 * Fetch markup and other info for the preview of a product.
54 *
55 * @param int $product_id The ID of the product to fetch preview for.
56 * @return array|WP_Error Preview data or error object.
57 */
58 public static function fetch_product_preview( int $product_id ) {
59 $url = 'https://woocommerce.com/wp-json/wccom-extensions/1.0/product-previews?product_id=' . $product_id;
60
61 $fetch_options = array(
62 'locale' => true,
63 );
64
65 $raw_preview = self::fetch( $url, $fetch_options );
66
67 return self::process_api_response( $raw_preview, 'product preview', true );
68 }
69
70 /**
71 * Check if the error is due to an SSL error
72 *
73 * @param string $error_message Error message.
74 *
75 * @return bool True if SSL error, false otherwise
76 */
77 public static function is_ssl_error( $error_message ) {
78 return false !== stripos( $error_message, 'cURL error 35' );
79 }
80
81 /**
82 * Get sections for the addons screen
83 *
84 * @return array of objects
85 */
86 public static function get_sections() {
87 $locale = get_user_locale();
88 $addon_sections = self::get_locale_data_from_transient( 'wc_addons_sections', $locale );
89 if ( false === ( $addon_sections ) ) {
90 $parameter_string = '?' . http_build_query( array( 'locale' => get_user_locale() ) );
91 $raw_sections = wp_safe_remote_get(
92 'https://woocommerce.com/wp-json/wccom-extensions/1.0/categories' . $parameter_string,
93 array(
94 'user-agent' => 'WooCommerce/' . WC()->version . '; ' . get_bloginfo( 'url' ),
95 )
96 );
97 if ( ! is_wp_error( $raw_sections ) ) {
98 $addon_sections = json_decode( wp_remote_retrieve_body( $raw_sections ) );
99 if ( $addon_sections ) {
100 self::set_locale_data_in_transient( 'wc_addons_sections', $addon_sections, $locale, WEEK_IN_SECONDS );
101 }
102 }
103 }
104 return apply_filters( 'woocommerce_addons_sections', $addon_sections );
105 }
106
107 /**
108 * Get section for the addons screen.
109 *
110 * @param string $section_id Required section ID.
111 *
112 * @return object|bool
113 */
114 public static function get_section( $section_id ) {
115 $sections = self::get_sections();
116 if ( isset( $sections[ $section_id ] ) ) {
117 return $sections[ $section_id ];
118 }
119 return false;
120 }
121
122 /**
123 * Returns in-app-purchase URL params.
124 */
125 public static function get_in_app_purchase_url_params() {
126 // Get url (from path onward) for the current page,
127 // so WCCOM "back" link returns user to where they were.
128 $back_admin_path = add_query_arg( array() );
129 return array(
130 'wccom-site' => site_url(),
131 'wccom-back' => rawurlencode( $back_admin_path ),
132 'wccom-woo-version' => WC()->stable_version(),
133 'wccom-connect-nonce' => wp_create_nonce( 'connect' ),
134 );
135 }
136
137 /**
138 * Add in-app-purchase URL params to link.
139 *
140 * Adds various url parameters to a url to support a streamlined
141 * flow for obtaining and setting up WooCommerce extensons.
142 *
143 * @param string $url Destination URL.
144 */
145 public static function add_in_app_purchase_url_params( $url ) {
146 return add_query_arg(
147 self::get_in_app_purchase_url_params(),
148 $url
149 );
150 }
151
152 /**
153 * Outputs a button.
154 *
155 * @param string $url Destination URL.
156 * @param string $text Button label text.
157 * @param string $style Button style class.
158 * @param string $plugin The plugin the button is promoting.
159 */
160 public static function output_button( $url, $text, $style, $plugin = '' ) {
161 $style = __( 'Free', 'woocommerce' ) === $text ? 'addons-button-outline-purple' : $style;
162 $style = is_plugin_active( $plugin ) ? 'addons-button-installed' : $style;
163 $text = is_plugin_active( $plugin ) ? __( 'Installed', 'woocommerce' ) : $text;
164 $url = self::add_in_app_purchase_url_params( $url );
165 ?>
166 <a
167 class="addons-button <?php echo esc_attr( $style ); ?>"
168 href="<?php echo esc_url( $url ); ?>">
169 <?php echo esc_html( $text ); ?>
170 </a>
171 <?php
172 }
173
174 /**
175 * Process requests to legacy marketplace menu and redirect to correct in-app pages.
176 *
177 * @return void
178 */
179 public static function handle_legacy_marketplace_redirects() {
180 $section = isset( $_GET['section'] ) ? sanitize_text_field( wp_unslash( $_GET['section'] ) ) : '_featured';
181 $search = isset( $_GET['search'] ) ? sanitize_text_field( wp_unslash( $_GET['search'] ) ) : '';
182
183 if ( 'helper' === $section ) {
184 $url = admin_url( 'admin.php?page=wc-admin&tab=my-subscriptions&path=%2Fextensions' );
185
186 if ( isset( $_GET['connect'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
187 $url .= '&connect';
188 }
189
190 wp_safe_redirect( $url );
191 exit();
192 }
193
194 if ( 'search' === $section || ! empty( $search ) ) {
195 wp_safe_redirect( admin_url( 'admin.php?page=wc-admin&term=' . $search . '&tab=search&path=%2Fextensions' ) );
196 exit();
197 }
198
199 $sections = self::get_sections();
200 $allowed_sections = array_map( fn( $section_object ) => $section_object->slug, $sections );
201 // Validate if the category is supported.
202 $section = in_array( $section, $allowed_sections, true ) ? $section : '_featured';
203
204 if ( '_featured' === $section ) {
205 wp_safe_redirect( admin_url( 'admin.php?page=wc-admin&path=%2Fextensions' ) );
206 exit();
207 }
208
209 wp_safe_redirect( admin_url( 'admin.php?page=wc-admin&tab=extensions&path=%2Fextensions&category=' . $section ) );
210 exit();
211 }
212
213 /**
214 * We're displaying page=wc-addons and page=wc-addons&section=helper as two separate pages.
215 * When we're on those pages, add body classes to distinguishe them.
216 *
217 * @param string $admin_body_class Unfiltered body class.
218 *
219 * @return string Body class with added class for Marketplace or My Subscriptions page.
220 */
221 public static function filter_admin_body_classes( string $admin_body_class = '' ): string {
222 if ( isset( $_GET['section'] ) && 'helper' === $_GET['section'] ) {
223 return " $admin_body_class woocommerce-page-wc-subscriptions ";
224 }
225
226 return " $admin_body_class woocommerce-page-wc-marketplace ";
227 }
228
229 /**
230 * Take an action object and return the URL based on properties of the action.
231 *
232 * @param object $action Action object.
233 * @return string URL.
234 */
235 public static function get_action_url( $action ): string {
236 if ( ! isset( $action->url ) ) {
237 return '';
238 }
239
240 if ( isset( $action->url_is_admin_query ) && $action->url_is_admin_query ) {
241 return wc_admin_url( $action->url );
242 }
243
244 if ( isset( $action->url_is_admin_nonce_query ) && $action->url_is_admin_nonce_query ) {
245 if ( empty( $action->nonce ) ) {
246 return '';
247 }
248 return wp_nonce_url(
249 admin_url( $action->url ),
250 $action->nonce
251 );
252 }
253
254 return $action->url;
255 }
256
257 /**
258 * Retrieves the locale data from a transient.
259 *
260 * Transient value is an array of locale data in the following format:
261 * array(
262 * 'en_US' => ...,
263 * 'fr_FR' => ...,
264 * )
265 *
266 * If the transient does not exist, does not have a value, or has expired,
267 * then the return value will be false.
268 *
269 * @param string $transient Transient name. Expected to not be SQL-escaped.
270 * @param string $locale Locale to retrieve.
271 * @return mixed Value of transient.
272 */
273 private static function get_locale_data_from_transient( $transient, $locale ) {
274 $transient_value = get_transient( $transient );
275 $transient_value = is_array( $transient_value ) ? $transient_value : array();
276 return $transient_value[ $locale ] ?? false;
277 }
278
279 /**
280 * Sets the locale data in a transient.
281 *
282 * Transient value is an array of locale data in the following format:
283 * array(
284 * 'en_US' => ...,
285 * 'fr_FR' => ...,
286 * )
287 *
288 * @param string $transient Transient name. Expected to not be SQL-escaped.
289 * Must be 172 characters or fewer in length.
290 * @param mixed $value Transient value. Must be serializable if non-scalar.
291 * Expected to not be SQL-escaped.
292 * @param string $locale Locale to set.
293 * @param int $expiration Optional. Time until expiration in seconds. Default 0 (no expiration).
294 * @return bool True if the value was set, false otherwise.
295 */
296 private static function set_locale_data_in_transient( $transient, $value, $locale, $expiration = 0 ) {
297 $transient_value = get_transient( $transient );
298 $transient_value = is_array( $transient_value ) ? $transient_value : array();
299 $transient_value[ $locale ] = $value;
300 return set_transient( $transient, $transient_value, $expiration );
301 }
302
303 /**
304 * Process API response from WooCommerce.com endpoints.
305 *
306 * @param array|WP_Error $response The response from the API request.
307 * @param string $context Context for error messages (e.g. 'featured', 'product-preview').
308 * @param bool $associative Whether to decode the JSON as an associative array.
309 *
310 * @return array|WP_Error Processed API data or WP_Error on failure.
311 */
312 private static function process_api_response( $response, $context = 'api', $associative = false ) {
313 if ( is_wp_error( $response ) ) {
314 /**
315 * Hook fired when there is a connection error with WooCommerce.com.
316 *
317 * @since 6.1.0
318 * @param string $error_message The error message.
319 */
320 do_action( 'woocommerce_page_wc_addons_connection_error', $response->get_error_message() );
321
322 $message = self::is_ssl_error( $response->get_error_message() )
323 ? __(
324 'We encountered an SSL error. Please ensure your site supports TLS version 1.2 or above.',
325 'woocommerce'
326 )
327 : $response->get_error_message();
328
329 return new WP_Error( 'wc-addons-connection-error', $message );
330 }
331
332 $response_code = (int) wp_remote_retrieve_response_code( $response );
333 if ( 200 !== $response_code ) {
334 /**
335 * Hook fired when there is a connection error with WooCommerce.com.
336 *
337 * @since 6.1.0
338 * @param int $response_code The HTTP response code.
339 */
340 do_action( 'woocommerce_page_wc_addons_connection_error', $response_code );
341
342 $message = sprintf(
343 /* translators: 1: Context (e.g. 'featured', 'product-preview') 2: HTTP error code */
344 __( 'Our request to the %1$s API got error code %2$d.', 'woocommerce' ),
345 $context,
346 $response_code
347 );
348
349 return new WP_Error( 'wc-addons-connection-error', $message );
350 }
351
352 $data = json_decode( wp_remote_retrieve_body( $response ), $associative );
353 if ( empty( $data ) || ! is_array( $data ) ) {
354 /**
355 * Hook fired when there is a connection error with WooCommerce.com.
356 *
357 * @since 6.1.0
358 * @param string $error_message The error message.
359 */
360 do_action( 'woocommerce_page_wc_addons_connection_error', 'Empty or malformed response' );
361
362 $message = sprintf(
363 /* translators: %s: Context (e.g. 'featured', 'product-preview') */
364 __( 'Our request to the %s API got a malformed response.', 'woocommerce' ),
365 $context
366 );
367
368 return new WP_Error( 'wc-addons-connection-error', $message );
369 }
370
371 return $data;
372 }
373
374 /**
375 * Make wp_safe_remote_get request to WooCommerce.com endpoint.
376 * Optionally pass user auth token, locale or country.
377 *
378 * @param string $url URL to request.
379 * @param ?array $options Options for the request. For example, to pass auth token, locale and country,
380 * pass array( 'auth' => true, 'locale' => true, 'country' => true, ).
381 *
382 * @return array|WP_Error
383 */
384 public static function fetch( $url, $options = array() ) {
385 $headers = array();
386
387 if ( isset( $options['auth'] ) && $options['auth'] ) {
388 $auth = WC_Helper_Options::get( 'auth' );
389
390 if ( isset( $auth['access_token'] ) && ! empty( $auth['access_token'] ) ) {
391 $headers['Authorization'] = 'Bearer ' . $auth['access_token'];
392 }
393 }
394
395 $parameters = array();
396
397 if ( isset( $options['locale'] ) && $options['locale'] ) {
398 $parameters['locale'] = get_user_locale();
399 }
400
401 if ( isset( $options['country'] ) && $options['country'] ) {
402 $country = WC()->countries->get_base_country();
403 if ( ! empty( $country ) ) {
404 $parameters['country'] = $country;
405 }
406 }
407
408 // Check if URL already has query parameters.
409 $connector = strpos( $url, '?' ) !== false ? '&' : '?';
410 $query_string = ! empty( $parameters ) ? $connector . http_build_query( $parameters ) : '';
411
412 return wp_safe_remote_get(
413 $url . $query_string,
414 array(
415 'headers' => $headers,
416 'user-agent' => 'WooCommerce/' . WC()->version . '; ' . get_bloginfo( 'url' ),
417 )
418 );
419 }
420 }
421