File: /home/mciraet/www/wp-content/plugins/polylang-wc/src/admin/admin-wc-install.php
<?php
/**
* @package Polylang-WC
*/
/**
* Allows to automatically install the translations of the WooCommerce default pages.
* Manages the installation of the default product category.
*
* @since 0.1
*/
class PLLWC_Admin_WC_Install {
/**
* List of WooCommerce pages in all languages.
*
* @var array<string, array<string, array<string, string>>>
*/
private $pages = array();
/**
* Constructor.
*
* @since 0.1
*/
public function __construct() {
// Add post state for translations of the shop, cart, etc...
add_filter( 'display_post_states', array( $this, 'display_post_states' ), 10, 2 );
// Allow WC to install the default pages and their translations through status page.
add_filter( 'woocommerce_debug_tools', array( $this, 'debug_tools' ) );
// Make sure to load only on setup wizard as initializing translated pages is expensive.
if ( isset( $_GET['page'], $_GET['path'] ) && 'wc-admin' === $_GET['page'] && '/setup-wizard' === $_GET['path'] ) { // phpcs:ignore WordPress.Security.NonceVerification
$this->init_translated_pages();
if ( ! empty( $this->pages ) ) {
add_action( 'init', array( $this, 'translate_default_wc_pages' ) ); // $wp_rewrite is not available yet and is required when wp_unique_post_slug() is called, so we need to wait for init.
}
}
// Add default product category when adding a new language.
add_action( 'pll_add_language', array( $this, 'add_language' ) );
}
/**
* Translates the default WooCommerce pages in all existing languages.
*
* @since 1.7
*
* @return void
*/
public function translate_default_wc_pages() {
foreach ( pll_languages_list() as $lang ) {
foreach ( array_keys( $this->pages[ $lang ] ) as $key ) {
$this->translate_page( $key, $lang );
}
}
}
/**
* Add post states for the translations of the shop, cart, checkout, account and terms pages.
*
* @since 0.9
*
* @param string[] $post_states List of post display states.
* @param WP_Post $post The post object.
* @return string[]
*/
public function display_post_states( $post_states, $post ) {
if ( in_array( $post->ID, pll_get_post_translations( wc_get_page_id( 'shop' ) ) ) ) {
$post_states['wc_page_for_shop'] = __( 'Shop Page', 'polylang-wc' );
}
if ( in_array( $post->ID, pll_get_post_translations( wc_get_page_id( 'cart' ) ) ) ) {
$post_states['wc_page_for_cart'] = __( 'Cart Page', 'polylang-wc' );
}
if ( in_array( $post->ID, pll_get_post_translations( wc_get_page_id( 'checkout' ) ) ) ) {
$post_states['wc_page_for_checkout'] = __( 'Checkout Page', 'polylang-wc' );
}
if ( in_array( $post->ID, pll_get_post_translations( wc_get_page_id( 'myaccount' ) ) ) ) {
$post_states['wc_page_for_myaccount'] = __( 'My Account Page', 'polylang-wc' );
}
if ( in_array( $post->ID, pll_get_post_translations( wc_get_page_id( 'terms' ) ) ) ) {
$post_states['wc_page_for_terms'] = __( 'Terms and Conditions Page', 'polylang-wc' );
}
return $post_states;
}
/**
* Replaces the Install WooCommerce Pages tool by our own to be able to create translations.
*
* @since 0.1
*
* @param array $tools List of available tools.
* @return array
*/
public function debug_tools( $tools ) {
$n = array_search( 'install_pages', array_keys( $tools ) );
if ( false === $n ) {
return $tools;
}
$end = array_slice( $tools, $n + 1 );
$tools = array_slice( $tools, 0, $n );
$tools['pll_install_pages'] = array(
'name' => __( 'Install WooCommerce pages', 'polylang-wc' ),
'button' => __( 'Install pages', 'polylang-wc' ),
'desc' => sprintf(
'<strong class="red">%1$s</strong> %2$s',
__( 'Note:', 'polylang-wc' ),
__( 'This tool will install all the missing WooCommerce pages. Pages already defined and set up will not be replaced.', 'polylang-wc' )
),
'callback' => array( $this, 'install_pages' ),
);
return array_merge( $tools, $end );
}
/**
* Initializes the page names and content in all available languages.
* The method does not actually create the pages.
*
* It implements its own locale switch rather than using switch_to_locale()
* for performance reasons as we only need our own translations.
*
* @since 0.1
*
* @return void
*/
public function init_translated_pages() {
/** @var PLL_Language $language */
foreach ( pll_languages_list( array( 'fields' => '' ) ) as $language ) {
// Load all text domains in the new language.
switch_to_locale( $language->locale );
/*
* Partly copy paste of WC_Install::create_pages that we can't use it directly
* because Woocommerce checks for the unicity of each page.
*/
$this->pages[ $language->slug ] = apply_filters(
'woocommerce_create_pages',
array(
'shop' => array(
'name' => _x( 'shop', 'Page slug', 'polylang-wc' ),
'title' => _x( 'Shop', 'Page title', 'polylang-wc' ),
'content' => '',
),
'cart' => array(
'name' => _x( 'cart', 'Page slug', 'polylang-wc' ),
'title' => _x( 'Cart', 'Page title', 'polylang-wc' ),
'content' => '[' . apply_filters( 'woocommerce_cart_shortcode_tag', 'woocommerce_cart' ) . ']',
),
'checkout' => array(
'name' => _x( 'checkout', 'Page slug', 'polylang-wc' ),
'title' => _x( 'Checkout', 'Page title', 'polylang-wc' ),
'content' => '[' . apply_filters( 'woocommerce_checkout_shortcode_tag', 'woocommerce_checkout' ) . ']',
),
'myaccount' => array(
'name' => _x( 'my-account', 'Page slug', 'polylang-wc' ),
'title' => _x( 'My account', 'Page title', 'polylang-wc' ),
'content' => '[' . apply_filters( 'woocommerce_my_account_shortcode_tag', 'woocommerce_my_account' ) . ']',
),
)
);
}
// Reloads the current text domains.
restore_current_locale();
}
/**
* Install pages from the WooCommerce status tools when using the "Install pages" button.
*
* @since 0.1
*
* @return string
*/
public function install_pages() {
// Let WooCommerce create the pages in the default language.
WC_Install::create_pages();
$this->init_translated_pages();
$default_language = pll_default_language();
// In case pages were installed before Polylang, the pages may have no language. We must assign one.
foreach ( array_keys( $this->pages[ $default_language ] ) as $key ) {
$post_id = wc_get_page_id( $key );
if ( ! pll_get_post_language( $post_id ) ) {
pll_set_post_language( $post_id, (string) $default_language );
}
}
// Then translate them.
$this->translate_default_wc_pages();
return __( 'All missing WooCommerce pages successfully installed', 'polylang-wc' );
}
/**
* Creates a page translation.
*
* @since 0.1
*
* @param string $page WooCommerce Page slug.
* @param string $lang Language slug.
* @return void
*/
public function translate_page( $page, $lang ) {
$post_id = wc_get_page_id( $page );
if ( $post_id < 0 ) {
// The given page doesn't exist.
return;
}
$translations = pll_get_post_translations( $post_id );
// Create the translation only if it doesn't exist yet.
if ( ! empty( $translations[ $lang ] ) ) {
return;
}
$post = get_post( $post_id, ARRAY_A );
unset( $post['ID'] );
// FIXME post parent?
$post['post_title'] = $this->pages[ $lang ][ $page ]['title'];
$post['post_status'] = 'draft'; // Keep it draft before we set the language, to correctly handle auto added pages to menu.
$tr_id = wp_insert_post( wp_slash( $post ) );
if ( empty( $tr_id ) ) {
return;
}
// Assign the language and translations.
pll_set_post_language( $tr_id, $lang );
$translations[ $lang ] = $tr_id;
pll_save_post_translations( $translations );
$tr_post = get_post( $tr_id );
if ( empty( $tr_post ) ) {
return;
}
/*
* We can now publish the page which will also add it to menus if auto add pages to menu is checked
* and attempt to share the slug if needed ( to do after the language has been set ).
*/
$tr_post->post_name = $this->pages[ $lang ][ $page ]['name'];
$tr_post->post_status = 'publish';
wp_update_post( $tr_post );
}
/**
* Creates a default product category for a language.
*
* @since 0.9.3
*
* @param string $lang Language code.
* @return void
*/
protected static function create_default_product_cat( $lang ) {
$default = get_option( 'default_product_cat' );
if ( empty( $default ) || ! is_numeric( $default ) ) {
return;
}
$default = (int) $default;
if ( pll_get_term( $default, $lang ) ) {
return;
}
$name = _x( 'Uncategorized', 'Default category slug', 'polylang-wc' );
$slug = sanitize_title( $name . '-' . $lang );
$cat = wp_insert_term( $name, 'product_cat', array( 'slug' => $slug ) );
// Bail in case of database error, but continue if we got a term.
if ( is_wp_error( $cat ) && array_key_exists( 'term_exists', $cat->errors ) && isset( $cat->error_data['term_exists'] ) ) {
$cat_id = $cat->error_data['term_exists'];
} elseif ( is_array( $cat ) ) {
$cat_id = $cat['term_id'];
}
if ( empty( $cat_id ) ) {
return;
}
// Assign the language and translations.
pll_set_term_language( (int) $cat_id, $lang );
$translations = pll_get_term_translations( $default );
$translations[ $lang ] = $cat_id;
pll_save_term_translations( $translations );
}
/**
* Creates a default product category when adding a language.
*
* @since 0.9.3
*
* @param array $args New language arguments.
* @return void
*/
public function add_language( $args ) {
$default = get_option( 'default_product_cat' );
if ( empty( $default ) || ! is_numeric( $default ) ) {
return;
}
$default = (int) $default;
$default_cat_lang = pll_get_term_language( $default );
// Assign a default language to the default product category.
if ( empty( $default_cat_lang ) ) {
pll_set_term_language( $default, (string) pll_default_language() );
} else {
self::create_default_product_cat( $args['slug'] );
}
}
/**
* Assigns the default language to the default product category
* and creates translated default categories.
*
* @since 0.9.3
*
* @return void
*/
public static function create_default_product_cats() {
$default = get_option( 'default_product_cat' );
if ( empty( $default ) || ! is_numeric( $default ) ) {
return;
}
$default = (int) $default;
$default_cat_lang = pll_get_term_language( $default );
// Assign a default language to default product category.
if ( empty( $default_cat_lang ) ) {
pll_set_term_language( $default, (string) pll_default_language() );
}
foreach ( pll_languages_list() as $language ) {
if ( $language !== $default_cat_lang && ! pll_get_term( $default, $language ) ) {
self::create_default_product_cat( $language );
}
}
}
/**
* Replaces the Uncategorized product cat in default language by the correct translation.
*
* @since 0.9.3
*
* @return void
*/
public static function replace_default_product_cats() {
global $wpdb;
$default = get_option( 'default_product_cat' );
if ( empty( $default ) || ! is_numeric( $default ) ) {
return;
}
$default_category = get_term( (int) $default, 'product_cat' );
if ( ! $default_category instanceof WP_Term ) {
return;
}
foreach ( PLL()->model->get_languages_list() as $language ) {
if ( pll_default_language() === $language->slug ) {
continue;
}
$tr_cat = pll_get_term( $default_category->term_id, $language->slug );
if ( empty( $tr_cat ) ) {
continue;
}
$tr_cat = get_term( $tr_cat, 'product_cat' );
if ( ! $tr_cat instanceof WP_Term ) {
continue;
}
$wpdb->query(
$wpdb->prepare(
"UPDATE {$wpdb->term_relationships} as tr1
JOIN {$wpdb->term_relationships} as tr2 ON tr1.object_id = tr2.object_id
AND tr2.term_taxonomy_id = %d
SET tr1.term_taxonomy_id = %d
WHERE tr1.term_taxonomy_id = %d",
$language->get_tax_prop( 'language', 'term_taxonomy_id' ),
$tr_cat->term_taxonomy_id,
$default_category->term_taxonomy_id
)
);
}
wp_cache_flush();
delete_transient( 'wc_term_counts' );
wp_update_term_count_now( pll_get_term_translations( $default_category->term_id ), 'product_cat' );
}
/**
* Updates the default product categories after update to WooCommerce 3.3.
*
* @since 0.9.3
*
* @param string $option Option name.
* @param string $value WooCommerce DB version.
* @return void
*/
public static function update_330_wc_db_version( $option, $value ) {
if ( version_compare( $value, '3.3.0', '>=' ) ) {
self::replace_default_product_cats();
}
}
}