array( 'name' => 'Réalisations', 'singular_name' => 'Réalisation', 'add_new_item' => 'Ajouter une réalisation', 'edit_item' => 'Modifier la réalisation', ), 'public' => true, 'has_archive' => false, 'supports' => array('title', 'editor', 'thumbnail', 'excerpt'), 'menu_icon' => 'dashicons-portfolio', 'show_in_rest' => true, 'rewrite' => array('slug' => 'realisations'), )); register_post_type('service', array( 'labels' => array( 'name' => 'Services', 'singular_name' => 'Service', 'add_new_item' => 'Ajouter un service', 'edit_item' => 'Modifier le service', ), 'public' => true, 'has_archive' => false, 'supports' => array('title', 'editor', 'thumbnail', 'excerpt'), 'menu_icon' => 'dashicons-portfolio', 'show_in_rest' => true, 'rewrite' => array('slug' => 'services'), )); } add_action('init', 'yb2026_post_types'); function yb2026_flush() { yb2026_post_types(); flush_rewrite_rules(); } add_action('after_switch_theme', 'yb2026_flush'); /* ── Meta-box réalisation : champs de l'étude de cas ────────────────── */ function yb2026_add_metaboxes() { add_meta_box('yb_real_meta', 'Étude de cas (design v2)', 'yb2026_render_real_metabox', 'realisation', 'normal', 'high'); } add_action('add_meta_boxes', 'yb2026_add_metaboxes'); function yb2026_render_real_metabox($post) { wp_nonce_field('yb_real_nonce_action', 'yb_real_nonce'); $f = function ($k) use ($post) { return esc_attr(get_post_meta($post->ID, $k, true)); }; $sections = get_post_meta($post->ID, '_yb_sections', true); $sections_txt = ''; if ($sections) { $arr = json_decode($sections, true); if (is_array($arr)) { foreach ($arr as $s) { $sections_txt .= '/ ' . $s['h'] . "\n" . $s['p'] . "\n\n"; } } } ?>
'_yb_order', 'yb_tag' => '_yb_tag', 'yb_year' => '_yb_year', 'yb_role' => '_yb_role', 'yb_short' => '_yb_short', 'yb_note' => '_yb_note') as $field => $key) { if (isset($_POST[$field])) { update_post_meta($post_id, $key, sanitize_text_field($_POST[$field])); } } if (isset($_POST['yb_desc'])) { update_post_meta($post_id, '_yb_desc', sanitize_textarea_field($_POST['yb_desc'])); } if (isset($_POST['yb_sections'])) { $raw = str_replace("\r\n", "\n", (string) $_POST['yb_sections']); $out = array(); foreach (preg_split('/\n\s*\n/', trim($raw)) as $block) { $lines = explode("\n", trim($block)); if (count($lines) < 2 || strpos($lines[0], '/') !== 0) continue; $out[] = array( 'h' => sanitize_text_field(ltrim(substr($lines[0], 1))), 'p' => sanitize_textarea_field(implode(' ', array_slice($lines, 1))), ); } update_post_meta($post_id, '_yb_sections', $out ? wp_json_encode($out, JSON_UNESCAPED_UNICODE) : ''); } } add_action('save_post_realisation', 'yb2026_save_metaboxes'); /* ── Helpers ─────────────────────────────────────────────────────────── */ /** Toutes les réalisations triées par _yb_order (fallback date). */ function yb2026_get_projects($limit = -1) { $q = new WP_Query(array( 'post_type' => 'realisation', 'posts_per_page' => $limit, 'meta_key' => '_yb_order', 'orderby' => array('meta_value_num' => 'ASC', 'date' => 'DESC'), 'no_found_rows' => true, )); return $q->posts; } /** Numéro « 01 » d'une réalisation. */ function yb2026_num($post_id) { $o = (int) get_post_meta($post_id, '_yb_order', true); return str_pad($o ? $o : 1, 2, '0', STR_PAD_LEFT); } /** Nom court d'un projet : partie avant le « : » du titre WP (ancien séparateur « : » toléré). */ function yb2026_short_title($p) { $t = get_the_title($p); $parts = preg_split('/\s+[:\x{2014}]\s+/u', $t, 2); return $parts[0]; } /** Carte projet (piste des travaux sur l'accueil + grille réalisations). Classes .card / .card-img attendues par effects.css et effects.js (compteur, hover N&B). */ function yb2026_project_card($p, $home = false) { $tag = get_post_meta($p->ID, '_yb_tag', true); if (!$tag) $tag = strtoupper((string) get_post_meta($p->ID, '_real_technologies', true)); $short = get_post_meta($p->ID, '_yb_short', true); if (!$short) $short = get_the_excerpt($p); $year = get_post_meta($p->ID, '_yb_year', true); $name = yb2026_short_title($p); ?> > 'lazy', 'alt' => esc_attr($name))); ?> ID)); ?> → ]*>(?:(?!).)*?' . $basename . '(?:(?!).)*?#is', '', $content); $content = preg_replace('#]*?' . $basename . '[^>]*?/?>#i', '', $content); $content = preg_replace('#

\s*

#i', '', $content); return $content; }, 20); /* ── Options pages ACF (shim) ────────────────────────────────────────── */ add_action('acf/init', function () { if (function_exists('acf_add_options_page')) { acf_add_options_page(array( 'page_title' => 'Theme General Settings', 'menu_title' => 'Theme Settings', 'menu_slug' => 'theme-general-settings', 'capability' => 'edit_posts', 'redirect' => false, )); acf_add_options_sub_page(array('page_title' => 'Theme Header Settings', 'menu_title' => 'Header', 'parent_slug' => 'theme-general-settings')); acf_add_options_sub_page(array('page_title' => 'Theme Social Settings', 'menu_title' => 'Social', 'parent_slug' => 'theme-general-settings')); acf_add_options_sub_page(array('page_title' => 'Theme Coordonnée Settings', 'menu_title' => 'Coordonnée', 'parent_slug' => 'theme-general-settings')); } }); /* Autoptimize : ne pas agréger le script inline anti-flash du wipe (il doit s'exécuter immédiatement après l'élément #yb-wipe, avant le paint). */ add_filter('autoptimize_filter_js_exclude', function ($exclude) { return $exclude . ', ybWipe, ybTheme'; }); /* Shortcode hérité (présent dans d'anciens contenus) */ add_shortcode('tavu', function () { return "

T'a vue ?

"; }); /* Ancienne adresse de la page Compétences : /services/ → /competences/ (301). Les contenus du CPT « service » gardent leurs adresses /services//. */ add_action('template_redirect', function () { $path = trim((string) parse_url($_SERVER['REQUEST_URI'] ?? '', PHP_URL_PATH), '/'); if ($path === 'services') { wp_redirect(home_url('/competences/'), 301); exit; } }, 1); /* ── Ressources tierces : rien n'est chargé depuis un CDN externe côté visiteur ── */ add_action('wp_enqueue_scripts', function () { wp_dequeue_style('acf-shim-fontawesome'); // icônes Font Awesome de l'admin ACF, inutiles sur le site }, 100);