plugin install

This commit is contained in:
Tony Volpe
2024-06-18 17:29:05 -04:00
parent e1aaedd1ae
commit 41f50eacc4
5880 changed files with 1057631 additions and 39681 deletions

View File

@@ -0,0 +1,239 @@
<?php
/**
* WooCommerce Account Settings.
*
* @package WooCommerce\Admin
*/
defined( 'ABSPATH' ) || exit;
if ( class_exists( 'WC_Settings_Accounts', false ) ) {
return new WC_Settings_Accounts();
}
/**
* WC_Settings_Accounts.
*/
class WC_Settings_Accounts extends WC_Settings_Page {
/**
* Constructor.
*/
public function __construct() {
$this->id = 'account';
$this->label = __( 'Accounts &amp; Privacy', 'woocommerce' );
parent::__construct();
}
/**
* Get settings array.
*
* @return array
*/
protected function get_settings_for_default_section() {
$erasure_text = esc_html__( 'account erasure request', 'woocommerce' );
$privacy_text = esc_html__( 'privacy page', 'woocommerce' );
if ( current_user_can( 'manage_privacy_options' ) ) {
if ( version_compare( get_bloginfo( 'version' ), '5.3', '<' ) ) {
$erasure_text = sprintf( '<a href="%s">%s</a>', esc_url( admin_url( 'tools.php?page=remove_personal_data' ) ), $erasure_text );
} else {
$erasure_text = sprintf( '<a href="%s">%s</a>', esc_url( admin_url( 'erase-personal-data.php' ) ), $erasure_text );
}
$privacy_text = sprintf( '<a href="%s">%s</a>', esc_url( admin_url( 'options-privacy.php' ) ), $privacy_text );
}
$account_settings = array(
array(
'title' => '',
'type' => 'title',
'id' => 'account_registration_options',
),
array(
'title' => __( 'Guest checkout', 'woocommerce' ),
'desc' => __( 'Allow customers to place orders without an account', 'woocommerce' ),
'id' => 'woocommerce_enable_guest_checkout',
'default' => 'yes',
'type' => 'checkbox',
'checkboxgroup' => 'start',
'autoload' => false,
),
array(
'title' => __( 'Login', 'woocommerce' ),
'desc' => __( 'Allow customers to log into an existing account during checkout', 'woocommerce' ),
'id' => 'woocommerce_enable_checkout_login_reminder',
'default' => 'no',
'type' => 'checkbox',
'checkboxgroup' => 'end',
'autoload' => false,
),
array(
'title' => __( 'Account creation', 'woocommerce' ),
'desc' => __( 'Allow customers to create an account during checkout', 'woocommerce' ),
'id' => 'woocommerce_enable_signup_and_login_from_checkout',
'default' => 'no',
'type' => 'checkbox',
'checkboxgroup' => 'start',
'autoload' => false,
),
array(
'desc' => __( 'Allow customers to create an account on the "My account" page', 'woocommerce' ),
'id' => 'woocommerce_enable_myaccount_registration',
'default' => 'no',
'type' => 'checkbox',
'checkboxgroup' => '',
'autoload' => false,
),
array(
'desc' => __( 'When creating an account, automatically generate an account username for the customer based on their name, surname or email', 'woocommerce' ),
'id' => 'woocommerce_registration_generate_username',
'default' => 'yes',
'type' => 'checkbox',
'checkboxgroup' => '',
'autoload' => false,
),
array(
'desc' => __( 'When creating an account, send the new user a link to set their password', 'woocommerce' ),
'id' => 'woocommerce_registration_generate_password',
'default' => 'yes',
'type' => 'checkbox',
'checkboxgroup' => 'end',
'autoload' => false,
),
array(
'title' => __( 'Account erasure requests', 'woocommerce' ),
'desc' => __( 'Remove personal data from orders on request', 'woocommerce' ),
/* Translators: %s URL to erasure request screen. */
'desc_tip' => sprintf( esc_html__( 'When handling an %s, should personal data within orders be retained or removed?', 'woocommerce' ), $erasure_text ),
'id' => 'woocommerce_erasure_request_removes_order_data',
'type' => 'checkbox',
'default' => 'no',
'checkboxgroup' => 'start',
'autoload' => false,
),
array(
'desc' => __( 'Remove access to downloads on request', 'woocommerce' ),
/* Translators: %s URL to erasure request screen. */
'desc_tip' => sprintf( esc_html__( 'When handling an %s, should access to downloadable files be revoked and download logs cleared?', 'woocommerce' ), $erasure_text ),
'id' => 'woocommerce_erasure_request_removes_download_data',
'type' => 'checkbox',
'default' => 'no',
'checkboxgroup' => 'end',
'autoload' => false,
),
array(
'title' => __( 'Personal data removal', 'woocommerce' ),
'desc' => __( 'Allow personal data to be removed in bulk from orders', 'woocommerce' ),
'desc_tip' => __( 'Adds an option to the orders screen for removing personal data in bulk. Note that removing personal data cannot be undone.', 'woocommerce' ),
'id' => 'woocommerce_allow_bulk_remove_personal_data',
'type' => 'checkbox',
'checkboxgroup' => 'start',
'default' => 'no',
'autoload' => false,
),
array(
'type' => 'sectionend',
'id' => 'account_registration_options',
),
array(
'title' => __( 'Privacy policy', 'woocommerce' ),
'type' => 'title',
'id' => 'privacy_policy_options',
/* translators: %s: privacy page link. */
'desc' => sprintf( esc_html__( 'This section controls the display of your website privacy policy. The privacy notices below will not show up unless a %s is set.', 'woocommerce' ), $privacy_text ),
),
array(
'title' => __( 'Registration privacy policy', 'woocommerce' ),
'desc_tip' => __( 'Optionally add some text about your store privacy policy to show on account registration forms.', 'woocommerce' ),
'id' => 'woocommerce_registration_privacy_policy_text',
/* translators: %s privacy policy page name and link */
'default' => sprintf( __( 'Your personal data will be used to support your experience throughout this website, to manage access to your account, and for other purposes described in our %s.', 'woocommerce' ), '[privacy_policy]' ),
'type' => 'textarea',
'css' => 'min-width: 50%; height: 75px;',
),
array(
'title' => __( 'Checkout privacy policy', 'woocommerce' ),
'desc_tip' => __( 'Optionally add some text about your store privacy policy to show during checkout.', 'woocommerce' ),
'id' => 'woocommerce_checkout_privacy_policy_text',
/* translators: %s privacy policy page name and link */
'default' => sprintf( __( 'Your personal data will be used to process your order, support your experience throughout this website, and for other purposes described in our %s.', 'woocommerce' ), '[privacy_policy]' ),
'type' => 'textarea',
'css' => 'min-width: 50%; height: 75px;',
),
array(
'type' => 'sectionend',
'id' => 'privacy_policy_options',
),
array(
'title' => __( 'Personal data retention', 'woocommerce' ),
'desc' => __( 'Choose how long to retain personal data when it\'s no longer needed for processing. Leave the following options blank to retain this data indefinitely.', 'woocommerce' ),
'type' => 'title',
'id' => 'personal_data_retention',
),
array(
'title' => __( 'Retain inactive accounts ', 'woocommerce' ),
'desc_tip' => __( 'Inactive accounts are those which have not logged in, or placed an order, for the specified duration. They will be deleted. Any orders will be converted into guest orders.', 'woocommerce' ),
'id' => 'woocommerce_delete_inactive_accounts',
'type' => 'relative_date_selector',
'placeholder' => __( 'N/A', 'woocommerce' ),
'default' => array(
'number' => '',
'unit' => 'months',
),
'autoload' => false,
),
array(
'title' => __( 'Retain pending orders ', 'woocommerce' ),
'desc_tip' => __( 'Pending orders are unpaid and may have been abandoned by the customer. They will be trashed after the specified duration.', 'woocommerce' ),
'id' => 'woocommerce_trash_pending_orders',
'type' => 'relative_date_selector',
'placeholder' => __( 'N/A', 'woocommerce' ),
'default' => '',
'autoload' => false,
),
array(
'title' => __( 'Retain failed orders', 'woocommerce' ),
'desc_tip' => __( 'Failed orders are unpaid and may have been abandoned by the customer. They will be trashed after the specified duration.', 'woocommerce' ),
'id' => 'woocommerce_trash_failed_orders',
'type' => 'relative_date_selector',
'placeholder' => __( 'N/A', 'woocommerce' ),
'default' => '',
'autoload' => false,
),
array(
'title' => __( 'Retain cancelled orders', 'woocommerce' ),
'desc_tip' => __( 'Cancelled orders are unpaid and may have been cancelled by the store owner or customer. They will be trashed after the specified duration.', 'woocommerce' ),
'id' => 'woocommerce_trash_cancelled_orders',
'type' => 'relative_date_selector',
'placeholder' => __( 'N/A', 'woocommerce' ),
'default' => '',
'autoload' => false,
),
array(
'title' => __( 'Retain completed orders', 'woocommerce' ),
'desc_tip' => __( 'Retain completed orders for a specified duration before anonymizing the personal data within them.', 'woocommerce' ),
'id' => 'woocommerce_anonymize_completed_orders',
'type' => 'relative_date_selector',
'placeholder' => __( 'N/A', 'woocommerce' ),
'default' => array(
'number' => '',
'unit' => 'months',
),
'autoload' => false,
),
array(
'type' => 'sectionend',
'id' => 'personal_data_retention',
),
);
return apply_filters(
'woocommerce_' . $this->id . '_settings',
$account_settings
);
}
}
return new WC_Settings_Accounts();

View File

@@ -0,0 +1,514 @@
<?php
/**
* WooCommerce advanced settings
*
* @package WooCommerce\Admin
*/
use Automattic\WooCommerce\Admin\Features\Features;
defined( 'ABSPATH' ) || exit;
/**
* Settings for API.
*/
if ( class_exists( 'WC_Settings_Advanced', false ) ) {
return new WC_Settings_Advanced();
}
/**
* WC_Settings_Advanced.
*/
class WC_Settings_Advanced extends WC_Settings_Page {
/**
* Constructor.
*/
public function __construct() {
$this->id = 'advanced';
$this->label = __( 'Advanced', 'woocommerce' );
parent::__construct();
$this->notices();
}
/**
* Get own sections.
*
* @return array
*/
protected function get_own_sections() {
return array(
'' => __( 'Page setup', 'woocommerce' ),
'keys' => __( 'REST API', 'woocommerce' ),
'webhooks' => __( 'Webhooks', 'woocommerce' ),
'legacy_api' => __( 'Legacy API', 'woocommerce' ),
'woocommerce_com' => __( 'WooCommerce.com', 'woocommerce' ),
);
}
/**
* Get settings for the default section.
*
* @return array
*/
protected function get_settings_for_default_section() {
$settings =
array(
array(
'title' => __( 'Page setup', 'woocommerce' ),
'desc' => __( 'These pages need to be set so that WooCommerce knows where to send users to checkout.', 'woocommerce' ),
'type' => 'title',
'id' => 'advanced_page_options',
),
array(
'title' => __( 'Cart page', 'woocommerce' ),
/* Translators: %s Page contents. */
'desc' => __( 'Page where shoppers review their shopping cart', 'woocommerce' ),
'id' => 'woocommerce_cart_page_id',
'type' => 'single_select_page_with_search',
'default' => '',
'class' => 'wc-page-search',
'css' => 'min-width:300px;',
'args' => array(
'exclude' =>
array(
wc_get_page_id( 'checkout' ),
wc_get_page_id( 'myaccount' ),
),
),
'desc_tip' => true,
'autoload' => false,
),
array(
'title' => __( 'Checkout page', 'woocommerce' ),
/* Translators: %s Page contents. */
'desc' => __( 'Page where shoppers go to finalize their purchase', 'woocommerce' ),
'id' => 'woocommerce_checkout_page_id',
'type' => 'single_select_page_with_search',
'default' => wc_get_page_id( 'checkout' ),
'class' => 'wc-page-search',
'css' => 'min-width:300px;',
'args' => array(
'exclude' =>
array(
wc_get_page_id( 'cart' ),
wc_get_page_id( 'myaccount' ),
),
),
'desc_tip' => true,
'autoload' => false,
),
array(
'title' => __( 'My account page', 'woocommerce' ),
/* Translators: %s Page contents. */
'desc' => sprintf( __( 'Page contents: [%s]', 'woocommerce' ), apply_filters( 'woocommerce_my_account_shortcode_tag', 'woocommerce_my_account' ) ),
'id' => 'woocommerce_myaccount_page_id',
'type' => 'single_select_page_with_search',
'default' => '',
'class' => 'wc-page-search',
'css' => 'min-width:300px;',
'args' => array(
'exclude' =>
array(
wc_get_page_id( 'cart' ),
wc_get_page_id( 'checkout' ),
),
),
'desc_tip' => true,
'autoload' => false,
),
array(
'title' => __( 'Terms and conditions', 'woocommerce' ),
'desc' => __( 'If you define a "Terms" page the customer will be asked if they accept them when checking out.', 'woocommerce' ),
'id' => 'woocommerce_terms_page_id',
'default' => '',
'class' => 'wc-page-search',
'css' => 'min-width:300px;',
'type' => 'single_select_page_with_search',
'args' => array( 'exclude' => wc_get_page_id( 'checkout' ) ),
'desc_tip' => true,
'autoload' => false,
),
array(
'type' => 'sectionend',
'id' => 'advanced_page_options',
),
array(
'title' => '',
'type' => 'title',
'id' => 'checkout_process_options',
),
'force_ssl_checkout' => array(
'title' => __( 'Secure checkout', 'woocommerce' ),
'desc' => __( 'Force secure checkout', 'woocommerce' ),
'id' => 'woocommerce_force_ssl_checkout',
'default' => 'no',
'type' => 'checkbox',
'checkboxgroup' => 'start',
'show_if_checked' => 'option',
/* Translators: %s Docs URL. */
'desc_tip' => sprintf( __( 'Force SSL (HTTPS) on the checkout pages (<a href="%s" target="_blank">an SSL Certificate is required</a>).', 'woocommerce' ), 'https://woocommerce.com/document/ssl-and-https/#section-3' ),
),
'unforce_ssl_checkout' => array(
'desc' => __( 'Force HTTP when leaving the checkout', 'woocommerce' ),
'id' => 'woocommerce_unforce_ssl_checkout',
'default' => 'no',
'type' => 'checkbox',
'checkboxgroup' => 'end',
'show_if_checked' => 'yes',
),
array(
'type' => 'sectionend',
'id' => 'checkout_process_options',
),
array(
'title' => __( 'Checkout endpoints', 'woocommerce' ),
'type' => 'title',
'desc' => __( 'Endpoints are appended to your page URLs to handle specific actions during the checkout process. They should be unique.', 'woocommerce' ),
'id' => 'checkout_endpoint_options',
),
array(
'title' => __( 'Pay', 'woocommerce' ),
'desc' => __( 'Endpoint for the "Checkout &rarr; Pay" page.', 'woocommerce' ),
'id' => 'woocommerce_checkout_pay_endpoint',
'type' => 'text',
'default' => 'order-pay',
'desc_tip' => true,
),
array(
'title' => __( 'Order received', 'woocommerce' ),
'desc' => __( 'Endpoint for the "Checkout &rarr; Order received" page.', 'woocommerce' ),
'id' => 'woocommerce_checkout_order_received_endpoint',
'type' => 'text',
'default' => 'order-received',
'desc_tip' => true,
),
array(
'title' => __( 'Add payment method', 'woocommerce' ),
'desc' => __( 'Endpoint for the "Checkout &rarr; Add payment method" page.', 'woocommerce' ),
'id' => 'woocommerce_myaccount_add_payment_method_endpoint',
'type' => 'text',
'default' => 'add-payment-method',
'desc_tip' => true,
),
array(
'title' => __( 'Delete payment method', 'woocommerce' ),
'desc' => __( 'Endpoint for the delete payment method page.', 'woocommerce' ),
'id' => 'woocommerce_myaccount_delete_payment_method_endpoint',
'type' => 'text',
'default' => 'delete-payment-method',
'desc_tip' => true,
),
array(
'title' => __( 'Set default payment method', 'woocommerce' ),
'desc' => __( 'Endpoint for the setting a default payment method page.', 'woocommerce' ),
'id' => 'woocommerce_myaccount_set_default_payment_method_endpoint',
'type' => 'text',
'default' => 'set-default-payment-method',
'desc_tip' => true,
),
array(
'type' => 'sectionend',
'id' => 'checkout_endpoint_options',
),
array(
'title' => __( 'Account endpoints', 'woocommerce' ),
'type' => 'title',
'desc' => __( 'Endpoints are appended to your page URLs to handle specific actions on the accounts pages. They should be unique and can be left blank to disable the endpoint.', 'woocommerce' ),
'id' => 'account_endpoint_options',
),
array(
'title' => __( 'Orders', 'woocommerce' ),
'desc' => __( 'Endpoint for the "My account &rarr; Orders" page.', 'woocommerce' ),
'id' => 'woocommerce_myaccount_orders_endpoint',
'type' => 'text',
'default' => 'orders',
'desc_tip' => true,
),
array(
'title' => __( 'View order', 'woocommerce' ),
'desc' => __( 'Endpoint for the "My account &rarr; View order" page.', 'woocommerce' ),
'id' => 'woocommerce_myaccount_view_order_endpoint',
'type' => 'text',
'default' => 'view-order',
'desc_tip' => true,
),
array(
'title' => __( 'Downloads', 'woocommerce' ),
'desc' => __( 'Endpoint for the "My account &rarr; Downloads" page.', 'woocommerce' ),
'id' => 'woocommerce_myaccount_downloads_endpoint',
'type' => 'text',
'default' => 'downloads',
'desc_tip' => true,
),
array(
'title' => __( 'Edit account', 'woocommerce' ),
'desc' => __( 'Endpoint for the "My account &rarr; Edit account" page.', 'woocommerce' ),
'id' => 'woocommerce_myaccount_edit_account_endpoint',
'type' => 'text',
'default' => 'edit-account',
'desc_tip' => true,
),
array(
'title' => __( 'Addresses', 'woocommerce' ),
'desc' => __( 'Endpoint for the "My account &rarr; Addresses" page.', 'woocommerce' ),
'id' => 'woocommerce_myaccount_edit_address_endpoint',
'type' => 'text',
'default' => 'edit-address',
'desc_tip' => true,
),
array(
'title' => __( 'Payment methods', 'woocommerce' ),
'desc' => __( 'Endpoint for the "My account &rarr; Payment methods" page.', 'woocommerce' ),
'id' => 'woocommerce_myaccount_payment_methods_endpoint',
'type' => 'text',
'default' => 'payment-methods',
'desc_tip' => true,
),
array(
'title' => __( 'Lost password', 'woocommerce' ),
'desc' => __( 'Endpoint for the "My account &rarr; Lost password" page.', 'woocommerce' ),
'id' => 'woocommerce_myaccount_lost_password_endpoint',
'type' => 'text',
'default' => 'lost-password',
'desc_tip' => true,
),
array(
'title' => __( 'Logout', 'woocommerce' ),
'desc' => __( 'Endpoint for the triggering logout. You can add this to your menus via a custom link: yoursite.com/?customer-logout=true', 'woocommerce' ),
'id' => 'woocommerce_logout_endpoint',
'type' => 'text',
'default' => 'customer-logout',
'desc_tip' => true,
),
array(
'type' => 'sectionend',
'id' => 'account_endpoint_options',
),
);
$settings = apply_filters( 'woocommerce_settings_pages', $settings );
if ( wc_site_is_https() ) {
unset( $settings['unforce_ssl_checkout'], $settings['force_ssl_checkout'] );
}
return $settings;
}
/**
* Get settings for the WooCommerce.com section.
*
* @return array
*/
protected function get_settings_for_woocommerce_com_section() {
$tracking_info_text = sprintf( '<a href="%s" target="_blank">%s</a>', 'https://woocommerce.com/usage-tracking', esc_html__( 'WooCommerce.com Usage Tracking Documentation', 'woocommerce' ) );
$settings =
array(
array(
'title' => esc_html__( 'Usage Tracking', 'woocommerce' ),
'type' => 'title',
'id' => 'tracking_options',
'desc' => __( 'Gathering usage data allows us to tailor your store setup experience, offer more relevant content, and help make WooCommerce better for everyone.', 'woocommerce' ),
),
array(
'title' => __( 'Enable tracking', 'woocommerce' ),
'desc' => __( 'Allow usage of WooCommerce to be tracked', 'woocommerce' ),
/* Translators: %s URL to tracking info screen. */
'desc_tip' => sprintf( esc_html__( 'To opt out, leave this box unticked. Your store remains untracked, and no data will be collected. Read about what usage data is tracked at: %s.', 'woocommerce' ), $tracking_info_text ),
'id' => 'woocommerce_allow_tracking',
'type' => 'checkbox',
'checkboxgroup' => 'start',
'default' => 'no',
'autoload' => false,
),
array(
'type' => 'sectionend',
'id' => 'tracking_options',
),
array(
'title' => esc_html__( 'Marketplace suggestions', 'woocommerce' ),
'type' => 'title',
'id' => 'marketplace_suggestions',
'desc' => __( 'We show contextual suggestions for official extensions that may be helpful to your store.', 'woocommerce' ),
),
array(
'title' => __( 'Show Suggestions', 'woocommerce' ),
'desc' => __( 'Display suggestions within WooCommerce', 'woocommerce' ),
'desc_tip' => esc_html__( 'Leave this box unchecked if you do not want to pull suggested extensions from WooCommerce.com. You will see a static list of extensions instead.', 'woocommerce' ),
'id' => 'woocommerce_show_marketplace_suggestions',
'type' => 'checkbox',
'checkboxgroup' => 'start',
'default' => 'yes',
'autoload' => false,
),
array(
'type' => 'sectionend',
'id' => 'marketplace_suggestions',
),
);
return apply_filters( 'woocommerce_com_integration_settings', $settings );
}
/**
* Get settings for the legacy API section.
*
* @return array
*/
protected function get_settings_for_legacy_api_section() {
$legacy_api_setting_desc =
'yes' === get_option( 'woocommerce_api_enabled' ) ?
__( 'The legacy REST API is enabled', 'woocommerce' ) :
__( 'The legacy REST API is NOT enabled', 'woocommerce' );
$legacy_api_setting_tip =
is_plugin_active( 'woocommerce-legacy-rest-api/woocommerce-legacy-rest-api.php' ) ?
__( ' The WooCommerce Legacy REST API extension is installed and active.', 'woocommerce' ) :
sprintf(
/* translators: placeholders are URLs */
__( '⚠️ The WooCommerce Legacy REST API has been moved to <a target=”_blank” href="%1$s">a dedicated extension</a>. <b><a target=”_blank” href="%2$s">Learn more about this change</a></b>', 'woocommerce' ),
'https://wordpress.org/plugins/woocommerce-legacy-rest-api/',
'https://developer.woocommerce.com/2023/10/03/the-legacy-rest-api-will-move-to-a-dedicated-extension-in-woocommerce-9-0/'
);
$settings =
array(
array(
'title' => '',
'type' => 'title',
'desc' => '',
'id' => 'legacy_api_options',
),
array(
'title' => __( 'Legacy API', 'woocommerce' ),
'desc' => $legacy_api_setting_desc,
'id' => 'woocommerce_api_enabled',
'type' => 'checkbox',
'default' => 'no',
'disabled' => true,
'desc_tip' => $legacy_api_setting_tip,
),
array(
'type' => 'sectionend',
'id' => 'legacy_api_options',
),
);
return apply_filters( 'woocommerce_settings_rest_api', $settings );
}
/**
* Form method.
*
* @deprecated 3.4.4
*
* @param string $method Method name.
*
* @return string
*/
public function form_method( $method ) {
return 'post';
}
/**
* Notices.
*/
private function notices() {
// phpcs:disable WordPress.Security.NonceVerification.Recommended
if ( isset( $_GET['section'] ) && 'webhooks' === $_GET['section'] ) {
WC_Admin_Webhooks::notices();
}
if ( isset( $_GET['section'] ) && 'keys' === $_GET['section'] ) {
WC_Admin_API_Keys::notices();
}
// phpcs:enable
}
/**
* Output the settings.
*/
public function output() {
global $current_section;
if ( 'webhooks' === $current_section ) {
WC_Admin_Webhooks::page_output();
} elseif ( 'keys' === $current_section ) {
WC_Admin_API_Keys::page_output();
} else {
parent::output();
}
}
/**
* Save settings.
*/
public function save() {
// phpcs:disable WordPress.Security.NonceVerification.Missing
global $current_section;
if ( apply_filters( 'woocommerce_rest_api_valid_to_save', ! in_array( $current_section, array( 'keys', 'webhooks' ), true ) ) ) {
// Prevent the T&Cs and checkout page from being set to the same page.
if ( isset( $_POST['woocommerce_terms_page_id'], $_POST['woocommerce_checkout_page_id'] ) && $_POST['woocommerce_terms_page_id'] === $_POST['woocommerce_checkout_page_id'] ) {
$_POST['woocommerce_terms_page_id'] = '';
}
// Prevent the Cart, checkout and my account page from being set to the same page.
if ( isset( $_POST['woocommerce_cart_page_id'], $_POST['woocommerce_checkout_page_id'], $_POST['woocommerce_myaccount_page_id'] ) ) {
if ( $_POST['woocommerce_cart_page_id'] === $_POST['woocommerce_checkout_page_id'] ) {
$_POST['woocommerce_checkout_page_id'] = '';
}
if ( $_POST['woocommerce_cart_page_id'] === $_POST['woocommerce_myaccount_page_id'] ) {
$_POST['woocommerce_myaccount_page_id'] = '';
}
if ( $_POST['woocommerce_checkout_page_id'] === $_POST['woocommerce_myaccount_page_id'] ) {
$_POST['woocommerce_myaccount_page_id'] = '';
}
}
$this->save_settings_for_current_section();
$this->do_update_options_action();
}
// phpcs:enable
}
}
// phpcs:disable Generic.Files.OneObjectStructurePerFile.MultipleFound, Generic.Commenting.Todo.CommentFound
/**
* WC_Settings_Rest_API class.
*
* @deprecated 3.4 in favour of WC_Settings_Advanced.
*/
class WC_Settings_Rest_API extends WC_Settings_Advanced {
}
return new WC_Settings_Advanced();
// phpcs:enable

View File

@@ -0,0 +1,11 @@
<?php // @codingStandardsIgnoreFile.
/**
* Settings class file.
*
* @deprecated 3.4.0 Replaced with class-wc-settings-payment-gateways.php.
* @todo remove in 4.0.
*/
defined( 'ABSPATH' ) || exit;
return include __DIR__ . '/class-wc-settings-payment-gateways.php';

View File

@@ -0,0 +1,371 @@
<?php
/**
* WooCommerce Email Settings
*
* @package WooCommerce\Admin
* @version 2.1.0
*/
defined( 'ABSPATH' ) || exit;
if ( class_exists( 'WC_Settings_Emails', false ) ) {
return new WC_Settings_Emails();
}
/**
* WC_Settings_Emails.
*/
class WC_Settings_Emails extends WC_Settings_Page {
/**
* Constructor.
*/
public function __construct() {
$this->id = 'email';
$this->label = __( 'Emails', 'woocommerce' );
add_action( 'woocommerce_admin_field_email_notification', array( $this, 'email_notification_setting' ) );
parent::__construct();
}
/**
* Get own sections.
*
* @return array
*/
protected function get_own_sections() {
return array(
'' => __( 'Email options', 'woocommerce' ),
);
}
/**
* Get settings array.
*
* @return array
*/
protected function get_settings_for_default_section() {
$desc_help_text = sprintf(
/* translators: %1$s: Link to WP Mail Logging plugin, %2$s: Link to Email FAQ support page. */
__( 'To ensure your store&rsquo;s notifications arrive in your and your customers&rsquo; inboxes, we recommend connecting your email address to your domain and setting up a dedicated SMTP server. If something doesn&rsquo;t seem to be sending correctly, install the <a href="%1$s">WP Mail Logging Plugin</a> or check the <a href="%2$s">Email FAQ page</a>.', 'woocommerce' ),
'https://wordpress.org/plugins/wp-mail-logging/',
'https://woocommerce.com/document/email-faq'
);
$settings =
array(
array(
'title' => __( 'Email notifications', 'woocommerce' ),
/* translators: %s: help description with link to WP Mail logging and support page. */
'desc' => sprintf( __( 'Email notifications sent from WooCommerce are listed below. Click on an email to configure it.<br>%s', 'woocommerce' ), $desc_help_text ),
'type' => 'title',
'id' => 'email_notification_settings',
),
array( 'type' => 'email_notification' ),
array(
'type' => 'sectionend',
'id' => 'email_notification_settings',
),
array(
'type' => 'sectionend',
'id' => 'email_recipient_options',
),
array(
'title' => __( 'Email sender options', 'woocommerce' ),
'type' => 'title',
'desc' => '',
'id' => 'email_options',
),
array(
'title' => __( '"From" name', 'woocommerce' ),
'desc' => __( 'How the sender name appears in outgoing WooCommerce emails.', 'woocommerce' ),
'id' => 'woocommerce_email_from_name',
'type' => 'text',
'css' => 'min-width:400px;',
'default' => esc_attr( get_bloginfo( 'name', 'display' ) ),
'autoload' => false,
'desc_tip' => true,
),
array(
'title' => __( '"From" address', 'woocommerce' ),
'desc' => __( 'How the sender email appears in outgoing WooCommerce emails.', 'woocommerce' ),
'id' => 'woocommerce_email_from_address',
'type' => 'email',
'custom_attributes' => array(
'multiple' => 'multiple',
),
'css' => 'min-width:400px;',
'default' => get_option( 'admin_email' ),
'autoload' => false,
'desc_tip' => true,
),
array(
'type' => 'sectionend',
'id' => 'email_options',
),
array(
'title' => __( 'Email template', 'woocommerce' ),
'type' => 'title',
/* translators: %s: Nonced email preview link */
'desc' => sprintf( __( 'This section lets you customize the WooCommerce emails. <a href="%s" target="_blank">Click here to preview your email template</a>.', 'woocommerce' ), wp_nonce_url( admin_url( '?preview_woocommerce_mail=true' ), 'preview-mail' ) ),
'id' => 'email_template_options',
),
array(
'title' => __( 'Header image', 'woocommerce' ),
'desc' => __( 'Paste the URL of an image you want to show in the email header. Upload images using the media uploader (Media > Add New).', 'woocommerce' ),
'id' => 'woocommerce_email_header_image',
'type' => 'text',
'css' => 'min-width:400px;',
'placeholder' => __( 'N/A', 'woocommerce' ),
'default' => '',
'autoload' => false,
'desc_tip' => true,
),
array(
'title' => __( 'Footer text', 'woocommerce' ),
/* translators: %s: Available placeholders for use */
'desc' => __( 'The text to appear in the footer of all WooCommerce emails.', 'woocommerce' ) . ' ' . sprintf( __( 'Available placeholders: %s', 'woocommerce' ), '{site_title} {site_url}' ),
'id' => 'woocommerce_email_footer_text',
'css' => 'width:400px; height: 75px;',
'placeholder' => __( 'N/A', 'woocommerce' ),
'type' => 'textarea',
'default' => '{site_title} &mdash; Built with {WooCommerce}',
'autoload' => false,
'desc_tip' => true,
),
array(
'title' => __( 'Base color', 'woocommerce' ),
/* translators: %s: default color */
'desc' => sprintf( __( 'The base color for WooCommerce email templates. Default %s.', 'woocommerce' ), '<code>#7f54b3</code>' ),
'id' => 'woocommerce_email_base_color',
'type' => 'color',
'css' => 'width:6em;',
'default' => '#7f54b3',
'autoload' => false,
'desc_tip' => true,
),
array(
'title' => __( 'Background color', 'woocommerce' ),
/* translators: %s: default color */
'desc' => sprintf( __( 'The background color for WooCommerce email templates. Default %s.', 'woocommerce' ), '<code>#f7f7f7</code>' ),
'id' => 'woocommerce_email_background_color',
'type' => 'color',
'css' => 'width:6em;',
'default' => '#f7f7f7',
'autoload' => false,
'desc_tip' => true,
),
array(
'title' => __( 'Body background color', 'woocommerce' ),
/* translators: %s: default color */
'desc' => sprintf( __( 'The main body background color. Default %s.', 'woocommerce' ), '<code>#ffffff</code>' ),
'id' => 'woocommerce_email_body_background_color',
'type' => 'color',
'css' => 'width:6em;',
'default' => '#ffffff',
'autoload' => false,
'desc_tip' => true,
),
array(
'title' => __( 'Body text color', 'woocommerce' ),
/* translators: %s: default color */
'desc' => sprintf( __( 'The main body text color. Default %s.', 'woocommerce' ), '<code>#3c3c3c</code>' ),
'id' => 'woocommerce_email_text_color',
'type' => 'color',
'css' => 'width:6em;',
'default' => '#3c3c3c',
'autoload' => false,
'desc_tip' => true,
),
array(
'type' => 'sectionend',
'id' => 'email_template_options',
),
array(
'title' => __( 'Store management insights', 'woocommerce' ),
'type' => 'title',
'id' => 'email_merchant_notes',
),
array(
'title' => __( 'Enable email insights', 'woocommerce' ),
'desc' => __( 'Receive email notifications with additional guidance to complete the basic store setup and helpful insights', 'woocommerce' ),
'id' => 'woocommerce_merchant_email_notifications',
'type' => 'checkbox',
'checkboxgroup' => 'start',
'default' => 'no',
'autoload' => false,
),
array(
'type' => 'sectionend',
'id' => 'email_merchant_notes',
),
);
return apply_filters( 'woocommerce_email_settings', $settings );
}
/**
* Output the settings.
*/
public function output() {
global $current_section;
// Define emails that can be customised here.
$mailer = WC()->mailer();
$email_templates = $mailer->get_emails();
if ( $current_section ) {
foreach ( $email_templates as $email_key => $email ) {
if ( strtolower( $email_key ) === $current_section ) {
$this->run_email_admin_options( $email );
break;
}
}
}
parent::output();
}
/**
* Run the 'admin_options' method on a given email.
* This method exists to easy unit testing.
*
* @param object $email The email object to run the method on.
*/
protected function run_email_admin_options( $email ) {
$email->admin_options();
}
/**
* Save settings.
*/
public function save() {
global $current_section;
if ( ! $current_section ) {
$this->save_settings_for_current_section();
$this->do_update_options_action();
} else {
$wc_emails = WC_Emails::instance();
if ( in_array( $current_section, array_map( 'sanitize_title', array_keys( $wc_emails->get_emails() ) ), true ) ) {
foreach ( $wc_emails->get_emails() as $email_id => $email ) {
if ( sanitize_title( $email_id ) === $current_section ) {
$this->do_update_options_action( $email->id );
}
}
} else {
$this->save_settings_for_current_section();
$this->do_update_options_action();
}
}
}
/**
* Output email notification settings.
*/
public function email_notification_setting() {
// Define emails that can be customised here.
$mailer = WC()->mailer();
$email_templates = $mailer->get_emails();
?>
<tr valign="top">
<td class="wc_emails_wrapper" colspan="2">
<table class="wc_emails widefat" cellspacing="0">
<thead>
<tr>
<?php
$columns = apply_filters(
'woocommerce_email_setting_columns',
array(
'status' => '',
'name' => __( 'Email', 'woocommerce' ),
'email_type' => __( 'Content type', 'woocommerce' ),
'recipient' => __( 'Recipient(s)', 'woocommerce' ),
'actions' => '',
)
);
foreach ( $columns as $key => $column ) {
echo '<th class="wc-email-settings-table-' . esc_attr( $key ) . '">' . esc_html( $column ) . '</th>';
}
?>
</tr>
</thead>
<tbody>
<?php
foreach ( $email_templates as $email_key => $email ) {
echo '<tr>';
foreach ( $columns as $key => $column ) {
switch ( $key ) {
case 'name':
echo '<td class="wc-email-settings-table-' . esc_attr( $key ) . '">
<a href="' . esc_url( admin_url( 'admin.php?page=wc-settings&tab=email&section=' . strtolower( $email_key ) ) ) . '">' . esc_html( $email->get_title() ) . '</a>
' . wc_help_tip( $email->get_description() ) . '
</td>';
break;
case 'recipient':
echo '<td class="wc-email-settings-table-' . esc_attr( $key ) . '">
' . esc_html( $email->is_customer_email() ? __( 'Customer', 'woocommerce' ) : $email->get_recipient() ) . '
</td>';
break;
case 'status':
echo '<td class="wc-email-settings-table-' . esc_attr( $key ) . '">';
if ( $email->is_manual() ) {
echo '<span class="status-manual tips" data-tip="' . esc_attr__( 'Manually sent', 'woocommerce' ) . '">' . esc_html__( 'Manual', 'woocommerce' ) . '</span>';
} elseif ( $email->is_enabled() ) {
echo '<span class="status-enabled tips" data-tip="' . esc_attr__( 'Enabled', 'woocommerce' ) . '">' . esc_html__( 'Yes', 'woocommerce' ) . '</span>';
} else {
echo '<span class="status-disabled tips" data-tip="' . esc_attr__( 'Disabled', 'woocommerce' ) . '">-</span>';
}
echo '</td>';
break;
case 'email_type':
echo '<td class="wc-email-settings-table-' . esc_attr( $key ) . '">
' . esc_html( $email->get_content_type() ) . '
</td>';
break;
case 'actions':
echo '<td class="wc-email-settings-table-' . esc_attr( $key ) . '">
<a class="button alignright" href="' . esc_url( admin_url( 'admin.php?page=wc-settings&tab=email&section=' . strtolower( $email_key ) ) ) . '">' . esc_html__( 'Manage', 'woocommerce' ) . '</a>
</td>';
break;
default:
do_action( 'woocommerce_email_setting_column_' . $key, $email );
break;
}
}
echo '</tr>';
}
?>
</tbody>
</table>
</td>
</tr>
<?php
}
}
return new WC_Settings_Emails();

View File

@@ -0,0 +1,312 @@
<?php
/**
* WooCommerce General Settings
*
* @package WooCommerce\Admin
*/
defined( 'ABSPATH' ) || exit;
if ( class_exists( 'WC_Settings_General', false ) ) {
return new WC_Settings_General();
}
/**
* WC_Admin_Settings_General.
*/
class WC_Settings_General extends WC_Settings_Page {
/**
* Constructor.
*/
public function __construct() {
$this->id = 'general';
$this->label = __( 'General', 'woocommerce' );
parent::__construct();
}
/**
* Get settings or the default section.
*
* @return array
*/
protected function get_settings_for_default_section() {
$currency_code_options = get_woocommerce_currencies();
foreach ( $currency_code_options as $code => $name ) {
$currency_code_options[ $code ] = $name . ' (' . get_woocommerce_currency_symbol( $code ) . ') — ' . esc_html( $code );
}
$settings =
array(
array(
'title' => __( 'Store Address', 'woocommerce' ),
'type' => 'title',
'desc' => __( 'This is where your business is located. Tax rates and shipping rates will use this address.', 'woocommerce' ),
'id' => 'store_address',
),
array(
'title' => __( 'Address line 1', 'woocommerce' ),
'desc' => __( 'The street address for your business location.', 'woocommerce' ),
'id' => 'woocommerce_store_address',
'default' => '',
'type' => 'text',
'desc_tip' => true,
),
array(
'title' => __( 'Address line 2', 'woocommerce' ),
'desc' => __( 'An additional, optional address line for your business location.', 'woocommerce' ),
'id' => 'woocommerce_store_address_2',
'default' => '',
'type' => 'text',
'desc_tip' => true,
),
array(
'title' => __( 'City', 'woocommerce' ),
'desc' => __( 'The city in which your business is located.', 'woocommerce' ),
'id' => 'woocommerce_store_city',
'default' => '',
'type' => 'text',
'desc_tip' => true,
),
array(
'title' => __( 'Country / State', 'woocommerce' ),
'desc' => __( 'The country and state or province, if any, in which your business is located.', 'woocommerce' ),
'id' => 'woocommerce_default_country',
'default' => 'US:CA',
'type' => 'single_select_country',
'desc_tip' => true,
),
array(
'title' => __( 'Postcode / ZIP', 'woocommerce' ),
'desc' => __( 'The postal code, if any, in which your business is located.', 'woocommerce' ),
'id' => 'woocommerce_store_postcode',
'css' => 'min-width:50px;',
'default' => '',
'type' => 'text',
'desc_tip' => true,
),
array(
'type' => 'sectionend',
'id' => 'store_address',
),
array(
'title' => __( 'General options', 'woocommerce' ),
'type' => 'title',
'desc' => '',
'id' => 'general_options',
),
array(
'title' => __( 'Selling location(s)', 'woocommerce' ),
'desc' => __( 'This option lets you limit which countries you are willing to sell to.', 'woocommerce' ),
'id' => 'woocommerce_allowed_countries',
'default' => 'all',
'type' => 'select',
'class' => 'wc-enhanced-select',
'css' => 'min-width: 350px;',
'desc_tip' => true,
'options' => array(
'all' => __( 'Sell to all countries', 'woocommerce' ),
'all_except' => __( 'Sell to all countries, except for&hellip;', 'woocommerce' ),
'specific' => __( 'Sell to specific countries', 'woocommerce' ),
),
),
array(
'title' => __( 'Sell to all countries, except for&hellip;', 'woocommerce' ),
'desc' => '',
'id' => 'woocommerce_all_except_countries',
'css' => 'min-width: 350px;',
'default' => '',
'type' => 'multi_select_countries',
),
array(
'title' => __( 'Sell to specific countries', 'woocommerce' ),
'desc' => '',
'id' => 'woocommerce_specific_allowed_countries',
'css' => 'min-width: 350px;',
'default' => '',
'type' => 'multi_select_countries',
),
array(
'title' => __( 'Shipping location(s)', 'woocommerce' ),
'desc' => __( 'Choose which countries you want to ship to, or choose to ship to all locations you sell to.', 'woocommerce' ),
'id' => 'woocommerce_ship_to_countries',
'default' => '',
'type' => 'select',
'class' => 'wc-enhanced-select',
'desc_tip' => true,
'options' => array(
'' => __( 'Ship to all countries you sell to', 'woocommerce' ),
'all' => __( 'Ship to all countries', 'woocommerce' ),
'specific' => __( 'Ship to specific countries only', 'woocommerce' ),
'disabled' => __( 'Disable shipping &amp; shipping calculations', 'woocommerce' ),
),
),
array(
'title' => __( 'Ship to specific countries', 'woocommerce' ),
'desc' => '',
'id' => 'woocommerce_specific_ship_to_countries',
'css' => '',
'default' => '',
'type' => 'multi_select_countries',
),
array(
'title' => __( 'Default customer location', 'woocommerce' ),
'id' => 'woocommerce_default_customer_address',
'desc_tip' => __( 'This option determines a customers default location. The MaxMind GeoLite Database will be periodically downloaded to your wp-content directory if using geolocation.', 'woocommerce' ),
'default' => 'base',
'type' => 'select',
'class' => 'wc-enhanced-select',
'options' => array(
'' => __( 'No location by default', 'woocommerce' ),
'base' => __( 'Shop country/region', 'woocommerce' ),
'geolocation' => __( 'Geolocate', 'woocommerce' ),
'geolocation_ajax' => __( 'Geolocate (with page caching support)', 'woocommerce' ),
),
),
array(
'title' => __( 'Enable taxes', 'woocommerce' ),
'desc' => __( 'Enable tax rates and calculations', 'woocommerce' ),
'id' => 'woocommerce_calc_taxes',
'default' => 'no',
'type' => 'checkbox',
'desc_tip' => __( 'Rates will be configurable and taxes will be calculated during checkout.', 'woocommerce' ),
),
array(
'title' => __( 'Enable coupons', 'woocommerce' ),
'desc' => __( 'Enable the use of coupon codes', 'woocommerce' ),
'id' => 'woocommerce_enable_coupons',
'default' => 'yes',
'type' => 'checkbox',
'checkboxgroup' => 'start',
'show_if_checked' => 'option',
'desc_tip' => __( 'Coupons can be applied from the cart and checkout pages.', 'woocommerce' ),
),
array(
'desc' => __( 'Calculate coupon discounts sequentially', 'woocommerce' ),
'id' => 'woocommerce_calc_discounts_sequentially',
'default' => 'no',
'type' => 'checkbox',
'desc_tip' => __( 'When applying multiple coupons, apply the first coupon to the full price and the second coupon to the discounted price and so on.', 'woocommerce' ),
'show_if_checked' => 'yes',
'checkboxgroup' => 'end',
'autoload' => false,
),
array(
'type' => 'sectionend',
'id' => 'general_options',
),
array(
'title' => __( 'Currency options', 'woocommerce' ),
'type' => 'title',
'desc' => __( 'The following options affect how prices are displayed on the frontend.', 'woocommerce' ),
'id' => 'pricing_options',
),
array(
'title' => __( 'Currency', 'woocommerce' ),
'desc' => __( 'This controls what currency prices are listed at in the catalog and which currency gateways will take payments in.', 'woocommerce' ),
'id' => 'woocommerce_currency',
'default' => 'USD',
'type' => 'select',
'class' => 'wc-enhanced-select',
'desc_tip' => true,
'options' => $currency_code_options,
),
array(
'title' => __( 'Currency position', 'woocommerce' ),
'desc' => __( 'This controls the position of the currency symbol.', 'woocommerce' ),
'id' => 'woocommerce_currency_pos',
'class' => 'wc-enhanced-select',
'default' => 'left',
'type' => 'select',
'options' => array(
'left' => __( 'Left', 'woocommerce' ),
'right' => __( 'Right', 'woocommerce' ),
'left_space' => __( 'Left with space', 'woocommerce' ),
'right_space' => __( 'Right with space', 'woocommerce' ),
),
'desc_tip' => true,
),
array(
'title' => __( 'Thousand separator', 'woocommerce' ),
'desc' => __( 'This sets the thousand separator of displayed prices.', 'woocommerce' ),
'id' => 'woocommerce_price_thousand_sep',
'css' => 'width:50px;',
'default' => ',',
'type' => 'text',
'desc_tip' => true,
),
array(
'title' => __( 'Decimal separator', 'woocommerce' ),
'desc' => __( 'This sets the decimal separator of displayed prices.', 'woocommerce' ),
'id' => 'woocommerce_price_decimal_sep',
'css' => 'width:50px;',
'default' => '.',
'type' => 'text',
'desc_tip' => true,
),
array(
'title' => __( 'Number of decimals', 'woocommerce' ),
'desc' => __( 'This sets the number of decimal points shown in displayed prices.', 'woocommerce' ),
'id' => 'woocommerce_price_num_decimals',
'css' => 'width:50px;',
'default' => '2',
'desc_tip' => true,
'type' => 'number',
'custom_attributes' => array(
'min' => 0,
'step' => 1,
),
),
array(
'type' => 'sectionend',
'id' => 'pricing_options',
),
);
return apply_filters( 'woocommerce_general_settings', $settings );
}
/**
* Output a color picker input box.
*
* @param mixed $name Name of input.
* @param string $id ID of input.
* @param mixed $value Value of input.
* @param string $desc (default: '') Description for input.
*/
public function color_picker( $name, $id, $value, $desc = '' ) {
echo '<div class="color_box">' . wc_help_tip( $desc ) . '
<input name="' . esc_attr( $id ) . '" id="' . esc_attr( $id ) . '" type="text" value="' . esc_attr( $value ) . '" class="colorpick" /> <div id="colorPickerDiv_' . esc_attr( $id ) . '" class="colorpickdiv"></div>
</div>';
}
}
return new WC_Settings_General();

View File

@@ -0,0 +1,96 @@
<?php
/**
* WooCommerce Integration Settings
*
* @package WooCommerce\Admin
* @version 2.1.0
*/
use Automattic\Jetpack\Constants;
defined( 'ABSPATH' ) || exit;
if ( ! class_exists( 'WC_Settings_Integrations', false ) ) :
/**
* WC_Settings_Integrations.
*/
class WC_Settings_Integrations extends WC_Settings_Page {
/**
* Constructor.
*/
public function __construct() {
$this->id = 'integration';
$this->label = __( 'Integration', 'woocommerce' );
if ( isset( WC()->integrations ) && WC()->integrations->get_integrations() ) {
parent::__construct();
}
}
/**
* Get own sections.
*
* @return array
*/
protected function get_own_sections() {
global $current_section;
$sections = array();
if ( ! $this->wc_is_installing() ) {
$integrations = $this->get_integrations();
if ( ! $current_section && ! empty( $integrations ) ) {
$current_section = current( $integrations )->id;
}
if ( count( $integrations ) > 1 ) {
foreach ( $integrations as $integration ) {
$title = empty( $integration->method_title ) ? ucfirst( $integration->id ) : $integration->method_title;
$sections[ strtolower( $integration->id ) ] = esc_html( $title );
}
}
}
return $sections;
}
/**
* Is WC_INSTALLING constant defined?
* This method exists to ease unit testing.
*
* @return bool True is the WC_INSTALLING constant is defined.
*/
protected function wc_is_installing() {
return Constants::is_defined( 'WC_INSTALLING' );
}
/**
* Get the currently available integrations.
* This method exists to ease unit testing.
*
* @return array Currently available integrations.
*/
protected function get_integrations() {
return WC()->integrations->get_integrations();
}
/**
* Output the settings.
*/
public function output() {
global $current_section;
$integrations = $this->get_integrations();
if ( isset( $integrations[ $current_section ] ) ) {
$integrations[ $current_section ]->admin_options();
}
}
}
endif;
return new WC_Settings_Integrations();

View File

@@ -0,0 +1,270 @@
<?php
/**
* WooCommerce Settings Page/Tab
*
* @package WooCommerce\Admin
* @version 2.1.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
if ( ! class_exists( 'WC_Settings_Page', false ) ) :
/**
* WC_Settings_Page.
*/
abstract class WC_Settings_Page {
/**
* Setting page id.
*
* @var string
*/
protected $id = '';
/**
* Setting page label.
*
* @var string
*/
protected $label = '';
/**
* Constructor.
*/
public function __construct() {
add_filter( 'woocommerce_settings_tabs_array', array( $this, 'add_settings_page' ), 20 );
add_action( 'woocommerce_sections_' . $this->id, array( $this, 'output_sections' ) );
add_action( 'woocommerce_settings_' . $this->id, array( $this, 'output' ) );
add_action( 'woocommerce_settings_save_' . $this->id, array( $this, 'save' ) );
add_action( 'woocommerce_admin_field_add_settings_slot', array( $this, 'add_settings_slot' ) );
}
/**
* Get settings page ID.
*
* @since 3.0.0
* @return string
*/
public function get_id() {
return $this->id;
}
/**
* Get settings page label.
*
* @since 3.0.0
* @return string
*/
public function get_label() {
return $this->label;
}
/**
* Creates the React mount point for settings slot.
*/
public function add_settings_slot() {
?>
<div id="wc_settings_slotfill"> </div>
<?php
}
/**
* Add this page to settings.
*
* @param array $pages The settings array where we'll add ourselves.
*
* @return mixed
*/
public function add_settings_page( $pages ) {
$pages[ $this->id ] = $this->label;
return $pages;
}
/**
* Get settings array for the default section.
*
* External settings classes (registered via 'woocommerce_get_settings_pages' filter)
* might have redefined this method as "get_settings($section_id='')", thus we need
* to use this method internally instead of 'get_settings_for_section' to register settings
* and render settings pages.
*
* *But* we can't just redefine the method as "get_settings($section_id='')" here, since this
* will break on PHP 8 if any external setting class have it as 'get_settings()'.
*
* Thus we leave the method signature as is and use 'func_get_arg' to get the setting id
* if it's supplied, and we use this method internally; but it's deprecated and should
* otherwise never be used.
*
* @deprecated 5.4.0 Use 'get_settings_for_section' (passing an empty string for default section)
*
* @return array Settings array, each item being an associative array representing a setting.
*/
public function get_settings() {
$section_id = 0 === func_num_args() ? '' : func_get_arg( 0 );
return $this->get_settings_for_section( $section_id );
}
/**
* Get settings array.
*
* The strategy for getting the settings is as follows:
*
* - If a method named 'get_settings_for_{section_id}_section' exists in the class
* it will be invoked (for the default '' section, the method name is 'get_settings_for_default_section').
* Derived classes can implement these methods as required.
*
* - Otherwise, 'get_settings_for_section_core' will be invoked. Derived classes can override it
* as an alternative to implementing 'get_settings_for_{section_id}_section' methods.
*
* @param string $section_id The id of the section to return settings for, an empty string for the default section.
*
* @return array Settings array, each item being an associative array representing a setting.
*/
final public function get_settings_for_section( $section_id ) {
if ( '' === $section_id ) {
$method_name = 'get_settings_for_default_section';
} else {
$method_name = "get_settings_for_{$section_id}_section";
}
if ( method_exists( $this, $method_name ) ) {
$settings = $this->$method_name();
} else {
$settings = $this->get_settings_for_section_core( $section_id );
}
return apply_filters( 'woocommerce_get_settings_' . $this->id, $settings, $section_id );
}
/**
* Get the settings for a given section.
* This method is invoked from 'get_settings_for_section' when no 'get_settings_for_{current_section}_section'
* method exists in the class.
*
* When overriding, note that the 'woocommerce_get_settings_' filter must NOT be triggered,
* as this is already done by 'get_settings_for_section'.
*
* @param string $section_id The section name to get the settings for.
*
* @return array Settings array, each item being an associative array representing a setting.
*/
protected function get_settings_for_section_core( $section_id ) {
return array();
}
/**
* Get all sections for this page, both the own ones and the ones defined via filters.
*
* @return array
*/
public function get_sections() {
$sections = $this->get_own_sections();
/**
* Filters the sections for this settings page.
*
* @since 2.2.0
* @param array $sections The sections for this settings page.
*/
return (array) apply_filters( 'woocommerce_get_sections_' . $this->id, $sections );
}
/**
* Get own sections for this page.
* Derived classes should override this method if they define sections.
* There should always be one default section with an empty string as identifier.
*
* Example:
* return array(
* '' => __( 'General', 'woocommerce' ),
* 'foobars' => __( 'Foos & Bars', 'woocommerce' ),
* );
*
* @return array An associative array where keys are section identifiers and the values are translated section names.
*/
protected function get_own_sections() {
return array( '' => __( 'General', 'woocommerce' ) );
}
/**
* Output sections.
*/
public function output_sections() {
global $current_section;
$sections = $this->get_sections();
if ( empty( $sections ) || 1 === count( $sections ) ) {
return;
}
echo '<ul class="subsubsub">';
$array_keys = array_keys( $sections );
foreach ( $sections as $id => $label ) {
$url = admin_url( 'admin.php?page=wc-settings&tab=' . $this->id . '&section=' . sanitize_title( $id ) );
$class = ( $current_section === $id ? 'current' : '' );
$separator = ( end( $array_keys ) === $id ? '' : '|' );
$text = esc_html( $label );
echo "<li><a href='$url' class='$class'>$text</a> $separator </li>"; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}
echo '</ul><br class="clear" />';
}
/**
* Output the HTML for the settings.
*/
public function output() {
global $current_section;
// We can't use "get_settings_for_section" here
// for compatibility with derived classes overriding "get_settings".
$settings = $this->get_settings( $current_section );
WC_Admin_Settings::output_fields( $settings );
}
/**
* Save settings and trigger the 'woocommerce_update_options_'.id action.
*/
public function save() {
$this->save_settings_for_current_section();
$this->do_update_options_action();
}
/**
* Save settings for current section.
*/
protected function save_settings_for_current_section() {
global $current_section;
// We can't use "get_settings_for_section" here
// for compatibility with derived classes overriding "get_settings".
$settings = $this->get_settings( $current_section );
WC_Admin_Settings::save_fields( $settings );
}
/**
* Trigger the 'woocommerce_update_options_'.id action.
*
* @param string $section_id Section to trigger the action for, or null for current section.
*/
protected function do_update_options_action( $section_id = null ) {
global $current_section;
if ( is_null( $section_id ) ) {
$section_id = $current_section;
}
if ( $section_id ) {
do_action( 'woocommerce_update_options_' . $this->id . '_' . $section_id );
}
}
}
endif;

View File

@@ -0,0 +1,314 @@
<?php // @codingStandardsIgnoreLine.
/**
* WooCommerce Checkout Settings
*
* @package WooCommerce\Admin
*/
use Automattic\WooCommerce\Admin\Features\OnboardingTasks\Tasks\WooCommercePayments;
use Automattic\WooCommerce\Admin\Features\PaymentGatewaySuggestions\Init;
use Automattic\WooCommerce\Admin\PluginsHelper;
defined( 'ABSPATH' ) || exit;
if ( class_exists( 'WC_Settings_Payment_Gateways', false ) ) {
return new WC_Settings_Payment_Gateways();
}
/**
* WC_Settings_Payment_Gateways.
*/
class WC_Settings_Payment_Gateways extends WC_Settings_Page {
/**
* Constructor.
*/
public function __construct() {
$this->id = 'checkout'; // @todo In future versions this may make more sense as 'payment' however to avoid breakage lets leave this alone until we refactor settings APIs in general.
$this->label = _x( 'Payments', 'Settings tab label', 'woocommerce' );
add_action( 'woocommerce_admin_field_payment_gateways_banner', array( $this, 'payment_gateways_banner' ) );
add_action( 'woocommerce_admin_field_payment_gateways', array( $this, 'payment_gateways_setting' ) );
parent::__construct();
}
/**
* Get own sections.
*
* @return array
*/
protected function get_own_sections() {
return array(
'' => __( 'Payment methods', 'woocommerce' ),
);
}
/**
* Get settings array.
*
* @return array
*/
protected function get_settings_for_default_section() {
$settings =
array(
array(
'type' => 'title', // this is needed as <table> tag is generated by this element, even if it has no other content.
),
array( 'type' => 'payment_gateways_banner' ), // React mount point for embedded banner slotfill.
array(
'type' => 'payment_gateways',
),
array(
'type' => 'sectionend',
'id' => 'payment_gateways_options',
),
);
return apply_filters( 'woocommerce_payment_gateways_settings', $settings );
}
/**
* Output the settings.
*/
public function output() {
//phpcs:disable WordPress.Security.NonceVerification.Recommended
global $current_section;
// Load gateways so we can show any global options they may have.
$payment_gateways = WC()->payment_gateways->payment_gateways();
if ( $current_section ) {
foreach ( $payment_gateways as $gateway ) {
if ( in_array( $current_section, array( $gateway->id, sanitize_title( get_class( $gateway ) ) ), true ) ) {
if ( isset( $_GET['toggle_enabled'] ) ) {
$enabled = $gateway->get_option( 'enabled' );
if ( $enabled ) {
$gateway->settings['enabled'] = wc_string_to_bool( $enabled ) ? 'no' : 'yes';
}
}
$this->run_gateway_admin_options( $gateway );
break;
}
}
}
parent::output();
//phpcs:enable
}
/**
* Run the 'admin_options' method on a given gateway.
* This method exists to easy unit testing.
*
* @param object $gateway The gateway object to run the method on.
*/
protected function run_gateway_admin_options( $gateway ) {
$gateway->admin_options();
}
/**
* Creates the React mount point for the embedded banner.
*/
public function payment_gateways_banner() {
?>
<div id="wc_payments_settings_slotfill"> </div>
<?php
}
/**
* Output payment gateway settings.
*/
public function payment_gateways_setting() {
?>
<tr valign="top">
<td class="wc_payment_gateways_wrapper" colspan="2">
<table class="wc_gateways widefat" cellspacing="0" aria-describedby="payment_gateways_options-description">
<thead>
<tr>
<?php
$default_columns = array(
'sort' => '',
'name' => __( 'Method', 'woocommerce' ),
'status' => __( 'Enabled', 'woocommerce' ),
'description' => __( 'Description', 'woocommerce' ),
'action' => '',
);
$columns = apply_filters( 'woocommerce_payment_gateways_setting_columns', $default_columns );
foreach ( $columns as $key => $column ) {
echo '<th class="' . esc_attr( $key ) . '">' . esc_html( $column ) . '</th>';
}
?>
</tr>
</thead>
<tbody>
<?php
$payment_gateways = WC()->payment_gateways->payment_gateways();
foreach ( $payment_gateways as $gateway ) {
echo '<tr data-gateway_id="' . esc_attr( $gateway->id ) . '">';
foreach ( $columns as $key => $column ) {
if ( ! array_key_exists( $key, $default_columns ) ) {
do_action( 'woocommerce_payment_gateways_setting_column_' . $key, $gateway );
continue;
}
$width = '';
if ( in_array( $key, array( 'sort', 'status', 'action' ), true ) ) {
$width = '1%';
}
$method_title = $gateway->get_method_title() ? $gateway->get_method_title() : $gateway->get_title();
$custom_title = $gateway->get_title();
echo '<td class="' . esc_attr( $key ) . '" width="' . esc_attr( $width ) . '">';
switch ( $key ) {
case 'sort':
?>
<div class="wc-item-reorder-nav">
<button type="button" class="wc-move-up" tabindex="0" aria-hidden="false" aria-label="<?php /* Translators: %s Payment gateway name. */ echo esc_attr( sprintf( __( 'Move the "%s" payment method up', 'woocommerce' ), $method_title ) ); ?>"><?php esc_html_e( 'Move up', 'woocommerce' ); ?></button>
<button type="button" class="wc-move-down" tabindex="0" aria-hidden="false" aria-label="<?php /* Translators: %s Payment gateway name. */ echo esc_attr( sprintf( __( 'Move the "%s" payment method down', 'woocommerce' ), $method_title ) ); ?>"><?php esc_html_e( 'Move down', 'woocommerce' ); ?></button>
<input type="hidden" name="gateway_order[]" value="<?php echo esc_attr( $gateway->id ); ?>" />
</div>
<?php
break;
case 'name':
echo '<a href="' . esc_url( admin_url( 'admin.php?page=wc-settings&tab=checkout&section=' . strtolower( $gateway->id ) ) ) . '" class="wc-payment-gateway-method-title">' . wp_kses_post( $method_title ) . '</a>';
if ( $method_title !== $custom_title ) {
echo '<span class="wc-payment-gateway-method-name">&nbsp;&ndash;&nbsp;' . wp_kses_post( $custom_title ) . '</span>';
}
break;
case 'description':
echo wp_kses_post( $gateway->get_method_description() );
break;
case 'action':
if ( wc_string_to_bool( $gateway->enabled ) ) {
/* Translators: %s Payment gateway name. */
echo '<a class="button alignright" aria-label="' . esc_attr( sprintf( __( 'Manage the "%s" payment method', 'woocommerce' ), $method_title ) ) . '" href="' . esc_url( admin_url( 'admin.php?page=wc-settings&tab=checkout&section=' . strtolower( $gateway->id ) ) ) . '">' . esc_html__( 'Manage', 'woocommerce' ) . '</a>';
} else {
if (
// Keep old brand name for backwards compatibility.
( 'WooCommerce Payments' === $method_title || 'WooPayments' === $method_title ) &&
class_exists( 'WC_Payments_Account' )
) {
$setup_url = WC_Payments_Account::get_connect_url();
} else {
$setup_url = admin_url( 'admin.php?page=wc-settings&tab=checkout&section=' . strtolower( $gateway->id ) );
}
/* Translators: %s Payment gateway name. */
echo '<a class="button alignright" aria-label="' . esc_attr( sprintf( __( 'Set up the "%s" payment method', 'woocommerce' ), $method_title ) ) . '" href="' . esc_url( $setup_url ) . '">' . esc_html__( 'Finish set up', 'woocommerce' ) . '</a>';
}
break;
case 'status':
echo '<a class="wc-payment-gateway-method-toggle-enabled" href="' . esc_url( admin_url( 'admin.php?page=wc-settings&tab=checkout&section=' . strtolower( $gateway->id ) ) ) . '">';
if ( wc_string_to_bool( $gateway->enabled ) ) {
/* Translators: %s Payment gateway name. */
echo '<span class="woocommerce-input-toggle woocommerce-input-toggle--enabled" aria-label="' . esc_attr( sprintf( __( 'The "%s" payment method is currently enabled', 'woocommerce' ), $method_title ) ) . '">' . esc_attr__( 'Yes', 'woocommerce' ) . '</span>';
} else {
/* Translators: %s Payment gateway name. */
echo '<span class="woocommerce-input-toggle woocommerce-input-toggle--disabled" aria-label="' . esc_attr( sprintf( __( 'The "%s" payment method is currently disabled', 'woocommerce' ), $method_title ) ) . '">' . esc_attr__( 'No', 'woocommerce' ) . '</span>';
}
echo '</a>';
break;
}
echo '</td>';
}
echo '</tr>';
}
/**
* Add "Other payment methods" link in WooCommerce -> Settings -> Payments
* When the store is in WC Payments eligible country.
* See https://github.com/woocommerce/woocommerce/issues/32130 for more details.
*/
if ( WooCommercePayments::is_supported() ) {
$wcpay_setup = isset( $payment_gateways['woocommerce_payments'] ) && ! $payment_gateways['woocommerce_payments']->needs_setup();
$country = wc_get_base_location()['country'];
$plugin_suggestions = Init::get_suggestions();
$active_plugins = PluginsHelper::get_active_plugin_slugs();
if ( $wcpay_setup ) {
$link_text = __( 'Discover additional payment providers', 'woocommerce' );
$filter_by = 'category_additional';
} else {
$link_text = __( 'Discover other payment providers', 'woocommerce' );
$filter_by = 'category_other';
}
$plugin_suggestions = array_filter(
$plugin_suggestions,
function( $plugin ) use ( $country, $filter_by, $active_plugins ) {
if ( ! isset( $plugin->{$filter_by} ) || ! isset( $plugin->image_72x72 ) || ! isset( $plugin->plugins[0] ) || in_array( $plugin->plugins[0], $active_plugins, true ) ) {
return false;
}
return in_array( $country, $plugin->{$filter_by}, true );
}
);
$columns_count = count( $columns );
$external_link_icon = '<svg style="margin-left: 4px" class="gridicon gridicons-external needs-offset" height="18" width="18" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g><path d="M19 13v6a2 2 0 01-2 2H5a2 2 0 01-2-2V7a2 2 0 012-2h6v2H5v12h12v-6h2zM13 3v2h4.586l-7.793 7.793 1.414 1.414L19 6.414V11h2V3h-8z"></path></g></svg>';
echo '<tr>';
// phpcs:ignore -- ignoring the error since the value is harded.
echo "<td style='border-top: 1px solid #c3c4c7; background-color: #fff' colspan='{$columns_count}'>";
echo "<a id='settings-other-payment-methods' href='https://woocommerce.com/product-category/woocommerce-extensions/payment-gateways/?utm_source=payments_recommendations' target='_blank' class='components-button is-tertiary'>";
// phpcs:ignore
echo $link_text;
// phpcs:ignore
echo $external_link_icon;
echo '</a>';
if ( count( $plugin_suggestions ) ) {
foreach ( $plugin_suggestions as $plugin_suggestion ) {
$alt = str_replace( '.png', '', basename( $plugin_suggestion->image_72x72 ) );
// phpcs:ignore
echo "<img src='{$plugin_suggestion->image_72x72}' alt='{$alt}' width='24' height='24' style='vertical-align: middle; margin-right: 8px;'/>";
}
echo '& more.';
}
echo '</td>';
echo '</tr>';
}
?>
</tbody>
</table>
</td>
</tr>
<?php
}
/**
* Save settings.
*/
public function save() {
global $current_section;
$wc_payment_gateways = WC_Payment_Gateways::instance();
$this->save_settings_for_current_section();
if ( ! $current_section ) {
// If section is empty, we're on the main settings page. This makes sure 'gateway ordering' is saved.
$wc_payment_gateways->process_admin_options();
$wc_payment_gateways->init();
} else {
// There is a section - this may be a gateway or custom section.
foreach ( $wc_payment_gateways->payment_gateways() as $gateway ) {
if ( in_array( $current_section, array( $gateway->id, sanitize_title( get_class( $gateway ) ) ), true ) ) {
do_action( 'woocommerce_update_options_payment_gateways_' . $gateway->id );
$wc_payment_gateways->init();
}
}
$this->do_update_options_action();
}
}
}
return new WC_Settings_Payment_Gateways();

View File

@@ -0,0 +1,474 @@
<?php
/**
* WooCommerce Product Settings
*
* @package WooCommerce\Admin
* @version 2.4.0
*/
use Automattic\WooCommerce\Utilities\I18nUtil;
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
if ( class_exists( 'WC_Settings_Products', false ) ) {
return new WC_Settings_Products();
}
/**
* WC_Settings_Products.
*/
class WC_Settings_Products extends WC_Settings_Page {
/**
* Constructor.
*/
public function __construct() {
$this->id = 'products';
$this->label = __( 'Products', 'woocommerce' );
parent::__construct();
}
/**
* Get own sections.
*
* @return array
*/
protected function get_own_sections() {
return array(
'' => __( 'General', 'woocommerce' ),
'inventory' => __( 'Inventory', 'woocommerce' ),
'downloadable' => __( 'Downloadable products', 'woocommerce' ),
);
}
/**
* Get settings for the default section.
*
* @return array
*/
protected function get_settings_for_default_section() {
$settings =
array(
array(
'title' => __( 'Shop pages', 'woocommerce' ),
'type' => 'title',
'desc' => '',
'id' => 'catalog_options',
),
array(
'title' => __( 'Shop page', 'woocommerce' ),
/* translators: %s: URL to settings. */
'desc' => sprintf( __( 'The base page can also be used in your <a href="%s">product permalinks</a>.', 'woocommerce' ), admin_url( 'options-permalink.php' ) ),
'id' => 'woocommerce_shop_page_id',
'type' => 'single_select_page',
'default' => '',
'class' => 'wc-enhanced-select-nostd',
'css' => 'min-width:300px;',
'desc_tip' => __( 'This sets the base page of your shop - this is where your product archive will be.', 'woocommerce' ),
),
array(
'title' => __( 'Add to cart behaviour', 'woocommerce' ),
'desc' => __( 'Redirect to the cart page after successful addition', 'woocommerce' ),
'id' => 'woocommerce_cart_redirect_after_add',
'default' => 'no',
'type' => 'checkbox',
'checkboxgroup' => 'start',
),
array(
'desc' => __( 'Enable AJAX add to cart buttons on archives', 'woocommerce' ),
'id' => 'woocommerce_enable_ajax_add_to_cart',
'default' => 'yes',
'type' => 'checkbox',
'checkboxgroup' => 'end',
),
array(
'title' => __( 'Placeholder image', 'woocommerce' ),
'id' => 'woocommerce_placeholder_image',
'type' => 'text',
'default' => '',
'class' => '',
'css' => '',
'placeholder' => __( 'Enter attachment ID or URL to an image', 'woocommerce' ),
'desc_tip' => __( 'This is the attachment ID, or image URL, used for placeholder images in the product catalog. Products with no image will use this.', 'woocommerce' ),
),
array(
'type' => 'sectionend',
'id' => 'catalog_options',
),
array(
'title' => __( 'Measurements', 'woocommerce' ),
'type' => 'title',
'id' => 'product_measurement_options',
),
array(
'title' => __( 'Weight unit', 'woocommerce' ),
'desc' => __( 'This controls what unit you will define weights in.', 'woocommerce' ),
'id' => 'woocommerce_weight_unit',
'class' => 'wc-enhanced-select',
'css' => 'min-width:300px;',
'default' => 'kg',
'type' => 'select',
'options' => array(
'kg' => I18nUtil::get_weight_unit_label( 'kg' ),
'g' => I18nUtil::get_weight_unit_label( 'g' ),
'lbs' => I18nUtil::get_weight_unit_label( 'lbs' ),
'oz' => I18nUtil::get_weight_unit_label( 'oz' ),
),
'desc_tip' => true,
),
array(
'title' => __( 'Dimensions unit', 'woocommerce' ),
'desc' => __( 'This controls what unit you will define lengths in.', 'woocommerce' ),
'id' => 'woocommerce_dimension_unit',
'class' => 'wc-enhanced-select',
'css' => 'min-width:300px;',
'default' => 'cm',
'type' => 'select',
'options' => array(
'm' => I18nUtil::get_dimensions_unit_label( 'm' ),
'cm' => I18nUtil::get_dimensions_unit_label( 'cm' ),
'mm' => I18nUtil::get_dimensions_unit_label( 'mm' ),
'in' => I18nUtil::get_dimensions_unit_label( 'in' ),
'yd' => I18nUtil::get_dimensions_unit_label( 'yd' ),
),
'desc_tip' => true,
),
array(
'type' => 'sectionend',
'id' => 'product_measurement_options',
),
array(
'title' => __( 'Reviews', 'woocommerce' ),
'type' => 'title',
'desc' => '',
'id' => 'product_rating_options',
),
array(
'title' => __( 'Enable reviews', 'woocommerce' ),
'desc' => __( 'Enable product reviews', 'woocommerce' ),
'id' => 'woocommerce_enable_reviews',
'default' => 'yes',
'type' => 'checkbox',
'checkboxgroup' => 'start',
'show_if_checked' => 'option',
),
array(
'desc' => __( 'Show "verified owner" label on customer reviews', 'woocommerce' ),
'id' => 'woocommerce_review_rating_verification_label',
'default' => 'yes',
'type' => 'checkbox',
'checkboxgroup' => '',
'show_if_checked' => 'yes',
'autoload' => false,
),
array(
'desc' => __( 'Reviews can only be left by "verified owners"', 'woocommerce' ),
'id' => 'woocommerce_review_rating_verification_required',
'default' => 'no',
'type' => 'checkbox',
'checkboxgroup' => 'end',
'show_if_checked' => 'yes',
'autoload' => false,
),
array(
'title' => __( 'Product ratings', 'woocommerce' ),
'desc' => __( 'Enable star rating on reviews', 'woocommerce' ),
'id' => 'woocommerce_enable_review_rating',
'default' => 'yes',
'type' => 'checkbox',
'checkboxgroup' => 'start',
'show_if_checked' => 'option',
),
array(
'desc' => __( 'Star ratings should be required, not optional', 'woocommerce' ),
'id' => 'woocommerce_review_rating_required',
'default' => 'yes',
'type' => 'checkbox',
'checkboxgroup' => 'end',
'show_if_checked' => 'yes',
'autoload' => false,
),
array(
'type' => 'sectionend',
'id' => 'product_rating_options',
),
);
$settings = apply_filters( 'woocommerce_products_general_settings', $settings );
return apply_filters( 'woocommerce_product_settings', $settings );
}
/**
* Get settings for the inventory section.
*
* @return array
*/
protected function get_settings_for_inventory_section() {
$settings =
array(
array(
'title' => __( 'Inventory', 'woocommerce' ),
'type' => 'title',
'desc' => '',
'id' => 'product_inventory_options',
),
array(
'title' => __( 'Manage stock', 'woocommerce' ),
'desc' => __( 'Enable stock management', 'woocommerce' ),
'id' => 'woocommerce_manage_stock',
'default' => 'yes',
'type' => 'checkbox',
),
array(
'title' => __( 'Hold stock (minutes)', 'woocommerce' ),
'desc' => __( 'Hold stock (for unpaid orders) for x minutes. When this limit is reached, the pending order will be cancelled. Leave blank to disable.', 'woocommerce' ),
'id' => 'woocommerce_hold_stock_minutes',
'type' => 'number',
'custom_attributes' => array(
'min' => 0,
'step' => 1,
),
'css' => 'width: 80px;',
'default' => '60',
'autoload' => false,
'class' => 'manage_stock_field',
),
array(
'title' => __( 'Notifications', 'woocommerce' ),
'desc' => __( 'Enable low stock notifications', 'woocommerce' ),
'id' => 'woocommerce_notify_low_stock',
'default' => 'yes',
'type' => 'checkbox',
'checkboxgroup' => 'start',
'autoload' => false,
'class' => 'manage_stock_field',
),
array(
'desc' => __( 'Enable out of stock notifications', 'woocommerce' ),
'id' => 'woocommerce_notify_no_stock',
'default' => 'yes',
'type' => 'checkbox',
'checkboxgroup' => 'end',
'autoload' => false,
'class' => 'manage_stock_field',
),
array(
'title' => __( 'Notification recipient(s)', 'woocommerce' ),
'desc' => __( 'Enter recipients (comma separated) that will receive this notification.', 'woocommerce' ),
'id' => 'woocommerce_stock_email_recipient',
'type' => 'text',
'default' => get_option( 'admin_email' ),
'css' => 'width: 250px;',
'autoload' => false,
'desc_tip' => true,
'class' => 'manage_stock_field',
),
array(
'title' => __( 'Low stock threshold', 'woocommerce' ),
'desc' => __( 'When product stock reaches this amount you will be notified via email.', 'woocommerce' ),
'id' => 'woocommerce_notify_low_stock_amount',
'css' => 'width:50px;',
'type' => 'number',
'custom_attributes' => array(
'min' => 0,
'step' => 1,
),
'default' => '2',
'autoload' => false,
'desc_tip' => true,
'class' => 'manage_stock_field',
),
array(
'title' => __( 'Out of stock threshold', 'woocommerce' ),
'desc' => __( 'When product stock reaches this amount the stock status will change to "out of stock" and you will be notified via email. This setting does not affect existing "in stock" products.', 'woocommerce' ),
'id' => 'woocommerce_notify_no_stock_amount',
'css' => 'width:50px;',
'type' => 'number',
'custom_attributes' => array(
'min' => 0,
'step' => 1,
),
'default' => '0',
'desc_tip' => true,
'class' => 'manage_stock_field',
),
array(
'title' => __( 'Out of stock visibility', 'woocommerce' ),
'desc' => __( 'Hide out of stock items from the catalog', 'woocommerce' ),
'id' => 'woocommerce_hide_out_of_stock_items',
'default' => 'no',
'type' => 'checkbox',
),
array(
'title' => __( 'Stock display format', 'woocommerce' ),
'desc' => __( 'This controls how stock quantities are displayed on the frontend.', 'woocommerce' ),
'id' => 'woocommerce_stock_format',
'css' => 'min-width:150px;',
'class' => 'wc-enhanced-select',
'default' => '',
'type' => 'select',
'options' => array(
'' => __( 'Always show quantity remaining in stock e.g. "12 in stock"', 'woocommerce' ),
'low_amount' => __( 'Only show quantity remaining in stock when low e.g. "Only 2 left in stock"', 'woocommerce' ),
'no_amount' => __( 'Never show quantity remaining in stock', 'woocommerce' ),
),
'desc_tip' => true,
),
array(
'type' => 'sectionend',
'id' => 'product_inventory_options',
),
);
return apply_filters( 'woocommerce_inventory_settings', $settings );
}
/**
* Get settings for the downloadable section.
*
* @return array
*/
protected function get_settings_for_downloadable_section() {
$settings =
array(
array(
'title' => __( 'Downloadable products', 'woocommerce' ),
'type' => 'title',
'id' => 'digital_download_options',
),
array(
'title' => __( 'File download method', 'woocommerce' ),
'desc_tip' => sprintf(
/* translators: 1: X-Accel-Redirect 2: X-Sendfile 3: mod_xsendfile */
__( 'Forcing downloads will keep URLs hidden, but some servers may serve large files unreliably. If supported, %1$s / %2$s can be used to serve downloads instead (server requires %3$s).', 'woocommerce' ),
'<code>X-Accel-Redirect</code>',
'<code>X-Sendfile</code>',
'<code>mod_xsendfile</code>'
),
'id' => 'woocommerce_file_download_method',
'type' => 'select',
'class' => 'wc-enhanced-select',
'css' => 'min-width:300px;',
'default' => 'force',
'desc' => sprintf(
// translators: Link to WooCommerce Docs.
__( "If you are using X-Accel-Redirect download method along with NGINX server, make sure that you have applied settings as described in <a href='%s'>Digital/Downloadable Product Handling</a> guide.", 'woocommerce' ),
'https://woocommerce.com/document/digital-downloadable-product-handling#nginx-setting'
),
'options' => array(
'force' => __( 'Force downloads', 'woocommerce' ),
'xsendfile' => __( 'X-Accel-Redirect/X-Sendfile', 'woocommerce' ),
'redirect' => apply_filters( 'woocommerce_redirect_only_method_is_secure', false ) ? __( 'Redirect only', 'woocommerce' ) : __( 'Redirect only (Insecure)', 'woocommerce' ),
),
'autoload' => false,
),
array(
'desc' => __( 'Allow using redirect mode (insecure) as a last resort', 'woocommerce' ),
'id' => 'woocommerce_downloads_redirect_fallback_allowed',
'type' => 'checkbox',
'default' => 'no',
'desc_tip' => sprintf(
/* translators: %1$s is a link to the WooCommerce documentation. */
__( 'If the "Force Downloads" or "X-Accel-Redirect/X-Sendfile" download method is selected but does not work, the system will use the "Redirect" method as a last resort. <a href="%1$s">See this guide</a> for more details.', 'woocommerce' ),
'https://woocommerce.com/document/digital-downloadable-product-handling/'
),
'checkboxgroup' => 'start',
'autoload' => false,
),
array(
'title' => __( 'Access restriction', 'woocommerce' ),
'desc' => __( 'Downloads require login', 'woocommerce' ),
'id' => 'woocommerce_downloads_require_login',
'type' => 'checkbox',
'default' => 'no',
'desc_tip' => __( 'This setting does not apply to guest purchases.', 'woocommerce' ),
'checkboxgroup' => 'start',
'autoload' => false,
),
array(
'desc' => __( 'Grant access to downloadable products after payment', 'woocommerce' ),
'id' => 'woocommerce_downloads_grant_access_after_payment',
'type' => 'checkbox',
'default' => 'yes',
'desc_tip' => __( 'Enable this option to grant access to downloads when orders are "processing", rather than "completed".', 'woocommerce' ),
'checkboxgroup' => 'end',
'autoload' => false,
),
array(
'title' => __( 'Open in browser', 'woocommerce' ),
'desc' => __( 'Open downloadable files in the browser, instead of saving them to the device.', 'woocommerce' ),
'id' => 'woocommerce_downloads_deliver_inline',
'type' => 'checkbox',
'default' => false,
'desc_tip' => __( 'Customers can still save the file to their device, but by default file will be opened instead of being downloaded (does not work with redirects).', 'woocommerce' ),
'autoload' => false,
),
array(
'title' => __( 'Filename', 'woocommerce' ),
'desc' => __( 'Append a unique string to filename for security', 'woocommerce' ),
'id' => 'woocommerce_downloads_add_hash_to_filename',
'type' => 'checkbox',
'default' => 'yes',
'desc_tip' => sprintf(
// translators: Link to WooCommerce Docs.
__( "Not required if your download directory is protected. <a href='%s'>See this guide</a> for more details. Files already uploaded will not be affected.", 'woocommerce' ),
'https://woocommerce.com/document/digital-downloadable-product-handling#unique-string'
),
),
array(
'type' => 'sectionend',
'id' => 'digital_download_options',
),
);
return apply_filters( 'woocommerce_downloadable_products_settings', $settings );
}
/**
* Save settings and trigger the 'woocommerce_update_options_'.id action.
*/
public function save() {
$this->save_settings_for_current_section();
/*
* Product->Inventory has a setting `Out of stock visibility`.
* Because of this, we need to recount the terms to keep them in-sync.
*/
WC()->call_function( 'wc_recount_all_terms' );
$this->do_update_options_action();
}
}
return new WC_Settings_Products();

View File

@@ -0,0 +1,460 @@
<?php
/**
* WooCommerce Shipping Settings
*
* @package WooCommerce\Admin
* @version 2.6.0
*/
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Internal\Admin\WCAdminAssets;
defined( 'ABSPATH' ) || exit;
if ( class_exists( 'WC_Settings_Shipping', false ) ) {
return new WC_Settings_Shipping();
}
/**
* WC_Settings_Shipping.
*/
class WC_Settings_Shipping extends WC_Settings_Page {
/**
* Constructor.
*/
public function __construct() {
$this->id = 'shipping';
$this->label = __( 'Shipping', 'woocommerce' );
parent::__construct();
}
/**
* Add this page to settings.
*
* @param array $pages Current pages.
* @return array|mixed
*/
public function add_settings_page( $pages ) {
return wc_shipping_enabled() ? parent::add_settings_page( $pages ) : $pages;
}
/**
* Get own sections.
*
* @return array
*/
protected function get_own_sections() {
$sections = array(
'' => __( 'Shipping zones', 'woocommerce' ),
'options' => __( 'Shipping settings', 'woocommerce' ),
'classes' => __( 'Classes', 'woocommerce' ),
);
if ( ! $this->wc_is_installing() ) {
// Load shipping methods so we can show any global options they may have.
$shipping_methods = $this->get_shipping_methods();
foreach ( $shipping_methods as $method ) {
if ( ! $method->has_settings() ) {
continue;
}
$title = empty( $method->method_title ) ? ucfirst( $method->id ) : $method->method_title;
$sections[ strtolower( $method->id ) ] = esc_html( $title );
}
}
return $sections;
}
/**
* Is WC_INSTALLING constant defined?
* This method exists to ease unit testing.
*
* @return bool True is the WC_INSTALLING constant is defined.
*/
protected function wc_is_installing() {
return Constants::is_defined( 'WC_INSTALLING' );
}
/**
* Get the currently available shipping methods.
* This method exists to ease unit testing.
*
* @return array Currently available shipping methods.
*/
protected function get_shipping_methods() {
return WC()->shipping()->get_shipping_methods();
}
/**
* Get settings for the default section.
*
* The original implementation of 'get_settings' was returning the settings for the "Options" section
* when the supplied value for $current_section was ''.
*
* @return array
*/
protected function get_settings_for_default_section() {
return $this->get_settings_for_options_section();
}
/**
* Get settings for the options section.
*
* @return array
*/
protected function get_settings_for_options_section() {
$settings =
array(
array(
'title' => __( 'Shipping settings', 'woocommerce' ),
'type' => 'title',
'id' => 'shipping_options',
),
array(
'title' => __( 'Calculations', 'woocommerce' ),
'desc' => __( 'Enable the shipping calculator on the cart page', 'woocommerce' ),
'id' => 'woocommerce_enable_shipping_calc',
'default' => 'yes',
'type' => 'checkbox',
'checkboxgroup' => 'start',
'autoload' => false,
),
array(
'desc' => __( 'Hide shipping costs until an address is entered', 'woocommerce' ),
'id' => 'woocommerce_shipping_cost_requires_address',
'default' => 'no',
'type' => 'checkbox',
'checkboxgroup' => 'end',
),
array(
'title' => __( 'Shipping destination', 'woocommerce' ),
'desc' => __( 'This controls which shipping address is used by default.', 'woocommerce' ),
'id' => 'woocommerce_ship_to_destination',
'default' => 'billing',
'type' => 'radio',
'options' => array(
'shipping' => __( 'Default to customer shipping address', 'woocommerce' ),
'billing' => __( 'Default to customer billing address', 'woocommerce' ),
'billing_only' => __( 'Force shipping to the customer billing address', 'woocommerce' ),
),
'autoload' => false,
'desc_tip' => true,
'show_if_checked' => 'option',
),
array(
'title' => __( 'Debug mode', 'woocommerce' ),
'desc' => __( 'Enable debug mode', 'woocommerce' ),
'desc_tip' => __( 'Enable shipping debug mode to show matching shipping zones and to bypass shipping rate cache.', 'woocommerce' ),
'id' => 'woocommerce_shipping_debug_mode',
'default' => 'no',
'type' => 'checkbox',
),
array(
'type' => 'sectionend',
'id' => 'shipping_options',
),
);
return apply_filters( 'woocommerce_shipping_settings', $settings );
}
/**
* Output the settings.
*/
public function output() {
global $current_section, $hide_save_button;
// Load shipping methods so we can show any global options they may have.
$shipping_methods = $this->get_shipping_methods();
if ( '' === $current_section ) {
$this->output_zones_screen();
} elseif ( 'classes' === $current_section ) {
$hide_save_button = true;
$this->output_shipping_class_screen();
} else {
$is_shipping_method = false;
foreach ( $shipping_methods as $method ) {
if ( in_array( $current_section, array( $method->id, sanitize_title( get_class( $method ) ) ), true ) && $method->has_settings() ) {
$is_shipping_method = true;
$method->admin_options();
}
}
if ( ! $is_shipping_method ) {
parent::output();
}
}
}
/**
* Save settings.
*/
public function save() {
global $current_section;
switch ( $current_section ) {
case 'options':
$this->save_settings_for_current_section();
$this->do_update_options_action();
break;
case 'classes':
$this->do_update_options_action();
break;
case '':
break;
default:
$is_shipping_method = false;
foreach ( $this->get_shipping_methods() as $method_id => $method ) {
if ( in_array( $current_section, array( $method->id, sanitize_title( get_class( $method ) ) ), true ) ) {
$is_shipping_method = true;
$this->do_update_options_action( $method->id );
}
}
if ( ! $is_shipping_method ) {
$this->save_settings_for_current_section();
}
break;
}
// Increments the transient version to invalidate cache.
WC_Cache_Helper::get_transient_version( 'shipping', true );
}
/**
* Handles output of the shipping zones page in admin.
*/
protected function output_zones_screen() {
// phpcs:disable WordPress.Security.NonceVerification.Recommended
global $hide_save_button;
if ( isset( $_REQUEST['zone_id'] ) ) {
$hide_save_button = true;
$this->zone_methods_screen( wc_clean( wp_unslash( $_REQUEST['zone_id'] ) ) );
} elseif ( isset( $_REQUEST['instance_id'] ) ) {
$this->instance_settings_screen( absint( wp_unslash( $_REQUEST['instance_id'] ) ) );
} else {
$hide_save_button = true;
$this->zones_screen();
}
// phpcs:enable WordPress.Security.NonceVerification.Recommended
}
/**
* Get all available regions.
*
* @param int $allowed_countries Zone ID.
* @param int $shipping_continents Zone ID.
*/
protected function get_region_options( $allowed_countries, $shipping_continents ) {
$options = array();
foreach ( $shipping_continents as $continent_code => $continent ) {
$continent_data = array(
'value' => 'continent:' . esc_attr( $continent_code ),
'label' => esc_html( $continent['name'] ),
'children' => array(),
);
$countries = array_intersect( array_keys( $allowed_countries ), $continent['countries'] );
foreach ( $countries as $country_code ) {
$country_data = array(
'value' => 'country:' . esc_attr( $country_code ),
'label' => esc_html( $allowed_countries[ $country_code ] ),
'children' => array(),
);
$states = WC()->countries->get_states( $country_code );
if ( $states ) {
foreach ( $states as $state_code => $state_name ) {
$country_data['children'][] = array(
'value' => 'state:' . esc_attr( $country_code . ':' . $state_code ),
'label' => esc_html( $state_name . ', ' . $allowed_countries[ $country_code ] ),
);
}
}
$continent_data['children'][] = $country_data;
}
$options[] = $continent_data;
}
return $options;
}
/**
* Show method for a zone
*
* @param int $zone_id Zone ID.
*/
protected function zone_methods_screen( $zone_id ) {
if ( 'new' === $zone_id ) {
$zone = new WC_Shipping_Zone();
} else {
$zone = WC_Shipping_Zones::get_zone( absint( $zone_id ) );
}
if ( ! $zone ) {
wp_die( esc_html__( 'Zone does not exist!', 'woocommerce' ) );
}
$allowed_countries = WC()->countries->get_shipping_countries();
$shipping_continents = WC()->countries->get_shipping_continents();
// Prepare locations.
$locations = array();
$postcodes = array();
foreach ( $zone->get_zone_locations() as $location ) {
if ( 'postcode' === $location->type ) {
$postcodes[] = $location->code;
} else {
$locations[] = $location->type . ':' . $location->code;
}
}
$localized_object = array(
'methods' => $zone->get_shipping_methods( false, 'json' ),
'zone_name' => $zone->get_zone_name(),
'zone_id' => $zone->get_id(),
'locations' => $locations,
'wc_shipping_zones_nonce' => wp_create_nonce( 'wc_shipping_zones_nonce' ),
'strings' => array(
'unload_confirmation_msg' => __( 'Your changed data will be lost if you leave this page without saving.', 'woocommerce' ),
'save_changes_prompt' => __( 'Do you wish to save your changes first? Your changed data will be discarded if you choose to cancel.', 'woocommerce' ),
'save_failed' => __( 'Your changes were not saved. Please retry.', 'woocommerce' ),
'add_method_failed' => __( 'Shipping method could not be added. Please retry.', 'woocommerce' ),
'remove_method_failed' => __( 'Shipping method could not be removed. Please retry.', 'woocommerce' ),
'yes' => __( 'Yes', 'woocommerce' ),
'no' => __( 'No', 'woocommerce' ),
'default_zone_name' => __( 'Zone', 'woocommerce' ),
'delete_shipping_method_confirmation' => __( 'Are you sure you want to delete this shipping method?', 'woocommerce' ),
),
);
if ( 0 !== $zone->get_id() ) {
WCAdminAssets::register_script( 'wp-admin-scripts', 'shipping-settings-region-picker', true, array( 'wc-shipping-zone-methods' ) );
$localized_object['region_options'] = $this->get_region_options( $allowed_countries, $shipping_continents );
}
wp_localize_script(
'wc-shipping-zone-methods',
'shippingZoneMethodsLocalizeScript',
$localized_object,
);
wp_enqueue_script( 'wc-shipping-zone-methods' );
include_once dirname( __FILE__ ) . '/views/html-admin-page-shipping-zone-methods.php';
}
/**
* Show zones
*/
protected function zones_screen() {
$method_count = wc_get_shipping_method_count( false, true );
wp_localize_script(
'wc-shipping-zones',
'shippingZonesLocalizeScript',
array(
'zones' => WC_Shipping_Zones::get_zones( 'json' ),
'default_zone' => array(
'zone_id' => 0,
'zone_name' => '',
'zone_order' => null,
),
'wc_shipping_zones_nonce' => wp_create_nonce( 'wc_shipping_zones_nonce' ),
'strings' => array(
'unload_confirmation_msg' => __( 'Your changed data will be lost if you leave this page without saving.', 'woocommerce' ),
'delete_confirmation_msg' => __( 'Are you sure you want to delete this zone? This action cannot be undone.', 'woocommerce' ),
'save_failed' => __( 'Your changes were not saved. Please retry.', 'woocommerce' ),
'no_shipping_methods_offered' => __( 'No shipping methods offered to this zone.', 'woocommerce' ),
),
)
);
wp_enqueue_script( 'wc-shipping-zones' );
include_once dirname( __FILE__ ) . '/views/html-admin-page-shipping-zones.php';
}
/**
* Show instance settings
*
* @param int $instance_id Shipping instance ID.
*/
protected function instance_settings_screen( $instance_id ) {
$zone = WC_Shipping_Zones::get_zone_by( 'instance_id', $instance_id );
$shipping_method = WC_Shipping_Zones::get_shipping_method( $instance_id );
if ( ! $shipping_method ) {
wp_die( esc_html__( 'Invalid shipping method!', 'woocommerce' ) );
}
if ( ! $zone ) {
wp_die( esc_html__( 'Zone does not exist!', 'woocommerce' ) );
}
if ( ! $shipping_method->has_settings() ) {
wp_die( esc_html__( 'This shipping method does not have any settings to configure.', 'woocommerce' ) );
}
if ( ! empty( $_POST['save'] ) ) {
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
if ( empty( $_REQUEST['_wpnonce'] ) || ! wp_verify_nonce( wp_unslash( $_REQUEST['_wpnonce'] ), 'woocommerce-settings' ) ) {
echo '<div class="updated error"><p>' . esc_html__( 'Edit failed. Please try again.', 'woocommerce' ) . '</p></div>';
}
$shipping_method->process_admin_options();
$shipping_method->display_errors();
}
include_once dirname( __FILE__ ) . '/views/html-admin-page-shipping-zones-instance.php';
}
/**
* Handles output of the shipping class settings screen.
*/
protected function output_shipping_class_screen() {
$wc_shipping = WC_Shipping::instance();
wp_localize_script(
'wc-shipping-classes',
'shippingClassesLocalizeScript',
array(
'classes' => $wc_shipping->get_shipping_classes(),
'default_shipping_class' => array(
'term_id' => 0,
'name' => '',
'description' => '',
),
'wc_shipping_classes_nonce' => wp_create_nonce( 'wc_shipping_classes_nonce' ),
'strings' => array(
'unload_confirmation_msg' => __( 'Your changed data will be lost if you leave this page without saving.', 'woocommerce' ),
'save_failed' => __( 'Your changes were not saved. Please retry.', 'woocommerce' ),
),
)
);
wp_enqueue_script( 'wc-shipping-classes' );
// Extendable columns to show on the shipping classes screen.
$shipping_class_columns = apply_filters(
'woocommerce_shipping_classes_columns',
array(
'wc-shipping-class-name' => __( 'Shipping class', 'woocommerce' ),
'wc-shipping-class-slug' => __( 'Slug', 'woocommerce' ),
'wc-shipping-class-description' => __( 'Description', 'woocommerce' ),
'wc-shipping-class-count' => __( 'Product count', 'woocommerce' ),
)
);
include_once dirname( __FILE__ ) . '/views/html-admin-page-shipping-classes.php';
}
}
return new WC_Settings_Shipping();

View File

@@ -0,0 +1,52 @@
<?php
/**
* WooCommerce site visibility settings
*
* @package WooCommerce\Admin
*/
defined( 'ABSPATH' ) || exit;
/**
* Settings for API.
*/
if ( class_exists( 'WC_Settings_Site_Visibility', false ) ) {
return new WC_Settings_Site_Visibility();
}
/**
* WC_Settings_Advanced.
*/
class WC_Settings_Site_Visibility extends WC_Settings_Page {
/**
* Constructor.
*/
public function __construct() {
$this->id = 'site-visibility';
$this->label = __( 'Site visibility', 'woocommerce' );
parent::__construct();
}
/**
* Get settings for the default section.
*
* @return array
*/
protected function get_settings_for_default_section() {
$settings =
array(
array(
'id' => 'wc_settings_site_visibility_slotfill',
'type' => 'slotfill_placeholder',
),
);
return $settings;
}
}
return new WC_Settings_Site_Visibility();

View File

@@ -0,0 +1,363 @@
<?php
/**
* WooCommerce Tax Settings
*
* @package WooCommerce\Admin
* @version 2.1.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
if ( class_exists( 'WC_Settings_Tax', false ) ) {
return new WC_Settings_Tax();
}
/**
* WC_Settings_Tax.
*/
class WC_Settings_Tax extends WC_Settings_Page {
/**
* Constructor.
*/
public function __construct() {
$this->id = 'tax';
$this->label = __( 'Tax', 'woocommerce' );
add_filter( 'woocommerce_settings_tabs_array', array( $this, 'add_settings_page' ), 20 );
add_action( 'woocommerce_admin_field_conflict_error', array( $this, 'conflict_error' ) );
if ( wc_tax_enabled() ) {
add_action( 'woocommerce_sections_' . $this->id, array( $this, 'output_sections' ) );
add_action( 'woocommerce_settings_' . $this->id, array( $this, 'output' ) );
add_action( 'woocommerce_settings_save_' . $this->id, array( $this, 'save' ) );
}
}
/**
* Creates the React mount point for the embedded banner.
*/
public function conflict_error() {
?>
<tr valign="top">
<th scope="row" class="titledesc woocommerce_admin_tax_settings_slotfill_th">
</th>
<td class="forminp forminp-text woocommerce_admin_tax_settings_slotfill_td">
<div id="wc_tax_settings_slotfill"> </div>
</td>
</tr>
<?php
}
/**
* Add this page to settings.
*
* @param array $pages Existing pages.
* @return array|mixed
*/
public function add_settings_page( $pages ) {
if ( wc_tax_enabled() ) {
return parent::add_settings_page( $pages );
} else {
return $pages;
}
}
/**
* Get own sections.
*
* @return array
*/
protected function get_own_sections() {
$sections = array(
'' => __( 'Tax options', 'woocommerce' ),
'standard' => __( 'Standard rates', 'woocommerce' ),
);
// Get tax classes and display as links.
$tax_classes = WC_Tax::get_tax_classes();
foreach ( $tax_classes as $class ) {
/* translators: $s tax rate section name */
$sections[ sanitize_title( $class ) ] = sprintf( __( '%s rates', 'woocommerce' ), $class );
}
return $sections;
}
/**
* Get settings array.
*
* @return array
*/
public function get_settings_for_default_section() {
return include __DIR__ . '/views/settings-tax.php';
}
/**
* Output the settings.
*/
public function output() {
global $current_section;
$tax_classes = WC_Tax::get_tax_class_slugs();
if ( 'standard' === $current_section || in_array( $current_section, array_filter( $tax_classes ), true ) ) {
$this->output_tax_rates();
} else {
parent::output();
}
}
/**
* Save settings.
*/
public function save() {
// phpcs:disable WordPress.Security.NonceVerification.Missing
global $current_section;
if ( ! $current_section ) {
$this->save_settings_for_current_section();
if ( isset( $_POST['woocommerce_tax_classes'] ) ) {
$this->save_tax_classes( wp_unslash( $_POST['woocommerce_tax_classes'] ) ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
}
} elseif ( ! empty( $_POST['tax_rate_country'] ) ) {
$this->save_tax_rates();
} else {
$this->save_settings_for_current_section();
}
$this->do_update_options_action();
// Invalidate caches.
WC_Cache_Helper::invalidate_cache_group( 'taxes' );
WC_Cache_Helper::get_transient_version( 'shipping', true );
// phpcs:enable WordPress.Security.NonceVerification.Missing
}
/**
* Saves tax classes defined in the textarea to the tax class table instead of an option.
*
* @param string $raw_tax_classes Posted value.
* @return null
*/
public function save_tax_classes( $raw_tax_classes ) {
$tax_classes = array_filter( array_map( 'trim', explode( "\n", $raw_tax_classes ) ) );
$existing_tax_classes = WC_Tax::get_tax_classes();
$removed = array_diff( $existing_tax_classes, $tax_classes );
$added = array_diff( $tax_classes, $existing_tax_classes );
foreach ( $removed as $name ) {
WC_Tax::delete_tax_class_by( 'name', $name );
}
foreach ( $added as $name ) {
$tax_class = WC_Tax::create_tax_class( $name );
// Display any error that could be triggered while creating tax classes.
if ( is_wp_error( $tax_class ) ) {
WC_Admin_Settings::add_error(
sprintf(
/* translators: 1: tax class name 2: error message */
esc_html__( 'Additional tax class "%1$s" couldn\'t be saved. %2$s.', 'woocommerce' ),
esc_html( $name ),
$tax_class->get_error_message()
)
);
}
}
return null;
}
/**
* Output tax rate tables.
*/
public function output_tax_rates() {
global $current_section;
$current_class = self::get_current_tax_class();
$countries = array();
foreach ( WC()->countries->get_allowed_countries() as $value => $label ) {
$countries[] = array(
'value' => $value,
'label' => esc_js( html_entity_decode( $label ) ),
);
}
$states = array();
foreach ( WC()->countries->get_allowed_country_states() as $label ) {
foreach ( $label as $code => $state ) {
$states[] = array(
'value' => $code,
'label' => esc_js( html_entity_decode( $state ) ),
);
}
}
$base_url = admin_url(
add_query_arg(
array(
'page' => 'wc-settings',
'tab' => 'tax',
'section' => $current_section,
),
'admin.php'
)
);
// Localize and enqueue our js.
wp_localize_script(
'wc-settings-tax',
'htmlSettingsTaxLocalizeScript',
array(
'current_class' => $current_class,
'wc_tax_nonce' => wp_create_nonce( 'wc_tax_nonce-class:' . $current_class ),
'base_url' => $base_url,
'rates' => array_values( WC_Tax::get_rates_for_tax_class( $current_class ) ),
'page' => ! empty( $_GET['p'] ) ? absint( $_GET['p'] ) : 1, // phpcs:ignore WordPress.Security.NonceVerification.Recommended
'limit' => 100,
'countries' => $countries,
'states' => $states,
'default_rate' => array(
'tax_rate_id' => 0,
'tax_rate_country' => '',
'tax_rate_state' => '',
'tax_rate' => '',
'tax_rate_name' => '',
'tax_rate_priority' => 1,
'tax_rate_compound' => 0,
'tax_rate_shipping' => 1,
'tax_rate_order' => null,
'tax_rate_class' => $current_class,
),
'strings' => array(
'no_rows_selected' => __( 'No row(s) selected', 'woocommerce' ),
'unload_confirmation_msg' => __( 'Your changed data will be lost if you leave this page without saving.', 'woocommerce' ),
'csv_data_cols' => array(
__( 'Country code', 'woocommerce' ),
__( 'State code', 'woocommerce' ),
__( 'Postcode / ZIP', 'woocommerce' ),
__( 'City', 'woocommerce' ),
__( 'Rate %', 'woocommerce' ),
__( 'Tax name', 'woocommerce' ),
__( 'Priority', 'woocommerce' ),
__( 'Compound', 'woocommerce' ),
__( 'Shipping', 'woocommerce' ),
__( 'Tax class', 'woocommerce' ),
),
),
)
);
wp_enqueue_script( 'wc-settings-tax' );
include __DIR__ . '/views/html-settings-tax.php';
}
/**
* Get tax class being edited.
*
* @return string
*/
private static function get_current_tax_class() {
global $current_section;
$tax_classes = WC_Tax::get_tax_classes();
$current_class = '';
foreach ( $tax_classes as $class ) {
if ( sanitize_title( $class ) === $current_section ) {
$current_class = $class;
}
}
return $current_class;
}
/**
* Get a posted tax rate.
*
* @param string $key Key of tax rate in the post data array.
* @param int $order Position/order of rate.
* @param string $class Tax class for rate.
* @return array
*/
private function get_posted_tax_rate( $key, $order, $class ) {
// phpcs:disable WordPress.Security.NonceVerification.Missing -- this is called from 'save_tax_rates' only, where nonce is already verified.
$tax_rate = array();
$tax_rate_keys = array(
'tax_rate_country',
'tax_rate_state',
'tax_rate',
'tax_rate_name',
'tax_rate_priority',
);
// phpcs:disable WordPress.Security.NonceVerification.Missing
foreach ( $tax_rate_keys as $tax_rate_key ) {
if ( isset( $_POST[ $tax_rate_key ], $_POST[ $tax_rate_key ][ $key ] ) ) {
$tax_rate[ $tax_rate_key ] = wc_clean( wp_unslash( $_POST[ $tax_rate_key ][ $key ] ) );
}
}
$tax_rate['tax_rate_compound'] = isset( $_POST['tax_rate_compound'][ $key ] ) ? 1 : 0;
$tax_rate['tax_rate_shipping'] = isset( $_POST['tax_rate_shipping'][ $key ] ) ? 1 : 0;
$tax_rate['tax_rate_order'] = $order;
$tax_rate['tax_rate_class'] = $class;
// phpcs:enable WordPress.Security.NonceVerification.Missing
return $tax_rate;
// phpcs:enable WordPress.Security.NonceVerification.Missing
}
/**
* Save tax rates.
*/
public function save_tax_rates() {
// phpcs:disable WordPress.Security.NonceVerification.Missing -- this is called via "do_action('woocommerce_settings_save_'...") in base class, where nonce is verified first.
global $wpdb;
$current_class = sanitize_title( self::get_current_tax_class() );
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated, WordPress.Security.NonceVerification.Missing
$posted_countries = wc_clean( wp_unslash( $_POST['tax_rate_country'] ) );
// get the tax rate id of the first submitted row.
$first_tax_rate_id = key( $posted_countries );
// get the order position of the first tax rate id.
$tax_rate_order = absint( $wpdb->get_var( $wpdb->prepare( "SELECT tax_rate_order FROM {$wpdb->prefix}woocommerce_tax_rates WHERE tax_rate_id = %s", $first_tax_rate_id ) ) );
$index = isset( $tax_rate_order ) ? $tax_rate_order : 0;
// Loop posted fields.
// phpcs:disable WordPress.Security.NonceVerification.Missing
foreach ( $posted_countries as $key => $value ) {
$mode = ( 0 === strpos( $key, 'new-' ) ) ? 'insert' : 'update';
$tax_rate = $this->get_posted_tax_rate( $key, $index ++, $current_class );
if ( 'insert' === $mode ) {
$tax_rate_id = WC_Tax::_insert_tax_rate( $tax_rate );
} elseif ( isset( $_POST['remove_tax_rate'][ $key ] ) && 1 === absint( $_POST['remove_tax_rate'][ $key ] ) ) {
$tax_rate_id = absint( $key );
WC_Tax::_delete_tax_rate( $tax_rate_id );
continue;
} else {
$tax_rate_id = absint( $key );
WC_Tax::_update_tax_rate( $tax_rate_id, $tax_rate );
}
if ( isset( $_POST['tax_rate_postcode'][ $key ] ) ) {
WC_Tax::_update_tax_rate_postcodes( $tax_rate_id, wc_clean( wp_unslash( $_POST['tax_rate_postcode'][ $key ] ) ) );
}
if ( isset( $_POST['tax_rate_city'][ $key ] ) ) {
WC_Tax::_update_tax_rate_cities( $tax_rate_id, wc_clean( wp_unslash( $_POST['tax_rate_city'][ $key ] ) ) );
}
}
// phpcs:enable WordPress.Security.NonceVerification.Missing
}
}
return new WC_Settings_Tax();

View File

@@ -0,0 +1,11 @@
<?php // @codingStandardsIgnoreFile.
/**
* Settings class file.
*
* @deprecated 3.4.0 Replaced with class-wc-settings-advanced.php.
* @todo remove in 4.0.
*/
defined( 'ABSPATH' ) || exit;
return include __DIR__ . '/class-wc-settings-advanced.php';

View File

@@ -0,0 +1,166 @@
<?php
/**
* Shipping classes admin
*
* @package WooCommerce\Admin\Shipping
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
?>
<h2 class="wc-shipping-zones-heading">
<span><?php esc_html_e( 'Shipping classes', 'woocommerce' ); ?></span>
<a class="page-title-action wc-shipping-class-add-new" href="#"><?php esc_html_e( 'Add shipping class', 'woocommerce' ); ?></a>
</h2>
<p class="wc-shipping-zone-help-text">
<?php esc_html_e( 'Use shipping classes to customize the shipping rates for different groups of products, such as heavy items that require higher postage fees.', 'woocommerce' ); ?> <a target="_blank" href="https://woocommerce.com/document/product-shipping-classes/"><?php esc_html_e( 'Learn more', 'woocommerce' ); ?></a>
</p>
<table class="wc-shipping-classes widefat">
<thead>
<tr>
<?php foreach ( $shipping_class_columns as $class => $heading ) : ?>
<th class="<?php echo esc_attr( $class ); ?>"><?php echo esc_html( $heading ); ?></th>
<?php endforeach; ?>
<th />
</tr>
</thead>
<tbody class="wc-shipping-class-rows wc-shipping-tables-tbody"></tbody>
</table>
<script type="text/html" id="tmpl-wc-shipping-class-row-blank">
<tr>
<td class="wc-shipping-classes-blank-state" colspan="<?php echo absint( count( $shipping_class_columns ) + 1 ); ?>"><p><?php esc_html_e( 'No shipping classes have been created.', 'woocommerce' ); ?></p></td>
</tr>
</script>
<!-- 1. Placeholder becomes the "label" in view class div -->
<!-- 1. Add labelFor or some kind of attribute for semantic HTML-->
<script type="text/html" id="tmpl-wc-shipping-class-configure">
<div class="wc-backbone-modal wc-shipping-class-modal">
<div class="wc-backbone-modal-content" data-id="{{ data.term_id }}">
<section class="wc-backbone-modal-main" role="main">
<header class="wc-backbone-modal-header">
<h1><?php esc_html_e( 'Add shipping class', 'woocommerce' ); ?></h1>
<button class="modal-close modal-close-link dashicons dashicons-no-alt">
<span class="screen-reader-text"><?php esc_html_e( 'Close modal panel', 'woocommerce' ); ?></span>
</button>
</header>
<article>
<form action="" method="post">
<input type="hidden" name="term_id" value="{{{ data.term_id }}}" />
<?php
foreach ( $shipping_class_columns as $class => $heading ) {
echo '<div class="wc-shipping-class-modal-input ' . esc_attr( $class ) . '">';
switch ( $class ) {
case 'wc-shipping-class-name':
?>
<div class="view">
<?php echo esc_html( $heading ); ?> *
</div>
<div class="edit">
<input type="text" name="name" data-attribute="name" value="{{ data.name }}" placeholder="<?php esc_attr_e( 'e.g. Heavy', 'woocommerce' ); ?>" />
</div>
<div class="wc-shipping-class-modal-help-text"><?php esc_html_e( 'Give your shipping class a name for easy identification', 'woocommerce' ); ?></div>
<?php
break;
case 'wc-shipping-class-slug':
?>
<div class="view">
<?php echo esc_html( $heading ); ?>
</div>
<div class="edit">
<input type="text" name="slug" data-attribute="slug" value="{{ data.slug }}" placeholder="<?php esc_attr_e( 'e.g. heavy-packages', 'woocommerce' ); ?>" />
</div>
<div class="wc-shipping-class-modal-help-text"><?php esc_html_e( 'Slug (unique identifier) can be left blank and auto-generated, or you can enter one', 'woocommerce' ); ?></div>
<?php
break;
case 'wc-shipping-class-description':
?>
<div class="view">
<?php echo esc_html( $heading ); ?> *
</div>
<div class="edit">
<input type="text" name="description" data-attribute="description" value="{{ data.description }}" placeholder="<?php esc_attr_e( 'e.g. For heavy items requiring higher postage', 'woocommerce' ); ?>" />
</div>
<?php
break;
case 'wc-shipping-class-count':
break;
default:
?>
<div class="view wc-shipping-class-hide-sibling-view">
<?php echo esc_html( $heading ); ?>
</div>
<?php
// phpcs:ignore WooCommerce.Commenting.CommentHooks.MissingHookComment
do_action( 'woocommerce_shipping_classes_column_' . $class );
break;
}
echo '</div>';
}
?>
</form>
</article>
<footer>
<div class="inner">
<button id="btn-ok" disabled class="button button-primary button-large disabled">
<div class="wc-backbone-modal-action-{{ data.action === 'create' ? 'active' : 'inactive' }}"><?php esc_html_e( 'Create', 'woocommerce' ); ?></div>
<div class="wc-backbone-modal-action-{{ data.action === 'edit' ? 'active' : 'inactive' }}"><?php esc_html_e( 'Save', 'woocommerce' ); ?></div>
</button>
</div>
</footer>
</section>
</div>
</div>
<div class="wc-backbone-modal-backdrop modal-close"></div>
</script>
<script type="text/html" id="tmpl-wc-shipping-class-row">
<tr data-id="{{ data.term_id }}">
<?php
foreach ( $shipping_class_columns as $class => $heading ) {
echo '<td class="' . esc_attr( $class ) . '">';
switch ( $class ) {
case 'wc-shipping-class-name':
?>
<div class="view">
{{ data.name }}
</div>
<?php
break;
case 'wc-shipping-class-slug':
?>
<div class="view">{{ data.slug }}</div>
<?php
break;
case 'wc-shipping-class-description':
?>
<div class="view">{{ data.description }}</div>
<?php
break;
case 'wc-shipping-class-count':
?>
<a href="<?php echo esc_url( admin_url( 'edit.php?post_type=product&product_shipping_class=' ) ); ?>{{data.slug}}">{{ data.count }}</a>
<?php
break;
default:
// phpcs:ignore WooCommerce.Commenting.CommentHooks.MissingHookComment
do_action( 'woocommerce_shipping_classes_column_' . $class );
break;
}
echo '</td>';
}
?>
<td class="wc-shipping-zone-actions">
<div>
<a class="wc-shipping-class-edit wc-shipping-zone-action-edit" href="#"><?php esc_html_e( 'Edit', 'woocommerce' ); ?></a> | <a href="#" class="wc-shipping-class-delete wc-shipping-zone-actions"><?php esc_html_e( 'Delete', 'woocommerce' ); ?></a>
</div>
</td>
</tr>
</script>

View File

@@ -0,0 +1,274 @@
<?php
/**
* Shipping zone admin
*
* @package WooCommerce\Admin\Shipping
*/
use Automattic\WooCommerce\Blocks\Utils\CartCheckoutUtils;
use Automattic\WooCommerce\Blocks\Shipping\ShippingController;
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
?>
<h2>
<a href="<?php echo esc_url( admin_url( 'admin.php?page=wc-settings&tab=shipping' ) ); ?>"><?php esc_html_e( 'Shipping zones', 'woocommerce' ); ?></a> &gt;
<span class="wc-shipping-zone-name"><?php echo esc_html( $zone->get_zone_name() ? $zone->get_zone_name() : __( 'Zone', 'woocommerce' ) ); ?></span>
</h2>
<?php
// phpcs:ignore WooCommerce.Commenting.CommentHooks.MissingHookComment
do_action( 'woocommerce_shipping_zone_before_methods_table', $zone );
?>
<table class="form-table wc-shipping-zone-settings">
<tbody>
<?php if ( 0 !== $zone->get_id() ) : ?>
<tr valign="top" class="">
<th scope="row" class="titledesc">
<label for="zone_name">
<?php esc_html_e( 'Zone name', 'woocommerce' ); ?>
</label>
<p class="wc-shipping-zone-help-text">
<?php esc_html_e( 'Give your zone a name! E.g. Local, or Worldwide.', 'woocommerce' ); ?>
</p>
</th>
<td class="forminp">
<input type="text" data-attribute="zone_name" name="zone_name" id="zone_name" value="<?php echo esc_attr( $zone->get_zone_name( 'edit' ) ); ?>" placeholder="<?php esc_attr_e( 'Zone name', 'woocommerce' ); ?>">
</td>
</tr>
<tr valign="top" class="">
<th scope="row" class="titledesc">
<label for="zone_locations">
<?php esc_html_e( 'Zone regions', 'woocommerce' ); ?>
</label>
<p class="wc-shipping-zone-help-text">
<?php esc_html_e( 'List the regions you\'d like to include in your shipping zone. Customers will be matched against these regions.', 'woocommerce' ); ?>
</p>
</th>
<td>
<div>
<div id="wc-shipping-zone-region-picker-root"/>
</div>
<?php if ( empty( $postcodes ) ) : ?>
<a class="wc-shipping-zone-postcodes-toggle" href="#"><?php esc_html_e( 'Limit to specific ZIP/postcodes', 'woocommerce' ); ?></a>
<?php endif; ?>
<div class="wc-shipping-zone-postcodes">
<textarea name="zone_postcodes" data-attribute="zone_postcodes" id="zone_postcodes" placeholder="<?php esc_attr_e( 'List 1 postcode per line', 'woocommerce' ); ?>" class="input-text large-text" cols="25" rows="5"><?php echo esc_textarea( implode( "\n", $postcodes ) ); ?></textarea>
<?php /* translators: WooCommerce link to setting up shipping zones */ ?>
<span class="description"><?php printf( __( 'Postcodes containing wildcards (e.g. CB23*) or fully numeric ranges (e.g. <code>90210...99000</code>) are also supported. Please see the shipping zones <a href="%s" target="_blank">documentation</a> for more information.', 'woocommerce' ), 'https://woocommerce.com/document/setting-up-shipping-zones/#section-3' ); ?></span><?php // @codingStandardsIgnoreLine. ?>
</div>
</td>
</tr>
<?php endif; ?>
<tr valign="top" class="">
<th scope="row" class="titledesc">
<label>
<?php esc_html_e( 'Shipping methods', 'woocommerce' ); ?>
</label>
<p class="wc-shipping-zone-help-text">
<?php esc_html_e( 'Add the shipping methods you\'d like to make available to customers in this zone.', 'woocommerce' ); ?>
</p>
</th>
<td class="">
<table class="wc-shipping-zone-methods widefat">
<thead>
<tr>
<th class="wc-shipping-zone-method-sort"></th>
<th class="wc-shipping-zone-method-title"><?php esc_html_e( 'Title', 'woocommerce' ); ?></th>
<th class="wc-shipping-zone-method-enabled"><?php esc_html_e( 'Enabled', 'woocommerce' ); ?></th>
<th class="wc-shipping-zone-method-description"><?php esc_html_e( 'Description', 'woocommerce' ); ?></th>
<th></th>
</tr>
</thead>
<tbody class="wc-shipping-zone-method-rows wc-shipping-tables-tbody"></tbody>
</table>
</td>
</tr>
<tr>
<th scope="row"></th>
<td>
<button type="submit" class="wc-shipping-zone-add-method components-button is-primary" value="<?php esc_attr_e( 'Add shipping method', 'woocommerce' ); ?>"><?php esc_html_e( 'Add shipping method', 'woocommerce' ); ?></button>
</td>
</tr>
</tbody>
</table>
<?php
// phpcs:ignore WooCommerce.Commenting.CommentHooks.MissingHookComment
do_action( 'woocommerce_shipping_zone_after_methods_table', $zone );
?>
<p class="submit">
<button type="submit" name="submit" id="submit" class="button-primary button-large wc-shipping-zone-method-save components-button is-primary" value="<?php esc_attr_e( 'Save changes', 'woocommerce' ); ?>" disabled><?php esc_html_e( 'Save changes', 'woocommerce' ); ?></button>
</p>
<script type="text/html" id="tmpl-wc-shipping-zone-method-row-blank">
<tr>
<td class="wc-shipping-zone-method-blank-state" colspan="5">
<p><?php esc_html_e( 'You can add multiple shipping methods within this zone. Only customers within the zone will see them.', 'woocommerce' ); ?></p>
</td>
</tr>
</script>
<script type="text/html" id="tmpl-wc-shipping-zone-method-row">
<tr data-id="{{ data.instance_id }}" data-enabled="{{ data.enabled }}">
<td width="1%" class="wc-shipping-zone-method-sort"></td>
<td class="wc-shipping-zone-method-title">
{{{ data.title }}}
</td>
<td width="1%" class="wc-shipping-zone-method-enabled"><a href="#">{{{ data.enabled_icon }}}</a></td>
<td class="wc-shipping-zone-method-description">
{{{ data.method_description }}}
</td>
<td class="wc-shipping-zone-actions">
<div>
<a class="wc-shipping-zone-method-settings wc-shipping-zone-action-edit" href="admin.php?page=wc-settings&amp;tab=shipping&amp;instance_id={{ data.instance_id }}"><?php esc_html_e( 'Edit', 'woocommerce' ); ?></a> | <a href="#" class="wc-shipping-zone-method-delete wc-shipping-zone-actions"><?php esc_html_e( 'Delete', 'woocommerce' ); ?></a>
</div>
</td>
</tr>
</script>
<script type="text/template" id="tmpl-wc-modal-shipping-method-settings">
<div class="wc-backbone-modal wc-backbone-modal-shipping-method-settings">
<div class="wc-backbone-modal-content">
<section class="wc-backbone-modal-main" role="main">
<header class="wc-backbone-modal-header">
<h1>
<?php
printf(
/* translators: %s: shipping method title */
esc_html__( 'Set up %s', 'woocommerce' ),
'{{{ data.method.method_title.toLowerCase() }}}'
);
?>
</h1>
<button class="modal-close modal-close-link dashicons dashicons-no-alt">
<span class="screen-reader-text"><?php esc_html_e( 'Close modal panel', 'woocommerce' ); ?></span>
</button>
</header>
<article class="wc-modal-shipping-method-settings" data-id="{{{ data.instance_id }}}" data-status="{{{ data.status }}}" data-shipping-classes-count="<?php echo count( WC()->shipping()->get_shipping_classes() ); ?>">
<form action="" method="post">
{{{ data.method.settings_html }}}
<input type="hidden" name="instance_id" value="{{{ data.instance_id }}}" />
</form>
<a class="wc-shipping-method-add-class-costs" style="display:none;" target="_blank" href="<?php echo esc_url( admin_url( 'admin.php?page=wc-settings&tab=shipping&section=classes' ) ); ?>"><?php esc_html_e( 'Add shipping class costs', 'woocommerce' ); ?></a>
</article>
<footer>
<div class="inner">
<div>
<button id="btn-back" class="button button-large wc-backbone-modal-back-{{ data.status === 'new' ? 'active' : 'inactive' }}"><?php esc_html_e( 'Back', 'woocommerce' ); ?></button>
<button id="btn-ok" data-status='{{ data.status }}' class="button button-primary button-large">
<div class="wc-backbone-modal-action-{{ data.status === 'new' ? 'active' : 'inactive' }}"><?php esc_html_e( 'Create and save', 'woocommerce' ); ?></div>
<div class="wc-backbone-modal-action-{{ data.status === 'existing' ? 'active' : 'inactive' }}"><?php esc_html_e( 'Save', 'woocommerce' ); ?></div>
</button>
</div>
<div class="wc-shipping-zone-method-modal-info wc-shipping-zone-method-modal-info-{{ data.status === 'existing' ? 'inactive' : 'active' }}"><?php esc_html_e( 'STEP 2 OF 2', 'woocommerce' ); ?></div>
</div>
</footer>
</section>
</div>
</div>
<div class="wc-backbone-modal-backdrop modal-close"></div>
</script>
<script type="text/template" id="tmpl-wc-modal-add-shipping-method">
<div class="wc-backbone-modal wc-backbone-modal-add-shipping-method">
<div class="wc-backbone-modal-content">
<section class="wc-backbone-modal-main" role="main">
<header class="wc-backbone-modal-header">
<h1><?php esc_html_e( 'Create shipping method', 'woocommerce' ); ?></h1>
<button class="modal-close modal-close-link dashicons dashicons-no-alt">
<span class="screen-reader-text"><?php esc_html_e( 'Close modal panel', 'woocommerce' ); ?></span>
</button>
</header>
<article>
<form action="" method="post">
<fieldset class="wc-shipping-zone-method-selector">
<legend class="screen-reader-text"><?php esc_html_e( 'Choose the shipping method you wish to add. Only shipping methods which support zones are listed.', 'woocommerce' ); ?></legend>
<?php
$methods = WC()->shipping()->load_shipping_methods();
$methods_placed_in_order = array();
$first_methods_ids = array( 'free_shipping', 'flat_rate', 'local_pickup' );
foreach ( $first_methods_ids as $first_method_id ) {
foreach ( $methods as $key => $obj ) {
if ( $obj->id === $first_method_id ) {
$methods_placed_in_order[] = $obj;
unset( $methods[ $key ] );
break;
}
}
}
$methods_placed_in_order = array_merge( $methods_placed_in_order, array_values( $methods ) );
foreach ( $methods_placed_in_order as $method ) {
if ( CartCheckoutUtils::is_checkout_block_default() && ! ShippingController::is_legacy_local_pickup_active() && 'local_pickup' === $method->id ) {
continue;
}
if ( ! $method->supports( 'shipping-zones' ) ) {
continue;
}
echo '<div class="wc-shipping-zone-method-input"><input type="radio" value="' . esc_attr( $method->id ) . '" id="' . esc_attr( $method->id ) . '" name="add_method_id"/><label for="' . esc_attr( $method->id ) . '">' . esc_html( $method->get_method_title() ) . '<span class="dashicons dashicons-yes"></span></label></div>';
}
echo '<div class="wc-shipping-zone-method-input-help-text-container">';
foreach ( $methods_placed_in_order as $method ) {
if ( ! $method->supports( 'shipping-zones' ) ) {
continue;
}
echo '<div id=' . esc_attr( $method->id ) . '-description class="wc-shipping-zone-method-input-help-text"><span>' . wp_kses_post( wpautop( $method->get_method_description() ) ) . '</span></div>';
}
if ( CartCheckoutUtils::is_checkout_block_default() ) {
echo '<p class="wc-shipping-legacy-local-pickup-help-text-container">';
if ( ShippingController::is_legacy_local_pickup_active() ) {
printf(
wp_kses(
/* translators: %s: Local pickup settings page URL. */
__( 'Explore a new enhanced delivery method that allows you to easily offer one or more pickup locations to your customers in the <a href="%s">Local pickup settings page</a>.', 'woocommerce' ),
array( 'a' => array( 'href' => array() ) )
),
esc_url( admin_url( 'admin.php?page=wc-settings&tab=shipping&section=pickup_location' ) )
);
} else {
printf(
wp_kses(
/* translators: %s: Local pickup settings page URL. */
__( 'Local pickup: Set up pickup locations in the <a href="%s">Local pickup settings page</a>.', 'woocommerce' ),
array( 'a' => array( 'href' => array() ) )
),
esc_url( admin_url( 'admin.php?page=wc-settings&tab=shipping&section=pickup_location' ) )
);
}
echo '</p>';
}
echo '</div>';
?>
</fieldset>
</form>
</article>
<footer>
<div class="inner">
<button id="btn-next" disabled class="button button-primary button-large disabled"><?php esc_html_e( 'Continue', 'woocommerce' ); ?></button>
<div class="wc-shipping-zone-method-modal-info"><?php esc_html_e( 'STEP 1 OF 2', 'woocommerce' ); ?></div>
</div>
</footer>
</section>
</div>
</div>
<div class="wc-backbone-modal-backdrop modal-close"></div>
</script>

View File

@@ -0,0 +1,12 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
?>
<h2>
<a href="<?php echo admin_url( 'admin.php?page=wc-settings&tab=shipping' ); ?>"><?php _e( 'Shipping zones', 'woocommerce' ); ?></a> &gt;
<a href="<?php echo admin_url( 'admin.php?page=wc-settings&tab=shipping&zone_id=' . absint( $zone->get_id() ) ); ?>"><?php echo esc_html( $zone->get_zone_name() ); ?></a> &gt;
<?php echo esc_html( $shipping_method->get_method_title() ); ?>
</h2>
<?php $shipping_method->admin_options(); ?>

View File

@@ -0,0 +1,131 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
?>
<h2 class="wc-shipping-zones-heading">
<span><?php esc_html_e( 'Shipping zones', 'woocommerce' ); ?></span>
<a href="<?php echo esc_url( admin_url( 'admin.php?page=wc-settings&tab=shipping&zone_id=new' ) ); ?>" class="page-title-action"><?php esc_html_e( 'Add zone', 'woocommerce' ); ?></a>
</h2>
<p class="wc-shipping-zone-heading-help-text"><?php echo esc_html_e( 'A shipping zone consists of the region(s) you\'d like to ship to and the shipping method(s) offered. A shopper can only be matched to one zone, and we\'ll use their shipping address to show them the methods available in their area.', 'woocommerce' ); ?></p>
<table class="wc-shipping-zones widefat">
<thead>
<tr>
<th class="wc-shipping-zone-sort"><?php echo wc_help_tip( __( 'Drag and drop to re-order your custom zones. This is the order in which they will be matched against the customer address.', 'woocommerce' ) ); ?></th>
<th class="wc-shipping-zone-name"><?php esc_html_e( 'Zone name', 'woocommerce' ); ?></th>
<th class="wc-shipping-zone-region"><?php esc_html_e( 'Region(s)', 'woocommerce' ); ?></th>
<th class="wc-shipping-zone-methods"><?php esc_html_e( 'Shipping method(s)', 'woocommerce' ); ?></th>
<th></th>
</tr>
</thead>
<tbody class="wc-shipping-zone-rows wc-shipping-tables-tbody"></tbody>
<tfoot data-id="0" class="wc-shipping-zone-worldwide wc-shipping-zone-rows-tfoot">
<td width="1%" class="wc-shipping-zone-worldwide"></td>
<td class="wc-shipping-zone-name">
<?php esc_html_e( 'Rest of the world', 'woocommerce' ); ?>
</td>
<td class="wc-shipping-zone-region"><?php esc_html_e( 'An optional zone you can use to set the shipping method(s) available to any regions that have not been listed above.', 'woocommerce' ); ?></td>
<td class="wc-shipping-zone-methods">
<ul>
<?php
$worldwide = new WC_Shipping_Zone( 0 );
$methods = $worldwide->get_shipping_methods();
uasort( $methods, 'wc_shipping_zone_method_order_uasort_comparison' );
if ( ! empty( $methods ) ) {
foreach ( $methods as $method ) {
$class_name = 'yes' === $method->enabled ? 'method_enabled' : 'method_disabled';
echo '<li class="wc-shipping-zone-method ' . esc_attr( $class_name ) . '">' . esc_html( $method->get_title() ) . '</li>';
}
} else {
echo '<li>' . esc_html_e( 'No shipping methods offered to this zone.', 'woocommerce' ) . '</li>';
}
?>
</ul>
</td>
<td class="wc-shipping-zone-actions">
<a class="wc-shipping-zone-action-edit" href="admin.php?page=wc-settings&amp;tab=shipping&amp;zone_id=0"><?php esc_html_e( 'Edit', 'woocommerce' ); ?></a>
</td>
</tfoot>
</table>
<script type="text/html" id="tmpl-wc-shipping-zone-row-blank">
<?php if ( 0 === $method_count ) : ?>
<tr>
<td class="wc-shipping-zones-blank-state" colspan="5">
<p class="main"><?php _e( 'A shipping zone is a geographic region where a certain set of shipping methods and rates apply.', 'woocommerce' ); ?></p>
<p><?php _e( 'For example:', 'woocommerce' ); ?></p>
<ul>
<li><?php _e( 'Local zone = California ZIP 90210 = Local pickup', 'woocommerce' ); ?>
<li><?php _e( 'US domestic zone = All US states = Flat rate shipping', 'woocommerce' ); ?>
<li><?php _e( 'Europe zone = Any country in Europe = Flat rate shipping', 'woocommerce' ); ?>
</ul>
<p><?php _e( 'Add as many zones as you need &ndash; customers will only see the methods available for their address.', 'woocommerce' ); ?></p>
<a class="button button-primary wc-shipping-zone-add" href="<?php echo esc_url( admin_url( 'admin.php?page=wc-settings&tab=shipping&zone_id=new' ) ); ?>"><?php _e( 'Add shipping zone', 'woocommerce' ); ?></a>
</td>
</tr>
<?php endif; ?>
</script>
<script type="text/html" id="tmpl-wc-shipping-zone-row">
<tr data-id="{{ data.zone_id }}">
<td width="1%" class="wc-shipping-zone-sort"></td>
<td class="wc-shipping-zone-name">
{{ data.zone_name }}
</td>
<td class="wc-shipping-zone-region">
{{ data.formatted_zone_location }}
</td>
<td class="wc-shipping-zone-methods">
<div><ul></ul></div>
</td>
<td class="wc-shipping-zone-actions">
<div>
<a class="wc-shipping-zone-action-edit" href="admin.php?page=wc-settings&amp;tab=shipping&amp;zone_id={{ data.zone_id }}"><?php esc_html_e( 'Edit', 'woocommerce' ); ?></a> | <a href="#" class="wc-shipping-zone-delete wc-shipping-zone-actions"><?php esc_html_e( 'Delete', 'woocommerce' ); ?></a>
</div>
</td>
</tr>
</script>
<script type="text/template" id="tmpl-wc-modal-add-shipping-method">
<div class="wc-backbone-modal">
<div class="wc-backbone-modal-content">
<section class="wc-backbone-modal-main" role="main">
<header class="wc-backbone-modal-header">
<h1><?php _e( 'Add shipping method', 'woocommerce' ); ?></h1>
<button class="modal-close modal-close-link dashicons dashicons-no-alt">
<span class="screen-reader-text"><?php _e( 'Close modal panel', 'woocommerce' ); ?></span>
</button>
</header>
<article>
<form action="" method="post">
<div class="wc-shipping-zone-method-selector">
<p><?php esc_html_e( 'Choose the shipping method you wish to add. Only shipping methods which support zones are listed.', 'woocommerce' ); ?></p>
<select name="add_method_id">
<?php
foreach ( WC()->shipping()->load_shipping_methods() as $method ) {
if ( ! $method->supports( 'shipping-zones' ) ) {
continue;
}
echo '<option data-description="' . esc_attr( wp_kses_post( wpautop( $method->get_method_description() ) ) ) . '" value="' . esc_attr( $method->id ) . '">' . esc_html( $method->get_method_title() ) . '</li>';
}
?>
</select>
<input type="hidden" name="zone_id" value="{{{ data.zone_id }}}" />
</div>
</form>
</article>
<footer>
<div class="inner">
<button id="btn-ok" class="button button-primary button-large"><?php _e( 'Add shipping method', 'woocommerce' ); ?></button>
</div>
</footer>
</section>
</div>
</div>
<div class="wc-backbone-modal-backdrop modal-close"></div>
</script>

View File

@@ -0,0 +1,156 @@
<?php
/**
* Admin view: Edit API keys
*
* @package WooCommerce\Admin\Settings
*/
defined( 'ABSPATH' ) || exit;
?>
<div id="key-fields" class="settings-panel">
<h2><?php esc_html_e( 'Key details', 'woocommerce' ); ?></h2>
<input type="hidden" id="key_id" value="<?php echo esc_attr( $key_id ); ?>" />
<table id="api-keys-options" class="form-table">
<tbody>
<tr valign="top">
<th scope="row" class="titledesc">
<label for="key_description">
<?php esc_html_e( 'Description', 'woocommerce' ); ?>
<?php echo wc_help_tip( __( 'Friendly name for identifying this key.', 'woocommerce' ) ); ?>
</label>
</th>
<td class="forminp">
<input maxlength="200" id="key_description" type="text" class="input-text regular-input" value="<?php echo esc_attr( $key_data['description'] ); ?>" />
</td>
</tr>
<tr valign="top">
<th scope="row" class="titledesc">
<label for="key_user">
<?php esc_html_e( 'User', 'woocommerce' ); ?>
<?php echo wc_help_tip( __( 'Owner of these keys.', 'woocommerce' ) ); ?>
</label>
</th>
<td class="forminp">
<?php
$current_user_id = get_current_user_id();
$user_id = ! empty( $key_data['user_id'] ) ? absint( $key_data['user_id'] ) : $current_user_id;
$user = get_user_by( 'id', $user_id );
$user_string = sprintf(
/* translators: 1: user display name 2: user ID 3: user email */
esc_html__( '%1$s (#%2$s &ndash; %3$s)', 'woocommerce' ),
$user->display_name,
absint( $user->ID ),
$user->user_email
);
?>
<select class="wc-customer-search" id="key_user" data-placeholder="<?php esc_attr_e( 'Search for a user&hellip;', 'woocommerce' ); ?>" data-allow_clear="true">
<option value="<?php echo esc_attr( $user_id ); ?>" selected="selected"><?php echo htmlspecialchars( wp_kses_post( $user_string ) ); // htmlspecialchars to prevent XSS when rendered by selectWoo. ?></option>
</select>
</td>
</tr>
<tr valign="top">
<th scope="row" class="titledesc">
<label for="key_permissions">
<?php esc_html_e( 'Permissions', 'woocommerce' ); ?>
<?php echo wc_help_tip( __( 'Select the access type of these keys.', 'woocommerce' ) ); ?>
</label>
</th>
<td class="forminp">
<select id="key_permissions" class="wc-enhanced-select">
<?php
$permissions = array(
'read' => __( 'Read', 'woocommerce' ),
'write' => __( 'Write', 'woocommerce' ),
'read_write' => __( 'Read/Write', 'woocommerce' ),
);
foreach ( $permissions as $permission_id => $permission_name ) :
?>
<option value="<?php echo esc_attr( $permission_id ); ?>" <?php selected( $key_data['permissions'], $permission_id, true ); ?>><?php echo esc_html( $permission_name ); ?></option>
<?php endforeach; ?>
</select>
</td>
</tr>
<?php if ( 0 !== $key_id ) : ?>
<tr valign="top">
<th scope="row" class="titledesc">
<?php esc_html_e( 'Consumer key ending in', 'woocommerce' ); ?>
</th>
<td class="forminp">
<code>&hellip;<?php echo esc_html( $key_data['truncated_key'] ); ?></code>
</td>
</tr>
<tr valign="top">
<th scope="row" class="titledesc">
<?php esc_html_e( 'Last access', 'woocommerce' ); ?>
</th>
<td class="forminp">
<span>
<?php
if ( ! empty( $key_data['last_access'] ) ) {
/* translators: 1: last access date 2: last access time */
$date = sprintf( __( '%1$s at %2$s', 'woocommerce' ), date_i18n( wc_date_format(), strtotime( $key_data['last_access'] ) ), date_i18n( wc_time_format(), strtotime( $key_data['last_access'] ) ) );
echo esc_html( apply_filters( 'woocommerce_api_key_last_access_datetime', $date, $key_data['last_access'] ) );
} else {
esc_html_e( 'Unknown', 'woocommerce' );
}
?>
</span>
</td>
</tr>
<?php endif ?>
</tbody>
</table>
<?php do_action( 'woocommerce_admin_key_fields', $key_data ); ?>
<?php
if ( 0 === intval( $key_id ) ) {
submit_button( __( 'Generate API key', 'woocommerce' ), 'primary', 'update_api_key' );
} else {
?>
<p class="submit">
<?php submit_button( __( 'Save changes', 'woocommerce' ), 'primary', 'update_api_key', false ); ?>
<a style="color: #a00; text-decoration: none; margin-left: 10px;" href="<?php echo esc_url( wp_nonce_url( add_query_arg( array( 'revoke-key' => $key_id ), admin_url( 'admin.php?page=wc-settings&tab=advanced&section=keys' ) ), 'revoke' ) ); ?>"><?php esc_html_e( 'Revoke key', 'woocommerce' ); ?></a>
</p>
<?php
}
?>
</div>
<script type="text/template" id="tmpl-api-keys-template">
<p id="copy-error"></p>
<table class="form-table">
<tbody>
<tr valign="top">
<th scope="row" class="titledesc">
<?php esc_html_e( 'Consumer key', 'woocommerce' ); ?>
</th>
<td class="forminp">
<input id="key_consumer_key" type="text" value="{{ data.consumer_key }}" size="55" readonly="readonly"> <button type="button" class="button-secondary copy-key" data-tip="<?php esc_attr_e( 'Copied!', 'woocommerce' ); ?>"><?php esc_html_e( 'Copy', 'woocommerce' ); ?></button>
</td>
</tr>
<tr valign="top">
<th scope="row" class="titledesc">
<?php esc_html_e( 'Consumer secret', 'woocommerce' ); ?>
</th>
<td class="forminp">
<input id="key_consumer_secret" type="text" value="{{ data.consumer_secret }}" size="55" readonly="readonly"> <button type="button" class="button-secondary copy-secret" data-tip="<?php esc_attr_e( 'Copied!', 'woocommerce' ); ?>"><?php esc_html_e( 'Copy', 'woocommerce' ); ?></button>
</td>
</tr>
<tr valign="top">
<th scope="row" class="titledesc">
<?php esc_html_e( 'QRCode', 'woocommerce' ); ?>
</th>
<td class="forminp">
<div id="keys-qrcode"></div>
</td>
</tr>
</tbody>
</table>
</script>

View File

@@ -0,0 +1,155 @@
<?php
/**
* Admin view: Settings tax
*
* @package WooCommerce\Admin\Settings
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
?>
<div class="wc-tax-rates-search" id="rates-search">
<input type="search" class="wc-tax-rates-search-field" placeholder="<?php esc_attr_e( 'Search&hellip;', 'woocommerce' ); ?>" value="<?php echo isset( $_GET['s'] ) ? esc_attr( $_GET['s'] ) : ''; ?>" />
</div>
<div id="rates-pagination"></div>
<h3>
<?php
/* translators: %s: tax rate */
printf(
__( '"%s" tax rates', 'woocommerce' ),
$current_class ? esc_html( $current_class ) : __( 'Standard', 'woocommerce' )
);
?>
</h3>
<table class="wc_tax_rates wc_input_table widefat">
<thead>
<tr>
<th width="8%"><a href="https://en.wikipedia.org/wiki/ISO_3166-1#Current_codes" target="_blank"><?php _e( 'Country&nbsp;code', 'woocommerce' ); ?></a>&nbsp;<?php echo wc_help_tip( __( 'A 2 digit country code, e.g. US. Leave blank to apply to all.', 'woocommerce' ) ); ?></th>
<th width="8%"><?php _e( 'State code', 'woocommerce' ); ?>&nbsp;<?php echo wc_help_tip( __( 'A 2 digit state code, e.g. AL. Leave blank to apply to all.', 'woocommerce' ) ); ?></th>
<th><?php _e( 'Postcode / ZIP', 'woocommerce' ); ?>&nbsp;<?php echo wc_help_tip( __( 'Postcode for this rule. Semi-colon (;) separate multiple values. Leave blank to apply to all areas. Wildcards (*) and ranges for numeric postcodes (e.g. 12345...12350) can also be used.', 'woocommerce' ) ); ?></th>
<th><?php _e( 'City', 'woocommerce' ); ?>&nbsp;<?php echo wc_help_tip( __( 'Cities for this rule. Semi-colon (;) separate multiple values. Leave blank to apply to all cities.', 'woocommerce' ) ); ?></th>
<th width="8%"><?php _e( 'Rate&nbsp;%', 'woocommerce' ); ?>&nbsp;<?php echo wc_help_tip( __( 'Enter a tax rate (percentage) to 4 decimal places.', 'woocommerce' ) ); ?></th>
<th width="8%"><?php _e( 'Tax name', 'woocommerce' ); ?>&nbsp;<?php echo wc_help_tip( __( 'Enter a name for this tax rate.', 'woocommerce' ) ); ?></th>
<th width="8%"><?php _e( 'Priority', 'woocommerce' ); ?>&nbsp;<?php echo wc_help_tip( __( 'Choose a priority for this tax rate. Only 1 matching rate per priority will be used. To define multiple tax rates for a single area you need to specify a different priority per rate.', 'woocommerce' ) ); ?></th>
<th width="8%"><?php _e( 'Compound', 'woocommerce' ); ?>&nbsp;<?php echo wc_help_tip( __( 'Choose whether or not this is a compound rate. Compound tax rates are applied on top of other tax rates.', 'woocommerce' ) ); ?></th>
<th width="8%"><?php _e( 'Shipping', 'woocommerce' ); ?>&nbsp;<?php echo wc_help_tip( __( 'Choose whether or not this tax rate also gets applied to shipping.', 'woocommerce' ) ); ?></th>
</tr>
</thead>
<tfoot>
<tr>
<th colspan="9">
<a href="#" class="button plus insert"><?php _e( 'Insert row', 'woocommerce' ); ?></a>
<a href="#" class="button minus remove_tax_rates"><?php _e( 'Remove selected row(s)', 'woocommerce' ); ?></a>
<a href="#" download="tax_rates.csv" class="button export"><?php _e( 'Export CSV', 'woocommerce' ); ?></a>
<a href="<?php echo admin_url( 'admin.php?import=woocommerce_tax_rate_csv' ); ?>" class="button import"><?php _e( 'Import CSV', 'woocommerce' ); ?></a>
</th>
</tr>
</tfoot>
<tbody id="rates">
<tr>
<th colspan="9" style="text-align: center;"><?php esc_html_e( 'Loading&hellip;', 'woocommerce' ); ?></th>
</tr>
</tbody>
</table>
<div id="rates-bottom-pagination"></div>
<script type="text/html" id="tmpl-wc-tax-table-row">
<tr class="tips" data-tip="<?php printf( esc_attr__( 'Tax rate ID: %s', 'woocommerce' ), '{{ data.tax_rate_id }}' ); ?>" data-id="{{ data.tax_rate_id }}">
<td class="country">
<input type="text" value="{{ data.tax_rate_country }}" placeholder="*" name="tax_rate_country[{{ data.tax_rate_id }}]" class="wc_input_country_iso" data-attribute="tax_rate_country" style="text-transform:uppercase" />
</td>
<td class="state">
<input type="text" value="{{ data.tax_rate_state }}" placeholder="*" name="tax_rate_state[{{ data.tax_rate_id }}]" data-attribute="tax_rate_state" />
</td>
<td class="postcode">
<input type="text" value="<# if ( data.postcode ) print( _.escape( data.postcode.join( '; ' ) ) ); #>" placeholder="*" data-name="tax_rate_postcode[{{ data.tax_rate_id }}]" data-attribute="postcode" />
</td>
<td class="city">
<input type="text" value="<# if ( data.city ) print( _.escape( data.city.join( '; ' ) ) ); #>" placeholder="*" data-name="tax_rate_city[{{ data.tax_rate_id }}]" data-attribute="city" />
</td>
<td class="rate">
<input type="text" value="{{ data.tax_rate }}" placeholder="0" name="tax_rate[{{ data.tax_rate_id }}]" data-attribute="tax_rate" />
</td>
<td class="name">
<input type="text" value="{{ data.tax_rate_name }}" name="tax_rate_name[{{ data.tax_rate_id }}]" data-attribute="tax_rate_name" />
</td>
<td class="priority">
<input type="number" step="1" min="1" value="{{ data.tax_rate_priority }}" name="tax_rate_priority[{{ data.tax_rate_id }}]" data-attribute="tax_rate_priority" />
</td>
<td class="compound">
<input type="checkbox" class="checkbox" name="tax_rate_compound[{{ data.tax_rate_id }}]" <# if ( parseInt( data.tax_rate_compound, 10 ) ) { #> checked="checked" <# } #> data-attribute="tax_rate_compound" />
</td>
<td class="apply_to_shipping">
<input type="checkbox" class="checkbox" name="tax_rate_shipping[{{ data.tax_rate_id }}]" <# if ( parseInt( data.tax_rate_shipping, 10 ) ) { #> checked="checked" <# } #> data-attribute="tax_rate_shipping" />
</td>
</tr>
</script>
<script type="text/html" id="tmpl-wc-tax-table-row-empty">
<tr>
<th colspan="9" style="text-align:center"><?php esc_html_e( 'No matching tax rates found.', 'woocommerce' ); ?></th>
</tr>
</script>
<script type="text/html" id="tmpl-wc-tax-table-pagination">
<div class="tablenav">
<div class="tablenav-pages">
<span class="displaying-num">
<?php
/* translators: %s: number */
printf(
__( '%s items', 'woocommerce' ), // %s will be a number eventually, but must be a string for now.
'{{ data.qty_rates }}'
);
?>
</span>
<span class="pagination-links">
<a class="tablenav-pages-navspan" data-goto="1">
<span class="screen-reader-text"><?php esc_html_e( 'First page', 'woocommerce' ); ?></span>
<span aria-hidden="true">&laquo;</span>
</a>
<a class="tablenav-pages-navspan" data-goto="<# print( Math.max( 1, parseInt( data.current_page, 10 ) - 1 ) ) #>">
<span class="screen-reader-text"><?php esc_html_e( 'Previous page', 'woocommerce' ); ?></span>
<span aria-hidden="true">&lsaquo;</span>
</a>
<span class="paging-input">
<label for="current-page-selector" class="screen-reader-text"><?php esc_html_e( 'Current page', 'woocommerce' ); ?></label>
<?php
/* translators: 1: current page 2: total pages */
printf(
esc_html_x( '%1$s of %2$s', 'Pagination', 'woocommerce' ),
'<input class="current-page" id="current-page-selector" type="text" name="paged" value="{{ data.current_page }}" size="<# print( data.qty_pages.toString().length ) #>" aria-describedby="table-paging">',
'<span class="total-pages">{{ data.qty_pages }}</span>'
);
?>
</span>
<a class="tablenav-pages-navspan" data-goto="<# print( Math.min( data.qty_pages, parseInt( data.current_page, 10 ) + 1 ) ) #>">
<span class="screen-reader-text"><?php esc_html_e( 'Next page', 'woocommerce' ); ?></span>
<span aria-hidden="true">&rsaquo;</span>
</a>
<a class="tablenav-pages-navspan" data-goto="{{ data.qty_pages }}">
<span class="screen-reader-text"><?php esc_html_e( 'Last page', 'woocommerce' ); ?></span>
<span aria-hidden="true">&raquo;</span>
</a>
</span>
</div>
</div>
</script>

View File

@@ -0,0 +1,242 @@
<?php
/**
* Admin View: Edit Webhooks
*
* @package WooCommerce\Admin\Webhooks\Views
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
?>
<input type="hidden" name="webhook_id" value="<?php echo esc_attr( $webhook->get_id() ); ?>" />
<div id="webhook-options" class="settings-panel">
<h2><?php esc_html_e( 'Webhook data', 'woocommerce' ); ?></h2>
<table class="form-table">
<tbody>
<tr valign="top">
<th scope="row" class="titledesc">
<label for="webhook_name">
<?php esc_html_e( 'Name', 'woocommerce' ); ?>
<?php
/* translators: %s: date */
echo wc_help_tip( sprintf( __( 'Friendly name for identifying this webhook, defaults to Webhook created on %s.', 'woocommerce' ), (new DateTime('now'))->format( _x( 'M d, Y @ h:i A', 'Webhook created on date parsed by DateTime::format', 'woocommerce' ) ) ) ); // @codingStandardsIgnoreLine
?>
</label>
</th>
<td class="forminp">
<input name="webhook_name" id="webhook_name" type="text" class="input-text regular-input" value="<?php echo esc_attr( $webhook->get_name() ); ?>" />
</td>
</tr>
<tr valign="top">
<th scope="row" class="titledesc">
<label for="webhook_status">
<?php esc_html_e( 'Status', 'woocommerce' ); ?>
<?php echo wc_help_tip( __( 'The options are &quot;Active&quot; (delivers payload), &quot;Paused&quot; (does not deliver), or &quot;Disabled&quot; (does not deliver due delivery failures).', 'woocommerce' ) ); ?>
</label>
</th>
<td class="forminp">
<select name="webhook_status" id="webhook_status" class="wc-enhanced-select">
<?php
$statuses = wc_get_webhook_statuses();
$current_status = $webhook->get_status();
foreach ( $statuses as $status_slug => $status_name ) :
?>
<option value="<?php echo esc_attr( $status_slug ); ?>" <?php selected( $current_status, $status_slug, true ); ?>><?php echo esc_html( $status_name ); ?></option>
<?php endforeach; ?>
</select>
</td>
</tr>
<tr valign="top">
<th scope="row" class="titledesc">
<label for="webhook_topic">
<?php esc_html_e( 'Topic', 'woocommerce' ); ?>
<?php echo wc_help_tip( __( 'Select when the webhook will fire.', 'woocommerce' ) ); ?>
</label>
</th>
<td class="forminp">
<select name="webhook_topic" id="webhook_topic" class="wc-enhanced-select">
<?php
$topic_data = WC_Admin_Webhooks::get_topic_data( $webhook );
$topics = apply_filters(
'woocommerce_webhook_topics',
array(
'' => __( 'Select an option&hellip;', 'woocommerce' ),
'coupon.created' => __( 'Coupon created', 'woocommerce' ),
'coupon.updated' => __( 'Coupon updated', 'woocommerce' ),
'coupon.deleted' => __( 'Coupon deleted', 'woocommerce' ),
'coupon.restored' => __( 'Coupon restored', 'woocommerce' ),
'customer.created' => __( 'Customer created', 'woocommerce' ),
'customer.updated' => __( 'Customer updated', 'woocommerce' ),
'customer.deleted' => __( 'Customer deleted', 'woocommerce' ),
'order.created' => __( 'Order created', 'woocommerce' ),
'order.updated' => __( 'Order updated', 'woocommerce' ),
'order.deleted' => __( 'Order deleted', 'woocommerce' ),
'order.restored' => __( 'Order restored', 'woocommerce' ),
'product.created' => __( 'Product created', 'woocommerce' ),
'product.updated' => __( 'Product updated', 'woocommerce' ),
'product.deleted' => __( 'Product deleted', 'woocommerce' ),
'product.restored' => __( 'Product restored', 'woocommerce' ),
'action' => __( 'Action', 'woocommerce' ),
)
);
foreach ( $topics as $topic_slug => $topic_name ) :
$selected = $topic_slug === $topic_data['topic'] || $topic_slug === $topic_data['resource'] . '.' . $topic_data['event'];
?>
<option value="<?php echo esc_attr( $topic_slug ); ?>" <?php selected( $selected, true, true ); ?>><?php echo esc_html( $topic_name ); ?></option>
<?php endforeach; ?>
</select>
</td>
</tr>
<tr valign="top" id="webhook-action-event-wrap">
<th scope="row" class="titledesc">
<label for="webhook_action_event">
<?php esc_html_e( 'Action event', 'woocommerce' ); ?>
<?php echo wc_help_tip( __( 'Enter the action that will trigger this webhook.', 'woocommerce' ) ); ?>
</label>
</th>
<td class="forminp">
<input name="webhook_action_event" id="webhook_action_event" type="text" class="input-text regular-input" value="<?php echo esc_attr( $topic_data['event'] ); ?>" />
</td>
</tr>
<tr valign="top">
<th scope="row" class="titledesc">
<label for="webhook_delivery_url">
<?php esc_html_e( 'Delivery URL', 'woocommerce' ); ?>
<?php echo wc_help_tip( __( 'URL where the webhook payload is delivered.', 'woocommerce' ) ); ?>
</label>
</th>
<td class="forminp">
<input name="webhook_delivery_url" id="webhook_delivery_url" type="text" class="input-text regular-input" value="<?php echo esc_attr( $webhook->get_delivery_url() ); ?>" />
</td>
</tr>
<tr valign="top">
<th scope="row" class="titledesc">
<label for="webhook_secret">
<?php esc_html_e( 'Secret', 'woocommerce' ); ?>
<?php echo wc_help_tip( __( 'The secret key is used to generate a hash of the delivered webhook and provided in the request headers.', 'woocommerce' ) ); ?>
</label>
</th>
<td class="forminp">
<input name="webhook_secret" id="webhook_secret" type="text" class="input-text regular-input" value="<?php echo esc_attr( $webhook->get_secret() ); ?>" />
</td>
</tr>
<tr valign="top">
<th scope="row" class="titledesc">
<label for="webhook_api_version">
<?php esc_html_e( 'API Version', 'woocommerce' ); ?>
<?php echo wc_help_tip( __( 'REST API version used in the webhook deliveries.', 'woocommerce' ) ); ?>
</label>
</th>
<td class="forminp">
<select name="webhook_api_version" id="webhook_api_version">
<?php foreach ( array_reverse( wc_get_webhook_rest_api_versions() ) as $version ) : ?>
<option value="<?php echo esc_attr( $version ); ?>" <?php selected( $version, $webhook->get_api_version(), true ); ?>>
<?php
/* translators: %d: rest api version number */
echo esc_html( sprintf( __( 'WP REST API Integration v%d', 'woocommerce' ), str_replace( 'wp_api_v', '', $version ) ) );
?>
</option>
<?php endforeach; ?>
<?php
$legacy_api_option_name =
is_null( wc()->api ) ?
__( 'Legacy API v3 (⚠️ NOT AVAILABLE)', 'woocommerce' ) :
__( 'Legacy API v3 (deprecated)', 'woocommerce' );
?>
<option value="legacy_v3" <?php selected( 'legacy_v3', $webhook->get_api_version(), true ); ?>><?php echo esc_html( $legacy_api_option_name ); ?></option>
</select>
</td>
</tr>
</tbody>
</table>
<?php
/**
* Fires within the webhook editor, after the Webhook Data fields have rendered.
*
* @param WC_Webhook $webhook
*/
do_action( 'woocommerce_webhook_options', $webhook );
?>
</div>
<div id="webhook-actions" class="settings-panel">
<h2><?php esc_html_e( 'Webhook actions', 'woocommerce' ); ?></h2>
<table class="form-table">
<tbody>
<?php if ( $webhook->get_date_created() && '0000-00-00 00:00:00' !== $webhook->get_date_created()->date( 'Y-m-d H:i:s' ) ) : ?>
<?php if ( is_null( $webhook->get_date_modified() ) ) : ?>
<tr valign="top">
<th scope="row" class="titledesc">
<?php esc_html_e( 'Created at', 'woocommerce' ); ?>
</th>
<td class="forminp">
<?php echo esc_html( date_i18n( __( 'M j, Y @ G:i', 'woocommerce' ), strtotime( $webhook->get_date_created()->date( 'Y-m-d H:i:s' ) ) ) ); ?>
</td>
</tr>
<?php else : ?>
<tr valign="top">
<th scope="row" class="titledesc">
<?php esc_html_e( 'Created at', 'woocommerce' ); ?>
</th>
<td class="forminp">
<?php echo esc_html( date_i18n( __( 'M j, Y @ G:i', 'woocommerce' ), strtotime( $webhook->get_date_created()->date( 'Y-m-d H:i:s' ) ) ) ); ?>
</td>
</tr>
<tr valign="top">
<th scope="row" class="titledesc">
<?php esc_html_e( 'Updated at', 'woocommerce' ); ?>
</th>
<td class="forminp">
<?php echo esc_html( date_i18n( __( 'M j, Y @ G:i', 'woocommerce' ), strtotime( $webhook->get_date_modified()->date( 'Y-m-d H:i:s' ) ) ) ); ?>
</td>
</tr>
<?php endif; ?>
<?php endif; ?>
<tr valign="top">
<td colspan="2" scope="row" style="padding-left: 0;">
<p class="submit">
<button type="submit" class="button button-primary button-large" name="save" id="publish" accesskey="p"><?php esc_html_e( 'Save webhook', 'woocommerce' ); ?></button>
<?php
if ( $webhook->get_id() ) :
$delete_url = wp_nonce_url(
add_query_arg(
array(
'delete' => $webhook->get_id(),
),
admin_url( 'admin.php?page=wc-settings&tab=advanced&section=webhooks' )
),
'delete-webhook'
);
?>
<a style="color: #a00; text-decoration: none; margin-left: 10px;" href="<?php echo esc_url( $delete_url ); ?>"><?php esc_html_e( 'Delete permanently', 'woocommerce' ); ?></a>
<?php endif; ?>
</p>
</td>
</tr>
</tbody>
</table>
</div>
<script type="text/javascript">
jQuery( function ( $ ) {
$( '#webhook-options' ).find( '#webhook_topic' ).on( 'change', function() {
var current = $( this ).val(),
action_event_field = $( '#webhook-options' ).find( '#webhook-action-event-wrap' );
action_event_field.hide();
if ( 'action' === current ) {
action_event_field.show();
}
}).trigger( 'change' );
});
</script>

View File

@@ -0,0 +1,136 @@
<?php
/**
* Tax settings.
*
* @package WooCommerce\Admin\Settings.
*/
defined( 'ABSPATH' ) || exit;
$settings = array(
array(
'title' => __( 'Tax options', 'woocommerce' ),
'type' => 'title',
'desc' => '',
'id' => 'tax_options',
),
array(
'title' => __( 'Prices entered with tax', 'woocommerce' ),
'id' => 'woocommerce_prices_include_tax',
'default' => 'no',
'type' => 'radio',
'desc_tip' => __( 'This option is important as it will affect how you input prices. Changing it will not update existing products.', 'woocommerce' ),
'options' => array(
'yes' => __( 'Yes, I will enter prices inclusive of tax', 'woocommerce' ),
'no' => __( 'No, I will enter prices exclusive of tax', 'woocommerce' ),
),
),
array(
'title' => __( 'Calculate tax based on', 'woocommerce' ),
'id' => 'woocommerce_tax_based_on',
'desc_tip' => __( 'This option determines which address is used to calculate tax.', 'woocommerce' ),
'default' => 'shipping',
'type' => 'select',
'class' => 'wc-enhanced-select',
'options' => array(
'shipping' => __( 'Customer shipping address', 'woocommerce' ),
'billing' => __( 'Customer billing address', 'woocommerce' ),
'base' => __( 'Shop base address', 'woocommerce' ),
),
),
'shipping-tax-class' => array(
'title' => __( 'Shipping tax class', 'woocommerce' ),
'desc' => __( 'Optionally control which tax class shipping gets, or leave it so shipping tax is based on the cart items themselves.', 'woocommerce' ),
'id' => 'woocommerce_shipping_tax_class',
'css' => 'min-width:150px;',
'default' => 'inherit',
'type' => 'select',
'class' => 'wc-enhanced-select',
'options' => array( 'inherit' => __( 'Shipping tax class based on cart items', 'woocommerce' ) ) + wc_get_product_tax_class_options(),
'desc_tip' => true,
),
array(
'title' => __( 'Rounding', 'woocommerce' ),
'desc' => __( 'Round tax at subtotal level, instead of rounding per line', 'woocommerce' ),
'id' => 'woocommerce_tax_round_at_subtotal',
'default' => 'no',
'type' => 'checkbox',
),
array(
'title' => __( 'Additional tax classes', 'woocommerce' ),
'desc_tip' => __( 'List additional tax classes you need below (1 per line, e.g. Reduced Rates). These are in addition to "Standard rate" which exists by default.', 'woocommerce' ),
'id' => 'woocommerce_tax_classes',
'css' => 'height: 65px;',
'type' => 'textarea',
'default' => '',
'is_option' => false,
'value' => implode( "\n", WC_Tax::get_tax_classes() ),
),
array(
'title' => __( 'Display prices in the shop', 'woocommerce' ),
'id' => 'woocommerce_tax_display_shop',
'default' => 'excl',
'type' => 'select',
'class' => 'wc-enhanced-select',
'options' => array(
'incl' => __( 'Including tax', 'woocommerce' ),
'excl' => __( 'Excluding tax', 'woocommerce' ),
),
),
array(
'title' => __( 'Display prices during cart and checkout', 'woocommerce' ),
'id' => 'woocommerce_tax_display_cart',
'default' => 'excl',
'type' => 'select',
'class' => 'wc-enhanced-select',
'options' => array(
'incl' => __( 'Including tax', 'woocommerce' ),
'excl' => __( 'Excluding tax', 'woocommerce' ),
),
),
array( 'type' => 'conflict_error' ), // React mount point for embedded banner slotfill.
array( 'type' => 'add_settings_slot' ), // React mount point for settings slotfill.
array(
'title' => __( 'Price display suffix', 'woocommerce' ),
'id' => 'woocommerce_price_display_suffix',
'default' => '',
'placeholder' => __( 'N/A', 'woocommerce' ),
'type' => 'text',
'desc_tip' => __( 'Define text to show after your product prices. This could be, for example, "inc. Vat" to explain your pricing. You can also have prices substituted here using one of the following: {price_including_tax}, {price_excluding_tax}.', 'woocommerce' ),
),
array(
'title' => __( 'Display tax totals', 'woocommerce' ),
'id' => 'woocommerce_tax_total_display',
'default' => 'itemized',
'type' => 'select',
'class' => 'wc-enhanced-select',
'options' => array(
'single' => __( 'As a single total', 'woocommerce' ),
'itemized' => __( 'Itemized', 'woocommerce' ),
),
'autoload' => false,
),
array(
'type' => 'sectionend',
'id' => 'tax_options',
),
);
if ( ! wc_shipping_enabled() ) {
unset( $settings['shipping-tax-class'] );
}
return apply_filters( 'woocommerce_tax_settings', $settings );