Files
2026-04-28 15:13:50 +02:00

252 lines
7.3 KiB
PHP

<?php
/**
* WP Taxonomies Class.
*
* @package WP Product Feed Manager/Data/Classes
* @version 5.2.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
if ( ! class_exists( 'WPPFM_Taxonomies' ) ) :
/**
* Taxonomies Class
*/
class WPPFM_Taxonomies {
/**
* Generates a string of shop taxonomies (like a category string) in the correct order
*
* @param string $product_id
* @param string $tax
* @param string $separator
*
* @since 2.31.0 Update the function to include a primary category selection.
* @since 2.31.1 Changed the make_shop_taxonomy_string() methode, so it returns the correct value for non-category related attributes.
* @since 2.33.0 Added a result test after the get_term_by_id call, to prevent an error message.
*
* @return string
*/
public static function make_shop_taxonomies_string( $product_id, $tax = 'product_cat', $separator = ' > ' ) {
// Only check the category if the attribute is a category attribute.
$primary_category = 'category' === $tax || 'product_cat' === $tax ? self::get_primary_cat( $product_id) : false;
if ( $primary_category ) {
$cats = $primary_category;
} else {
$args = array(
'taxonomy' => $tax,
'orderby' => 'parent',
'order' => 'DESC',
);
// get the post-term ordered with the last child cat first
$cats = wp_get_post_terms( $product_id, $tax, $args );
}
$result = array();
if ( count( $cats ) === 0 ) {
return '';
}
// anonymous function to get the correct taxonomy string
$cat_string = function ( $id ) use ( &$result, &$cat_string, $tax ) {
// get the first term
$term = get_term_by( 'id', $id, $tax, 'ARRAY_A' );
if ( ! $term ) { return; }
// check if the term has a parent
if ( $term['parent'] ) {
// start the anonymous function again with the parent id
$cat_string( $term['parent'] );
}
// add the term name to the result
$result[] = $term['name'];
};
// activate the anonymous function with the term_id
foreach( $cats as $cat ) {
$cat_string( $cat->term_id );
}
return implode( $separator, $result );
}
/**
* Single category path: Yoast/Rank Math primary breadcrumb, or the first assigned term's breadcrumb when no primary is set.
*
* Unlike {@see self::make_shop_taxonomies_string()}, this never merges paths from multiple categories.
*
* @param int|string $product_id Post ID.
* @param string $tax Taxonomy slug.
* @param string $separator Hierarchy separator.
*
* @since 3.22.0
*
* @return string
*/
public static function make_main_product_category_string( $product_id, $tax = 'product_cat', $separator = ' > ' ) {
$product_id = absint( $product_id );
if ( ! $product_id ) {
return '';
}
$term_id = 0;
if ( 'category' === $tax || 'product_cat' === $tax ) {
$primary = self::get_primary_cat( $product_id );
if ( $primary && isset( $primary[0]->term_id ) ) {
$term_id = absint( $primary[0]->term_id );
}
}
if ( ! $term_id ) {
$terms = wp_get_post_terms(
$product_id,
$tax,
array(
'orderby' => 'term_id',
'order' => 'ASC',
)
);
if ( is_wp_error( $terms ) || empty( $terms ) ) {
return '';
}
$term_id = absint( $terms[0]->term_id );
}
return self::get_single_term_taxonomy_breadcrumb_string( $term_id, $tax, $separator );
}
/**
* Generates a string with all selected categories
*
* @param string $post_id
* @param string $separator
*
* @return string
*/
public static function get_shop_categories( $post_id, $separator = ', ' ) {
$return_string = '';
$args = array(
'taxonomy' => 'product_cat',
'orderby' => 'term_id',
);
$cats = wp_get_post_terms( $post_id, 'product_cat', $args );
foreach ( $cats as $cat ) {
$return_string .= $cat->name . $separator;
}
return rtrim( $return_string, $separator );
}
/**
* Returns the product category that is selected as primary (only when Yoast SEO or RankMath plugin is installed)
*
* @param string $product_id
*
* @return array|boolean
*/
public static function get_primary_cat( $product_id ) {
$primary_cat_id = '';
if ( is_plugin_active( 'wordpress-seo/wp-seo.php' ) || is_plugin_active_for_network( 'wordpress-seo/wp-seo.php' )
|| is_plugin_active( 'wordpress-seo-premium/wp-seo-premium.php' ) || is_plugin_active_for_network( 'wordpress-seo-premium/wp-seo-premium.php' ) ) {
$primary_cat_id = get_post_meta( $product_id, '_yoast_wpseo_primary_product_cat', true );
}
if ( is_plugin_active( 'seo-by-rank-math/rank-math.php' ) || is_plugin_active_for_network( 'seo-by-rank-math/rank-math.php' )
|| is_plugin_active( 'seo-by-rank-math-pro/rank-math-pro.php' ) || is_plugin_active_for_network( 'seo-by-rank-math-pro/rank-math-pro.php' ) ) {
$primary_cat_id = get_post_meta( $product_id, 'rank_math_primary_product_cat', true );
}
if ( $primary_cat_id ) {
$product_cat[0] = get_term( $primary_cat_id, 'product_cat' );
if ( isset( $product_cat[0]->term_id ) ) {
return $product_cat;
}
} else {
return false;
}
return false;
}
public static function get_shop_categories_list() {
$args = array(
'hide_empty' => 0,
'taxonomy' => 'product_cat',
'hierarchical' => 1,
'orderby' => 'name',
'order' => 'ASC',
// phpcs:ignore WordPressVIPMinimum.Performance.WPQueryParams.PostNotIn_exclude -- The exclude parameter is necessary to filter out specific categories from category mapping. This is a user-configurable feature and essential functionality.
'exclude' => apply_filters( 'wppfm_category_mapping_exclude', array() ),
'exclude_tree' => apply_filters( 'wppfm_category_mapping_exclude_tree', array() ),
'number' => absint( apply_filters( 'wppfm_category_mapping_max_categories', 0 ) ),
'child_of' => 0,
);
// see https://developer.wordpress.org/reference/classes/wp_term_query/__construct/ for valid args
$args = apply_filters( 'wppfm_category_mapping_args', $args );
return self::get_cat_hierarchy( 0, $args );
}
/**
* Builds root-to-leaf names for a single taxonomy term (same ordering as make_shop_taxonomies_string per term).
*
* @param int $term_id Term ID.
* @param string $tax Taxonomy slug.
* @param string $separator String used between segments.
*
* @return string
*/
private static function get_single_term_taxonomy_breadcrumb_string( $term_id, $tax, $separator ) {
$result = array();
$term_id = absint( $term_id );
$cat_string = function ( $id ) use ( &$result, &$cat_string, $tax ) {
$term = get_term_by( 'id', absint( $id ), $tax, 'ARRAY_A' );
if ( ! $term ) {
return;
}
if ( ! empty( $term['parent'] ) ) {
$cat_string( $term['parent'] );
}
$result[] = $term['name'];
};
$cat_string( $term_id );
return implode( $separator, $result );
}
private static function get_cat_hierarchy( $parent, $args ) {
$cats = get_categories( $args );
$ret = new stdClass;
foreach ( $cats as $cat ) {
if ( $cat->parent == $parent ) {
$id = $cat->cat_ID;
$ret->$id = $cat;
$ret->$id->children = self::get_cat_hierarchy( $id, $args );
}
}
return $ret;
}
}
// end of WPPFM_Taxonomies_Class
endif;