Merge branch 'update/marketplace-1' into update/styling-product-cards

This commit is contained in:
And Finally 2021-08-09 15:00:51 +01:00
commit 1ec1f25d26
22 changed files with 396 additions and 155 deletions

View File

@ -4,29 +4,39 @@ on:
types: [closed]
jobs:
assign-milestone:
name: "Assign milestone to merged pull request"
if: github.event.pull_request.merged == true && ! github.event.pull_request.milestone
process-pull-request-after-merge:
name: "Process a pull request after it's merged"
if: github.event.pull_request.merged == true
runs-on: ubuntu-latest
steps:
- name: "Get the milestone changer script"
run: |
curl \
--silent \
--fail \
--header 'Authorization: bearer ${{ secrets.GITHUB_TOKEN }}' \
--header 'User-Agent: GitHub action to set the milestone for a pull request' \
--header 'Accept: application/vnd.github.v3.raw' \
--remote-name \
--location $GITHUB_API_URL/repos/${{ github.repository }}/contents/.github/workflows/scripts/assign-milestone-to-merged-pr.php
env:
GITHUB_API_URL: ${{ env.GITHUB_API_URL }}
- name: "Install PHP"
uses: shivammathur/setup-php@v2
with:
php-version: '7.4'
- name: "Run the milestone changer script"
run: php assign-milestone-to-merged-pr.php
env:
PULL_REQUEST_ID: ${{ github.event.pull_request.node_id }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: "Get the action scripts"
run: |
scripts="assign-milestone-to-merged-pr.php add-post-merge-comment.php post-request-shared.php"
for script in $scripts
do
curl \
--silent \
--fail \
--header 'Authorization: bearer ${{ secrets.GITHUB_TOKEN }}' \
--header 'User-Agent: GitHub action to set the milestone for a pull request' \
--header 'Accept: application/vnd.github.v3.raw' \
--output $script \
--location "$GITHUB_API_URL/repos/${{ github.repository }}/contents/.github/workflows/scripts/$script?ref=${{ github.event.pull_request.base.ref }}"
done
env:
GITHUB_API_URL: ${{ env.GITHUB_API_URL }}
- name: "Install PHP"
uses: shivammathur/setup-php@v2
with:
php-version: '7.4'
- name: "Run the script to assign a milestone"
if: "!github.event.pull_request.milestone"
run: php assign-milestone-to-merged-pr.php
env:
PULL_REQUEST_ID: ${{ github.event.pull_request.node_id }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: "Run the script to post a comment with next steps hint"
run: php add-post-merge-comment.php
env:
PULL_REQUEST_ID: ${{ github.event.pull_request.node_id }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@ -0,0 +1,95 @@
<?php
/**
* Script to automatically add a comment to a pull request when it's merged.
*
* @package WooCommerce/GithubActions
*/
// phpcs:disable WordPress.Security.EscapeOutput.OutputNotEscaped, WordPress.WP.AlternativeFunctions
require_once __DIR__ . '/post-request-shared.php';
/*
* Get the merger login name.
*/
echo 'Retrieving the merger user name... ';
$get_pr_merged_username_query = "
node(id: \"$pr_id\") {
... on PullRequest {
timelineItems(first: 1, itemTypes: MERGED_EVENT) {
edges {
node {
... on MergedEvent {
actor {
login
}
}
}
}
}
}
}";
$result = do_graphql_api_request( $get_pr_merged_username_query );
if ( is_array( $result ) ) {
if ( empty( $result['errors'] ) ) {
echo "Ok!\n";
} else {
echo "\n*** Errors found while retrieving the merger user name:\n";
echo var_dump( $result['errors'] );
return;
}
} else {
echo "\n*** Error found while retrieving the merger user name: file_get_contents returned the following:\n";
echo var_dump( $result );
return;
}
$merger_user_name = $result['data']['node']['timelineItems']['edges'][0]['node']['actor']['login'];
echo "The pull request was merged by: $merger_user_name\n";
/*
* Post the comment.
*/
$comment_body = "Hi @$merger_user_name, thanks for merging this pull request. Please take a look at these follow-up tasks you may need to perform:
- [ ] Add the `status: needs changelog` label
- [ ] Add the `status: needs testing instructions` label";
$add_comment_mutation = "
addComment(input: {subjectId: \"$pr_id\", body: \"$comment_body\", clientMutationId: \"$github_token\"}) {
commentEdge {
node {
id
databaseId
url
}
}
}";
echo 'Publishing the comment... ';
$result = do_graphql_api_request( $add_comment_mutation, true );
if ( is_array( $result ) ) {
if ( empty( $result['errors'] ) ) {
echo "Ok!\n";
} else {
echo "\n*** Errors found while publishing the comment:\n";
echo var_dump( $result['errors'] );
return;
}
} else {
echo "\n*** Error found while publishing the comment: file_get_contents returned the following:\n";
echo var_dump( $result );
return;
}
$comment_url = $result['data']['addComment']['commentEdge']['node']['url'];
echo "Comment URL: $comment_url\n";
// phpcs:enable WordPress.Security.EscapeOutput.OutputNotEscaped, WordPress.WP.AlternativeFunctions

View File

@ -7,21 +7,9 @@
// phpcs:disable WordPress.Security.EscapeOutput.OutputNotEscaped, WordPress.WP.AlternativeFunctions
global $repo_owner, $repo_name, $github_token, $graphql_api_url;
require_once __DIR__ . '/post-request-shared.php';
/**
* Grab/process input.
*/
$repo_parts = explode( '/', getenv( 'GITHUB_REPOSITORY' ) );
$repo_owner = $repo_parts[0];
$repo_name = $repo_parts[1];
$pr_id = getenv( 'PULL_REQUEST_ID' );
$github_token = getenv( 'GITHUB_TOKEN' );
$graphql_api_url = getenv( 'GITHUB_GRAPHQL_URL' );
/**
/*
* Select the milestone to be added:
*
* 1. Get the first 10 milestones sorted by creation date descending.
@ -122,35 +110,4 @@ if ( is_array( $result ) ) {
echo var_dump( $result );
}
/**
* Function to query the GitHub GraphQL API.
*
* @param string $body The GraphQL-formatted request body, without "query" or "mutation" wrapper.
* @param bool $is_mutation True if the request is a mutation, false if it's a query.
* @return mixed The json-decoded response if a response is received, 'false' (or whatever file_get_contents returns) otherwise.
*/
function do_graphql_api_request( $body, $is_mutation = false ) {
global $github_token, $graphql_api_url;
$keyword = $is_mutation ? 'mutation' : 'query';
$data = array( 'query' => "$keyword { $body }" );
$context = stream_context_create(
array(
'http' => array(
'method' => 'POST',
'header' => array(
'Accept: application/json',
'Content-Type: application/json',
'User-Agent: GitHub action to set the milestone for a pull request',
'Authorization: bearer ' . $github_token,
),
'content' => json_encode( $data ),
),
)
);
$result = file_get_contents( $graphql_api_url, false, $context );
return is_string( $result ) ? json_decode( $result, true ) : $result;
}
// phpcs:enable WordPress.Security.EscapeOutput.OutputNotEscaped, WordPress.WP.AlternativeFunctions

View File

@ -0,0 +1,56 @@
<?php
/**
* Common code for the post-merge GitHub action scripts.
*
* @package WooCommerce/GithubActions
*/
// phpcs:disable WordPress.Security.EscapeOutput.OutputNotEscaped, WordPress.WP.AlternativeFunctions
global $repo_owner, $repo_name, $github_token, $graphql_api_url;
/*
* Grab/process input.
*/
$repo_parts = explode( '/', getenv( 'GITHUB_REPOSITORY' ) );
$repo_owner = $repo_parts[0];
$repo_name = $repo_parts[1];
$pr_id = getenv( 'PULL_REQUEST_ID' );
$github_token = getenv( 'GITHUB_TOKEN' );
$graphql_api_url = getenv( 'GITHUB_GRAPHQL_URL' );
/**
* Function to query the GitHub GraphQL API.
*
* @param string $body The GraphQL-formatted request body, without "query" or "mutation" wrapper.
* @param bool $is_mutation True if the request is a mutation, false if it's a query.
* @return mixed The json-decoded response if a response is received, 'false' (or whatever file_get_contents returns) otherwise.
*/
function do_graphql_api_request( $body, $is_mutation = false ) {
global $github_token, $graphql_api_url;
$keyword = $is_mutation ? 'mutation' : 'query';
$data = array( 'query' => "$keyword { $body }" );
$context = stream_context_create(
array(
'http' => array(
'method' => 'POST',
'header' => array(
'Accept: application/json',
'Content-Type: application/json',
'User-Agent: GitHub action to set the milestone for a pull request',
'Authorization: bearer ' . $github_token,
),
'content' => json_encode( $data ),
),
)
);
$result = file_get_contents( $graphql_api_url, false, $context );
return is_string( $result ) ? json_decode( $result, true ) : $result;
}
// phpcs:enable WordPress.Security.EscapeOutput.OutputNotEscaped, WordPress.WP.AlternativeFunctions

View File

@ -21,6 +21,7 @@
* Fix - Replace hardcoded frontend JS script versions with WC version to bust cached/staled JS scripts. #30301
* Fix - Variable product showing HTML content while granting access for downloadable product in orders. #30305
* Fix - Replaced wp.passwordStrength deprecated method. #30191
* Fix - `woocommerce_email_settings` filter being triggered twice. #30404
* Dev - Apply `woocommerce_logout_default_redirect_url` filter to logout for custom endpoint. #29967
* Dev - Added new `woocommerce_email_sent` hook. #30123

View File

@ -1595,6 +1595,32 @@ return array(
'RSVO' => _x( 'Vojvodina', 'district', 'woocommerce' ),
),
'SE' => array(),
'UA' => array( // Ukraine. Ref: https://en.wikipedia.org/wiki/Oblasts_of_Ukraine.
'VN' => __( 'Vinnytsia Oblast', 'woocommerce' ),
'VL' => __( 'Volyn Oblast', 'woocommerce' ),
'DP' => __( 'Dnipropetrovsk Oblast', 'woocommerce' ),
'DT' => __( 'Donetsk Oblast', 'woocommerce' ),
'ZT' => __( 'Zhytomyr Oblast', 'woocommerce' ),
'ZK' => __( 'Zakarpattia Oblast', 'woocommerce' ),
'ZP' => __( 'Zaporizhzhia Oblast', 'woocommerce' ),
'IF' => __( 'Ivano-Frankivsk Oblast', 'woocommerce' ),
'KV' => __( 'Kyiv Oblast', 'woocommerce' ),
'KH' => __( 'Kirovohrad Oblast', 'woocommerce' ),
'LH' => __( 'Luhansk Oblast', 'woocommerce' ),
'LV' => __( 'Lviv Oblast', 'woocommerce' ),
'MY' => __( 'Mykolaiv Oblast', 'woocommerce' ),
'OD' => __( 'Odessa Oblast', 'woocommerce' ),
'PL' => __( 'Poltava Oblast', 'woocommerce' ),
'RV' => __( 'Rivne Oblast', 'woocommerce' ),
'SM' => __( 'Sumy Oblast', 'woocommerce' ),
'TP' => __( 'Ternopil Oblast', 'woocommerce' ),
'KK' => __( 'Kharkiv Oblast', 'woocommerce' ),
'KS' => __( 'Kherson Oblast', 'woocommerce' ),
'KM' => __( 'Khmelnytskyi Oblast', 'woocommerce' ),
'CK' => __( 'Cherkasy Oblast', 'woocommerce' ),
'CH' => __( 'Chernihiv Oblast', 'woocommerce' ),
'CV' => __( 'Chernivtsi Oblast', 'woocommerce' ),
),
'UG' => array( // Uganda districts. Ref: https://en.wikipedia.org/wiki/ISO_3166-2:UG.
'UG314' => __( 'Abim', 'woocommerce' ),
'UG301' => __( 'Adjumani', 'woocommerce' ),

View File

@ -36,6 +36,8 @@ class WC_Admin_Menus {
add_filter( 'menu_order', array( $this, 'menu_order' ) );
add_filter( 'custom_menu_order', array( $this, 'custom_menu_order' ) );
add_filter( 'set-screen-option', array( $this, 'set_screen_option' ), 10, 3 );
add_filter( 'parent_file', array( $this, 'update_menu_highlight' ) );
add_filter( 'admin_title', array( $this, 'update_my_subscriptions_title' ) );
// Add endpoints custom URLs in Appearance > Menus > Pages.
add_action( 'admin_head-nav-menus.php', array( $this, 'add_nav_menu_meta_boxes' ) );
@ -149,8 +151,9 @@ class WC_Admin_Menus {
public function addons_menu() {
$count_html = WC_Helper_Updater::get_updates_count_html();
/* translators: %s: extensions count */
$menu_title = sprintf( __( 'Extensions %s', 'woocommerce' ), $count_html );
add_submenu_page( 'woocommerce', __( 'WooCommerce extensions', 'woocommerce' ), $menu_title, 'manage_woocommerce', 'wc-addons', array( $this, 'addons_page' ) );
$menu_title = sprintf( __( 'My Subscriptions %s', 'woocommerce' ), $count_html );
add_submenu_page( 'woocommerce', __( 'WooCommerce Marketplace', 'woocommerce' ), __( 'Marketplace', 'woocommerce' ), 'manage_woocommerce', 'wc-addons', array( $this, 'addons_page' ) );
add_submenu_page( 'woocommerce', __( 'My WooCommerce.com Subscriptions', 'woocommerce' ), $menu_title, 'manage_woocommerce', 'wc-addons&section=helper', array( $this, 'addons_page' ) );
}
/**
@ -387,6 +390,38 @@ class WC_Admin_Menus {
)
);
}
/**
* Highlight the My Subscriptions menu item when on that page
*
* @param string $parent_file currently opened page.
* @return string
*/
public function update_menu_highlight( $parent_file ) {
global $submenu_file;
if ( 'woocommerce' === $parent_file && isset( $_GET['section'] ) && 'helper' === $_GET['section'] ) {
$submenu_file = 'wc-addons&section=helper'; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
}
return $parent_file;
}
/**
* Update the My Subscriptions document title when on that page.
* We want to maintain existing page URL but add it as a separate page,
* which requires updating it manually.
*
* @param string $admin_title existing page title.
* @return string
*/
public function update_my_subscriptions_title( $admin_title ) {
if (
isset( $_GET['page'] ) && 'wc-addons' === $_GET['page'] &&
isset( $_GET['section'] ) && 'helper' === $_GET['section']
) {
$admin_title = 'My WooCommerce.com Subscriptions';
}
return $admin_title;
}
}
return new WC_Admin_Menus();

View File

@ -1,19 +1,46 @@
<?php defined( 'ABSPATH' ) or exit(); ?>
<?php
/**
* Helper main view
*
* @package WooCommerce\Helper
*/
?>
<?php defined( 'ABSPATH' ) || exit(); ?>
<div class="wrap woocommerce wc_addons_wrap wc-helper">
<?php require WC_Helper::get_view_filename( 'html-section-nav.php' ); ?>
<h1 class="screen-reader-text"><?php _e( 'WooCommerce Extensions', 'woocommerce' ); ?></h1>
<h1 class="screen-reader-text"><?php esc_html_e( 'My Subscriptions', 'woocommerce' ); ?></h1>
<?php require WC_Helper::get_view_filename( 'html-section-notices.php' ); ?>
<div class="subscriptions-header">
<h2><?php _e( 'Subscriptions', 'woocommerce' ); ?></h2>
<h2><?php esc_html_e( 'Subscriptions', 'woocommerce' ); ?></h2>
<?php require WC_Helper::get_view_filename( 'html-section-account.php' ); ?>
<p><?php printf( __( 'Below is a list of extensions available on your WooCommerce.com account. To receive extension updates please make sure the extension is installed, and its subscription activated and connected to your WooCommerce.com account. Extensions can be activated from the <a href="%s">Plugins</a> screen.', 'woocommerce' ), admin_url( 'plugins.php' ) ); ?></p>
<p>
<?php
printf(
wp_kses(
/* translators: Introduction to list of WooCommerce.com extensions the merchant has subscriptions for. */
__(
'Below is a list of extensions available on your WooCommerce.com account. To receive extension updates please make sure the extension is installed, and its subscription activated and connected to your WooCommerce.com account. Extensions can be activated from the <a href="%s">Plugins</a> screen.',
'woocommerce'
),
array(
'a' => array(
'href' => array(),
),
)
),
esc_url(
admin_url( 'plugins.php' )
)
);
?>
</p>
</div>
<ul class="subscription-filter">
<label><?php _e( 'Sort by:', 'woocommerce' ); ?> <span class="chevron dashicons dashicons-arrow-up-alt2"></span></label>
<label><?php esc_html_e( 'Sort by:', 'woocommerce' ); ?> <span class="chevron dashicons dashicons-arrow-up-alt2"></span></label>
<?php
$filters = array_keys( WC_Helper::get_filters() );
$last_filter = array_pop( $filters );
@ -32,7 +59,7 @@
$class_html = $current_filter === $key ? 'class="current"' : '';
?>
<li>
<a <?php echo $class_html; ?> href="<?php echo esc_url( $url ); ?>">
<a <?php echo esc_attr( $class_html ); ?> href="<?php echo esc_url( $url ); ?>">
<?php echo esc_html( $label ); ?>
<span class="count">(<?php echo absint( $counts[ $key ] ); ?>)</span>
</a>
@ -55,27 +82,27 @@
<div class="wp-list-table__ext-description">
<?php if ( $subscription['lifetime'] ) : ?>
<span class="renews">
<?php _e( 'Lifetime Subscription', 'woocommerce' ); ?>
<?php esc_html_e( 'Lifetime Subscription', 'woocommerce' ); ?>
</span>
<?php elseif ( $subscription['expired'] ) : ?>
<span class="renews">
<strong><?php _e( 'Expired :(', 'woocommerce' ); ?></strong>
<?php echo date_i18n( 'F jS, Y', $subscription['expires'] ); ?>
<strong><?php esc_html_e( 'Expired :(', 'woocommerce' ); ?></strong>
<?php echo esc_html( date_i18n( 'F jS, Y', $subscription['expires'] ) ); ?>
</span>
<?php elseif ( $subscription['autorenew'] ) : ?>
<span class="renews">
<?php _e( 'Auto renews on:', 'woocommerce' ); ?>
<?php echo date_i18n( 'F jS, Y', $subscription['expires'] ); ?>
<?php esc_html_e( 'Auto renews on:', 'woocommerce' ); ?>
<?php echo esc_html( date_i18n( 'F jS, Y', $subscription['expires'] ) ); ?>
</span>
<?php elseif ( $subscription['expiring'] ) : ?>
<span class="renews">
<strong><?php _e( 'Expiring soon!', 'woocommerce' ); ?></strong>
<?php echo date_i18n( 'F jS, Y', $subscription['expires'] ); ?>
<strong><?php esc_html_e( 'Expiring soon!', 'woocommerce' ); ?></strong>
<?php echo esc_html( date_i18n( 'F jS, Y', $subscription['expires'] ) ); ?>
</span>
<?php else : ?>
<span class="renews">
<?php _e( 'Expires on:', 'woocommerce' ); ?>
<?php echo date_i18n( 'F jS, Y', $subscription['expires'] ); ?>
<?php esc_html_e( 'Expires on:', 'woocommerce' ); ?>
<?php echo esc_html( date_i18n( 'F jS, Y', $subscription['expires'] ) ); ?>
</span>
<?php endif; ?>
@ -84,19 +111,21 @@
<?php
if ( ! $subscription['active'] && $subscription['maxed'] ) {
/* translators: %1$d: sites active, %2$d max sites active */
printf( __( 'Subscription: Not available - %1$d of %2$d already in use', 'woocommerce' ), absint( $subscription['sites_active'] ), absint( $subscription['sites_max'] ) );
printf( esc_html__( 'Subscription: Not available - %1$d of %2$d already in use', 'woocommerce' ), absint( $subscription['sites_active'] ), absint( $subscription['sites_max'] ) );
} elseif ( $subscription['sites_max'] > 0 ) {
/* translators: %1$d: sites active, %2$d max sites active */
printf( __( 'Subscription: Using %1$d of %2$d sites available', 'woocommerce' ), absint( $subscription['sites_active'] ), absint( $subscription['sites_max'] ) );
printf( esc_html__( 'Subscription: Using %1$d of %2$d sites available', 'woocommerce' ), absint( $subscription['sites_active'] ), absint( $subscription['sites_max'] ) );
} else {
_e( 'Subscription: Unlimited', 'woocommerce' );
esc_html_e( 'Subscription: Unlimited', 'woocommerce' );
}
// Check shared.
if ( ! empty( $subscription['is_shared'] ) && ! empty( $subscription['owner_email'] ) ) {
printf( '</br>' . __( 'Shared by %s', 'woocommerce' ), esc_html( $subscription['owner_email'] ) );
/* translators: Email address of person who shared the subscription. */
printf( '</br>' . esc_html__( 'Shared by %s', 'woocommerce' ), esc_html( $subscription['owner_email'] ) );
} elseif ( isset( $subscription['master_user_email'] ) ) {
printf( '</br>' . __( 'Shared by %s', 'woocommerce' ), esc_html( $subscription['master_user_email'] ) );
/* translators: Email address of person who shared the subscription. */
printf( '</br>' . esc_html__( 'Shared by %s', 'woocommerce' ), esc_html( $subscription['master_user_email'] ) );
}
?>
</span>
@ -104,35 +133,35 @@
</td>
<td class="wp-list-table__ext-actions">
<?php if ( ! $subscription['active'] && $subscription['maxed'] ) : ?>
<a class="button" href="https://woocommerce.com/my-account/my-subscriptions/" target="_blank"><?php _e( 'Upgrade', 'woocommerce' ); ?></a>
<a class="button" href="https://woocommerce.com/my-account/my-subscriptions/" target="_blank"><?php esc_html_e( 'Upgrade', 'woocommerce' ); ?></a>
<?php elseif ( ! $subscription['local']['installed'] && ! $subscription['expired'] ) : ?>
<a class="button <?php echo empty( $subscription['download_primary'] ) ? 'button-secondary' : ''; ?>" href="<?php echo esc_url( $subscription['download_url'] ); ?>" target="_blank"><?php _e( 'Download', 'woocommerce' ); ?></a>
<a class="button <?php echo empty( $subscription['download_primary'] ) ? 'button-secondary' : ''; ?>" href="<?php echo esc_url( $subscription['download_url'] ); ?>" target="_blank"><?php esc_html_e( 'Download', 'woocommerce' ); ?></a>
<?php elseif ( $subscription['active'] ) : ?>
<span class="form-toggle__wrapper">
<a href="<?php echo esc_url( $subscription['deactivate_url'] ); ?>" class="form-toggle active is-compact" role="link" aria-checked="true"><?php _e( 'Active', 'woocommerce' ); ?></a>
<a href="<?php echo esc_url( $subscription['deactivate_url'] ); ?>" class="form-toggle active is-compact" role="link" aria-checked="true"><?php esc_html_e( 'Active', 'woocommerce' ); ?></a>
<label class="form-toggle__label" for="activate-extension">
<span class="form-toggle__label-content">
<label for="activate-extension"><?php _e( 'Active', 'woocommerce' ); ?></label>
<label for="activate-extension"><?php esc_html_e( 'Active', 'woocommerce' ); ?></label>
</span>
<span class="form-toggle__switch"></span>
</label>
</span>
<?php elseif ( ! $subscription['expired'] ) : ?>
<span class="form-toggle__wrapper">
<a href="<?php echo esc_url( $subscription['activate_url'] ); ?>" class="form-toggle is-compact" role="link" aria-checked="false"><?php _e( 'Inactive', 'woocommerce' ); ?></a>
<a href="<?php echo esc_url( $subscription['activate_url'] ); ?>" class="form-toggle is-compact" role="link" aria-checked="false"><?php esc_html_e( 'Inactive', 'woocommerce' ); ?></a>
<label class="form-toggle__label" for="activate-extension">
<span class="form-toggle__label-content">
<label for="activate-extension"><?php _e( 'Inactive', 'woocommerce' ); ?></label>
<label for="activate-extension"><?php esc_html_e( 'Inactive', 'woocommerce' ); ?></label>
</span>
<span class="form-toggle__switch"></span>
</label>
</span>
<?php else : ?>
<span class="form-toggle__wrapper">
<span class="form-toggle disabled is-compact"><?php _e( 'Inactive', 'woocommerce' ); ?></span>
<span class="form-toggle disabled is-compact"><?php esc_html_e( 'Inactive', 'woocommerce' ); ?></span>
<label class="form-toggle__label" for="activate-extension">
<span class="form-toggle__label-content">
<label for="activate-extension"><?php _e( 'Inactive', 'woocommerce' ); ?></label>
<label for="activate-extension"><?php esc_html_e( 'Inactive', 'woocommerce' ); ?></label>
</span>
</label>
</span>
@ -140,16 +169,16 @@
</td>
</tr>
<?php foreach ( $subscription['actions'] as $action ) : ?>
<?php foreach ( $subscription['actions'] as $subscription_action ) : ?>
<tr class="wp-list-table__row wp-list-table__ext-updates">
<td class="wp-list-table__ext-status <?php echo sanitize_html_class( $action['status'] ); ?>">
<p><span class="dashicons <?php echo sanitize_html_class( $action['icon'] ); ?>"></span>
<?php echo $action['message']; ?>
<td class="wp-list-table__ext-status <?php echo sanitize_html_class( $subscription_action['status'] ); ?>">
<p><span class="dashicons <?php echo sanitize_html_class( $subscription_action['icon'] ); ?>"></span>
<?php echo wp_kses_post( $subscription_action['message'] ); ?>
</p>
</td>
<td class="wp-list-table__ext-actions">
<?php if ( ! empty( $action['button_label'] ) && ! empty( $action['button_url'] ) ) : ?>
<a class="button <?php echo empty( $action['primary'] ) ? 'button-secondary' : ''; ?>" href="<?php echo esc_url( $action['button_url'] ); ?>"><?php echo esc_html( $action['button_label'] ); ?></a>
<?php if ( ! empty( $subscription_action['button_label'] ) && ! empty( $subscription_action['button_url'] ) ) : ?>
<a class="button <?php echo empty( $subscription_action['primary'] ) ? 'button-secondary' : ''; ?>" href="<?php echo esc_url( $subscription_action['button_url'] ); ?>"><?php echo esc_html( $subscription_action['button_label'] ); ?></a>
<?php endif; ?>
</td>
</tr>
@ -159,14 +188,14 @@
<?php endforeach; ?>
<?php else : ?>
<tr>
<td colspan="3"><em><?php _e( 'Could not find any subscriptions on your WooCommerce.com account', 'woocommerce' ); ?></td>
<td colspan="3"><em><?php esc_html_e( 'Could not find any subscriptions on your WooCommerce.com account', 'woocommerce' ); ?></td>
</tr>
<?php endif; ?>
</tbody>
</table>
<?php if ( ! empty( $no_subscriptions ) ) : ?>
<h2><?php _e( 'Installed Extensions without a Subscription', 'woocommerce' ); ?></h2>
<h2><?php esc_html_e( 'Installed Extensions without a Subscription', 'woocommerce' ); ?></h2>
<p>Below is a list of WooCommerce.com products available on your site - but are either out-dated or do not have a valid subscription.</p>
<table class="wp-list-table widefat fixed striped">
@ -183,25 +212,25 @@
</td>
<td class="wp-list-table__ext-actions">
<span class="form-toggle__wrapper">
<span class="form-toggle disabled is-compact" ><?php _e( 'Inactive', 'woocommerce' ); ?></span>
<span class="form-toggle disabled is-compact" ><?php esc_html_e( 'Inactive', 'woocommerce' ); ?></span>
<label class="form-toggle__label" for="activate-extension">
<span class="form-toggle__label-content">
<label for="activate-extension"><?php _e( 'Inactive', 'woocommerce' ); ?></label>
<label for="activate-extension"><?php esc_html_e( 'Inactive', 'woocommerce' ); ?></label>
</span>
</label>
</span>
</td>
</tr>
<?php foreach ( $data['_actions'] as $action ) : ?>
<?php foreach ( $data['_actions'] as $subscription_action ) : ?>
<tr class="wp-list-table__row wp-list-table__ext-updates">
<td class="wp-list-table__ext-status <?php echo sanitize_html_class( $action['status'] ); ?>">
<p><span class="dashicons <?php echo sanitize_html_class( $action['icon'] ); ?>"></span>
<?php echo $action['message']; ?>
<td class="wp-list-table__ext-status <?php echo sanitize_html_class( $subscription_action['status'] ); ?>">
<p><span class="dashicons <?php echo sanitize_html_class( $subscription_action['icon'] ); ?>"></span>
<?php echo esc_html( $subscription_action['message'] ); ?>
</p>
</td>
<td class="wp-list-table__ext-actions">
<a class="button" href="<?php echo esc_url( $action['button_url'] ); ?>" target="_blank"><?php echo esc_html( $action['button_label'] ); ?></a>
<a class="button" href="<?php echo esc_url( $subscription_action['button_url'] ); ?>" target="_blank"><?php echo esc_html( $subscription_action['button_label'] ); ?></a>
</td>
</tr>
<?php endforeach; ?>

View File

@ -10,7 +10,6 @@ defined( 'ABSPATH' ) || exit();
?>
<div class="wrap woocommerce wc_addons_wrap wc-helper">
<?php require WC_Helper::get_view_filename( 'html-section-nav.php' ); ?>
<h1 class="screen-reader-text"><?php esc_html_e( 'WooCommerce Extensions', 'woocommerce' ); ?></h1>
<?php require WC_Helper::get_view_filename( 'html-section-notices.php' ); ?>

View File

@ -1,19 +0,0 @@
<?php
/**
* Helper admin navigation.
*
* @package WooCommerce\Helper
*/
defined( 'ABSPATH' ) || exit(); ?>
<nav class="nav-tab-wrapper woo-nav-tab-wrapper">
<a href="<?php echo esc_url( admin_url( 'admin.php?page=wc-addons' ) ); ?>" class="nav-tab"><?php esc_html_e( 'Browse Extensions', 'woocommerce' ); ?></a>
<?php
$count_html = WC_Helper_Updater::get_updates_count_html();
/* translators: %s: WooCommerce.com Subscriptions tab count HTML. */
$menu_title = sprintf( __( 'WooCommerce.com Subscriptions %s', 'woocommerce' ), $count_html );
?>
<a href="<?php echo esc_url( admin_url( 'admin.php?page=wc-addons&section=helper' ) ); ?>" class="nav-tab nav-tab-active"><?php echo wp_kses_post( $menu_title ); ?></a>
</nav>

View File

@ -607,6 +607,10 @@ class WC_Meta_Box_Order_Data {
$payment_method_title = $methods[ $payment_method ]->get_title();
}
if ( $payment_method == 'other') {
$payment_method_title = esc_html__( 'Other', 'woocommerce' );
}
$props['payment_method'] = $payment_method;
$props['payment_method_title'] = $payment_method_title;
}

View File

@ -13,6 +13,8 @@ if ( ! defined( 'ABSPATH' ) ) {
?>
<div class="wrap woocommerce wc_addons_wrap">
<h1 class="screen-reader-text"><?php esc_html_e( 'Marketplace', 'woocommerce' ); ?></h1>
<?php if ( $sections ) : ?>
<div class="marketplace-header">
<h1 class="marketplace-header__title"><?php esc_html_e( 'WooCommerce Marketplace', 'woocommerce' ); ?></h1>

View File

@ -78,6 +78,14 @@ class WC_Customer extends WC_Legacy_Customer {
*/
protected $calculated_shipping = false;
/**
* This is the name of this object type.
*
* @since 5.6.0
* @var string
*/
protected $object_type = 'customer';
/**
* Load customer data based on how WC_Customer is called.
*
@ -118,16 +126,6 @@ class WC_Customer extends WC_Legacy_Customer {
}
}
/**
* Prefix for action and filter hooks on data.
*
* @since 3.0.0
* @return string
*/
protected function get_hook_prefix() {
return 'woocommerce_customer_get_';
}
/**
* Delete a customer and reassign posts..
*

View File

@ -1315,6 +1315,8 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da
AND p.post_type = 'product'
",
'orderby' => '
ORDER BY RAND()',
'limits' => '
LIMIT ' . absint( $limit ) . '
',

View File

@ -492,6 +492,19 @@ add_action( 'woocommerce_scheduled_sales', 'wc_scheduled_sales' );
* @return array
*/
function wc_get_attachment_image_attributes( $attr ) {
/*
* If the user can manage woocommerce, allow them to
* see the image content.
*/
if ( current_user_can( 'manage_woocommerce' ) ) {
return $attr;
}
/*
* If the user does not have the right capabilities,
* filter out the image source and replace with placeholder
* image.
*/
if ( isset( $attr['src'] ) && strstr( $attr['src'], 'woocommerce_uploads/' ) ) {
$attr['src'] = wc_placeholder_img_src();
@ -511,7 +524,19 @@ add_filter( 'wp_get_attachment_image_attributes', 'wc_get_attachment_image_attri
* @return array
*/
function wc_prepare_attachment_for_js( $response ) {
/*
* If the user can manage woocommerce, allow them to
* see the image content.
*/
if ( current_user_can( 'manage_woocommerce' ) ) {
return $response;
}
/*
* If the user does not have the right capabilities,
* filter out the image source and replace with placeholder
* image.
*/
if ( isset( $response['url'] ) && strstr( $response['url'], 'woocommerce_uploads/' ) ) {
$response['full']['url'] = wc_placeholder_img_src();
if ( isset( $response['sizes'] ) ) {

View File

@ -1,5 +1,3 @@
/* eslint-disable jest/no-export, jest/no-disabled-tests */
/**
* Internal dependencies
*/
@ -37,6 +35,10 @@ const runOnboardingFlowTest = () => {
await withRestApi.deleteAllShippingZones();
});
it('can reset shipping classes', async () => {
await withRestApi.deleteAllShippingClasses();
})
it('can reset to default settings', async () => {
await withRestApi.resetSettingsGroupToDefault('general');
await withRestApi.resetSettingsGroupToDefault('products');
@ -55,7 +57,7 @@ const runTaskListTest = () => {
beforeAll(async () => {
await merchant.login();
});
it('can setup shipping', async () => {
await page.evaluate(() => {
document.querySelector('.woocommerce-list__item-title').scrollIntoView();

View File

@ -22,13 +22,7 @@ const runInitiateWccomConnectionTest = () => {
});
it('can initiate WCCOM connection', async () => {
await merchant.openExtensions();
// Click on a tab to choose WooCommerce Subscriptions extension
await Promise.all([
expect(page).toClick('a.nav-tab', {text: "WooCommerce.com Subscriptions"}),
page.waitForNavigation({waitUntil: 'networkidle0'}),
]);
await merchant.openHelper();
// Click on Connect button to initiate a WCCOM connection
await Promise.all([

View File

@ -12,6 +12,7 @@
- Added `describeIf()` to conditionally run a test suite
- Added `itIf()` to conditionally run a test case.
- Added merchant workflows around plugins: `uploadAndActivatePlugin()`, `activatePlugin()`, `deactivatePlugin()`, `deletePlugin()`
- Added `deleteAllShippingClasses()` which permanently deletes all shipping classes using the API
# 0.1.5

View File

@ -143,6 +143,7 @@ This package provides support for enabling retries in tests:
| `deleteAllCoupons` | | Permanently delete all coupons |
| `deleteAllProducts` | | Permanently delete all products |
| `deleteAllShippingZones` | | Permanently delete all shipping zones except the default |
| `deleteAllShippingClasses` | Permanently delete all shipping classes |
| `deleteCustomerByEmail` | `emailAddress` | Delete customer user account. Posts are reassigned to user ID 1 |
| `resetSettingsGroupToDefault` | `settingsGroup` | Reset settings in settings group to default except `select` fields |

View File

@ -41,6 +41,7 @@ export const WP_ADMIN_ANALYTICS_PAGES = WP_ADMIN_WC_HOME + '&path=%2Fanalytics%2
export const WP_ADMIN_WC_SETTINGS = WP_ADMIN_PLUGIN_PAGE + 'wc-settings&tab=';
export const WP_ADMIN_NEW_SHIPPING_ZONE = WP_ADMIN_WC_SETTINGS + 'shipping&zone_id=new';
export const WP_ADMIN_WC_EXTENSIONS = WP_ADMIN_PLUGIN_PAGE + 'wc-addons';
export const WP_ADMIN_WC_HELPER = WP_ADMIN_PLUGIN_PAGE + 'wc-addons&section=helper';
/**
* Shop pages.

View File

@ -21,6 +21,7 @@ const {
WP_ADMIN_WC_HOME,
WP_ADMIN_WC_SETTINGS,
WP_ADMIN_WC_EXTENSIONS,
WP_ADMIN_WC_HELPER,
WP_ADMIN_NEW_SHIPPING_ZONE,
WP_ADMIN_ANALYTICS_PAGES,
WP_ADMIN_ALL_USERS_VIEW,
@ -134,6 +135,12 @@ const merchant = {
} );
},
openHelper: async () => {
await page.goto( WP_ADMIN_WC_HELPER, {
waitUntil: 'networkidle0',
} );
},
runSetupWizard: async () => {
const setupWizard = IS_RETEST_MODE ? WP_ADMIN_SETUP_WIZARD : WP_ADMIN_WC_HOME;
await page.goto( setupWizard, {

View File

@ -4,6 +4,7 @@ import {Coupon, Setting, SimpleProduct} from '@woocommerce/api';
const client = factories.api.withDefaultPermalinks;
const onboardingProfileEndpoint = '/wc-admin/onboarding/profile';
const shippingZoneEndpoint = '/wc/v3/shipping/zones';
const shippingClassesEndpoint = '/wc/v3/products/shipping_classes';
const userEndpoint = '/wp/v2/users';
/**
@ -99,6 +100,20 @@ export const withRestApi = {
}
}
},
/**
* Use api package to delete shipping classes.
*
* @return {Promise} Promise resolving once shipping classes have been deleted.
*/
deleteAllShippingClasses: async () => {
const shippingClasses = await client.get( shippingClassesEndpoint );
if ( shippingClasses.data && shippingClasses.data.length ) {
for ( let c = 0; c < shippingClasses.data.length; c++ ) {
const response = await client.delete( shippingClassesEndpoint + `/${shippingClasses.data[c].id}?force=true` );
expect( response.statusCode ).toBe( 200 );
}
}
},
/**
* Delete a customer account by their email address if the user exists.
*