You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
268 lines
7.0 KiB
PHTML
268 lines
7.0 KiB
PHTML
8 months ago
|
<?php
|
||
|
/**
|
||
|
* The product permalink watcher class.
|
||
|
*
|
||
|
* @since 0.9.0
|
||
|
* @package RankMath
|
||
|
* @subpackage RankMath\WooCommerce
|
||
|
* @author Rank Math <support@rankmath.com>
|
||
|
*/
|
||
|
|
||
|
namespace RankMath\WooCommerce;
|
||
|
|
||
|
use RankMath\Helper;
|
||
|
use RankMath\Traits\Hooker;
|
||
|
use RankMath\Helpers\Sitepress;
|
||
|
use RankMath\Helpers\Str;
|
||
|
use RankMath\Helpers\Param;
|
||
|
|
||
|
defined( 'ABSPATH' ) || exit;
|
||
|
|
||
|
/**
|
||
|
* Permalink_Watcher class.
|
||
|
*/
|
||
|
class Permalink_Watcher {
|
||
|
|
||
|
use Hooker;
|
||
|
|
||
|
/**
|
||
|
* Hold product base.
|
||
|
*
|
||
|
* @var string
|
||
|
*/
|
||
|
private $product_base;
|
||
|
|
||
|
/**
|
||
|
* Hold product categories.
|
||
|
*
|
||
|
* @var array
|
||
|
*/
|
||
|
private $categories;
|
||
|
|
||
|
/**
|
||
|
* Remove product base.
|
||
|
*
|
||
|
* @var bool
|
||
|
*/
|
||
|
private $remove_product_base;
|
||
|
|
||
|
/**
|
||
|
* Remove category base.
|
||
|
*
|
||
|
* @var bool
|
||
|
*/
|
||
|
private $remove_category_base;
|
||
|
|
||
|
/**
|
||
|
* Remove parent slugs.
|
||
|
*
|
||
|
* @var bool
|
||
|
*/
|
||
|
private $remove_parent_slugs;
|
||
|
|
||
|
/**
|
||
|
* The Constructor.
|
||
|
*/
|
||
|
public function __construct() {
|
||
|
$this->remove_product_base = Helper::get_settings( 'general.wc_remove_product_base' );
|
||
|
$this->remove_category_base = Helper::get_settings( 'general.wc_remove_category_base' );
|
||
|
$this->remove_parent_slugs = Helper::get_settings( 'general.wc_remove_category_parent_slugs' );
|
||
|
|
||
|
if ( $this->remove_product_base && ! (bool) Param::get( 'elementor-preview' ) ) {
|
||
|
$this->filter( 'post_type_link', 'post_type_link', 1, 2 );
|
||
|
}
|
||
|
|
||
|
if ( $this->remove_category_base || $this->remove_parent_slugs ) {
|
||
|
$this->action( 'created_product_cat', 'flush_rules' );
|
||
|
$this->action( 'delete_product_cat', 'flush_rules' );
|
||
|
$this->action( 'edited_product_cat', 'flush_rules' );
|
||
|
|
||
|
$this->filter( 'term_link', 'term_link', 0, 3 );
|
||
|
$this->filter( 'rewrite_rules_array', 'add_rewrite_rules', 99 );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Flush rewrite rules (soft flush).
|
||
|
*
|
||
|
* @return void
|
||
|
*/
|
||
|
public function flush_rules() {
|
||
|
flush_rewrite_rules( false );
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Replace product permalink according to settings.
|
||
|
*
|
||
|
* @param string $permalink The existing permalink URL.
|
||
|
* @param WP_Post $post WP_Post object.
|
||
|
*
|
||
|
* @return string
|
||
|
*/
|
||
|
public function post_type_link( $permalink, $post ) {
|
||
|
if ( $this->can_change_link( 'product', $post->post_type ) ) {
|
||
|
return $permalink;
|
||
|
}
|
||
|
|
||
|
return str_replace( $this->get_product_base(), '/', $permalink );
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Replace category permalink according to settings.
|
||
|
*
|
||
|
* @param string $link Term link URL.
|
||
|
* @param object $term Term object.
|
||
|
* @param string $taxonomy Taxonomy slug.
|
||
|
*
|
||
|
* @return string
|
||
|
*/
|
||
|
public function term_link( $link, $term, $taxonomy ) {
|
||
|
if ( $this->can_change_link( 'product_cat', $taxonomy ) ) {
|
||
|
return $link;
|
||
|
}
|
||
|
|
||
|
$permalink_structure = wc_get_permalink_structure();
|
||
|
$category_base = trailingslashit( $permalink_structure['category_rewrite_slug'] );
|
||
|
$is_language_switcher = ( class_exists( 'Sitepress' ) && strpos( $link, 'lang=' ) );
|
||
|
|
||
|
if ( $this->remove_category_base ) {
|
||
|
$link = str_replace( $category_base, '', $link );
|
||
|
$category_base = '';
|
||
|
}
|
||
|
|
||
|
if ( $this->remove_parent_slugs && ! $is_language_switcher ) {
|
||
|
$link = home_url( user_trailingslashit( $category_base . $term->slug ) );
|
||
|
}
|
||
|
|
||
|
return $link;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Add rewrite rules.
|
||
|
*
|
||
|
* @param array $rules The compiled array of rewrite rules.
|
||
|
*
|
||
|
* @return array
|
||
|
*/
|
||
|
public function add_rewrite_rules( $rules ) {
|
||
|
global $wp_rewrite;
|
||
|
|
||
|
wp_cache_flush();
|
||
|
|
||
|
/**
|
||
|
* Remove WPML filters while getting terms, to get all languages
|
||
|
*/
|
||
|
Sitepress::get()->remove_term_filters();
|
||
|
|
||
|
$feed = '(' . trim( implode( '|', $wp_rewrite->feeds ) ) . ')';
|
||
|
|
||
|
$permalink_structure = wc_get_permalink_structure();
|
||
|
$category_base = $this->remove_category_base ? '' : $permalink_structure['category_rewrite_slug'];
|
||
|
$use_parent_slug = Str::contains( '%product_cat%', $permalink_structure['product_rewrite_slug'] );
|
||
|
|
||
|
$product_rules = [];
|
||
|
$category_rules = [];
|
||
|
foreach ( $this->get_categories() as $category ) {
|
||
|
$cat_path = $this->get_category_fullpath( $category );
|
||
|
$cat_slug = $category_base . ( $this->remove_parent_slugs ? $category['slug'] : $cat_path );
|
||
|
|
||
|
$category_rules[ "{$cat_slug}/?\$" ] = 'index.php?product_cat=' . $category['slug'];
|
||
|
$category_rules[ "{$cat_slug}/embed/?\$" ] = 'index.php?product_cat=' . $category['slug'] . '&embed=true';
|
||
|
$category_rules[ "{$cat_slug}/{$wp_rewrite->feed_base}/{$feed}/?\$" ] = 'index.php?product_cat=' . $category['slug'] . '&feed=$matches[1]';
|
||
|
$category_rules[ "{$cat_slug}/{$feed}/?\$" ] = 'index.php?product_cat=' . $category['slug'] . '&feed=$matches[1]';
|
||
|
$category_rules[ "{$cat_slug}/{$wp_rewrite->pagination_base}/?([0-9]{1,})/?\$" ] = 'index.php?product_cat=' . $category['slug'] . '&paged=$matches[1]';
|
||
|
|
||
|
if ( $this->remove_product_base && $use_parent_slug ) {
|
||
|
$product_rules[ $cat_path . '/([^/]+)/?$' ] = 'index.php?product=$matches[1]';
|
||
|
$product_rules[ $cat_path . '/([^/]+)/' . $wp_rewrite->comments_pagination_base . '-([0-9]{1,})/?$' ] = 'index.php?product=$matches[1]&cpage=$matches[2]';
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Register WPML filters back
|
||
|
*/
|
||
|
Sitepress::get()->restore_term_filters();
|
||
|
|
||
|
$rules = empty( $rules ) ? [] : $rules;
|
||
|
return $category_rules + $product_rules + $rules;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns categories array.
|
||
|
*
|
||
|
* ['category id' => ['slug' => 'category slug', 'parent' => 'parent category id']]
|
||
|
*
|
||
|
* @return array
|
||
|
*/
|
||
|
private function get_categories() {
|
||
|
if ( is_null( $this->categories ) ) {
|
||
|
$categories = get_categories(
|
||
|
[
|
||
|
'taxonomy' => 'product_cat',
|
||
|
'hide_empty' => false,
|
||
|
]
|
||
|
);
|
||
|
|
||
|
$slugs = [];
|
||
|
foreach ( $categories as $category ) {
|
||
|
$slugs[ $category->term_id ] = [
|
||
|
'parent' => $category->parent,
|
||
|
'slug' => $category->slug,
|
||
|
];
|
||
|
}
|
||
|
|
||
|
$this->categories = $slugs;
|
||
|
}
|
||
|
|
||
|
return $this->categories;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Recursively builds category full path.
|
||
|
*
|
||
|
* @param object $category Term object.
|
||
|
*
|
||
|
* @return string
|
||
|
*/
|
||
|
private function get_category_fullpath( $category ) {
|
||
|
$categories = $this->get_categories();
|
||
|
$parent = $category['parent'];
|
||
|
|
||
|
if ( $parent > 0 && array_key_exists( $parent, $categories ) ) {
|
||
|
return $this->get_category_fullpath( $categories[ $parent ] ) . '/' . $category['slug'];
|
||
|
}
|
||
|
|
||
|
return $category['slug'];
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get product base.
|
||
|
*
|
||
|
* @return string
|
||
|
*/
|
||
|
private function get_product_base() {
|
||
|
if ( is_null( $this->product_base ) ) {
|
||
|
$permalink_structure = wc_get_permalink_structure();
|
||
|
$this->product_base = $permalink_structure['product_rewrite_slug'];
|
||
|
if ( strpos( $this->product_base, '%product_cat%' ) !== false ) {
|
||
|
$this->product_base = str_replace( '%product_cat%', '', $this->product_base );
|
||
|
}
|
||
|
$this->product_base = '/' . trim( $this->product_base, '/' ) . '/';
|
||
|
}
|
||
|
|
||
|
return $this->product_base;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Check if the link can be changed or not.
|
||
|
*
|
||
|
* @param string $check Check string.
|
||
|
* @param string $against Against this.
|
||
|
*
|
||
|
* @return bool
|
||
|
*/
|
||
|
private function can_change_link( $check, $against ) {
|
||
|
return $check !== $against || ! get_option( 'permalink_structure' );
|
||
|
}
|
||
|
}
|