You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
580 lines
15 KiB
580 lines
15 KiB
<?php
|
|
/**
|
|
* Polylang for WooCommerce
|
|
*
|
|
* @package Polylang-WC
|
|
* @author WP SYNTEX
|
|
* @license GPL-3.0-or-later
|
|
*
|
|
* @wordpress-plugin
|
|
* Plugin name: Polylang for WooCommerce
|
|
* Plugin URI: https://polylang.pro
|
|
* Description: Adds multilingual capability to WooCommerce
|
|
* Version: 2.1
|
|
* Requires at least: 6.3
|
|
* Requires PHP: 7.4
|
|
* Author: WP SYNTEX
|
|
* Author URI: https://polylang.pro
|
|
* Text Domain: polylang-wc
|
|
* Domain Path: /languages
|
|
* License: GPL v3 or later
|
|
* License URI: https://www.gnu.org/licenses/gpl-3.0.txt
|
|
*
|
|
* WC requires at least: 8.5
|
|
* WC tested up to: 9.3
|
|
*
|
|
* Copyright 2016-2020 Frédéric Demarle
|
|
* Copyright 2020-2024 WP SYNTEX
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
if ( ! defined( 'ABSPATH' ) ) {
|
|
exit; // Don't access directly.
|
|
}
|
|
|
|
define( 'PLLWC_VERSION', '2.1' );
|
|
define( 'PLLWC_MIN_PLL_VERSION', '3.4' );
|
|
|
|
define( 'PLLWC_FILE', __FILE__ ); // This file.
|
|
define( 'PLLWC_BASENAME', plugin_basename( PLLWC_FILE ) ); // Plugin name as known by WP.
|
|
|
|
require_once __DIR__ . '/vendor/autoload.php';
|
|
require_once __DIR__ . '/include/functions.php';
|
|
|
|
use Automattic\WooCommerce\Utilities\OrderUtil;
|
|
|
|
/**
|
|
* Plugin controller.
|
|
*
|
|
* @since 0.1
|
|
*/
|
|
class Polylang_Woocommerce {
|
|
/**
|
|
* @var PLLWC_Admin_Menus
|
|
*/
|
|
public $admin_menus;
|
|
|
|
/**
|
|
* @var PLLWC_Admin_Products
|
|
*/
|
|
public $admin_products;
|
|
|
|
/**
|
|
* @var PLLWC_Admin_Product_Duplicate
|
|
*/
|
|
public $admin_product_duplicate;
|
|
|
|
/**
|
|
* @var PLLWC_Admin_Orders
|
|
*/
|
|
public $admin_orders;
|
|
|
|
/**
|
|
* @var PLLWC_Admin_Reports
|
|
*/
|
|
public $admin_reports;
|
|
|
|
/**
|
|
* @var PLLWC_Admin_Status_Reports
|
|
*/
|
|
public $admin_status_reports;
|
|
|
|
/**
|
|
* @var PLLWC_Admin_Taxonomies
|
|
*/
|
|
public $admin_taxonomies;
|
|
|
|
/**
|
|
* @var PLLWC_Admin_WC_Install
|
|
*/
|
|
public $admin_wc_install;
|
|
|
|
/**
|
|
* @var PLLWC_Frontend_Cart
|
|
*/
|
|
public $cart;
|
|
|
|
/**
|
|
* @var PLLWC_Coupons
|
|
*/
|
|
public $coupons;
|
|
|
|
/**
|
|
* @var PLLWC_Xdata
|
|
*/
|
|
public $data;
|
|
|
|
/**
|
|
* @var PLLWC_Emails
|
|
*/
|
|
public $emails;
|
|
|
|
/**
|
|
* @var PLLWC_Product_Export
|
|
*/
|
|
public $product_export;
|
|
|
|
/**
|
|
* @var PLLWC_Frontend
|
|
*/
|
|
public $frontend;
|
|
|
|
/**
|
|
* @var PLLWC_Product_Import
|
|
*/
|
|
public $product_import;
|
|
|
|
/**
|
|
* @var PLLWC_Links
|
|
*/
|
|
public $links;
|
|
|
|
/**
|
|
* @var PLLWC_Frontend_Account
|
|
*/
|
|
public $my_account;
|
|
|
|
/**
|
|
* @var PLLWC_Post_Types
|
|
*/
|
|
public $post_types;
|
|
|
|
/**
|
|
* @var PLLWC_Products
|
|
*/
|
|
public $products;
|
|
|
|
/**
|
|
* @var PLLWC_REST_API
|
|
*/
|
|
public $rest_api;
|
|
|
|
/**
|
|
* @var PLLWC_Admin_Site_Health
|
|
*/
|
|
public $site_health;
|
|
|
|
/**
|
|
* @var PLLWC_Stock
|
|
*/
|
|
public $stock;
|
|
|
|
/**
|
|
* @var PLLWC_Strings
|
|
*/
|
|
public $strings;
|
|
|
|
/**
|
|
* @var PLLWC_Sync_Content
|
|
*/
|
|
public $sync_content;
|
|
|
|
/**
|
|
* @var PLLWC_Frontend_WC_Pages
|
|
*/
|
|
public $wc_pages;
|
|
|
|
/**
|
|
* @var PLLWC_Wizard
|
|
*/
|
|
public $wizard;
|
|
|
|
/**
|
|
* @var PLLWC_Translation_Export|null
|
|
*/
|
|
public $translation_export;
|
|
|
|
/**
|
|
* @var PLLWC_Translation_Import|null
|
|
*/
|
|
public $translation_import;
|
|
|
|
/**
|
|
* @var PLLWC_HPOS_Orders_Query|null
|
|
*/
|
|
public $hpos_orders_query;
|
|
|
|
/**
|
|
* @var PLLWC_Feature|null
|
|
*/
|
|
public $hpos_feature;
|
|
|
|
/**
|
|
* @var PLLWC_Store_Blocks
|
|
*/
|
|
public $blocks;
|
|
|
|
/**
|
|
* Singleton.
|
|
*
|
|
* @var Polylang_Woocommerce
|
|
*/
|
|
protected static $instance;
|
|
|
|
/**
|
|
* Constructor.
|
|
*
|
|
* @since 0.1
|
|
*/
|
|
public function __construct() {
|
|
// Registers an action when the plugin is activated.
|
|
add_action( 'activated_plugin', array( $this, 'activated_plugin' ), 10, 2 );
|
|
|
|
$install = new PLLWC_Install( plugin_basename( __FILE__ ) );
|
|
|
|
// Stopping here if we are going to deactivate the plugin ( avoids breaking rewrite rules ).
|
|
if ( $install->is_deactivation() ) {
|
|
return;
|
|
}
|
|
|
|
// WC 3.3: Maybe update default product categories after WooCommerce did it.
|
|
$db_version = get_option( 'woocommerce_db_version' );
|
|
if ( is_string( $db_version ) && version_compare( $db_version, '3.3.0', '<' ) ) {
|
|
add_action( 'add_option_woocommerce_db_version', array( 'PLLWC_Admin_WC_Install', 'update_330_wc_db_version' ), 10, 2 );
|
|
}
|
|
|
|
/*
|
|
* Fix home url when using plain permalinks and the shop is on front.
|
|
* Added here because the filter is fired before the action 'pll_init'.
|
|
*/
|
|
add_filter( 'pll_additional_language_data', array( 'PLLWC_Links', 'set_home_url' ), 20, 2 ); // After Polylang.
|
|
|
|
add_filter( 'pll_is_ajax_on_front', array( $this, 'fix_ajax_product_import' ) );
|
|
|
|
// The "ajax" request for feature product is indeed a direct link and thus does not include the pll_ajax_backend query var.
|
|
if ( isset( $_GET['action'] ) && 'woocommerce_feature_product' === $_GET['action'] ) { // phpcs:ignore WordPress.Security.NonceVerification
|
|
define( 'PLL_ADMIN', true );
|
|
}
|
|
|
|
// Before Polylang is loaded.
|
|
add_action( 'plugins_loaded', array( $this, 'declare_features_compatibility' ), 0 );
|
|
|
|
add_action( 'pll_init', array( $this, 'init' ) );
|
|
PLLWC_Plugins_Compat::instance();
|
|
}
|
|
|
|
/**
|
|
* Get the Polylang for WooCommerce instance.
|
|
*
|
|
* @since 0.1
|
|
*
|
|
* @return Polylang_Woocommerce
|
|
*/
|
|
public static function instance() {
|
|
if ( empty( self::$instance ) ) {
|
|
self::$instance = new self();
|
|
}
|
|
return self::$instance;
|
|
}
|
|
|
|
/**
|
|
* Tells Polylang that the product import ajax request is made from the backend.
|
|
*
|
|
* @since 1.5.3
|
|
*
|
|
* @param bool $is_ajax_on_front Whether the current request is an ajax request on front.
|
|
* @return bool
|
|
*/
|
|
public function fix_ajax_product_import( $is_ajax_on_front ) {
|
|
return isset( $_POST['action'] ) && 'woocommerce_do_ajax_product_import' === $_POST['action'] ? false : $is_ajax_on_front; // phpcs:ignore WordPress.Security.NonceVerification
|
|
}
|
|
|
|
/**
|
|
* Initializes the plugin.
|
|
*
|
|
* @since 0.1
|
|
*
|
|
* @return void
|
|
*/
|
|
public function init() {
|
|
// Silently disable the plugin if WooCommerce are not active.
|
|
if ( ! defined( 'WOOCOMMERCE_VERSION' ) ) {
|
|
return;
|
|
}
|
|
|
|
// If the version of Polylang is too old.
|
|
if ( version_compare( POLYLANG_VERSION, PLLWC_MIN_PLL_VERSION, '<' ) ) {
|
|
add_action( 'all_admin_notices', array( $this, 'admin_notices' ) );
|
|
return;
|
|
}
|
|
|
|
if ( PLL() instanceof PLL_Admin_Base ) {
|
|
new PLL_License( __FILE__, 'Polylang for WooCommerce', PLLWC_VERSION, 'Frédéric Demarle' );
|
|
new PLL_T15S( 'polylang-wc', 'https://packages.translationspress.com/wp-syntex/polylang-wc/packages.json' );
|
|
}
|
|
|
|
// Instantiate PLL_Wizard before any language test to display the WooCommerce step in the Wizard.
|
|
if ( PLL() instanceof PLL_Admin_Base ) {
|
|
if ( class_exists( 'PLL_Wizard' ) && Polylang::is_wizard() && isset( PLL()->wizard ) ) {
|
|
$this->wizard = new PLLWC_Wizard( PLL()->model, PLL()->wizard );
|
|
}
|
|
$this->admin_status_reports = new PLLWC_Admin_Status_Reports();
|
|
load_plugin_textdomain( 'polylang-wc' );
|
|
}
|
|
|
|
add_action( 'admin_init', array( $this, 'maybe_install' ) );
|
|
|
|
// Bail early if no language has been defined yet.
|
|
if ( ! pll_languages_list() ) {
|
|
return;
|
|
}
|
|
|
|
// Custom order tables for WooCommerce (HPOS).
|
|
if ( ! empty( $this->hpos_feature ) && $this->hpos_feature->is_enabled() ) {
|
|
$this->hpos_orders_query = ( new PLLWC_HPOS_Orders_Query() )->init();
|
|
}
|
|
|
|
add_action( 'admin_init', array( $this, 'maybe_upgrade' ) );
|
|
|
|
add_action( 'woocommerce_delete_product_transients', array( $this, 'delete_product_transients' ) );
|
|
|
|
PLLWC_Variation_Data_Store_CPT::init();
|
|
|
|
$this->post_types = new PLLWC_Post_Types();
|
|
$this->links = defined( 'POLYLANG_PRO' ) && POLYLANG_PRO && get_option( 'permalink_structure' ) ? new PLLWC_Links_Pro() : new PLLWC_Links();
|
|
$this->stock = new PLLWC_Stock();
|
|
$this->emails = new PLLWC_Emails();
|
|
$this->strings = new PLLWC_Strings();
|
|
$this->data = new PLLWC_Xdata();
|
|
$this->product_export = new PLLWC_Product_Export();
|
|
$this->product_import = new PLLWC_Product_Import();
|
|
$this->products = new PLLWC_Products();
|
|
$this->blocks = new PLLWC_Store_Blocks();
|
|
|
|
$this->blocks->init();
|
|
|
|
if ( defined( 'POLYLANG_PRO' ) && POLYLANG_PRO ) {
|
|
$this->rest_api = new PLLWC_REST_API();
|
|
$this->sync_content = new PLLWC_Sync_Content();
|
|
}
|
|
|
|
/*
|
|
* We need to load our cart integration on all ajax requests, as WooCommerce does,
|
|
* but also on REST requests for WooCommerce Blocks 2.5+.
|
|
*/
|
|
if ( PLL() instanceof PLL_Frontend || wp_doing_ajax() || PLL() instanceof PLL_REST_Request ) {
|
|
$this->cart = new PLLWC_Frontend_Cart();
|
|
}
|
|
|
|
// Frontend only.
|
|
if ( PLL() instanceof PLL_Frontend ) {
|
|
$this->frontend = new PLLWC_Frontend();
|
|
$this->my_account = new PLLWC_Frontend_Account();
|
|
$this->coupons = new PLLWC_Coupons();
|
|
|
|
// WC pages on front.
|
|
if ( 'page' === get_option( 'show_on_front' ) ) {
|
|
$this->wc_pages = new PLLWC_Frontend_WC_Pages();
|
|
}
|
|
} else {
|
|
$this->admin_wc_install = new PLLWC_Admin_WC_Install();
|
|
|
|
// Admin only ( but not useful on Polylang settings pages ).
|
|
if ( PLL() instanceof PLL_Admin ) {
|
|
$this->admin_taxonomies = new PLLWC_Admin_Taxonomies();
|
|
$this->admin_products = new PLLWC_Admin_Products();
|
|
$this->admin_product_duplicate = new PLLWC_Admin_Product_Duplicate();
|
|
$this->admin_orders = ! empty( $this->hpos_feature ) && $this->hpos_feature->is_enabled() ? new PLLWC_Admin_Orders_HPOS() : new PLLWC_Admin_Orders_Legacy();
|
|
$this->admin_reports = new PLLWC_Admin_Reports();
|
|
$this->admin_menus = new PLLWC_Admin_Menus();
|
|
$this->coupons = new PLLWC_Admin_Coupons();
|
|
$this->site_health = new PLLWC_Admin_Site_Health();
|
|
|
|
if ( defined( 'POLYLANG_PRO' ) && POLYLANG_PRO ) {
|
|
$this->translation_export = ( new PLLWC_Translation_Export() )->init();
|
|
}
|
|
|
|
add_action( 'woocommerce_system_status_report', array( $this->admin_status_reports, 'status_report' ) );
|
|
add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) );
|
|
}
|
|
|
|
if ( PLL() instanceof PLL_Settings && defined( 'POLYLANG_PRO' ) && POLYLANG_PRO ) {
|
|
$this->translation_import = ( new PLLWC_Translation_Import() )->init();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Fires after the Polylang for WooCommerce object is initialized.
|
|
*
|
|
* @since 0.3.2
|
|
*
|
|
* @param object &$this The Polylang for WooCommerce object.
|
|
*/
|
|
do_action_ref_array( 'pllwc_init', array( &$this ) );
|
|
}
|
|
|
|
/**
|
|
* Displays an admin notice if Polylang is not at the right version.
|
|
*
|
|
* @since 0.1
|
|
*
|
|
* @return void
|
|
*/
|
|
public function admin_notices() {
|
|
load_plugin_textdomain( 'polylang-wc' );
|
|
printf(
|
|
'<div class="error"><p>%s</p><p>%s</p></div>',
|
|
esc_html(
|
|
sprintf(
|
|
/* translators: %s is the plugin name (Polylang or Polylang Pro) */
|
|
__( 'Polylang for WooCommerce has been deactivated because you are using an old version of %s.', 'polylang-wc' ),
|
|
POLYLANG
|
|
)
|
|
),
|
|
esc_html(
|
|
sprintf(
|
|
/* translators: %1$s and %2$s are plugin version numbers, %3$s is the plugin name (Polylang or Polylang Pro) */
|
|
__( 'You are using %3$s %1$s. Polylang for WooCommerce requires at least %3$s %2$s.', 'polylang-wc' ),
|
|
POLYLANG_VERSION,
|
|
PLLWC_MIN_PLL_VERSION,
|
|
POLYLANG
|
|
)
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Manages updates of the plugin.
|
|
*
|
|
* @since 0.9.3
|
|
*
|
|
* @return void
|
|
*/
|
|
public function maybe_upgrade() {
|
|
$options = get_option( 'polylang-wc' );
|
|
|
|
if ( is_array( $options ) && version_compare( $options['version'], PLLWC_VERSION, '<' ) ) {
|
|
// Version 0.4.3.
|
|
if ( version_compare( $options['version'], '0.4.3', '<' ) ) {
|
|
delete_transient( 'woocommerce_cache_excluded_uris' );
|
|
}
|
|
|
|
// Version 0.4.6.
|
|
if ( version_compare( $options['version'], '0.4.6', '<' ) ) {
|
|
// Same as Polylang 2.0.8, for WP 4.7.
|
|
global $wpdb;
|
|
$wpdb->update( $wpdb->usermeta, array( 'meta_key' => 'locale' ), array( 'meta_key' => 'user_lang' ) );
|
|
}
|
|
|
|
// Version 0.9.3, if already updated to WC 3.3.
|
|
if ( version_compare( $options['version'], '0.9.3', '<' ) ) {
|
|
if ( version_compare( WC()->version, '3.3.0', '>=' ) ) {
|
|
PLLWC_Admin_WC_Install::create_default_product_cats();
|
|
PLLWC_Admin_WC_Install::replace_default_product_cats();
|
|
}
|
|
}
|
|
|
|
$options['previous_version'] = $options['version']; // Remember the previous version.
|
|
$options['version'] = PLLWC_VERSION;
|
|
update_option( 'polylang-wc', $options );
|
|
}
|
|
|
|
PLLWC_Admin_WC_Install::create_default_product_cats();
|
|
}
|
|
|
|
/**
|
|
* Manage plugin set up.
|
|
*
|
|
* @since 1.5.7
|
|
*
|
|
* @return void
|
|
*/
|
|
public function maybe_install() {
|
|
$options = get_option( 'polylang-wc' );
|
|
|
|
if ( empty( $options ) ) {
|
|
$options = array( 'version' => PLLWC_VERSION );
|
|
update_option( 'polylang-wc', $options );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Clear all transients cache for translations when WC clears a product transient.
|
|
*
|
|
* @since 0.4.5
|
|
*
|
|
* @param int $product_id Product ID.
|
|
* @return void
|
|
*/
|
|
public function delete_product_transients( $product_id ) {
|
|
static $ids;
|
|
$ids[] = $product_id;
|
|
|
|
$data_store = PLLWC_Data_Store::load( 'product_language' );
|
|
foreach ( $data_store->get_translations( $product_id ) as $tr_id ) {
|
|
if ( ! in_array( $tr_id, $ids ) ) {
|
|
wc_delete_product_transients( $tr_id );
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Enqueues the stylesheet.
|
|
*
|
|
* @since 0.1
|
|
*
|
|
* @return void
|
|
*/
|
|
public function admin_enqueue_scripts() {
|
|
$suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
|
|
wp_enqueue_style( 'pll_wc_admin', plugins_url( '/css/build/admin' . $suffix . '.css', PLLWC_FILE ), array(), PLLWC_VERSION );
|
|
}
|
|
|
|
/**
|
|
* Saves a transient when Polylang For WooCommerce is activating to redirect to the Polylang wizard.
|
|
*
|
|
* @since 1.4
|
|
*
|
|
* @param string $plugin_name Plugin basename.
|
|
* @param bool $network_wide If activated for all sites in the network.
|
|
* @return void
|
|
*/
|
|
public static function activated_plugin( $plugin_name, $network_wide ) {
|
|
$options = get_option( 'polylang-wc' ); // If the polylang-wc option is set, the wizard has already been launched once.
|
|
|
|
if ( wp_doing_ajax() || $network_wide || ! empty( $options ) ) {
|
|
return;
|
|
}
|
|
|
|
if ( PLLWC_BASENAME === $plugin_name && class_exists( 'PLL_Wizard' ) ) {
|
|
set_transient( 'pll_activation_redirect', 1, 30 );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Declares Polylang For WooCommerce compatibility with WooCommerce features.
|
|
*
|
|
* @since 1.9.3
|
|
*
|
|
* @return void
|
|
*/
|
|
public function declare_features_compatibility() {
|
|
// Declare compatibility with custom order tables for WooCommerce (HPOS).
|
|
$this->hpos_feature = new PLLWC_Feature(
|
|
'custom_order_tables',
|
|
// Note: `Automattic\WooCommerce\Utilities\OrderUtil::custom_orders_table_usage_is_enabled()` is introduced in WC 6.9.
|
|
class_exists( OrderUtil::class ) ? array( OrderUtil::class, 'custom_orders_table_usage_is_enabled' ) : '__return_false'
|
|
);
|
|
$this->hpos_feature->declare_compatibility();
|
|
|
|
$cart_checkout_blocks_feature = new PLLWC_Feature(
|
|
'cart_checkout_blocks',
|
|
'__return_true'
|
|
);
|
|
$cart_checkout_blocks_feature->declare_compatibility();
|
|
}
|
|
}
|
|
|
|
PLLWC();
|
|
|