which runs the_content filter
add_filter('the_content', function ($content) {
if (!is_singular('fluent-products')) {
return $content;
}
global $post;
if (!$post || $post->post_type !== FluentProducts::CPT_NAME) {
return $content;
}
ob_start();
do_action('fluent_cart/product/after_product_content', $post->ID);
$extra = ob_get_clean();
if ($extra) {
$content .= $extra;
}
return $content;
}, 999);
add_shortcode('fluent_cart_product_header', function ($atts = []) {
$atts = shortcode_atts([
'id' => 0,
], $atts);
$productId = absint($atts['id']);
if (!$productId) {
$productId = get_the_ID();
}
if (!$productId) {
return 'Product ID not found';
}
$product = ProductDataSetup::getProductModel($productId);
if (!$product || !$product->detail) {
return 'Product not found';
}
ob_start();
$this->renderProductHeader($product->ID);
$content = ob_get_clean();
return $this->tempFixShortcodeContent($content);
});
add_shortcode('fluent_cart_related_products', function ($atts = []) {
$atts = shortcode_atts([
'id' => 0,
], $atts);
$productId = absint($atts['id']);
if (!$productId) {
$productId = get_the_ID();
}
if (!$productId) {
return __('Product ID not found', 'fluent-cart');
}
$product = ProductDataSetup::getProductModel($productId);
if (!$product || !$product->detail) {
return __('Product not found', 'fluent-cart');
}
// On the product page this shortcode is the block theme's
// equivalent of what filterSingleProductContent appends for
// classic themes, so it answers to the same setting and filter.
// Placed anywhere else it is an explicit choice and still renders.
if (is_singular(FluentProducts::CPT_NAME)) {
$showRelevant = (new StoreSettings())->get('show_relevant_product_in_single_page') == 'yes';
$showRelevant = apply_filters(
'fluent_cart/single_product_page/show_relevant_products',
$showRelevant,
$productId
);
if (!$showRelevant) {
return '';
}
}
$products = ShopResource::getSimilarProducts($productId, false);
if (empty($products)) {
return '';
}
ob_start();
(new ProductListRenderer(
$products,
__('Related Products', 'fluent-cart'),
'fct-similar-product-list-container'
))->render();
$content = ob_get_clean();
return $this->tempFixShortcodeContent($content);
});
add_action('fluent_cart/template/before_content', [$this, 'renderArchiveHeader']);
}
public function renderMainContent()
{
$isTaxPages = is_tax(get_object_taxonomies('fluent-products'));
if ($isTaxPages) {
do_action('fluent_cart/template/product_archive');
}
}
public function renderArchiveHeader()
{
if (TemplateService::getCurrentFcPageType() !== 'product_taxonomy') {
return;
}
?>
taxonomy) || !is_tax(get_object_taxonomies('fluent-products'))) {
return;
}
$productsQuery = (new ProductQuery([
'is_main_query' => true,
'paginate' => 'simple',
'with' => ['detail', 'variants']
]));
$publicTaxonomies = Taxonomy::getTaxonomies();
unset($publicTaxonomies[$queried_object->taxonomy]);
$connectedTerms = $productsQuery->getConnectedTerms(array_values($publicTaxonomies), true);
//TODO: also add the child terms
$taxFilters = [];
foreach ($connectedTerms as $taxonomyName => $term) {
$taxObj = get_taxonomy($taxonomyName);
if (!$taxObj) {
continue;
}
$taxFilters[$taxonomyName] = [
'options' => $term['terms'],
'term' => $taxonomyName,
'label' => $taxObj->label
];
}
$products = $productsQuery->get();
(new ShopAppRenderer($products, [
'default_filters' => $productsQuery->getDefaultFilters(),
'custom_filters' => [
'taxonomies' => [
$taxFilters
],
'search' => true,
'price_range' => true,
],
'pagination_type' => 'simple'
]))->render();
}
public function initSingleProductHooks()
{
add_filter('the_title', function ($title, $post_id) {
if (apply_filters('fluent_cart/disable_auto_single_product_page', false)) {
return $title;
}
global $post;
global $wp_query;
if (
// this is the main query for a single product page
$wp_query->is_main_query()
// post_id is get_queried id
&& $post_id == $wp_query->get_queried_object_id()
&& $post->post_type === FluentProducts::CPT_NAME
) {
return '';
}
return $title;
}, 10, 2);
add_filter('get_the_excerpt', function ($excerpt, $post) {
if (apply_filters('fluent_cart/disable_auto_single_product_page', false)) {
return $excerpt;
}
global $wp_query;
if (
$wp_query->is_main_query()
&& $post->ID == $wp_query->get_queried_object_id()
&& $post->post_type === FluentProducts::CPT_NAME
) {
return '';
}
return $excerpt;
}, 10, 2);
add_filter('the_content', [$this, 'filterSingleProductContent'], 999);
}
public function filterSingleProductContent($content)
{
if (apply_filters('fluent_cart/disable_auto_single_product_page', false)) {
return $content;
}
global $post;
global $wp_query;
if (!$wp_query->is_main_query() && $post->post_type !== FluentProducts::CPT_NAME) {
return $content;
}
remove_filter('the_content', [$this, 'filterSingleProductContent']);
ob_start();
do_action('fluent_cart/product/render_product_header', $post->ID);
$headerContent = ob_get_clean();
$content = $headerContent . $content;
$storeSettings = new StoreSettings();
$showRelevant = $storeSettings->get('show_relevant_product_in_single_page') == 'yes';
$showRelevant = apply_filters('fluent_cart/single_product_page/show_relevant_products', $showRelevant, $post->ID);
if ($showRelevant) {
$products = ShopResource::getSimilarProducts($post->ID, false);
ob_start();
(new ProductListRenderer(
$products,
__('Related Products', 'fluent-cart'),
'fct-similar-product-list-container'
))->render();
$relevantProducts = ob_get_clean();
$content .= $relevantProducts;
}
return $content;
}
public function renderProductHeader($productId = false)
{
if (!$productId) {
$productId = get_the_ID();
}
if (!$productId) {
return;
}
$product = ProductDataSetup::getProductModel($productId);
if (!$product || !$product->detail) {
return;
}
$storeSettings = new StoreSettings();
(new ProductRenderer($product, [
'view_type' => $storeSettings->get('variation_view', 'both'),
'column_type' => $storeSettings->get('variation_columns', 'masonry')
]))->render();
}
private function tempFixShortcodeContent($content)
{
if (!$content) {
return $content;
}
// Remove empty tags (including those with whitespace),
tags, and new lines
$cleaned = preg_replace([
'/
\s*<\/p>/i', // Remove empty
tags
'/
\s*
\s*<\/p>/i', // Remove
tags containing only
'/
/i', // Remove all
tags
'/[\r\n]+/' // Remove all new lines
], '', $content);
// Remove extra whitespace between tags to clean up the output
return preg_replace('/>\s+', '><', $cleaned);
}
}