File: /home/lesanew/anestetues2/web/app/themes/anes-tetues/app/setup.php
<?php
/**
* Theme setup.
*/
namespace App;
use Illuminate\Support\Facades\Vite;
/**
* Inject styles into the block editor.
*
* @return array
*/
add_filter('block_editor_settings_all', function ($settings) {
$style = Vite::asset('resources/css/editor.scss');
$settings['styles'][] = [
'css' => "@import url('{$style}')",
];
return $settings;
});
/**
* Inject scripts into the block editor.
*
* @return void
*/
add_filter('admin_head', function () {
if (! get_current_screen()?->is_block_editor()) {
return;
}
$dependencies = json_decode(Vite::content('editor.deps.json'));
foreach ($dependencies as $dependency) {
if (! wp_script_is($dependency)) {
wp_enqueue_script($dependency);
}
}
echo Vite::withEntryPoints([
'resources/js/editor.ts',
])->toHtml();
});
/**
* Use the generated theme.json file.
*
* @return string
*/
add_filter('theme_file_path', function ($path, $file) {
return $file === 'theme.json'
? public_path('build/assets/theme.json')
: $path;
}, 10, 2);
/**
* Register the initial theme setup.
*
* @return void
*/
add_action('after_setup_theme', function () {
/**
* Disable full-site editing support.
*
* @link https://wptavern.com/gutenberg-10-5-embeds-pdfs-adds-verse-block-color-options-and-introduces-new-patterns
*/
remove_theme_support('block-templates');
/**
* Register the navigation menus.
*
* @link https://developer.wordpress.org/reference/functions/register_nav_menus/
*/
register_nav_menus([
'primary_navigation' => __('Primary Navigation', 'sage'),
]);
/**
* Disable the default block patterns.
*
* @link https://developer.wordpress.org/block-editor/developers/themes/theme-support/#disabling-the-default-block-patterns
*/
remove_theme_support('core-block-patterns');
/**
* Enable plugins to manage the document title.
*
* @link https://developer.wordpress.org/reference/functions/add_theme_support/#title-tag
*/
add_theme_support('title-tag');
/**
* Enable post thumbnail support.
*
* @link https://developer.wordpress.org/themes/functionality/featured-images-post-thumbnails/
*/
add_theme_support('post-thumbnails');
/**
* Enable responsive embed support.
*
* @link https://developer.wordpress.org/block-editor/how-to-guides/themes/theme-support/#responsive-embedded-content
*/
add_theme_support('responsive-embeds');
/**
* Enable HTML5 markup support.
*
* @link https://developer.wordpress.org/reference/functions/add_theme_support/#html5
*/
add_theme_support('html5', [
'caption',
'comment-form',
'comment-list',
'gallery',
'search-form',
'script',
'style',
]);
/**
* Enable selective refresh for widgets in customizer.
*
* @link https://developer.wordpress.org/reference/functions/add_theme_support/#customize-selective-refresh-widgets
*/
add_theme_support('customize-selective-refresh-widgets');
}, 20);
/**
* Register the theme sidebars.
*
* @return void
*/
add_action('widgets_init', function () {
$config = [
'before_widget' => '<section class="widget %1$s %2$s">',
'after_widget' => '</section>',
'before_title' => '<h3>',
'after_title' => '</h3>',
];
register_sidebar([
'name' => __('Primary', 'sage'),
'id' => 'sidebar-primary',
] + $config);
register_sidebar([
'name' => __('Footer', 'sage'),
'id' => 'sidebar-footer',
] + $config);
});
/**
* Configure ACF to save JSON files in the theme directory.
* This allows versioning ACF field groups in Git.
*
* @return void
*/
add_filter('acf/settings/save_json', function ($path) {
// Save JSON files in the theme's acf-json directory
$path = get_stylesheet_directory().'/acf-json';
// Create directory if it doesn't exist
if (! file_exists($path)) {
wp_mkdir_p($path);
}
return $path;
});
add_filter('acf/settings/load_json', function ($paths) {
// Load JSON files from the theme's acf-json directory
$paths[] = get_stylesheet_directory().'/acf-json';
return $paths;
});
/**
* Register ACF options page.
*
* @return void
*/
add_action('acf/init', function () {
acf_add_options_page([
'page_title' => __('Informations Général', 'anes-tetues'),
'menu_title' => __('Informations Général', 'anes-tetues'),
'menu_slug' => 'informations-general',
'capability' => 'edit_posts',
'redirect' => false,
'position' => 30,
]);
acf_add_options_page([
'page_title' => __('Informations prochain concert', 'anes-tetues'),
'menu_title' => __('Informations prochain concert', 'anes-tetues'),
'menu_slug' => 'informations-prochain-concert',
'capability' => 'edit_posts',
'redirect' => false,
'icon_url' => 'dashicons-calendar-alt',
'position' => 31,
]);
});
/**
* Register "Line Up" custom post type.
*/
add_action('init', function () {
register_post_type('lineup', [
'labels' => [
'name' => __('Line Up', 'anes-tetues'),
'singular_name' => __('Line Up', 'anes-tetues'),
'add_new' => __('Ajouter un élément', 'anes-tetues'),
'add_new_item' => __('Ajouter un artiste', 'anes-tetues'),
'edit_item' => __("Modifier l'artiste", 'anes-tetues'),
'new_item' => __('Nouvel artiste', 'anes-tetues'),
'view_item' => __("Voir l'artiste", 'anes-tetues'),
'search_items' => __('Rechercher un artiste', 'anes-tetues'),
'not_found' => __('Aucun artiste trouvé', 'anes-tetues'),
'not_found_in_trash' => __('Aucun artiste dans la corbeille', 'anes-tetues'),
'all_items' => __('Tous les artistes', 'anes-tetues'),
'menu_name' => __('Line Up', 'anes-tetues'),
],
'public' => true,
'has_archive' => false,
'show_in_rest' => true,
'menu_position' => 20,
'menu_icon' => 'dashicons-playlist-audio',
'supports' => ['title'],
'rewrite' => [
'slug' => 'line-up',
'with_front' => false,
],
]);
});
/**
* Register "Partenaires" custom post type.
*/
add_action('init', function () {
register_post_type('partenaire', [
'labels' => [
'name' => __('Partenaires', 'anes-tetues'),
'singular_name' => __('Partenaire', 'anes-tetues'),
'add_new' => __('Ajouter un partenaire', 'anes-tetues'),
'add_new_item' => __('Ajouter un partenaire', 'anes-tetues'),
'edit_item' => __('Modifier le partenaire', 'anes-tetues'),
'new_item' => __('Nouveau partenaire', 'anes-tetues'),
'view_item' => __('Voir le partenaire', 'anes-tetues'),
'search_items' => __('Rechercher un partenaire', 'anes-tetues'),
'not_found' => __('Aucun partenaire trouvé', 'anes-tetues'),
'not_found_in_trash' => __('Aucun partenaire dans la corbeille', 'anes-tetues'),
'all_items' => __('Tous les partenaires', 'anes-tetues'),
'menu_name' => __('Partenaires', 'anes-tetues'),
],
'public' => true,
'has_archive' => false,
'show_in_rest' => true,
'menu_position' => 21,
'menu_icon' => 'dashicons-groups',
'supports' => ['title'],
'rewrite' => [
'slug' => 'partenaires',
'with_front' => false,
],
]);
register_post_type('createur_local', [
'labels' => [
'name' => __('Créateurs locaux', 'anes-tetues'),
'singular_name' => __('Créateur local', 'anes-tetues'),
'add_new' => __('Ajouter un créateur', 'anes-tetues'),
'add_new_item' => __('Ajouter un créateur local', 'anes-tetues'),
'edit_item' => __('Modifier le créateur local', 'anes-tetues'),
'new_item' => __('Nouveau créateur local', 'anes-tetues'),
'view_item' => __('Voir le créateur local', 'anes-tetues'),
'search_items' => __('Rechercher un créateur local', 'anes-tetues'),
'not_found' => __('Aucun créateur local trouvé', 'anes-tetues'),
'not_found_in_trash' => __('Aucun créateur local dans la corbeille', 'anes-tetues'),
'all_items' => __('Tous les créateurs locaux', 'anes-tetues'),
'menu_name' => __('Créateurs locaux', 'anes-tetues'),
],
'public' => true,
'has_archive' => false,
'show_in_rest' => true,
'menu_position' => 22,
'menu_icon' => 'dashicons-store',
'supports' => ['title', 'thumbnail'],
'rewrite' => [
'slug' => 'createurs-locaux',
'with_front' => false,
],
]);
});
/**
* Register "Produits créateurs" custom post type.
*/
add_action('init', function () {
register_post_type('produit_createur', [
'labels' => [
'name' => __('Produits créateurs', 'anes-tetues'),
'singular_name' => __('Produit créateur', 'anes-tetues'),
'add_new' => __('Ajouter un produit créateur', 'anes-tetues'),
'add_new_item' => __('Ajouter un produit créateur', 'anes-tetues'),
'edit_item' => __('Modifier le produit créateur', 'anes-tetues'),
'new_item' => __('Nouveau produit créateur', 'anes-tetues'),
'view_item' => __('Voir le produit créateur', 'anes-tetues'),
'search_items' => __('Rechercher un produit créateur', 'anes-tetues'),
'not_found' => __('Aucun produit créateur trouvé', 'anes-tetues'),
'not_found_in_trash' => __('Aucun produit créateur dans la corbeille', 'anes-tetues'),
'all_items' => __('Tous les produits créateurs', 'anes-tetues'),
'menu_name' => __('Produits créateurs', 'anes-tetues'),
],
'public' => true,
'has_archive' => false,
'show_in_rest' => true,
'menu_position' => 23,
'menu_icon' => 'dashicons-cart',
'supports' => ['title', 'thumbnail'],
'rewrite' => [
'slug' => 'produits-createurs',
'with_front' => false,
],
]);
register_post_type('reservation_createur', [
'labels' => [
'name' => __('Réservations créateurs', 'anes-tetues'),
'singular_name' => __('Réservation créateur', 'anes-tetues'),
'add_new' => __('Ajouter une réservation', 'anes-tetues'),
'add_new_item' => __('Ajouter une réservation créateur', 'anes-tetues'),
'edit_item' => __('Modifier la réservation créateur', 'anes-tetues'),
'new_item' => __('Nouvelle réservation créateur', 'anes-tetues'),
'view_item' => __('Voir la réservation créateur', 'anes-tetues'),
'search_items' => __('Rechercher une réservation créateur', 'anes-tetues'),
'not_found' => __('Aucune réservation trouvée', 'anes-tetues'),
'not_found_in_trash' => __('Aucune réservation dans la corbeille', 'anes-tetues'),
'all_items' => __('Toutes les réservations créateurs', 'anes-tetues'),
'menu_name' => __('Réservations créateurs', 'anes-tetues'),
],
'public' => false,
'show_ui' => true,
'show_in_menu' => true,
'has_archive' => false,
'show_in_rest' => false,
'menu_position' => 24,
'menu_icon' => 'dashicons-clipboard',
'supports' => ['title'],
]);
});
/**
* Métabox d'affichage des détails d'une réservation créateur.
*/
add_action('add_meta_boxes', function () {
add_meta_box(
'reservation_createur_details',
__('Détails de la réservation créateur', 'anes-tetues'),
function (\WP_Post $post) {
if ($post->post_type !== 'reservation_createur') {
return;
}
$order_id = get_post_meta($post->ID, '_order_id', true);
$order_num = get_post_meta($post->ID, '_order_number', true);
$customer = [
'name' => get_post_meta($post->ID, '_customer_name', true),
'email' => get_post_meta($post->ID, '_customer_email', true),
'phone' => get_post_meta($post->ID, '_customer_phone', true),
'address' => get_post_meta($post->ID, '_customer_address', true),
];
$creator_id = (int) get_post_meta($post->ID, '_creator_id', true);
$creator = [
'name' => get_post_meta($post->ID, '_creator_name', true),
'email' => get_post_meta($post->ID, '_creator_email', true),
'link' => $creator_id ? get_edit_post_link($creator_id) : '',
];
$product_id = (int) get_post_meta($post->ID, '_product_id', true);
$product = [
'name' => get_post_meta($post->ID, '_product_name', true),
'price' => get_post_meta($post->ID, '_product_price', true),
'qty' => get_post_meta($post->ID, '_quantity', true),
'link' => $product_id ? get_edit_post_link($product_id) : '',
];
$order_link = $order_id ? admin_url('post.php?post='.$order_id.'&action=edit') : '';
?>
<table class="form-table">
<tbody>
<tr>
<th scope="row"><?php echo esc_html(__('Commande', 'anes-tetues')); ?></th>
<td>
<?php if ($order_link) : ?>
<a href="<?php echo esc_url($order_link); ?>">
<?php echo esc_html(sprintf(__('Commande #%s', 'anes-tetues'), $order_num ?: $order_id)); ?>
</a>
<?php else : ?>
<?php echo esc_html($order_num ?: $order_id ?: '—'); ?>
<?php endif; ?>
</td>
</tr>
<tr>
<th scope="row"><?php echo esc_html(__('Client', 'anes-tetues')); ?></th>
<td>
<?php if (! empty($customer['name'])) : ?>
<strong><?php echo esc_html($customer['name']); ?></strong><br>
<?php endif; ?>
<?php if (! empty($customer['address'])) : ?>
<span><?php echo nl2br(esc_html($customer['address'])); ?></span><br>
<?php endif; ?>
<?php if (! empty($customer['phone'])) : ?>
<span><?php echo esc_html($customer['phone']); ?></span><br>
<?php endif; ?>
<?php if (! empty($customer['email'])) : ?>
<a href="mailto:<?php echo esc_attr($customer['email']); ?>">
<?php echo esc_html($customer['email']); ?>
</a>
<?php endif; ?>
</td>
</tr>
<tr>
<th scope="row"><?php echo esc_html(__('Créateur', 'anes-tetues')); ?></th>
<td>
<?php if (! empty($creator['name'])) : ?>
<?php if ($creator['link']) : ?>
<a href="<?php echo esc_url($creator['link']); ?>">
<strong><?php echo esc_html($creator['name']); ?></strong>
</a>
<?php else : ?>
<strong><?php echo esc_html($creator['name']); ?></strong>
<?php endif; ?>
<br>
<?php endif; ?>
<?php if (! empty($creator['email'])) : ?>
<a href="mailto:<?php echo esc_attr($creator['email']); ?>">
<?php echo esc_html($creator['email']); ?>
</a>
<?php endif; ?>
</td>
</tr>
<tr>
<th scope="row"><?php echo esc_html(__('Produit réservé', 'anes-tetues')); ?></th>
<td>
<?php if (! empty($product['name'])) : ?>
<?php if ($product['link']) : ?>
<a href="<?php echo esc_url($product['link']); ?>">
<strong><?php echo esc_html($product['name']); ?></strong>
</a>
<?php else : ?>
<strong><?php echo esc_html($product['name']); ?></strong>
<?php endif; ?>
<br>
<?php endif; ?>
<?php if (! empty($product['qty'])) : ?>
<span><?php echo esc_html(sprintf(__('Quantité : %s', 'anes-tetues'), $product['qty'])); ?></span><br>
<?php endif; ?>
<?php if ($product['price'] !== '') : ?>
<?php
$formatted_price = number_format((float) $product['price'], 2, ',', ' ') . ' €';
?>
<span><?php echo esc_html(sprintf(__('Prix unitaire : %s', 'anes-tetues'), $formatted_price)); ?></span>
<?php endif; ?>
</td>
</tr>
</tbody>
</table>
<?php
},
'reservation_createur',
'normal',
'high'
);
});
/**
* Personnalise les URLs des produits créateurs pour les mettre en
* sous-pages de leur créateur local :
* createurs-locaux/{slug-createur}/{slug-produit}
*/
add_filter('post_type_link', function ($permalink, $post, $leavename, $sample) {
if ($post->post_type !== 'produit_createur') {
return $permalink;
}
// Champ ACF "createur" (relation vers createur_local)
$createur_field = get_field('createur', $post->ID);
if (empty($createur_field)) {
return $permalink;
}
// Le champ peut être un tableau (plusieurs créateurs) ou un seul ID/objet
$createur = is_array($createur_field) ? reset($createur_field) : $createur_field;
if (is_numeric($createur)) {
$createur_post = get_post((int) $createur);
} elseif ($createur instanceof \WP_Post) {
$createur_post = $createur;
} else {
return $permalink;
}
if (! $createur_post instanceof \WP_Post) {
return $permalink;
}
$createur_slug = $createur_post->post_name;
return home_url(user_trailingslashit(sprintf(
'createurs-locaux/%s/%s',
$createur_slug,
$post->post_name
)));
}, 10, 4);
/**
* Règle de réécriture pour faire fonctionner les URLs
* createurs-locaux/{slug-createur}/{slug-produit}
* en pointant sur le CPT produit_createur.
*/
add_action('init', function () {
add_rewrite_rule(
'^createurs-locaux/([^/]+)/([^/]+)/?$',
'index.php?post_type=produit_createur&name=$matches[2]',
'top'
);
}, 20);
/**
* Register "Catégories" taxonomy for Partenaires.
*/
add_action('init', function () {
register_taxonomy('partenaire_categorie', ['partenaire'], [
'labels' => [
'name' => __('Catégories', 'anes-tetues'),
'singular_name' => __('Catégorie', 'anes-tetues'),
'search_items' => __('Rechercher une catégorie', 'anes-tetues'),
'all_items' => __('Toutes les catégories', 'anes-tetues'),
'parent_item' => __('Catégorie parente', 'anes-tetues'),
'parent_item_colon' => __('Catégorie parente :', 'anes-tetues'),
'edit_item' => __('Modifier la catégorie', 'anes-tetues'),
'update_item' => __('Mettre à jour la catégorie', 'anes-tetues'),
'add_new_item' => __('Ajouter une nouvelle catégorie', 'anes-tetues'),
'new_item_name' => __('Nouvelle catégorie', 'anes-tetues'),
'menu_name' => __('Catégories', 'anes-tetues'),
],
'public' => true,
'hierarchical' => true,
'show_ui' => true,
'show_admin_column' => true,
'show_in_rest' => true,
'rewrite' => [
'slug' => 'partenaires/categorie',
'with_front' => false,
],
]);
});
/**
* ACF: remplit dynamiquement les dates disponibles pour chaque artiste
* en fonction des dates du prochain concert (page d’options).
*
* Nécessite un champ ACF "Checkbox" sur le CPT Line Up :
* - Nom du champ : lineup_dates
* - Type : checkbox
* - Choices : laissés vides (remplis par ce filtre)
*/
add_filter('acf/load_field/name=lineup_dates', function (array $field): array {
$dateDebut = get_field('date_de_debut', 'option');
$dateFin = get_field('date_de_fin', 'option');
// Réinitialiser les choix
$field['choices'] = [];
if (!$dateDebut || !$dateFin) {
return $field;
}
try {
$start = \Carbon\Carbon::createFromFormat('d/m/Y', $dateDebut);
$end = \Carbon\Carbon::createFromFormat('d/m/Y', $dateFin);
} catch (\Exception $e) {
return $field;
}
if ($end->lessThan($start)) {
[$start, $end] = [$end, $start];
}
// Génère une case à cocher pour chaque jour entre début et fin (inclus)
for ($date = $start->copy(); $date->lte($end); $date->addDay()) {
$value = $date->format('Y-m-d'); // valeur stockée
$label = $date->locale('fr')->translatedFormat('d F Y'); // label lisible
$field['choices'][$value] = $label;
}
return $field;
});
// Enlève l'éditeur de wp sur les pages sauf pour les pages "mentions-legales" et "politique-de-confidentialite"
function init_remove_support(): void
{
$post_type = 'page';
// Vérifiez si nous sommes dans l'éditeur de page
if (isset($_GET['post'])) {
$post_id = $_GET['post'];
$post = get_post($post_id);
// Vérifiez si le post est une page et son post_name
if ($post && $post->post_type === $post_type && $post->post_name) {
$post_name = $post->post_name;
// Vérifiez si la page est "mentions-legales" ou "politique-de-confidentialite"
if ($post_name === 'mentions-legales' || $post_name === 'politique-de-confidentialite' || $post_name === 'newsletter') {
return; // Ne rien faire, permettre l'éditeur de contenu pour ces pages
}
}
}
// Si ce n'est pas "mentions-legales" ou "politique-de-confidentialite", supprimer le support
remove_post_type_support($post_type, 'editor');
remove_post_type_support($post_type, 'comments');
remove_post_type_support($post_type, 'author');
}
add_action('admin_init', function () {
init_remove_support();
});
add_theme_support('custom-logo');
add_action('after_setup_theme', function () {
add_theme_support('woocommerce');
}, 20);
/**
* Empêche WooCommerce d'ajouter automatiquement son message
* "Votre panier est vide" via le hook `woocommerce_cart_is_empty`.
* On gère nous-même l'affichage du message + bouton.
*/
add_action('init', function () {
if (function_exists('wc_empty_cart_message')) {
remove_action('woocommerce_cart_is_empty', 'wc_empty_cart_message', 10);
}
// On remplace aussi le rendu du bouton "Procéder au paiement"
// pour pouvoir insérer le tableau des réservations juste avant.
if (function_exists('woocommerce_button_proceed_to_checkout')) {
remove_action('woocommerce_proceed_to_checkout', 'woocommerce_button_proceed_to_checkout', 20);
add_action('woocommerce_proceed_to_checkout', function () {
if (function_exists('WC') && WC()->session) {
$reservations = WC()->session->get('createur_reservations', []);
if (is_array($reservations) && ! empty($reservations)) {
echo \Roots\view('partials.cart-reservations', [
'reservations' => $reservations,
'sectionClasses' => '',
'showReserveButton' => false,
]);
}
}
// Bouton WooCommerce standard
woocommerce_button_proceed_to_checkout();
}, 20);
}
});
/**
* Gestion des "produits créateurs" en session de réservation :
* - ajout depuis la fiche produit
* - suppression depuis le panier.
*
* Les données sont stockées séparément du panier WooCommerce
* dans WC()->session['createur_reservations'].
*
* Utilise le hook `wp` plutôt que `template_redirect` pour s'assurer
* que la logique est exécutée sur les pages de type `produit_createur`,
* même si d'autres extensions interfèrent avec `template_redirect`.
*/
add_action('wp', function () {
if (! function_exists('WC')) {
return;
}
// Si la session WooCommerce n'est pas initialisée, on affiche au moins
// un message explicite au client pour éviter l'impression que rien ne se passe.
if (! WC()->session) {
if (function_exists('wc_add_notice')) {
wc_add_notice(
__('Les réservations ne sont pas disponibles pour le moment (session WooCommerce non initialisée).', 'anes-tetues'),
'error'
);
}
return;
}
// Récupère la liste actuelle en session
$reservations = WC()->session->get('createur_reservations', []);
if (! is_array($reservations)) {
$reservations = [];
}
// 1) Suppression d'une réservation depuis le panier
if (! empty($_POST['remove_produit_createur_reservation']) && ! empty($_POST['produit_createur_id'])) {
$produit_createur_id = (int) $_POST['produit_createur_id'];
if (isset($reservations[$produit_createur_id])) {
unset($reservations[$produit_createur_id]);
WC()->session->set('createur_reservations', $reservations);
wc_add_notice(__('Réservation supprimée.', 'anes-tetues'));
}
// Retourne là d'où vient l'action (panier, etc.)
$fallback_url = function_exists('wc_get_cart_url') ? wc_get_cart_url() : home_url('/');
$redirect_url = wp_get_referer() ?: $fallback_url;
wp_safe_redirect($redirect_url);
exit;
}
// 2) Soumission des réservations seules (sans produits WooCommerce)
if (! empty($_POST['submit_createur_reservations_only'])) {
if (empty($reservations)) {
wc_add_notice(__('Aucune réservation à valider.', 'anes-tetues'), 'error');
} else {
$name = isset($_POST['reservation_customer_name']) ? trim(wp_unslash($_POST['reservation_customer_name'])) : '';
$email = isset($_POST['reservation_customer_email']) ? trim(wp_unslash($_POST['reservation_customer_email'])) : '';
$phone = isset($_POST['reservation_customer_phone']) ? trim(wp_unslash($_POST['reservation_customer_phone'])) : '';
if (! is_email($email)) {
wc_add_notice(__('Merci de renseigner un email valide pour vos réservations.', 'anes-tetues'), 'error');
} else {
// On enrichit d'abord les réservations (titre produit, prix, créateur...)
$enriched = [];
foreach ($reservations as $reservation) {
if (! isset($reservation['produit_createur_id'])) {
continue;
}
$produit_id = (int) $reservation['produit_createur_id'];
if (! $produit_id) {
continue;
}
$quantity = isset($reservation['quantity']) ? (int) $reservation['quantity'] : 1;
$quantity = $quantity > 0 ? $quantity : 1;
$post = get_post($produit_id);
if (! $post) {
continue;
}
$title = get_the_title($produit_id);
$price = get_field('prix', $produit_id);
$creator_id = null;
$creator_name = '';
$creator_email = '';
$creator_field = get_field('createur', $produit_id);
if (is_array($creator_field) && ! empty($creator_field)) {
$first = reset($creator_field);
if ($first instanceof \WP_Post) {
$creator_id = $first->ID;
} elseif (is_numeric($first)) {
$creator_id = (int) $first;
}
} elseif ($creator_field instanceof \WP_Post) {
$creator_id = $creator_field->ID;
} elseif (is_numeric($creator_field)) {
$creator_id = (int) $creator_field;
}
if ($creator_id) {
$creator_name = get_the_title($creator_id);
$creator_infos = get_field('informations', $creator_id);
if (is_array($creator_infos) && ! empty($creator_infos['mail'])) {
$creator_email = (string) $creator_infos['mail'];
}
}
$enriched[] = [
'produit_createur_id' => $produit_id,
'produit_createur_titre' => $title,
'produit_createur_prix' => $price !== null ? (float) $price : null,
'quantity' => $quantity,
'createur_id' => $creator_id,
'createur_nom' => $creator_name,
'creator_email' => $creator_email,
];
}
$reservations = $enriched;
// On réutilise la logique d'enregistrement et d'envoi d'emails,
// mais sans commande WooCommerce : on crée l'équivalent d'un "numéro de réservation".
$reservation_number = 'R-' . date('Ymd-His');
$blogname = wp_specialchars_decode(get_option('blogname'), ENT_QUOTES);
$headers = ['Content-Type: text/html; charset=UTF-8'];
// Création des CPT reservation_createur (une par ligne)
foreach ($reservations as $item) {
if (empty($item['createur_id']) || empty($item['produit_createur_id'])) {
continue;
}
$creator_id = (int) $item['createur_id'];
$produit_id = (int) $item['produit_createur_id'];
$quantity = isset($item['quantity']) ? (int) $item['quantity'] : 1;
$quantity = $quantity > 0 ? $quantity : 1;
$price = isset($item['produit_createur_prix']) ? (float) $item['produit_createur_prix'] : null;
$creator_name = $item['createur_nom'] ?? get_the_title($creator_id);
$product_name = $item['produit_createur_titre'] ?? get_the_title($produit_id);
$post_id = wp_insert_post([
'post_type' => 'reservation_createur',
'post_status' => 'publish',
'post_title' => sprintf(
__('Réservation %s – %s', 'anes-tetues'),
$reservation_number,
$product_name
),
]);
if ($post_id && ! is_wp_error($post_id)) {
update_post_meta($post_id, '_order_id', 0);
update_post_meta($post_id, '_order_number', $reservation_number);
update_post_meta($post_id, '_customer_name', $name);
update_post_meta($post_id, '_customer_email', $email);
update_post_meta($post_id, '_customer_phone', $phone);
update_post_meta($post_id, '_customer_address', '');
update_post_meta($post_id, '_creator_id', $creator_id);
update_post_meta($post_id, '_creator_name', $creator_name);
update_post_meta($post_id, '_creator_email', $item['creator_email'] ?? '');
update_post_meta($post_id, '_product_id', $produit_id);
update_post_meta($post_id, '_product_name', $product_name);
update_post_meta($post_id, '_product_price', $price);
update_post_meta($post_id, '_quantity', $quantity);
}
}
// Envoi des emails (client + créateurs) via le mailer WooCommerce
$mailer = WC()->mailer();
// On fabrique un petit objet avec une méthode get_order_number()
// pour réutiliser les templates existants.
$order_like = new class($reservation_number) {
private $number;
public function __construct($number) { $this->number = $number; }
public function get_order_number() { return $this->number; }
};
// Email client
if (! empty($email)) {
$subject = sprintf(
__('Vos réservations chez %s', 'anes-tetues'),
$blogname
);
$body = \Roots\view('emails.reservations-customer', [
'order' => $order_like,
'reservations' => array_values($reservations),
'customer_name' => $name,
'customer_email' => $email,
'site_name' => $blogname,
]);
$mailer->send($email, $subject, $body, $headers);
}
// Emails créateurs
$by_creator = [];
foreach ($reservations as $item) {
$creator_id = $item['createur_id'] ?? null;
if (! $creator_id) {
continue;
}
if (! isset($by_creator[$creator_id])) {
$by_creator[$creator_id] = [
'creator_id' => $creator_id,
'creator_nom' => $item['createur_nom'] ?? '',
'creator_email' => $item['creator_email'] ?? '',
'items' => [],
];
}
$by_creator[$creator_id]['items'][] = $item;
}
if (! empty($by_creator)) {
foreach ($by_creator as $creator) {
$to = trim((string) ($creator['creator_email'] ?? ''));
if ($to === '') {
continue;
}
$creator_name = $creator['creator_nom'] ?: __('Créateur', 'anes-tetues');
$subject = sprintf(
__('Nouvelles réservations via %s', 'anes-tetues'),
$blogname
);
$body = \Roots\view('emails.reservations-creator', [
'order' => $order_like,
'creator_name' => $creator_name,
'creator_email' => $to,
'reservations' => $creator['items'],
'customer_name' => $name,
'customer_email' => $email,
'site_name' => $blogname,
]);
$mailer->send($to, $subject, $body, $headers);
}
}
// On vide les réservations de session après traitement
WC()->session->set('createur_reservations', []);
wc_add_notice(__('Vos réservations ont bien été envoyées.', 'anes-tetues'));
}
}
$fallback_url = function_exists('wc_get_cart_url') ? wc_get_cart_url() : home_url('/');
$redirect_url = wp_get_referer() ?: $fallback_url;
wp_safe_redirect($redirect_url);
exit;
}
// 3) Ajout d'une réservation depuis la fiche produit créateur
// On accepte désormais aussi bien POST que GET pour être plus robuste
// face à d'éventuelles redirections qui convertiraient la requête.
$source = null;
if (! empty($_POST['produit_createur_reservation']) && ! empty($_POST['produit_createur_id'])) {
$source = $_POST;
} elseif (! empty($_GET['produit_createur_reservation']) && ! empty($_GET['produit_createur_id'])) {
$source = $_GET;
}
if (! $source) {
return;
}
$produit_createur_id = (int) $source['produit_createur_id'];
$quantity = isset($source['reservation_quantity']) ? (int) $source['reservation_quantity'] : 1;
$quantity = $quantity > 0 ? $quantity : 1;
// On regroupe les quantités par produit créateur
if (isset($reservations[$produit_createur_id])) {
$reservations[$produit_createur_id]['quantity'] += $quantity;
} else {
$reservations[$produit_createur_id] = [
'produit_createur_id' => $produit_createur_id,
'quantity' => $quantity,
];
}
// Sauvegarde en session WooCommerce
WC()->session->set('createur_reservations', $reservations);
// Message de confirmation pour l’utilisateur
wc_add_notice(__('Produit ajouté à votre liste de réservation.', 'anes-tetues'));
// Retourne sur la page d’où vient l’ajout (fiche produit en général)
$fallback_url = get_permalink($produit_createur_id) ?: (function_exists('wc_get_cart_url') ? wc_get_cart_url() : home_url('/'));
$redirect_url = wp_get_referer() ?: $fallback_url;
wp_safe_redirect($redirect_url);
exit;
});
/**
* Cart front: message + bouton vers la boutique quand le panier est vide.
*/
add_action('woocommerce_cart_is_empty', function () {
// Message unique "panier vide"
echo '<div class="wc-empty-cart-message">';
echo '<div class="cart-empty woocommerce-info" role="status">';
echo esc_html__('Votre panier est actuellement vide.', 'woocommerce');
echo '</div>';
echo '</div>';
// Si des réservations existent en session, on affiche quand même le bloc
// "Réservations" avec un bouton "Réserver".
if (function_exists('WC') && WC()->session) {
$reservations = WC()->session->get('createur_reservations', []);
if (is_array($reservations) && ! empty($reservations)) {
echo \Roots\view('partials.cart-reservations', [
'reservations' => $reservations,
'sectionClasses' => 'mb',
'showReserveButton' => true,
]);
}
}
// Bouton "Voir la boutique"
$shop_url = function_exists('wc_get_page_permalink') ? wc_get_page_permalink('shop') : home_url('/');
echo sprintf(
'<div class="cart-empty-back-shop"><a href="%s" class="btn bg-secondary arrow-primary">%s</a></div>',
esc_url($shop_url),
esc_html__('Voir la boutique', 'anes-tetues')
);
}, 20);
/**
* Quand la commande arrive sur la page "merci",
* on :
* - copie les réservations créateurs de la session vers la commande (si besoin) ;
* - envoie un mail récap au client ;
* - envoie un mail à chaque créateur concerné.
*/
add_action('woocommerce_thankyou', function ($order_id) {
$order = wc_get_order($order_id);
if (! $order) {
return;
}
// On évite les doublons si jamais le hook est appelé plusieurs fois.
$already_sent = get_post_meta($order_id, '_createur_reservations_emails_sent', true);
if ($already_sent) {
return;
}
// 1) Récupération des réservations associées à la commande.
$reservations = get_post_meta($order_id, '_createur_reservations', true);
// Si aucune meta n'est encore enregistrée, on tente de les récupérer depuis la session.
if (! is_array($reservations) || empty($reservations)) {
if (function_exists('WC') && WC()->session) {
$session_reservations = WC()->session->get('createur_reservations', []);
if (is_array($session_reservations) && ! empty($session_reservations)) {
$enriched = [];
foreach ($session_reservations as $reservation) {
if (! isset($reservation['produit_createur_id'])) {
continue;
}
$produit_id = (int) $reservation['produit_createur_id'];
if (! $produit_id) {
continue;
}
$quantity = isset($reservation['quantity']) ? (int) $reservation['quantity'] : 1;
$quantity = $quantity > 0 ? $quantity : 1;
$post = get_post($produit_id);
if (! $post) {
continue;
}
$title = get_the_title($produit_id);
$price = get_field('prix', $produit_id);
$creator_id = null;
$creator_name = '';
$creator_email = '';
// Champ ACF "createur" sur le CPT produit_createur
// type = relationship, return_format = object, min/max = 1
$creator_field = get_field('createur', $produit_id);
if (is_array($creator_field) && ! empty($creator_field)) {
// Relationship retourne un tableau d'objets WP_Post
$first = reset($creator_field);
if ($first instanceof \WP_Post) {
$creator_id = $first->ID;
} elseif (is_numeric($first)) {
$creator_id = (int) $first;
}
} elseif ($creator_field instanceof \WP_Post) {
$creator_id = $creator_field->ID;
} elseif (is_numeric($creator_field)) {
$creator_id = (int) $creator_field;
}
if ($creator_id) {
$creator_name = get_the_title($creator_id);
// Sur le CPT createur_local, l'email est dans le group "informations" > "mail"
$creator_infos = get_field('informations', $creator_id);
if (is_array($creator_infos) && ! empty($creator_infos['mail'])) {
$creator_email = (string) $creator_infos['mail'];
}
}
$enriched[] = [
'produit_createur_id' => $produit_id,
'produit_createur_titre' => $title,
'produit_createur_prix' => $price !== null ? (float) $price : null,
'quantity' => $quantity,
'createur_id' => $creator_id,
'createur_nom' => $creator_name,
'creator_email' => $creator_email,
];
}
if (! empty($enriched)) {
$reservations = $enriched;
update_post_meta($order_id, '_createur_reservations', $reservations);
// On nettoie la session une fois qu'on a tout recopié vers la commande.
WC()->session->set('createur_reservations', []);
}
}
}
}
$blogname = wp_specialchars_decode(get_option('blogname'), ENT_QUOTES);
$customer_email = $order->get_billing_email();
$customer_name = trim($order->get_billing_first_name() . ' ' . $order->get_billing_last_name());
$customer_phone = $order->get_billing_phone();
$customer_adress = trim($order->get_billing_address_1() . ' ' . $order->get_billing_postcode() . ' ' . $order->get_billing_city());
$headers = [
'Content-Type: text/html; charset=UTF-8',
];
// Si aucune réservation, on sort.
if (! is_array($reservations) || empty($reservations)) {
return;
}
// 2) Enregistrement dans le CPT reservation_createur (une entrée par ligne de réservation).
foreach ($reservations as $item) {
$creator_id = $item['createur_id'] ?? null;
if (! $creator_id) {
continue;
}
$produit_id = $item['produit_createur_id'] ?? null;
$quantity = isset($item['quantity']) ? (int) $item['quantity'] : 1;
$quantity = $quantity > 0 ? $quantity : 1;
$price = isset($item['produit_createur_prix']) ? (float) $item['produit_createur_prix'] : null;
$creator_name = $item['createur_nom'] ?? get_the_title($creator_id);
$product_name = $item['produit_createur_titre'] ?? ($produit_id ? get_the_title($produit_id) : '');
$post_id = wp_insert_post([
'post_type' => 'reservation_createur',
'post_status' => 'publish',
'post_title' => sprintf(
__('Réservation %s – %s', 'anes-tetues'),
$order->get_order_number(),
$product_name
),
]);
if ($post_id && ! is_wp_error($post_id)) {
update_post_meta($post_id, '_order_id', $order_id);
update_post_meta($post_id, '_order_number', $order->get_order_number());
update_post_meta($post_id, '_customer_name', $customer_name);
update_post_meta($post_id, '_customer_email', $customer_email);
update_post_meta($post_id, '_customer_phone', $customer_phone);
update_post_meta($post_id, '_customer_address', $customer_adress);
update_post_meta($post_id, '_creator_id', $creator_id);
update_post_meta($post_id, '_creator_name', $creator_name);
update_post_meta($post_id, '_creator_email', $item['creator_email'] ?? '');
update_post_meta($post_id, '_product_id', $produit_id);
update_post_meta($post_id, '_product_name', $product_name);
update_post_meta($post_id, '_product_price', $price);
update_post_meta($post_id, '_quantity', $quantity);
}
}
$mailer = function_exists('WC') ? WC()->mailer() : null;
// 2) Email client.
if ($mailer && ! empty($customer_email)) {
$subject = sprintf(
__('Vos réservations chez %s', 'anes-tetues'),
$blogname
);
$body = \Roots\view('emails.reservations-customer', [
'order' => $order,
'reservations' => $reservations,
'customer_name' => $customer_name,
'customer_email' => $customer_email,
'site_name' => $blogname,
]);
$mailer->send($customer_email, $subject, $body, $headers);
}
// 3) Emails aux créateurs (groupés par créateur).
if ($mailer) {
$by_creator = [];
foreach ($reservations as $item) {
$creator_id = $item['createur_id'] ?? null;
if (! $creator_id) {
continue;
}
if (! isset($by_creator[$creator_id])) {
$by_creator[$creator_id] = [
'creator_id' => $creator_id,
'creator_nom' => $item['createur_nom'] ?? '',
'creator_email' => $item['creator_email'] ?? '',
'items' => [],
];
}
$by_creator[$creator_id]['items'][] = $item;
}
if (! empty($by_creator)) {
foreach ($by_creator as $creator) {
$to = trim((string) ($creator['creator_email'] ?? ''));
if ($to === '') {
continue;
}
$creator_name = $creator['creator_nom'] ?: __('Créateur', 'anes-tetues');
$subject = sprintf(
__('Nouvelles réservations via %s', 'anes-tetues'),
$blogname
);
$body = \Roots\view('emails.reservations-creator', [
'order' => $order,
'creator_name' => $creator_name,
'creator_email' => $to,
'reservations' => $creator['items'],
'customer_name' => $customer_name,
'customer_email' => $customer_email,
'site_name' => $blogname,
]);
$mailer->send($to, $subject, $body, $headers);
}
}
}
// Marqueur pour ne pas renvoyer plusieurs fois les mêmes emails.
update_post_meta($order_id, '_createur_reservations_emails_sent', 1);
}, 10, 1);