/**
* Woodmart Child Om v1.0.7
*/
if ( ! defined( 'ABSPATH' ) ) { exit; }
/**
* WP Rocket — désactiver les « éléments prioritaires » automatiques.
*
* Sur ce catalogue multilingue, ces analyses sont recalculées pour un très
* grand nombre d'URL et ont rempli plusieurs tables techniques de WP Rocket.
* Les optimisations manuelles du thème restent actives.
*/
add_filter( 'rocket_above_the_fold_optimization', '__return_false', 999 );
add_filter( 'rocket_lrc_optimization', '__return_false', 999 );
add_filter( 'rocket_preconnect_external_domains_optimization', '__return_false', 999 );
add_action( 'wp_enqueue_scripts', function(){
$parent = wp_get_theme( get_template() );
/*
* OMYOKI — conserver le chargement du tear-off strictement inchangé,
* tout en évitant de forcer une deuxième fois le gros style.css global
* de Woodmart quand le thème a déjà enregistré son handle natif.
*
* Sécurité visuelle :
* - si Woodmart a bien enregistré "woodmart-style", "woodmart-parent"
* devient uniquement un alias de dépendance, sans fichier CSS supplémentaire ;
* - sinon, fallback automatique sur l'ancien chargement de style.css.
*/
if ( wp_style_is( 'woodmart-style', 'registered' ) ) {
wp_register_style(
'woodmart-parent',
false,
array( 'woodmart-style' ),
$parent->get('Version')
);
} else {
wp_enqueue_style(
'woodmart-parent',
get_template_directory_uri() . '/style.css',
array(),
$parent->get('Version')
);
}
// IMPORTANT : chargement du tear-off volontairement inchangé.
wp_enqueue_style( 'woodmart-child-om', get_stylesheet_directory_uri() . '/assets/css/tearoff.css', array('woodmart-parent'), filemtime( get_stylesheet_directory() . '/assets/css/tearoff.css' ) );
}, 20 );
add_filter( 'body_class', function( $classes ){
foreach ( array('omy-tearoff-enabled','omy-footer-tearoff') as $c ) {
if ( ! in_array( $c, $classes, true ) ) $classes[] = $c;
}
return $classes;
} );
// VC Row: checkbox param
add_action( 'init', function(){
if ( function_exists( 'vc_add_param' ) ) {
vc_add_param( 'vc_row', array(
'type' => 'checkbox',
'heading' => __( 'Tear-off Effect', 'woodmart-child-om' ),
'param_name' => 'omy_tearoff',
'description' => __( 'Ajoute un bord déchiré (haut/bas) – style Zass', 'woodmart-child-om' ),
'value' => array( __( 'Activer', 'woodmart-child-om' ) => 'yes' ),
'group' => __( 'Design Options', 'js_composer' ),
) );
}
}, 15 );
// VC Row: honor legacy Zass + checkbox
add_filter( 'shortcode_atts_vc_row', function( $out, $pairs, $atts ){
$legacy = ( isset( $atts['point_down'] ) && in_array( strtolower( (string) $atts['point_down'] ), array('yes','true','1'), true ) )
|| ( isset( $atts['el_class'] ) && false !== strpos( (string) $atts['el_class'], 'zass-point-down' ) );
$enabled = ( isset( $atts['omy_tearoff'] ) && 'yes' === $atts['omy_tearoff'] ) || $legacy;
if ( $enabled ) {
$el = isset( $out['el_class'] ) ? trim( (string) $out['el_class'] ) : '';
if ( false === strpos( $el, 'omy-row-tearoff' ) ) $el .= ( $el ? ' ' : '' ) . 'omy-row-tearoff';
if ( false === strpos( $el, 'zass-point-down' ) ) $el .= ' zass-point-down';
$out['el_class'] = trim( $el );
}
return $out;
}, 11, 3 );
// Legacy shortcode: [zass_icon_box] – render icon + title + text
add_action( 'init', function(){
add_shortcode( 'zass_icon_box', function( $atts, $content = '' ){
$atts = shortcode_atts( array(
'title' => '',
'icon_fontawesome' => '',
'icon_style' => '',
'color' => '',
), $atts, 'zass_icon_box' );
$title = sanitize_text_field( $atts['title'] );
$icon = sanitize_text_field( $atts['icon_fontawesome'] );
$color = sanitize_hex_color( $atts['color'] ) ?: '';
$style = $color ? ' style="--omy-ibox-color:' . esc_attr( $color ) . ';"' : '';
$icon_html = $icon ? '
' : '';
$title_html = $title ? '' . esc_html( $title ) . '
' : '';
$content = do_shortcode( $content );
$content_html= $content ? '' . wp_kses_post( wpautop( $content ) ) . '
' : '';
return '' . $icon_html . $title_html . $content_html . '
';
});
if ( function_exists( 'vc_map' ) ) {
vc_map( array(
'name' => __( 'Zass Icon Box (legacy)', 'woodmart-child-om' ),
'base' => 'zass_icon_box',
'icon' => 'dashicons dashicons-image-filter',
'category' => __( 'OMYOKI (legacy)', 'woodmart-child-om' ),
'description' => __( 'Compat Zass : icône + titre + texte', 'woodmart-child-om' ),
'params' => array(
array( 'type'=>'textfield', 'heading'=>__( 'Titre','woodmart-child-om' ), 'param_name'=>'title' ),
array( 'type'=>'iconpicker','heading'=>__( 'Icône FA','woodmart-child-om' ), 'param_name'=>'icon_fontawesome', 'settings'=>array('emptyIcon'=>true,'iconsPerPage'=>200) ),
array( 'type'=>'colorpicker','heading'=>__( 'Couleur','woodmart-child-om' ), 'param_name'=>'color' ),
array( 'type'=>'textarea_html', 'holder'=>'div', 'heading'=>__( 'Contenu','woodmart-child-om' ), 'param_name'=>'content' ),
),
) );
}
}, 20 );
// Admin tools (images, rows, and icon box conversion)
require_once __DIR__ . '/admin/migrate-zass-to-woodmart.php';
// Fallback shortcode [omy_info_box] used by converter if Woodmart box unavailable
add_action( 'init', function(){
add_shortcode( 'omy_info_box', function( $atts, $content = '' ){
$atts = shortcode_atts( array(
'title' => '',
'icon' => '',
'color' => '',
), $atts, 'omy_info_box' );
$title = sanitize_text_field($atts['title']);
$icon = sanitize_text_field($atts['icon']);
$color = sanitize_hex_color($atts['color']) ?: '';
$style = $color ? ' style="--omy-ibox-color:' . esc_attr( $color ) . ';"' : '';
$icon_h = $icon ? '
' : '';
$title_h= $title? '' . esc_html($title) . '
' : '';
$content = do_shortcode( $content );
$text_h = $content ? '' . wp_kses_post( wpautop($content) ) . '
' : '';
return '' . $icon_h . $title_h . $text_h . '
';
} );
}, 30 );
/**
* === OMYOKI additions (v1.0.9) ===
* Enqueue expand.css + force classic widgets + shortcode [expand].
*/
add_action('wp_enqueue_scripts', function () {
$base = get_stylesheet_directory();
$uri = get_stylesheet_directory_uri();
$css = $base . '/assets/css/expand.css';
if ( file_exists( $css ) ) {
wp_enqueue_style('woodmart-child-om-expand', $uri . '/assets/css/expand.css', array(), filemtime( $css ));
}
}, 50);
add_filter('use_widgets_block_editor', '__return_false');
add_action('init', function(){
if ( shortcode_exists('expand') ) { return; }
add_shortcode('expand', function($atts, $content = ''){
$a = shortcode_atts(array(
'title' => 'Lire la suite',
'open' => 'no',
'id' => '',
'align' => '',
), $atts, 'expand');
$open = in_array(strtolower((string)$a['open']), array('yes','true','1','open'), true) ? ' open' : '';
$id = $a['id'] ? sanitize_html_class($a['id']) : 'exp-' . wp_unique_id('omy_');
$title = wp_kses_post($a['title']);
$align = in_array(strtolower((string)$a['align']), array('left','center','right'), true) ? strtolower($a['align']) : '';
$data_align = $align ? ' data-align="' . esc_attr($align) . '"' : '';
$class_align = $align ? ' wd-expand--' . esc_attr($align) : '';
$body = do_shortcode($content);
return ''
. '' . $title . '
'
. '' . wpautop($body) . '
'
. ' ';
});
});
/* === End OMYOKI additions === */
/**
* === OMYOKI — Breadcrumbs for products (show ONLY Yoast in header) ===
*/
add_action('init', function() {
remove_action('woocommerce_before_main_content', 'woocommerce_breadcrumb', 20);
if ( function_exists('woodmart_woocommerce_breadcrumbs') ) {
remove_action('woocommerce_before_main_content', 'woodmart_woocommerce_breadcrumbs', 20);
}
}, 9);
add_filter('wpseo_breadcrumb_links', function($links){
if ( ! function_exists('is_singular') || ! is_singular('product') ) return $links;
$product_id = get_queried_object_id();
if ( ! $product_id ) return $links;
// Determine Yoast Primary product_cat (fallback: first assigned)
$primary_id = (int) get_post_meta( $product_id, '_yoast_wpseo_primary_product_cat', true );
$term = $primary_id ? get_term( $primary_id, 'product_cat' ) : null;
if ( ! $term || is_wp_error($term) ) {
$terms = get_the_terms( $product_id, 'product_cat' );
$term = ( $terms && ! is_wp_error($terms) ) ? array_shift( $terms ) : null;
}
// Build new breadcrumb: Shop -> Primary category -> Product
$new = array();
if ( function_exists('wc_get_page_id') ) {
$shop_id = wc_get_page_id('shop');
if ( $shop_id && $shop_id > 0 ) {
$new[] = array( 'url' => get_permalink($shop_id), 'text' => get_the_title($shop_id) );
}
}
if ( $term ) {
$new[] = array( 'url' => get_term_link( $term, 'product_cat' ), 'text' => $term->name );
}
$new[] = array( 'url' => '', 'text' => get_the_title( $product_id ) );
return $new;
}, 999);
/**
* Wishlist : message pour les invités avec CTA "Se connecter / Créer un compte"
* S'affiche seulement sur la page contenant [woodmart_wishlist] et pour les non-connectés.
*/
add_filter( 'the_content', function( $content ) {
if ( is_user_logged_in() ) {
return $content;
}
if ( is_page() ) {
// Détection robuste : la page contient le shortcode de wishlist
if ( has_shortcode( $content, 'woodmart_wishlist' ) ) {
$myaccount_url = wc_get_page_permalink( 'myaccount' );
// Le double class 'wd-login-opener js-open-login-modal' déclenche le popup WoodMart si dispo,
// sinon l'ancre reste un lien classique vers /mon-compte/.
$btn = '';
$btn .= esc_html__( 'Se connecter / Créer un compte', 'woodmart-child' ) . '';
$notice = '';
$notice .= esc_html__( 'Cette liste disparaîtra à la fermeture du site web. Créez un compte pour sauvegarder votre wishlist.', 'woodmart-child' ) . ' ';
$notice .= $btn . '
';
return $notice . $content;
}
}
return $content;
}, 9 );
add_action('wp_enqueue_scripts', function () {
if (is_front_page() || is_page('boutique-en-ligne')) {
global $wp_styles;
if (!isset($wp_styles->queue)) return;
foreach ($wp_styles->queue as $handle) {
$reg = $wp_styles->registered[$handle] ?? null;
if (!$reg) continue;
$src = $reg->src;
// Désactive les CSS de ces plugins sur home & boutique
if (
strpos($src, 'customer-reviews-woocommerce/css/frontend.css') !== false ||
strpos($src, 'customer-reviews-woocommerce/css/badges.css') !== false ||
strpos($src, 'yith-woocommerce-points-and-rewards-premium') !== false ||
strpos($src, 'cleantalk-') !== false
) {
wp_dequeue_style($handle);
}
}
}
}, 200);
add_action('woocommerce_proceed_to_checkout', function () {
echo do_shortcode('[html_block id="34833"]');
}, 40);
add_action('woocommerce_review_order_after_submit', function () {
echo do_shortcode('[html_block id="34833"]');
}, 30);
/**
* OMYOKI — Produits similaires (stable et pertinent)
*
* Objectif:
* - Un produit "bague" affiche des bagues ; un "bracelet" affiche des bracelets, etc.
* - On évite le mélange dû aux tags génériques ("fait-main", etc.)
* - On privilégie la catégorie principale Yoast si elle correspond au type.
* - On FORCE une liste finale de produits issus d’une seule catégorie "type",
* en sur-échantillonnant puis en filtrant la visibilité, pour obtenir (presque) toujours 8 produits.
*/
// Ignore le matching par tags (très souvent la cause du mélange)
add_filter( 'woocommerce_product_related_posts_relate_by_tag', '__return_false', 9999 );
add_filter( 'woocommerce_get_related_product_tag_terms', '__return_empty_array', 9999, 2 );
// Indique à WooCommerce une seule catégorie à utiliser pour le calcul interne
add_filter( 'woocommerce_get_related_product_cat_terms', function( $term_ids, $product_id ) {
$cat_id = omyoki_pick_type_category_id( (int) $product_id );
return $cat_id ? array( $cat_id ) : $term_ids;
}, 9999, 2 );
// Force la liste finale des produits similaires (même si WooCommerce mélange)
add_filter( 'woocommerce_related_products', function( $related, $product_id, $args ) {
$product_id = (int) $product_id;
$cat_id = omyoki_pick_type_category_id( $product_id );
if ( ! $cat_id ) {
return $related;
}
$limit = ! empty( $args['posts_per_page'] ) ? (int) $args['posts_per_page'] : 8;
$limit = max( 1, $limit );
// Sur-échantillonnage : on récupère plus d'IDs pour compenser les exclusions (visibilité / stock / etc.)
$fetch = min( 80, max( $limit * 8, $limit + 20 ) );
// Exclure les produits masqués (catalog/search/outofstock) via product_visibility
$vis_terms = function_exists( 'wc_get_product_visibility_term_ids' ) ? wc_get_product_visibility_term_ids() : array();
$exclude_vis = array();
foreach ( array( 'exclude-from-catalog', 'exclude-from-search', 'outofstock' ) as $k ) {
if ( ! empty( $vis_terms[ $k ] ) ) {
$exclude_vis[] = (int) $vis_terms[ $k ];
}
}
$tax_query = array(
'relation' => 'AND',
array(
'taxonomy' => 'product_cat',
'field' => 'term_id',
'terms' => array( (int) $cat_id ),
'include_children' => true, // IMPORTANT : beaucoup de produits sont souvent dans les sous-catégories
),
);
if ( $exclude_vis ) {
$tax_query[] = array(
'taxonomy' => 'product_visibility',
'field' => 'term_taxonomy_id',
'terms' => $exclude_vis,
'operator' => 'NOT IN',
);
}
$q = new WP_Query( array(
'post_type' => 'product',
'post_status' => 'publish',
'fields' => 'ids',
'posts_per_page' => $fetch,
'post__not_in' => array( $product_id ),
'orderby' => 'rand',
'no_found_rows' => true,
'update_post_meta_cache' => false,
'update_post_term_cache' => false,
'tax_query' => $tax_query,
) );
$ids = is_array( $q->posts ) ? $q->posts : array();
if ( empty( $ids ) ) {
return $related;
}
// Filtre "visible" comme WooCommerce, puis on prend les $limit premiers
$out = array();
$seen = array();
foreach ( $ids as $id ) {
$id = (int) $id;
if ( $id <= 0 || isset( $seen[ $id ] ) ) {
continue;
}
$seen[ $id ] = true;
$p = wc_get_product( $id );
if ( ! $p ) {
continue;
}
// Même si la tax_query exclut déjà, on garde le filtre WooCommerce pour être cohérent
if ( function_exists( 'wc_products_array_filter_visible' ) && ! wc_products_array_filter_visible( $p ) ) {
continue;
}
$out[] = $id;
if ( count( $out ) >= $limit ) {
break;
}
}
return ! empty( $out ) ? $out : $related;
}, 9999, 3 );
function omyoki_pick_type_category_id( $product_id ) {
$product = function_exists( 'wc_get_product' ) ? wc_get_product( $product_id ) : null;
// Matière (bonus)
$material = $product ? (string) $product->get_attribute( 'pa_matiere' ) : '';
$mat_l = strtolower( remove_accents( $material ) );
$want_argent = ( strpos( $mat_l, 'argent' ) !== false );
$want_dore = ( strpos( $mat_l, 'dor' ) !== false ) || ( strpos( $mat_l, 'laiton' ) !== false ) || ( strpos( $mat_l, 'or' ) !== false );
// Mots-clés "type"
$type_keys = array( 'bague', 'bracelet', 'boucle', 'collier', 'pendentif', 'sautoir', 'cheville' );
// 1) Yoast Primary (si c’est une catégorie "type")
$primary = (int) get_post_meta( $product_id, '_yoast_wpseo_primary_product_cat', true );
if ( $primary > 0 ) {
$t = get_term( $primary, 'product_cat' );
if ( $t && ! is_wp_error( $t ) ) {
$txt = strtolower( remove_accents( $t->slug . ' ' . $t->name ) );
foreach ( $type_keys as $k ) {
if ( false !== strpos( $txt, $k ) ) {
return $primary;
}
}
}
}
// 2) Sinon: meilleure catégorie assignée qui contient un mot "type"
$terms = get_the_terms( $product_id, 'product_cat' );
if ( empty( $terms ) || is_wp_error( $terms ) ) {
return 0;
}
$best_id = 0;
$best_score = -999999;
foreach ( $terms as $t ) {
$txt = strtolower( remove_accents( $t->slug . ' ' . $t->name ) );
$is_type = false;
foreach ( $type_keys as $k ) {
if ( false !== strpos( $txt, $k ) ) {
$is_type = true;
break;
}
}
if ( ! $is_type ) {
continue;
}
$depth = count( get_ancestors( (int) $t->term_id, 'product_cat' ) );
$score = $depth * 10;
if ( $want_argent && false !== strpos( $txt, 'argent' ) ) {
$score += 50;
}
if ( $want_dore && ( false !== strpos( $txt, 'dor' ) || false !== strpos( $txt, 'laiton' ) || false !== strpos( $txt, 'or' ) ) ) {
$score += 50;
}
if ( $score > $best_score ) {
$best_score = $score;
$best_id = (int) $t->term_id;
}
}
return $best_id;
}
/**
* OMYOKI — Lien "Guide des tailles" à côté du sélecteur de taille (variations),
* uniquement pour les produits dans les catégories bagues / bagues-homme-argent
* + attribut de variation "taille".
*/
add_filter('woocommerce_dropdown_variation_attribute_options_html', 'omyoki_add_size_guide_link_next_to_size_dropdown', 20, 2);
function omyoki_add_size_guide_link_next_to_size_dropdown($html, $args) {
if (empty($args['product']) || ! is_a($args['product'], 'WC_Product')) {
return $html;
}
$product_id = $args['product']->get_id();
// 1) Catégories ciblées (slugs)
$target_cat_slugs = array('bagues', 'bagues-homme-argent');
if (! omyoki_product_in_categories_or_ancestors($product_id, $target_cat_slugs)) {
return $html;
}
// 2) Attribut ciblé : "taille" (slug = taille => taxonomy = pa_taille)
$attr = isset($args['attribute']) ? (string) $args['attribute'] : '';
$size_attribute_names = array('pa_taille', 'taille');
if (! in_array($attr, $size_attribute_names, true)) {
return $html;
}
// 3) URL du guide des tailles (page_id=2356)
$guide_url = function_exists('get_permalink') ? get_permalink(2356) : home_url('/?page_id=2356');
$link = sprintf(
'Guide des tailles',
esc_url($guide_url)
);
return $html . $link;
}
/**
* True si le produit est dans une des catégories ciblées OU dans un de leurs enfants.
* (plus robuste que has_term seul, selon votre arborescence)
*/
function omyoki_product_in_categories_or_ancestors($product_id, array $target_slugs) {
$terms = get_the_terms($product_id, 'product_cat');
if (empty($terms) || is_wp_error($terms)) {
return false;
}
$target_slugs = array_map('sanitize_title', $target_slugs);
foreach ($terms as $term) {
// Catégorie directe
if (in_array($term->slug, $target_slugs, true)) {
return true;
}
// Ancêtres (si le produit est dans une sous-catégorie)
$ancestors = get_ancestors($term->term_id, 'product_cat');
if (! empty($ancestors)) {
foreach ($ancestors as $ancestor_id) {
$ancestor = get_term($ancestor_id, 'product_cat');
if ($ancestor && ! is_wp_error($ancestor) && in_array($ancestor->slug, $target_slugs, true)) {
return true;
}
}
}
}
return false;
}
/**
* OMYOKI — Badge "PIÈCE UNIQUE" inline juste après le prix (même ligne),
* uniquement pour la catégorie "bijoux-pieces-uniques" et uniquement sur la fiche produit.
*/
add_filter('woocommerce_get_price_html', 'omyoki_append_unique_badge_to_price_html', 20, 2);
function omyoki_append_unique_badge_to_price_html($price_html, $product) {
// Uniquement sur la fiche produit
if ( ! function_exists('is_product') || ! is_product() ) {
return $price_html;
}
if ( ! $product || ! is_a($product, 'WC_Product') ) {
return $price_html;
}
$product_id = $product->get_id();
if ( ! has_term('bijoux-pieces-uniques', 'product_cat', $product_id) ) {
return $price_html;
}
$badge = 'Pièce unique';
return $price_html . ' ' . $badge;
}
/**
* OMYOKI — Désactiver le champ coupon UNIQUEMENT sur la page panier
*/
add_filter('woocommerce_coupons_enabled', function($enabled){
if (function_exists('is_cart') && is_cart()) {
return false;
}
return $enabled;
});
/**
* OMYOKI — Add-ons cadeau sous la liste des produits du panier (style Woodmart)
* Affiche les produits via le shortcode WooCommerce => même rendu + même add-to-cart
*/
add_action('woocommerce_after_cart_table', function(){
if ( ! function_exists('WC') || ! WC()->cart || WC()->cart->is_empty() ) return;
$slugs = array(
'paquet-cadeau-2',
'carte-de-voeux-vegetale',
'pochon-a-bijoux-equitable-2',
);
$ids = array();
foreach ($slugs as $slug) {
$post = get_page_by_path($slug, OBJECT, 'product');
if ($post && ! empty($post->ID)) $ids[] = (int) $post->ID;
}
$ids = array_values(array_unique(array_filter($ids)));
if (empty($ids)) return;
echo '';
echo '
C’est pour un cadeau ?
';
// Important: utilise les templates produits du thème (Woodmart) + boutons AJAX natifs
echo do_shortcode('[products ids="' . esc_attr(implode(',', $ids)) . '" columns="3" limit="3" orderby="post__in"]');
echo '';
}, 25);
/**
* OMYOKI — Shortcode recommandations panier (Woodmart carousel)
* Usage: [omyoki_cart_recos]
* Logique: pierre (pa_pierres/pa_pierre/product_tag) -> fallback catégorie (product_cat)
*/
add_shortcode('omyoki_cart_recos', function ($atts) {
// Sécurité / contexte
if (is_admin() && !defined('DOING_AJAX')) return '';
if (!function_exists('WC') || !WC()->cart) return '';
if (WC()->cart->is_empty()) return '';
if (!shortcode_exists('woodmart_products')) return '';
$atts = shortcode_atts(array(
'limit' => 8,
'per_view' => 4,
'tablet' => 3,
'mobile' => 2,
), $atts, 'omyoki_cart_recos');
$limit = max(1, min(24, (int)$atts['limit']));
$per_view = max(1, min(6, (int)$atts['per_view']));
$tablet = max(1, min(6, (int)$atts['tablet']));
$mobile = max(1, min(6, (int)$atts['mobile']));
// Produits du panier (référence + exclusions)
$cart_ids = array();
foreach (WC()->cart->get_cart() as $item) {
if (!empty($item['product_id'])) $cart_ids[] = (int)$item['product_id'];
}
$cart_ids = array_values(array_unique(array_filter($cart_ids)));
if (empty($cart_ids)) return '';
$main_id = $cart_ids[0];
// Exclure aussi les 3 add-ons cadeaux
$addon_slugs = array('paquet-cadeau-2', 'carte-de-voeux-vegetale', 'pochon-a-bijoux-equitable-2');
$addon_ids = array();
foreach ($addon_slugs as $slug) {
$p = get_page_by_path($slug, OBJECT, 'product');
if ($p && !empty($p->ID)) $addon_ids[] = (int)$p->ID;
}
$exclude_ids = array_values(array_unique(array_merge($cart_ids, $addon_ids)));
// 1) Détecter une "pierre" (priorité)
$tax_candidates = array('pa_pierres', 'pa_pierre', 'product_tag');
$chosen_tax = '';
$term_ids = array();
foreach ($tax_candidates as $tax) {
if (!taxonomy_exists($tax)) continue;
$tmp = array();
foreach ($cart_ids as $pid) {
$t = wp_get_post_terms($pid, $tax, array('fields' => 'ids'));
if (!is_wp_error($t) && !empty($t)) $tmp = array_merge($tmp, $t);
}
$tmp = array_values(array_unique(array_map('intval', $tmp)));
if (!empty($tmp)) {
$chosen_tax = $tax;
$term_ids = array_slice($tmp, 0, 3); // limite à 3 "pierres"
break;
}
}
// 2) Fallback catégorie si pas de pierre
if (empty($chosen_tax) || empty($term_ids)) {
$chosen_tax = 'product_cat';
$cats = wp_get_post_terms($main_id, 'product_cat', array('fields' => 'ids'));
if (!is_wp_error($cats) && !empty($cats)) {
$term_ids = array_slice(array_map('intval', $cats), 0, 2);
}
}
if (empty($term_ids)) return '';
// Query légère (8 produits)
$q = new WP_Query(array(
'post_type' => 'product',
'post_status' => 'publish',
'posts_per_page' => $limit,
'no_found_rows' => true,
'fields' => 'ids',
'post__not_in' => $exclude_ids,
'orderby' => 'date',
'order' => 'DESC',
'meta_query' => array(
array(
'key' => '_stock_status',
'value' => 'instock',
),
),
'tax_query' => array(
array(
'taxonomy' => $chosen_tax,
'field' => 'term_id',
'terms' => $term_ids,
'operator' => 'IN',
),
array(
'taxonomy' => 'product_visibility',
'field' => 'name',
'terms' => array('exclude-from-catalog', 'outofstock'),
'operator' => 'NOT IN',
),
),
));
$ids = $q->posts;
if (empty($ids)) return '';
// Carousel Woodmart (format comme fiches produits)
return '' .
do_shortcode(
'[woodmart_products post_type="ids" include="' . esc_attr(implode(',', $ids)) . '" ' .
'layout="carousel" items_per_page="' . (int)$limit . '" ' .
'slides_per_view="' . (int)$per_view . '" slides_per_view_tablet="' . (int)$tablet . '" slides_per_view_mobile="' . (int)$mobile . '" ' .
'orderby="post__in" product_hover="icons" lazy_loading="yes"]'
) .
'
';
});
/**
* OMYOKI — Envoi authentifie des e-mails WordPress et WooCommerce par OVH.
* Les identifiants sont definis dans wp-config.php.
*/
add_action( 'phpmailer_init', function ( $mailer ) {
if (
! defined( 'OMYOKI_SMTP_HOST' ) ||
! defined( 'OMYOKI_SMTP_PORT' ) ||
! defined( 'OMYOKI_SMTP_USER' ) ||
! defined( 'OMYOKI_SMTP_PASSWORD' )
) {
return;
}
$mailer->isSMTP();
$mailer->Host = OMYOKI_SMTP_HOST;
$mailer->Port = (int) OMYOKI_SMTP_PORT;
$mailer->SMTPAuth = true;
$mailer->SMTPSecure = 'tls';
$mailer->Username = OMYOKI_SMTP_USER;
$mailer->Password = OMYOKI_SMTP_PASSWORD;
$mailer->Sender = OMYOKI_SMTP_USER;
$mailer->Timeout = 20;
} );
add_filter( 'wp_mail_from', function () {
return defined( 'OMYOKI_SMTP_USER' ) ? OMYOKI_SMTP_USER : 'infos@omyoki.com';
} );
add_filter( 'wp_mail_from_name', function () {
return 'Omyoki';
} );
https://www.omyoki.com/post-sitemap.xml
2026-07-28T15:51:26+00:00
https://www.omyoki.com/page-sitemap.xml
2026-08-19T09:29:25+00:00
https://www.omyoki.com/product-sitemap.xml
2026-08-28T07:25:17+00:00
https://www.omyoki.com/product-sitemap2.xml
2026-08-28T07:25:17+00:00
https://www.omyoki.com/category-sitemap.xml
2026-07-28T15:51:26+00:00
https://www.omyoki.com/post_tag-sitemap.xml
2024-11-26T08:38:03+00:00
https://www.omyoki.com/product_cat-sitemap.xml
2026-08-28T07:25:17+00:00
https://www.omyoki.com/product_tag-sitemap.xml
2026-08-28T07:25:17+00:00
https://www.omyoki.com/pa_genre-sitemap.xml
2026-08-28T07:25:17+00:00