Merged in feature/MAW-855-import-code-into-aws (pull request #2)

code import from pantheon

* code import from pantheon
This commit is contained in:
Tony Volpe
2023-12-04 23:08:14 +00:00
parent 8c9b1312bc
commit 8f4b5efda6
4766 changed files with 185592 additions and 239967 deletions

View File

@@ -97,7 +97,37 @@ class OnboardingFreeExtensions extends WC_REST_Data_Controller {
}
}
$extensions = $this->replace_jetpack_with_jetpack_boost_for_treatment( $extensions );
return new WP_REST_Response( $extensions );
}
private function replace_jetpack_with_jetpack_boost_for_treatment( array $extensions ) {
$is_treatment = \WooCommerce\Admin\Experimental_Abtest::in_treatment( 'woocommerce_jetpack_copy' );
if ( ! $is_treatment ) {
return $extensions;
}
$has_core_profiler = array_search( 'obw/core-profiler', array_column( $extensions, 'key' ) );
if ( $has_core_profiler === false ) {
return $extensions;
}
$has_jetpack = array_search( 'jetpack', array_column( $extensions[ $has_core_profiler ]['plugins'], 'key' ) );
if ( $has_jetpack === false ) {
return $extensions;
}
$jetpack = &$extensions[ $has_core_profiler ]['plugins'][ $has_jetpack ];
$jetpack->key = 'jetpack-boost';
$jetpack->name = 'Jetpack Boost';
$jetpack->label = __( 'Optimize store performance with Jetpack Boost', 'woocommerce' );
$jetpack->description = __( 'Speed up your store and improve your SEO with performance-boosting tools from Jetpack. Learn more', 'woocommerce' );
$jetpack->learn_more_link = 'https://jetpack.com/boost/';
return $extensions;
}
}

View File

@@ -148,6 +148,9 @@ class OnboardingPlugins extends WC_REST_Data_Controller {
true
);
}
add_action( 'woocommerce_plugins_install_error', array( $this, 'log_plugins_install_error' ), 10, 4 );
add_action( 'woocommerce_plugins_install_api_error', array( $this, 'log_plugins_install_api_error' ), 10, 2 );
}
/**
@@ -411,4 +414,41 @@ class OnboardingPlugins extends WC_REST_Data_Controller {
),
);
}
public function log_plugins_install_error( $slug, $api, $result, $upgrader ) {
$properties = array(
'error_message' => sprintf(
/* translators: %s: plugin slug (example: woocommerce-services) */
__(
'The requested plugin `%s` could not be installed.',
'woocommerce'
),
$slug
),
'type' => 'plugin_info_api_error',
'slug' => $slug,
'api_version' => $api->version,
'api_download_link' => $api->download_link,
'upgrader_skin_message' => implode( ',', $upgrader->skin->get_upgrade_messages() ),
'result' => is_wp_error( $result ) ? $result->get_error_message() : 'null',
);
wc_admin_record_tracks_event( 'coreprofiler_install_plugin_error', $properties );
}
public function log_plugins_install_api_error( $slug, $api ) {
$properties = array(
'error_message' => sprintf(
// translators: %s: plugin slug (example: woocommerce-services).
__(
'The requested plugin `%s` could not be installed. Plugin API call failed.',
'woocommerce'
),
$slug
),
'type' => 'plugin_install_error',
'api_error_message' => $api->get_error_message(),
'slug' => $slug,
);
wc_admin_record_tracks_event( 'coreprofiler_install_plugin_error', $properties );
}
}

View File

@@ -391,6 +391,7 @@ class OnboardingProfile extends \WC_REST_Data_Controller {
'items' => array(
'enum' => array(
'jetpack',
'jetpack-boost',
'woocommerce-services',
'woocommerce-payments',
'mailchimp-for-woocommerce',

View File

@@ -39,7 +39,7 @@ class OnboardingTasks extends \WC_REST_Data_Controller {
/**
* Duration to milisecond mapping.
*
* @var string
* @var array
*/
protected $duration_to_ms = array(
'day' => DAY_IN_SECONDS * 1000,
@@ -762,6 +762,7 @@ class OnboardingTasks extends \WC_REST_Data_Controller {
if ( ! $task && $id ) {
$task = new DeprecatedExtendedTask(
null,
array(
'id' => $id,
'is_dismissable' => true,
@@ -795,6 +796,7 @@ class OnboardingTasks extends \WC_REST_Data_Controller {
if ( ! $task && $id ) {
$task = new DeprecatedExtendedTask(
null,
array(
'id' => $id,
'is_dismissable' => true,
@@ -837,6 +839,7 @@ class OnboardingTasks extends \WC_REST_Data_Controller {
if ( ! $task && $task_id ) {
$task = new DeprecatedExtendedTask(
null,
array(
'id' => $task_id,
'is_snoozeable' => true,
@@ -874,6 +877,7 @@ class OnboardingTasks extends \WC_REST_Data_Controller {
if ( ! $task && $id ) {
$task = new DeprecatedExtendedTask(
null,
array(
'id' => $id,
'is_snoozeable' => true,
@@ -961,6 +965,7 @@ class OnboardingTasks extends \WC_REST_Data_Controller {
if ( ! $task && $id ) {
$task = new DeprecatedExtendedTask(
null,
array(
'id' => $id,
)

View File

@@ -61,6 +61,29 @@ class OnboardingThemes extends \WC_REST_Data_Controller {
'schema' => array( $this, 'get_item_schema' ),
)
);
register_rest_route(
$this->namespace,
'/' . $this->rest_base . '/recommended',
array(
'methods' => 'GET',
'callback' => array( $this, 'get_recommended_themes' ),
'permission_callback' => array( $this, 'get_item_permissions_check' ),
'args' => array(
'industry' => array(
'type' => 'string',
'description' => 'Limits the results to themes relevant for this industry (optional)',
),
'currency' => array(
'type' => 'string',
'enum' => array( 'USD', 'AUD', 'CAD', 'EUR', 'GBP' ),
'default' => 'USD',
'description' => 'Returns pricing in this currency (optional, default: USD)',
),
),
'schema' => array( $this, 'get_recommended_item_schema' ),
)
);
}
/**
@@ -83,12 +106,7 @@ class OnboardingThemes extends \WC_REST_Data_Controller {
* @return WP_Error|array Theme installation status.
*/
public function install_theme( $request ) {
$allowed_themes = Themes::get_allowed_themes();
$theme = sanitize_text_field( $request['theme'] );
if ( ! in_array( $theme, $allowed_themes, true ) ) {
return new \WP_Error( 'woocommerce_rest_invalid_theme', __( 'Invalid theme.', 'woocommerce' ), 404 );
}
$theme = sanitize_text_field( $request['theme'] );
$installed_themes = wp_get_themes();
@@ -120,7 +138,7 @@ class OnboardingThemes extends \WC_REST_Data_Controller {
return new \WP_Error(
'woocommerce_rest_theme_install',
sprintf(
/* translators: %s: theme slug (example: woocommerce-services) */
/* translators: %s: theme slug (example: woocommerce-services) */
__( 'The requested theme `%s` could not be installed. Theme API call failed.', 'woocommerce' ),
$theme
),
@@ -135,7 +153,7 @@ class OnboardingThemes extends \WC_REST_Data_Controller {
return new \WP_Error(
'woocommerce_rest_theme_install',
sprintf(
/* translators: %s: theme slug (example: woocommerce-services) */
/* translators: %s: theme slug (example: woocommerce-services) */
__( 'The requested theme `%s` could not be installed.', 'woocommerce' ),
$theme
),
@@ -157,11 +175,7 @@ class OnboardingThemes extends \WC_REST_Data_Controller {
* @return WP_Error|array Theme activation status.
*/
public function activate_theme( $request ) {
$allowed_themes = Themes::get_allowed_themes();
$theme = sanitize_text_field( $request['theme'] );
if ( ! in_array( $theme, $allowed_themes, true ) ) {
return new \WP_Error( 'woocommerce_rest_invalid_theme', __( 'Invalid theme.', 'woocommerce' ), 404 );
}
$theme = sanitize_text_field( $request['theme'] );
require_once ABSPATH . 'wp-admin/includes/theme.php';
@@ -184,6 +198,190 @@ class OnboardingThemes extends \WC_REST_Data_Controller {
) );
}
/**
* Get recommended themes.
*
* @param WP_REST_Request $request Full details about the request.
* @return WP_Error|array Theme activation status.
*/
public function get_recommended_themes( $request ) {
// Check if "industry" and "currency" parameters are provided in the request.
$industry = $request->get_param( 'industry' );
$currency = $request->get_param( 'currency' ) ?? 'USD';
// Return empty response if marketplace suggestions are disabled.
if (
/**
* Filter allow marketplace suggestions.
*
* User can disable all suggestions via filter.
*
* @since 8.3.0
*/
! apply_filters( 'woocommerce_allow_marketplace_suggestions', true ) ||
get_option( 'woocommerce_show_marketplace_suggestions', 'yes' ) === 'no'
) {
/**
* Filter the onboarding recommended themes response.
*
* @since 8.3.0
*
* @param array $response The recommended themes response.
* @param array $filtered_themes The filtered themes.
* @param string $industry The industry to filter by (if provided).
* @param string $currency The currency to convert prices to. (USD, AUD, CAD, EUR, GBP).
*
* @return array
*/
return apply_filters(
'__experimental_woocommerce_rest_get_recommended_themes',
array(
'themes' => array(),
'_links' => array(
'browse_all' => array(
'href' => home_url( '/wp-admin/themes.php' ),
),
),
),
$industry,
$currency
);
}
$current_theme_slug = wp_get_theme()->get_stylesheet();
// To be implemented: 1. Fetch themes from the marketplace API. 2. Convert prices to the requested currency.
// These are Dotcom themes.
$themes = array(
array(
'name' => 'Tsubaki',
'price' => 'Free',
'color_palettes' => array(),
'total_palettes' => 0,
'slug' => 'tsubaki',
'is_active' => 'tsubaki' === $current_theme_slug,
'thumbnail_url' => 'https://i0.wp.com/s2.wp.com/wp-content/themes/premium/tsubaki/screenshot.png',
'link_url' => 'https://wordpress.com/theme/tsubaki/',
),
array(
'name' => 'Tazza',
'price' => 'Free',
'color_palettes' => array(),
'total_palettes' => 0,
'slug' => 'tazza',
'is_active' => 'tazza' === $current_theme_slug,
'thumbnail_url' => 'https://i0.wp.com/s2.wp.com/wp-content/themes/premium/tazza/screenshot.png',
'link_url' => 'https://wordpress.com/theme/tazza/',
'total_palettes' => 0,
),
array(
'name' => 'Amulet',
'price' => 'Free',
'color_palettes' => array(
array(
'title' => 'Default',
'primary' => '#FEFBF3',
'secondary' => '#7F7E7A',
),
array(
'title' => 'Brown Sugar',
'primary' => '#EFEBE0',
'secondary' => '#AC6239',
),
array(
'title' => 'Midnight',
'primary' => '#161514',
'secondary' => '#AFADA7',
),
array(
'title' => 'Olive',
'primary' => '#FEFBF3',
'secondary' => '#7F7E7A',
),
),
'total_palettes' => 5,
'slug' => 'amulet',
'is_active' => 'amulet' === $current_theme_slug,
'thumbnail_url' => 'https://i0.wp.com/s2.wp.com/wp-content/themes/premium/amulet/screenshot.png',
'link_url' => 'https://wordpress.com/theme/amulet/',
),
array(
'name' => 'Zaino',
'price' => 'Free',
'color_palettes' => array(
array(
'title' => 'Default',
'primary' => '#202124',
'secondary' => '#E3CBC0',
),
array(
'title' => 'Aubergine',
'primary' => '#1B1031',
'secondary' => '#E1746D',
),
array(
'title' => 'Block out',
'primary' => '#FF5252',
'secondary' => '#252525',
),
array(
'title' => 'Canary',
'primary' => '#FDFF85',
'secondary' => '#353535',
),
),
'total_palettes' => 11,
'slug' => 'zaino',
'is_active' => 'zaino' === $current_theme_slug,
'thumbnail_url' => 'https://i0.wp.com/s2.wp.com/wp-content/themes/premium/zaino/screenshot.png',
'link_url' => 'https://wordpress.com/theme/zaino/',
),
);
// To be implemented: Filter themes based on industry.
if ( $industry ) {
$filtered_themes = array_filter(
$themes,
function ( $theme ) use ( $industry ) {
// Filter themes by industry.
// Example: return $theme['industry'] === $industry;.
return true;
}
);
} else {
$filtered_themes = $themes;
}
$response = array(
'themes' => $filtered_themes,
'_links' => array(
'browse_all' => array(
'href' => admin_url( 'themes.php' ),
),
),
);
/**
* Filter the onboarding recommended themes response.
*
* @since 8.3.0
*
* @param array $response The recommended themes response.
* @param array $filtered_themes The filtered themes.
* @param string $industry The industry to filter by (if provided).
* @param string $currency The currency to convert prices to. (USD, AUD, CAD, EUR, GBP).
*
* @return array
*/
return apply_filters(
'__experimental_woocommerce_rest_get_recommended_themes',
$response,
$industry,
$currency
);
}
/**
* Get the schema, conforming to JSON Schema.
*
@@ -218,4 +416,82 @@ class OnboardingThemes extends \WC_REST_Data_Controller {
return $this->add_additional_fields_schema( $schema );
}
/**
* Get the recommended themes schema, conforming to JSON Schema.
*
* @return array
*/
public function get_recommended_item_schema() {
$schema = array(
'$schema' => 'http://json-schema.org/draft-04/schema#',
'title' => 'onboarding_theme',
'type' => 'object',
'properties' => array(
'themes' => array(
'type' => 'array',
'items' => array(
'type' => 'object',
'properties' => array(
'name' => array(
'type' => 'string',
'description' => 'Theme Name',
),
'price' => array(
'type' => 'string',
'description' => 'Price',
),
'is_active' => array(
'type' => 'boolean',
'description' => 'Whether theme is active',
),
'thumbnail_url' => array(
'type' => 'string',
'description' => 'Thumbnail URL',
),
'link_url' => array(
'type' => 'string',
'description' => 'Link URL for the theme',
),
'color_palettes' => array(
'type' => 'array',
'description' => 'Array of color palette objects',
'items' => array(
'type' => 'object',
'properties' => array(
'primary' => array(
'type' => 'string',
'description' => 'Primary color',
),
'secondary' => array(
'type' => 'string',
'description' => 'Secondary color',
),
),
),
),
),
),
),
'_links' => array(
'type' => 'object',
'description' => 'Links related to this response',
'properties' => array(
'browse_all' => array(
'type' => 'object',
'description' => 'Link to browse all themes',
'properties' => array(
'href' => array(
'type' => 'string',
'description' => 'URL for browsing all themes',
),
),
),
),
),
),
);
return $this->add_additional_fields_schema( $schema );
}
}

View File

@@ -201,6 +201,7 @@ class Options extends \WC_REST_Data_Controller {
'woocommerce_dimension_unit',
'woocommerce_weight_unit',
'woocommerce_product_editor_show_feedback_bar',
'woocommerce_single_variation_notice_dismissed',
'woocommerce_product_tour_modal_hidden',
'woocommerce_block_product_tour_shown',
'woocommerce_revenue_report_date_tour_shown',
@@ -213,6 +214,10 @@ class Options extends \WC_REST_Data_Controller {
'wcpay_welcome_page_incentives_dismissed',
'wcpay_welcome_page_viewed_timestamp',
'wcpay_welcome_page_exit_survey_more_info_needed_timestamp',
'woocommerce_customize_store_onboarding_tour_hidden',
'woocommerce_customize_store_ai_suggestions',
'woocommerce_admin_customize_store_completed',
'woocommerce_admin_customize_store_completed_theme_id',
// WC Test helper options.
'wc-admin-test-helper-rest-api-filters',
'wc_admin_helper_feature_values',

View File

@@ -8,6 +8,7 @@
namespace Automattic\WooCommerce\Admin\API;
use Automattic\WooCommerce\Internal\Admin\Onboarding\OnboardingProfile;
use Automattic\WooCommerce\Admin\Features\OnboardingTasks\Tasks\WooCommercePayments;
use Automattic\WooCommerce\Admin\PaymentMethodSuggestionsDataSourcePoller;
use Automattic\WooCommerce\Admin\PluginsHelper;
use Automattic\WooCommerce\Internal\Admin\Notes\InstallJPAndWCSPlugins;
@@ -600,16 +601,16 @@ class Plugins extends \WC_REST_Data_Controller {
return new \WP_Error( 'woocommerce_rest_helper_connect', __( 'There was an error communicating with the WooPayments plugin.', 'woocommerce' ), 500 );
}
$connect_url = add_query_arg(
array(
'wcpay-connect' => 'WCADMIN_PAYMENT_TASK',
'_wpnonce' => wp_create_nonce( 'wcpay-connect' ),
),
admin_url()
);
$args = WooCommercePayments::is_account_partially_onboarded() ? [
'wcpay-login' => '1',
'_wpnonce' => wp_create_nonce( 'wcpay-login' ),
] : [
'wcpay-connect' => 'WCADMIN_PAYMENT_TASK',
'_wpnonce' => wp_create_nonce( 'wcpay-connect' ),
];
return( array(
'connectUrl' => $connect_url,
'connectUrl' => add_query_arg( $args, admin_url() ),
) );
}

View File

@@ -30,6 +30,13 @@ class DataStore extends SqlQuery {
*/
protected $cache_timeout = 3600;
/**
* Cache identifier.
*
* @var string
*/
protected $cache_key = '';
/**
* Table used as a data store for this report.
*

View File

@@ -542,6 +542,87 @@ class Segmenter {
}
}
/**
* Calculate segments for totals where the segmenting property is bound to product (e.g. category, product_id, variation_id).
*
* @param array $segmenting_selections SELECT part of segmenting SQL query--one for 'product_level' and one for 'order_level'.
* @param string $segmenting_from FROM part of segmenting SQL query.
* @param string $segmenting_where WHERE part of segmenting SQL query.
* @param string $segmenting_groupby GROUP BY part of segmenting SQL query.
* @param string $segmenting_dimension_name Name of the segmenting dimension.
* @param string $table_name Name of SQL table which is the stats table for orders.
* @param array $totals_query Array of SQL clauses for totals query.
* @param string $unique_orders_table Name of temporary SQL table that holds unique orders.
*
* @return array
*/
protected function get_product_related_totals_segments( $segmenting_selections, $segmenting_from, $segmenting_where, $segmenting_groupby, $segmenting_dimension_name, $table_name, $totals_query, $unique_orders_table ) {
return array();
}
/**
* Calculate segments for intervals where the segmenting property is bound to product (e.g. category, product_id, variation_id).
*
* @param array $segmenting_selections SELECT part of segmenting SQL query--one for 'product_level' and one for 'order_level'.
* @param string $segmenting_from FROM part of segmenting SQL query.
* @param string $segmenting_where WHERE part of segmenting SQL query.
* @param string $segmenting_groupby GROUP BY part of segmenting SQL query.
* @param string $segmenting_dimension_name Name of the segmenting dimension.
* @param string $table_name Name of SQL table which is the stats table for orders.
* @param array $intervals_query Array of SQL clauses for intervals query.
* @param string $unique_orders_table Name of temporary SQL table that holds unique orders.
*
* @return array
*/
protected function get_product_related_intervals_segments( $segmenting_selections, $segmenting_from, $segmenting_where, $segmenting_groupby, $segmenting_dimension_name, $table_name, $intervals_query, $unique_orders_table ) {
return array();
}
/**
* Calculate segments for totals query where the segmenting property is bound to order (e.g. coupon or customer type).
*
* @param string $segmenting_select SELECT part of segmenting SQL query.
* @param string $segmenting_from FROM part of segmenting SQL query.
* @param string $segmenting_where WHERE part of segmenting SQL query.
* @param string $segmenting_groupby GROUP BY part of segmenting SQL query.
* @param string $table_name Name of SQL table which is the stats table for orders.
* @param array $totals_query Array of SQL clauses for intervals query.
*
* @return array
*/
protected function get_order_related_totals_segments( $segmenting_select, $segmenting_from, $segmenting_where, $segmenting_groupby, $table_name, $totals_query ) {
return array();
}
/**
* Calculate segments for intervals query where the segmenting property is bound to order (e.g. coupon or customer type).
*
* @param string $segmenting_select SELECT part of segmenting SQL query.
* @param string $segmenting_from FROM part of segmenting SQL query.
* @param string $segmenting_where WHERE part of segmenting SQL query.
* @param string $segmenting_groupby GROUP BY part of segmenting SQL query.
* @param string $table_name Name of SQL table which is the stats table for orders.
* @param array $intervals_query Array of SQL clauses for intervals query.
*
* @return array
*/
protected function get_order_related_intervals_segments( $segmenting_select, $segmenting_from, $segmenting_where, $segmenting_groupby, $table_name, $intervals_query ) {
return array();
}
/**
* Return array of segments formatted for REST response.
*
* @param string $type Type of segments to return--'totals' or 'intervals'.
* @param array $query_params SQL query parameter array.
* @param string $table_name Name of main SQL table for the data store (used as basis for JOINS).
*
* @return array
*/
protected function get_segments( $type, $query_params, $table_name ) {
return array();
}
/**
* Calculate segments for segmenting property bound to product (e.g. category, product_id, variation_id).
*