Intermediaire 10 min de lecture · 2 037 mots

Développer un thème WordPress avec les standards 2025

Estimated reading time: 4 minutes

Introduction

Le développement de thèmes WordPress a connu une révolution avec l’introduction du Full Site Editing (FSE) et des block themes. En 2025, les standards de développement exigent une approche moderne qui combine l’éditeur de blocs, les global styles, l’accessibilité WCAG et les performances optimales. Ce guide complet vous accompagnera dans la création d’un thème WordPress professionnel conforme aux dernières normes.

Table of Contents

Architecture d’un block theme moderne

Structure de fichiers recommandée

La structure d’un block theme diffère des thèmes classiques. Voici l’organisation recommandée pour 2025 :

mon-theme/
├── style.css
├── theme.json
├── functions.php
├── templates/
│   ├── index.html
│   ├── single.html
│   ├── page.html
│   ├── archive.html
│   ├── 404.html
│   └── search.html
├── parts/
│   ├── header.html
│   ├── footer.html
│   └── sidebar.html
├── patterns/
│   ├── hero.php
│   ├── call-to-action.php
│   └── testimonials.php
├── assets/
│   ├── css/
│   ├── js/
│   └── images/
├── inc/
│   ├── block-patterns.php
│   ├── block-styles.php
│   └── custom-blocks.php
└── languages/

Le fichier style.css

Le header du fichier style.css est obligatoire et doit respecter ce format :

/
Theme Name: Mon Theme Moderne
Theme URI: https://exemple.com/mon-theme
Author: Votre Nom
Author URI: https://exemple.com
Description: Un theme WordPress moderne construit avec les standards 2025, Full Site Editing, et optimisé pour les performances.
Requires at least: 6.4
Tested up to: 6.5
Requires PHP: 8.0
Version: 1.0.0
License: GNU General Public License v2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
Text Domain: mon-theme
Tags: block-themes, full-site-editing, accessibility-ready, translation-ready, custom-colors, custom-menu, featured-images, threaded-comments, wide-blocks

This theme, like WordPress, is licensed under the GPL.
Use it to make something cool, have fun, and share what you've learned.
/

Le fichier theme.json : Le coeur du thème

Le fichier theme.json est le fichier de configuration central d’un block theme moderne. Il définit les styles globaux, les paramètres et les fonctionnalités.

Configuration complète de theme.json

{
  "$schema": "https://schemas.wp.org/trunk/theme.json",
  "version": 2,
  "settings": {
    "appearanceTools": true,
    "useRootPaddingAwareAlignments": true,
    "layout": {
      "contentSize": "840px",
      "wideSize": "1200px"
    },
    "color": {
      "custom": true,
      "customDuotone": true,
      "customGradient": true,
      "defaultGradients": false,
      "defaultPalette": false,
      "duotone": [
        {
          "colors": ["#000000", "#ffffff"],
          "slug": "black-and-white",
          "name": "Noir et Blanc"
        }
      ],
      "gradients": [
        {
          "slug": "primary-to-secondary",
          "gradient": "linear-gradient(135deg, var(--wp--preset--color--primary) 0%, var(--wp--preset--color--secondary) 100%)",
          "name": "Primaire vers Secondaire"
        }
      ],
      "palette": [
        {
          "slug": "primary",
          "color": "#0066cc",
          "name": "Primaire"
        },
        {
          "slug": "secondary",
          "color": "#ff6b35",
          "name": "Secondaire"
        },
        {
          "slug": "foreground",
          "color": "#1a1a1a",
          "name": "Premier plan"
        },
        {
          "slug": "background",
          "color": "#ffffff",
          "name": "Arrière-plan"
        },
        {
          "slug": "tertiary",
          "color": "#f5f5f5",
          "name": "Tertiaire"
        }
      ]
    },
    "typography": {
      "customFontSize": true,
      "fontStyle": true,
      "fontWeight": true,
      "letterSpacing": true,
      "textDecoration": true,
      "textTransform": true,
      "dropCap": false,
      "fluid": true,
      "fontSizes": [
        {
          "slug": "small",
          "size": "0.875rem",
          "name": "Petit",
          "fluid": {
            "min": "0.875rem",
            "max": "1rem"
          }
        },
        {
          "slug": "medium",
          "size": "1rem",
          "name": "Moyen",
          "fluid": false
        },
        {
          "slug": "large",
          "size": "1.5rem",
          "name": "Grand",
          "fluid": {
            "min": "1.25rem",
            "max": "1.5rem"
          }
        },
        {
          "slug": "x-large",
          "size": "2.5rem",
          "name": "Très grand",
          "fluid": {
            "min": "2rem",
            "max": "2.5rem"
          }
        }
      ],
      "fontFamilies": [
        {
          "fontFamily": "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif",
          "slug": "system",
          "name": "Système"
        },
        {
          "fontFamily": "'Inter', sans-serif",
          "slug": "inter",
          "name": "Inter",
          "fontFace": [
            {
              "fontFamily": "Inter",
              "fontWeight": "400",
              "fontStyle": "normal",
              "fontDisplay": "swap",
              "src": ["file:./assets/fonts/inter-regular.woff2"]
            },
            {
              "fontFamily": "Inter",
              "fontWeight": "700",
              "fontStyle": "normal",
              "fontDisplay": "swap",
              "src": ["file:./assets/fonts/inter-bold.woff2"]
            }
          ]
        }
      ]
    },
    "spacing": {
      "customSpacingSize": true,
      "spacingScale": {
        "steps": 0
      },
      "spacingSizes": [
        {
          "slug": "30",
          "size": "0.5rem",
          "name": "1"
        },
        {
          "slug": "40",
          "size": "1rem",
          "name": "2"
        },
        {
          "slug": "50",
          "size": "1.5rem",
          "name": "3"
        },
        {
          "slug": "60",
          "size": "2rem",
          "name": "4"
        },
        {
          "slug": "70",
          "size": "3rem",
          "name": "5"
        },
        {
          "slug": "80",
          "size": "4rem",
          "name": "6"
        }
      ],
      "units": ["px", "em", "rem", "vh", "vw", "%"]
    },
    "custom": {
      "spacing": {
        "gutter": "1.5rem"
      },
      "transition": {
        "duration": "0.3s"
      }
    }
  },
  "styles": {
    "color": {
      "background": "var(--wp--preset--color--background)",
      "text": "var(--wp--preset--color--foreground)"
    },
    "typography": {
      "fontFamily": "var(--wp--preset--font-family--inter)",
      "fontSize": "var(--wp--preset--font-size--medium)",
      "lineHeight": "1.6"
    },
    "spacing": {
      "padding": {
        "top": "0",
        "right": "var(--wp--preset--spacing--40)",
        "bottom": "0",
        "left": "var(--wp--preset--spacing--40)"
      }
    },
    "elements": {
      "link": {
        "color": {
          "text": "var(--wp--preset--color--primary)"
        },
        "typography": {
          "textDecoration": "underline"
        },
        ":hover": {
          "color": {
            "text": "var(--wp--preset--color--secondary)"
          }
        }
      },
      "button": {
        "color": {
          "background": "var(--wp--preset--color--primary)",
          "text": "var(--wp--preset--color--background)"
        },
        "typography": {
          "fontSize": "var(--wp--preset--font-size--medium)",
          "fontWeight": "700"
        },
        "spacing": {
          "padding": {
            "top": "0.75rem",
            "right": "1.5rem",
            "bottom": "0.75rem",
            "left": "1.5rem"
          }
        },
        "border": {
          "radius": "0.25rem"
        },
        ":hover": {
          "color": {
            "background": "var(--wp--preset--color--secondary)"
          }
        }
      },
      "h1": {
        "typography": {
          "fontSize": "var(--wp--preset--font-size--x-large)",
          "fontWeight": "700",
          "lineHeight": "1.2"
        },
        "spacing": {
          "margin": {
            "top": "0",
            "bottom": "var(--wp--preset--spacing--50)"
          }
        }
      },
      "h2": {
        "typography": {
          "fontSize": "var(--wp--preset--font-size--large)",
          "fontWeight": "700",
          "lineHeight": "1.3"
        }
      }
    },
    "blocks": {
      "core/navigation": {
        "typography": {
          "fontSize": "var(--wp--preset--font-size--medium)"
        }
      },
      "core/post-title": {
        "typography": {
          "fontSize": "var(--wp--preset--font-size--x-large)",
          "fontWeight": "700"
        }
      },
      "core/quote": {
        "color": {
          "background": "var(--wp--preset--color--tertiary)"
        },
        "spacing": {
          "padding": {
            "top": "var(--wp--preset--spacing--50)",
            "right": "var(--wp--preset--spacing--50)",
            "bottom": "var(--wp--preset--spacing--50)",
            "left": "var(--wp--preset--spacing--50)"
          }
        },
        "border": {
          "left": {
            "width": "4px",
            "style": "solid",
            "color": "var(--wp--preset--color--primary)"
          }
        }
      }
    }
  },
  "templateParts": [
    {
      "name": "header",
      "title": "En-tête",
      "area": "header"
    },
    {
      "name": "footer",
      "title": "Pied de page",
      "area": "footer"
    }
  ],
  "customTemplates": [
    {
      "name": "page-sans-titre",
      "title": "Page sans titre",
      "postTypes": ["page"]
    }
  ]
}

Templates HTML : L’architecture des pages

Template index.html

Le template templates/index.html est obligatoire :

L’élément de modèle a été supprimé ou n’est pas disponible : header


L’élément de modèle a été supprimé ou n’est pas disponible : footer

Template single.html

L’élément de modèle a été supprimé ou n’est pas disponible : header


Développer un thème WordPress avec les standards 2025

Estimated reading time: 4 minutes

Introduction

Le développement de thèmes WordPress a connu une révolution avec l’introduction du Full Site Editing (FSE) et des block themes. En 2025, les standards de développement exigent une approche moderne qui combine l’éditeur de blocs, les global styles, l’accessibilité WCAG et les performances optimales. Ce guide complet vous accompagnera dans la création d’un thème WordPress professionnel conforme aux dernières normes.

Architecture d’un block theme moderne

Structure de fichiers recommandée

La structure d’un block theme diffère des thèmes classiques. Voici l’organisation recommandée pour 2025 :

mon-theme/
├── style.css
├── theme.json
├── functions.php
├── templates/
│   ├── index.html
│   ├── single.html
│   ├── page.html
│   ├── archive.html
│   ├── 404.html
│   └── search.html
├── parts/
│   ├── header.html
│   ├── footer.html
│   └── sidebar.html
├── patterns/
│   ├── hero.php
│   ├── call-to-action.php
│   └── testimonials.php
├── assets/
│   ├── css/
│   ├── js/
│   └── images/
├── inc/
│   ├── block-patterns.php
│   ├── block-styles.php
│   └── custom-blocks.php
└── languages/

Le fichier style.css

Le header du fichier style.css est obligatoire et doit respecter ce format :

/
Theme Name: Mon Theme Moderne
Theme URI: https://exemple.com/mon-theme
Author: Votre Nom
Author URI: https://exemple.com
Description: Un theme WordPress moderne construit avec les standards 2025, Full Site Editing, et optimisé pour les performances.
Requires at least: 6.4
Tested up to: 6.5
Requires PHP: 8.0
Version: 1.0.0
License: GNU General Public License v2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
Text Domain: mon-theme
Tags: block-themes, full-site-editing, accessibility-ready, translation-ready, custom-colors, custom-menu, featured-images, threaded-comments, wide-blocks

This theme, like WordPress, is licensed under the GPL.
Use it to make something cool, have fun, and share what you've learned.
/

Le fichier theme.json : Le coeur du thème

Le fichier theme.json est le fichier de configuration central d’un block theme moderne. Il définit les styles globaux, les paramètres et les fonctionnalités.

Configuration complète de theme.json

{
  "$schema": "https://schemas.wp.org/trunk/theme.json",
  "version": 2,
  "settings": {
    "appearanceTools": true,
    "useRootPaddingAwareAlignments": true,
    "layout": {
      "contentSize": "840px",
      "wideSize": "1200px"
    },
    "color": {
      "custom": true,
      "customDuotone": true,
      "customGradient": true,
      "defaultGradients": false,
      "defaultPalette": false,
      "duotone": [
        {
          "colors": ["#000000", "#ffffff"],
          "slug": "black-and-white",
          "name": "Noir et Blanc"
        }
      ],
      "gradients": [
        {
          "slug": "primary-to-secondary",
          "gradient": "linear-gradient(135deg, var(--wp--preset--color--primary) 0%, var(--wp--preset--color--secondary) 100%)",
          "name": "Primaire vers Secondaire"
        }
      ],
      "palette": [
        {
          "slug": "primary",
          "color": "#0066cc",
          "name": "Primaire"
        },
        {
          "slug": "secondary",
          "color": "#ff6b35",
          "name": "Secondaire"
        },
        {
          "slug": "foreground",
          "color": "#1a1a1a",
          "name": "Premier plan"
        },
        {
          "slug": "background",
          "color": "#ffffff",
          "name": "Arrière-plan"
        },
        {
          "slug": "tertiary",
          "color": "#f5f5f5",
          "name": "Tertiaire"
        }
      ]
    },
    "typography": {
      "customFontSize": true,
      "fontStyle": true,
      "fontWeight": true,
      "letterSpacing": true,
      "textDecoration": true,
      "textTransform": true,
      "dropCap": false,
      "fluid": true,
      "fontSizes": [
        {
          "slug": "small",
          "size": "0.875rem",
          "name": "Petit",
          "fluid": {
            "min": "0.875rem",
            "max": "1rem"
          }
        },
        {
          "slug": "medium",
          "size": "1rem",
          "name": "Moyen",
          "fluid": false
        },
        {
          "slug": "large",
          "size": "1.5rem",
          "name": "Grand",
          "fluid": {
            "min": "1.25rem",
            "max": "1.5rem"
          }
        },
        {
          "slug": "x-large",
          "size": "2.5rem",
          "name": "Très grand",
          "fluid": {
            "min": "2rem",
            "max": "2.5rem"
          }
        }
      ],
      "fontFamilies": [
        {
          "fontFamily": "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif",
          "slug": "system",
          "name": "Système"
        },
        {
          "fontFamily": "'Inter', sans-serif",
          "slug": "inter",
          "name": "Inter",
          "fontFace": [
            {
              "fontFamily": "Inter",
              "fontWeight": "400",
              "fontStyle": "normal",
              "fontDisplay": "swap",
              "src": ["file:./assets/fonts/inter-regular.woff2"]
            },
            {
              "fontFamily": "Inter",
              "fontWeight": "700",
              "fontStyle": "normal",
              "fontDisplay": "swap",
              "src": ["file:./assets/fonts/inter-bold.woff2"]
            }
          ]
        }
      ]
    },
    "spacing": {
      "customSpacingSize": true,
      "spacingScale": {
        "steps": 0
      },
      "spacingSizes": [
        {
          "slug": "30",
          "size": "0.5rem",
          "name": "1"
        },
        {
          "slug": "40",
          "size": "1rem",
          "name": "2"
        },
        {
          "slug": "50",
          "size": "1.5rem",
          "name": "3"
        },
        {
          "slug": "60",
          "size": "2rem",
          "name": "4"
        },
        {
          "slug": "70",
          "size": "3rem",
          "name": "5"
        },
        {
          "slug": "80",
          "size": "4rem",
          "name": "6"
        }
      ],
      "units": ["px", "em", "rem", "vh", "vw", "%"]
    },
    "custom": {
      "spacing": {
        "gutter": "1.5rem"
      },
      "transition": {
        "duration": "0.3s"
      }
    }
  },
  "styles": {
    "color": {
      "background": "var(--wp--preset--color--background)",
      "text": "var(--wp--preset--color--foreground)"
    },
    "typography": {
      "fontFamily": "var(--wp--preset--font-family--inter)",
      "fontSize": "var(--wp--preset--font-size--medium)",
      "lineHeight": "1.6"
    },
    "spacing": {
      "padding": {
        "top": "0",
        "right": "var(--wp--preset--spacing--40)",
        "bottom": "0",
        "left": "var(--wp--preset--spacing--40)"
      }
    },
    "elements": {
      "link": {
        "color": {
          "text": "var(--wp--preset--color--primary)"
        },
        "typography": {
          "textDecoration": "underline"
        },
        ":hover": {
          "color": {
            "text": "var(--wp--preset--color--secondary)"
          }
        }
      },
      "button": {
        "color": {
          "background": "var(--wp--preset--color--primary)",
          "text": "var(--wp--preset--color--background)"
        },
        "typography": {
          "fontSize": "var(--wp--preset--font-size--medium)",
          "fontWeight": "700"
        },
        "spacing": {
          "padding": {
            "top": "0.75rem",
            "right": "1.5rem",
            "bottom": "0.75rem",
            "left": "1.5rem"
          }
        },
        "border": {
          "radius": "0.25rem"
        },
        ":hover": {
          "color": {
            "background": "var(--wp--preset--color--secondary)"
          }
        }
      },
      "h1": {
        "typography": {
          "fontSize": "var(--wp--preset--font-size--x-large)",
          "fontWeight": "700",
          "lineHeight": "1.2"
        },
        "spacing": {
          "margin": {
            "top": "0",
            "bottom": "var(--wp--preset--spacing--50)"
          }
        }
      },
      "h2": {
        "typography": {
          "fontSize": "var(--wp--preset--font-size--large)",
          "fontWeight": "700",
          "lineHeight": "1.3"
        }
      }
    },
    "blocks": {
      "core/navigation": {
        "typography": {
          "fontSize": "var(--wp--preset--font-size--medium)"
        }
      },
      "core/post-title": {
        "typography": {
          "fontSize": "var(--wp--preset--font-size--x-large)",
          "fontWeight": "700"
        }
      },
      "core/quote": {
        "color": {
          "background": "var(--wp--preset--color--tertiary)"
        },
        "spacing": {
          "padding": {
            "top": "var(--wp--preset--spacing--50)",
            "right": "var(--wp--preset--spacing--50)",
            "bottom": "var(--wp--preset--spacing--50)",
            "left": "var(--wp--preset--spacing--50)"
          }
        },
        "border": {
          "left": {
            "width": "4px",
            "style": "solid",
            "color": "var(--wp--preset--color--primary)"
          }
        }
      }
    }
  },
  "templateParts": [
    {
      "name": "header",
      "title": "En-tête",
      "area": "header"
    },
    {
      "name": "footer",
      "title": "Pied de page",
      "area": "footer"
    }
  ],
  "customTemplates": [
    {
      "name": "page-sans-titre",
      "title": "Page sans titre",
      "postTypes": ["page"]
    }
  ]
}

Templates HTML : L’architecture des pages

Template index.html

Le template templates/index.html est obligatoire :

L’élément de modèle a été supprimé ou n’est pas disponible : header


L’élément de modèle a été supprimé ou n’est pas disponible : footer

Template single.html

L’élément de modèle a été supprimé ou n’est pas disponible : header


Développer un thème WordPress avec les standards 2025

[rendu du bloc interrompu]

L’élément de modèle a été supprimé ou n’est pas disponible : footer

Le fichier functions.php : Configuration et extensions

Le fichier functions.php reste essentiel même dans un block theme :


  Functions and definitions
 
  @package MonTheme
  @since 1.0.0
 /

if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

// Définir les constantes du thème
define( 'MONTHEMEVERSION', '1.0.0' );
define( 'MONTHEMEDIR', gettemplatedirectory() );
define( 'MONTHEMEURI', gettemplatedirectoryuri() );

/
  Configuration du thème
 /
function monthemesetup() {
    // Support des traductions
    loadthemetextdomain( 'mon-theme', MONTHEMEDIR . '/languages' );

    // Support du titre automatique
    addthemesupport( 'title-tag' );

    // Support des images à la une
    addthemesupport( 'post-thumbnails' );

    // Tailles d'images personnalisées
    addimagesize( 'montheme-featured', 1200, 675, true );
    addimagesize( 'montheme-thumbnail', 400, 300, true );

    // Support du logo personnalisé
    addthemesupport( 'custom-logo', array(
        'height'      => 100,
        'width'       => 400,
        'flex-height' => true,
        'flex-width'  => true,
    ) );

    // Support HTML5
    addthemesupport( 'html5', array(
        'search-form',
        'comment-form',
        'comment-list',
        'gallery',
        'caption',
        'style',
        'script',
    ) );

    // Support de l'éditeur de blocs
    addthemesupport( 'wp-block-styles' );
    addthemesupport( 'responsive-embeds' );
    addthemesupport( 'editor-styles' );
    addeditorstyle( 'assets/css/editor-style.css' );

    // Support des liens Atom pour les commentaires
    addthemesupport( 'automatic-feed-links' );

    // Enregistrer les menus
    registernavmenus( array(
        'primary' => ( 'Menu principal', 'mon-theme' ),
        'footer'  => ( 'Menu pied de page', 'mon-theme' ),
    ) );
}
addaction( 'aftersetuptheme', 'monthemesetup' );

/
  Enregistrer et charger les scripts/styles
 /
function monthemeenqueuescripts() {
    // Style principal (déjà inclus par WordPress)
    wpenqueuestyle( 'montheme-style', getstylesheeturi(), array(), MONTHEMEVERSION );

    // Styles supplémentaires
    wpenqueuestyle(
        'montheme-blocks',
        MONTHEMEURI . '/assets/css/blocks.css',
        array( 'montheme-style' ),
        MONTHEMEVERSION
    );

    // Script principal avec dépendances modernes
    wpenqueuescript(
        'montheme-script',
        MONTHEMEURI . '/assets/js/main.js',
        array(),
        MONTHEMEVERSION,
        true
    );

    // Support des commentaires threaded
    if ( issingular() && commentsopen() && getoption( 'threadcomments' ) ) {
        wpenqueuescript( 'comment-reply' );
    }
}
addaction( 'wpenqueuescripts', 'monthemeenqueuescripts' );

/
  Enregistrer les scripts pour l'éditeur
 /
function monthemeenqueueeditorassets() {
    wpenqueuescript(
        'montheme-editor',
        MONTHEMEURI . '/assets/js/editor.js',
        array( 'wp-blocks', 'wp-dom-ready', 'wp-edit-post' ),
        MONTHEMEVERSION,
        true
    );
}
addaction( 'enqueueblockeditorassets', 'monthemeenqueueeditorassets' );

/
  Charger les fichiers d'inclusion
 /
requireonce MONTHEMEDIR . '/inc/block-patterns.php';
requireonce MONTHEMEDIR . '/inc/block-styles.php';

/
  Ajouter des styles de blocs personnalisés
 /
function monthemeregisterblockstyles() {
    // Style pour le bloc paragraphe
    registerblockstyle(
        'core/paragraph',
        array(
            'name'         => 'montheme-highlight',
            'label'        => ( 'Mise en évidence', 'mon-theme' ),
            'stylehandle' => 'montheme-blocks',
        )
    );

    // Style pour le bloc bouton
    registerblockstyle(
        'core/button',
        array(
            'name'         => 'montheme-outline',
            'label'        => ( 'Contour', 'mon-theme' ),
            'stylehandle' => 'montheme-blocks',
        )
    );

    // Style pour le bloc groupe
    registerblockstyle(
        'core/group',
        array(
            'name'         => 'montheme-card',
            'label'        => ( 'Carte', 'mon-theme' ),
            'stylehandle' => 'montheme-blocks',
        )
    );
}
addaction( 'init', 'monthemeregisterblockstyles' );

/
  Personnaliser la requête principale
 /
function monthemepregetposts( $query ) {
    // Modifier uniquement la requête principale sur le front-end
    if ( ! isadmin() && $query->ismainquery() ) {
        // Exemple : afficher 12 posts par page sur les archives
        if ( $query->isarchive() ) {
            $query->set( 'postsperpage', 12 );
        }
    }
}
addaction( 'pregetposts', 'monthemepregetposts' );

/
  Ajouter des classes CSS personnalisées au body
 /
function monthemebodyclasses( $classes ) {
    // Ajouter une classe si le sidebar est actif
    if ( isactivesidebar( 'sidebar-1' ) ) {
        $classes[] = 'has-sidebar';
    }

    // Ajouter une classe pour les pages sans titre
    if ( ispage() && ! getthetitle() ) {
        $classes[] = 'no-title';
    }

    return $classes;
}
addfilter( 'bodyclass', 'monthemebodyclasses' );

/
  Filtrer l'excerpt length
 /
function monthemeexcerptlength( $length ) {
    return 30;
}
addfilter( 'excerptlength', 'monthemeexcerptlength' );

/
  Personnaliser le "read more" de l'excerpt
 /
function monthemeexcerptmore( $more ) {
    if ( ! isadmin() ) {
        return sprintf(
            ' %s',
            escurl( getpermalink() ),
            eschtml( 'Continuer la lecture', 'mon-theme' )
        );
    }
    return $more;
}
addfilter( 'excerptmore', 'monthemeexcerptmore' );

/
  Optimisation des performances : Désactiver les emojis
 /
function monthemedisableemojis() {
    removeaction( 'wphead', 'printemojidetectionscript', 7 );
    removeaction( 'adminprintscripts', 'printemojidetectionscript' );
    removeaction( 'wpprintstyles', 'printemojistyles' );
    removeaction( 'adminprintstyles', 'printemojistyles' );
    removefilter( 'thecontentfeed', 'wpstaticizeemoji' );
    removefilter( 'commenttextrss', 'wpstaticizeemoji' );
    removefilter( 'wpmail', 'wpstaticizeemojiforemail' );
}
addaction( 'init', 'monthemedisableemojis' );

/
  Ajouter un préchargement pour les polices
 /
function monthemepreloadfonts() {
    ?>
    
    
    action( 'wphead', 'monthemepreloadfonts', 1 );

/
  Ajouter le support du lazy loading pour les iframes
 /
function monthemeaddiframeloadingattr( $content ) {
    if ( issingular() ) {
        $content = strreplace( '

Block Patterns : Créer des modèles réutilisables

Créez le fichier inc/block-patterns.php :


  Block Patterns
 
  @package MonTheme
 /

if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

/
  Enregistrer les catégories de patterns
 /
function monthemeregisterpatterncategories() {
    registerblockpatterncategory(
        'montheme-hero',
        array( 'label' => ( 'Sections Hero', 'mon-theme' ) )
    );

    registerblockpatterncategory(
        'montheme-cta',
        array( 'label' => ( 'Call to Action', 'mon-theme' ) )
    );

    registerblockpatterncategory(
        'montheme-testimonials',
        array( 'label' => ( 'Témoignages', 'mon-theme' ) )
    );
}
addaction( 'init', 'monthemeregisterpatterncategories' );

/
  Enregistrer les patterns
 /
function monthemeregisterpatterns() {

    // Pattern Hero avec image de fond
    registerblockpattern(
        'montheme/hero-with-background',
        array(
            'title'       => ( 'Hero avec image de fond', 'mon-theme' ),
            'description' => ( 'Une section hero avec image de fond et texte centré', 'mon-theme' ),
            'categories'  => array( 'montheme-hero' ),
            'content'     => '

Bienvenue sur notre site

Découvrez nos services exceptionnels

', ) ); // Pattern CTA register
blockpattern( 'montheme/cta-box', array( 'title' => ( 'Boîte CTA', 'mon-theme' ), 'description' => ( 'Une boîte call-to-action avec fond coloré', 'mon-theme' ), 'categories' => array( 'montheme-cta' ), 'content' => '

Prêt à commencer ?

Rejoignez des milliers d'utilisateurs satisfaits

', ) ); } add
action( 'init', 'monthemeregisterpatterns' );

Accessibilité : Standards WCAG 2025

Créez parts/header.html avec un skip link :




CSS pour l’accessibilité

Ajoutez dans assets/css/blocks.css :

/
  Styles d'accessibilité
 /

/ Skip link /
.skip-link {
    position: absolute;
    left: -9999px;
    top: 2.5em;
    z-index: 999999;
    text-decoration: underline;
    background-color: #fff;
    color: #000;
    padding: 1em;
    border-radius: 4px;
    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
}

.skip-link:focus {
    left: 1em;
}

/ Screen reader text /
.screen-reader-text {
    border: 0;
    clip: rect(1px, 1px, 1px, 1px);
    clip-path: inset(50%);
    height: 1px;
    margin: -1px;
    overflow: hidden;
    padding: 0;
    position: absolute;
    width: 1px;
    word-wrap: normal !important;
}

.screen-reader-text:focus {
    background-color: #fff;
    border-radius: 3px;
    box-shadow: 0 0 2px 2px rgba(0, 0, 0, 0.6);
    clip: auto !important;
    clip-path: none;
    color: #000;
    display: block;
    font-size: 0.875rem;
    font-weight: 700;
    height: auto;
    left: 5px;
    line-height: normal;
    padding: 15px 23px 14px;
    text-decoration: none;
    top: 5px;
    width: auto;
    z-index: 100000;
}

/ Focus visible pour la navigation au clavier /
a:focus-visible,
button:focus-visible,
input:focus-visible,
textarea:focus-visible,
select:focus-visible {
    outline: 2px solid var(--wp--preset--color--primary);
    outline-offset: 2px;
    border-radius: 2px;
}

/ Contraste élevé pour les liens /
a {
    text-decoration-thickness: 1px;
    text-underline-offset: 2px;
}

/ Améliorer la lisibilité /
body {
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

/ Animations respectant prefers-reduced-motion /
@media (prefers-reduced-motion: reduce) {
    ,
    ::before,
    ::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
    }
}

/ Mode sombre /
@media (prefers-color-scheme: dark) {
    :root {
        --wp--preset--color--foreground: #ffffff;
        --wp--preset--color--background: #1a1a1a;
        --wp--preset--color--tertiary: #2a2a2a;
    }
}

/
  Styles de blocs personnalisés
 /

/ Style highlight pour paragraphe /
.is-style-montheme-highlight {
    background-color: var(--wp--preset--color--tertiary);
    padding: var(--wp--preset--spacing--50);
    border-left: 4px solid var(--wp--preset--color--primary);
}

/ Style outline pour bouton /
.is-style-montheme-outline.wp-block-buttonlink {
    background-color: transparent;
    border: 2px solid currentColor;
}

.is-style-montheme-outline.wp-block-buttonlink:hover {
    background-color: var(--wp--preset--color--primary);
    color: var(--wp--preset--color--background);
}

/ Style card pour groupe /
.is-style-montheme-card {
    background-color: var(--wp--preset--color--background);
    border: 1px solid var(--wp--preset--color--tertiary);
    border-radius: 8px;
    padding: var(--wp--preset--spacing--60);
    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
    transition: transform 0.3s ease, box-shadow 0.3s ease;
}

.is-style-montheme-card:hover {
    transform: translateY(-4px);
    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
}

/
  Optimisations pour les performances
 /

/ Lazy loading fade-in /
img[loading="lazy"] {
    opacity: 0;
    transition: opacity 0.3s;
}

img[loading="lazy"].loaded {
    opacity: 1;
}

/ Optimisation des polices /
@font-face {
    font-family: 'Inter';
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url('../fonts/inter-regular.woff2') format('woff2');
}

@font-face {
    font-family: 'Inter';
    font-style: normal;
    font-weight: 700;
    font-display: swap;
    src: url('../fonts/inter-bold.woff2') format('woff2');
}

/ Conteneur responsive /
.wp-block-group.is-layout-constrained >  {
    max-width: 100%;
}

Optimisation des performances

Chargement différé des images JavaScript

Créez assets/js/main.js :

/
  Scripts front-end du thème
 /

(function() {
    'use strict';

    /
      Lazy loading manuel pour images
     /
    const lazyLoadImages = () => {
        const images = document.querySelectorAll('img[loading="lazy"]');

        if ('IntersectionObserver' in window) {
            const imageObserver = new IntersectionObserver((entries, observer) => {
                entries.forEach(entry => {
                    if (entry.isIntersecting) {
                        const img = entry.target;
                        img.classList.add('loaded');
                        observer.unobserve(img);
                    }
                });
            });

            images.forEach(img => imageObserver.observe(img));
        } else {
            // Fallback pour navigateurs anciens
            images.forEach(img => img.classList.add('loaded'));
        }
    };

    /
      Smooth scroll pour les liens d'ancrage
     /
    const initSmoothScroll = () => {
        const links = document.querySelectorAll('a[href^="#"]');

        links.forEach(link => {
            link.addEventListener('click', function(e) {
                const targetId = this.getAttribute('href');

                if (targetId === '#') return;

                const target = document.querySelector(targetId);

                if (target) {
                    e.preventDefault();

                    target.scrollIntoView({
                        behavior: 'smooth',
                        block: 'start'
                    });

                    // Mettre le focus sur l'élément cible (accessibilité)
                    target.focus();

                    // Mettre à jour l'URL
                    if (history.pushState) {
                        history.pushState(null, null, targetId);
                    }
                }
            });
        });
    };

    /
      Améliorer l'accessibilité du menu mobile
     /
    const enhanceMobileMenu = () => {
        const menuToggles = document.querySelectorAll('.wp-block-navigation_responsive-container-open');

        menuToggles.forEach(toggle => {
            toggle.addEventListener('click', function() {
                const isExpanded = this.getAttribute('aria-expanded') === 'true';
                this.setAttribute('aria-expanded', !isExpanded);
            });
        });
    };

    /
      Détecter et signaler les erreurs JavaScript
     /
    const setupErrorTracking = () => {
        window.addEventListener('error', function(e) {
            if (window.console && console.error) {
                console.error('Theme Error:', e.message, e.filename, e.lineno);
            }
        });
    };

    /
      Initialisation au chargement du DOM
     /
    document.addEventListener('DOMContentLoaded', function() {
        lazyLoadImages();
        initSmoothScroll();
        enhanceMobileMenu();
        setupErrorTracking();
    });

})();

Erreurs courantes à éviter

1. Oublier le support REST API

MAUVAIS : Ne pas inclure showin_rest dans theme.json

BON : Toujours activer le support REST pour FSE

2. Hardcoder les couleurs et tailles

MAUVAIS :

.mon-element {
    color: #0066cc;
    font-size: 16px;
}

BON :

.mon-element {
    color: var(--wp--preset--color--primary);
    font-size: var(--wp--preset--font-size--medium);
}

3. Ignorer l’accessibilité

MAUVAIS : Pas de skip link, pas de focus visible

BON : Implémenter tous les standards WCAG 2.1 niveau AA minimum

4. Ne pas tester les performances

Utilisez les outils de test :

  • Google PageSpeed Insights
  • WebPageTest
  • Lighthouse
  • Query Monitor (plugin)
  • Conclusion

    Le développement de thèmes WordPress en 2025 requiert une maîtrise du Full Site Editing, de theme.json, et une attention particulière à l’accessibilité et aux performances. Les block themes représentent l’avenir de WordPress et offrent une flexibilité sans précédent tout en maintenant une expérience utilisateur cohérente.

    Points clés à retenir :

  • Utilisez theme.json pour tous les réglages de design
  • Créez des templates HTML avec des blocs
  • Implémentez des block patterns réutilisables
  • Respectez les standards WCAG 2.1 niveau AA
  • Optimisez les performances (lazy loading, préchargement de polices)
  • Utilisez des variables CSS natives de WordPress
  • Testez sur différents navigateurs et appareils
  • Ressources supplémentaires

  • Block Theme Documentation
  • Theme.json Reference
  • Theme Handbook
  • Accessibility Handbook
  • Performance Best Practices

Mots-clés:* thème WordPress 2025, block theme, Full Site Editing, theme.json, WordPress FSE, développement thème WordPress, accessibilité WordPress WCAG, performances WordPress, WordPress global styles, block patterns WordPress


L’élément de modèle a été supprimé ou n’est pas disponible : footer

Le fichier functions.php : Configuration et extensions

Le fichier functions.php reste essentiel même dans un block theme :


  Functions and definitions
 
  @package MonTheme
  @since 1.0.0
 /

if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

// Définir les constantes du thème
define( 'MONTHEMEVERSION', '1.0.0' );
define( 'MONTHEMEDIR', gettemplatedirectory() );
define( 'MONTHEMEURI', gettemplatedirectoryuri() );

/
  Configuration du thème
 /
function monthemesetup() {
    // Support des traductions
    loadthemetextdomain( 'mon-theme', MONTHEMEDIR . '/languages' );

    // Support du titre automatique
    addthemesupport( 'title-tag' );

    // Support des images à la une
    addthemesupport( 'post-thumbnails' );

    // Tailles d'images personnalisées
    addimagesize( 'montheme-featured', 1200, 675, true );
    addimagesize( 'montheme-thumbnail', 400, 300, true );

    // Support du logo personnalisé
    addthemesupport( 'custom-logo', array(
        'height'      => 100,
        'width'       => 400,
        'flex-height' => true,
        'flex-width'  => true,
    ) );

    // Support HTML5
    addthemesupport( 'html5', array(
        'search-form',
        'comment-form',
        'comment-list',
        'gallery',
        'caption',
        'style',
        'script',
    ) );

    // Support de l'éditeur de blocs
    addthemesupport( 'wp-block-styles' );
    addthemesupport( 'responsive-embeds' );
    addthemesupport( 'editor-styles' );
    addeditorstyle( 'assets/css/editor-style.css' );

    // Support des liens Atom pour les commentaires
    addthemesupport( 'automatic-feed-links' );

    // Enregistrer les menus
    registernavmenus( array(
        'primary' => ( 'Menu principal', 'mon-theme' ),
        'footer'  => ( 'Menu pied de page', 'mon-theme' ),
    ) );
}
addaction( 'aftersetuptheme', 'monthemesetup' );

/
  Enregistrer et charger les scripts/styles
 /
function monthemeenqueuescripts() {
    // Style principal (déjà inclus par WordPress)
    wpenqueuestyle( 'montheme-style', getstylesheeturi(), array(), MONTHEMEVERSION );

    // Styles supplémentaires
    wpenqueuestyle(
        'montheme-blocks',
        MONTHEMEURI . '/assets/css/blocks.css',
        array( 'montheme-style' ),
        MONTHEMEVERSION
    );

    // Script principal avec dépendances modernes
    wpenqueuescript(
        'montheme-script',
        MONTHEMEURI . '/assets/js/main.js',
        array(),
        MONTHEMEVERSION,
        true
    );

    // Support des commentaires threaded
    if ( issingular() && commentsopen() && getoption( 'threadcomments' ) ) {
        wpenqueuescript( 'comment-reply' );
    }
}
addaction( 'wpenqueuescripts', 'monthemeenqueuescripts' );

/
  Enregistrer les scripts pour l'éditeur
 /
function monthemeenqueueeditorassets() {
    wpenqueuescript(
        'montheme-editor',
        MONTHEMEURI . '/assets/js/editor.js',
        array( 'wp-blocks', 'wp-dom-ready', 'wp-edit-post' ),
        MONTHEMEVERSION,
        true
    );
}
addaction( 'enqueueblockeditorassets', 'monthemeenqueueeditorassets' );

/
  Charger les fichiers d'inclusion
 /
requireonce MONTHEMEDIR . '/inc/block-patterns.php';
requireonce MONTHEMEDIR . '/inc/block-styles.php';

/
  Ajouter des styles de blocs personnalisés
 /
function monthemeregisterblockstyles() {
    // Style pour le bloc paragraphe
    registerblockstyle(
        'core/paragraph',
        array(
            'name'         => 'montheme-highlight',
            'label'        => ( 'Mise en évidence', 'mon-theme' ),
            'stylehandle' => 'montheme-blocks',
        )
    );

    // Style pour le bloc bouton
    registerblockstyle(
        'core/button',
        array(
            'name'         => 'montheme-outline',
            'label'        => ( 'Contour', 'mon-theme' ),
            'stylehandle' => 'montheme-blocks',
        )
    );

    // Style pour le bloc groupe
    registerblockstyle(
        'core/group',
        array(
            'name'         => 'montheme-card',
            'label'        => ( 'Carte', 'mon-theme' ),
            'stylehandle' => 'montheme-blocks',
        )
    );
}
addaction( 'init', 'monthemeregisterblockstyles' );

/
  Personnaliser la requête principale
 /
function monthemepregetposts( $query ) {
    // Modifier uniquement la requête principale sur le front-end
    if ( ! isadmin() && $query->ismainquery() ) {
        // Exemple : afficher 12 posts par page sur les archives
        if ( $query->isarchive() ) {
            $query->set( 'postsperpage', 12 );
        }
    }
}
addaction( 'pregetposts', 'monthemepregetposts' );

/
  Ajouter des classes CSS personnalisées au body
 /
function monthemebodyclasses( $classes ) {
    // Ajouter une classe si le sidebar est actif
    if ( isactivesidebar( 'sidebar-1' ) ) {
        $classes[] = 'has-sidebar';
    }

    // Ajouter une classe pour les pages sans titre
    if ( ispage() && ! getthetitle() ) {
        $classes[] = 'no-title';
    }

    return $classes;
}
addfilter( 'bodyclass', 'monthemebodyclasses' );

/
  Filtrer l'excerpt length
 /
function monthemeexcerptlength( $length ) {
    return 30;
}
addfilter( 'excerptlength', 'monthemeexcerptlength' );

/
  Personnaliser le "read more" de l'excerpt
 /
function monthemeexcerptmore( $more ) {
    if ( ! isadmin() ) {
        return sprintf(
            ' %s',
            escurl( getpermalink() ),
            eschtml( 'Continuer la lecture', 'mon-theme' )
        );
    }
    return $more;
}
addfilter( 'excerptmore', 'monthemeexcerptmore' );

/
  Optimisation des performances : Désactiver les emojis
 /
function monthemedisableemojis() {
    removeaction( 'wphead', 'printemojidetectionscript', 7 );
    removeaction( 'adminprintscripts', 'printemojidetectionscript' );
    removeaction( 'wpprintstyles', 'printemojistyles' );
    removeaction( 'adminprintstyles', 'printemojistyles' );
    removefilter( 'thecontentfeed', 'wpstaticizeemoji' );
    removefilter( 'commenttextrss', 'wpstaticizeemoji' );
    removefilter( 'wpmail', 'wpstaticizeemojiforemail' );
}
addaction( 'init', 'monthemedisableemojis' );

/
  Ajouter un préchargement pour les polices
 /
function monthemepreloadfonts() {
    ?>
    
    
    action( 'wphead', 'monthemepreloadfonts', 1 );

/
  Ajouter le support du lazy loading pour les iframes
 /
function monthemeaddiframeloadingattr( $content ) {
    if ( issingular() ) {
        $content = strreplace( '

Block Patterns : Créer des modèles réutilisables

Créez le fichier inc/block-patterns.php :


  Block Patterns
 
  @package MonTheme
 /

if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

/
  Enregistrer les catégories de patterns
 /
function monthemeregisterpatterncategories() {
    registerblockpatterncategory(
        'montheme-hero',
        array( 'label' => ( 'Sections Hero', 'mon-theme' ) )
    );

    registerblockpatterncategory(
        'montheme-cta',
        array( 'label' => ( 'Call to Action', 'mon-theme' ) )
    );

    registerblockpatterncategory(
        'montheme-testimonials',
        array( 'label' => ( 'Témoignages', 'mon-theme' ) )
    );
}
addaction( 'init', 'monthemeregisterpatterncategories' );

/
  Enregistrer les patterns
 /
function monthemeregisterpatterns() {

    // Pattern Hero avec image de fond
    registerblockpattern(
        'montheme/hero-with-background',
        array(
            'title'       => ( 'Hero avec image de fond', 'mon-theme' ),
            'description' => ( 'Une section hero avec image de fond et texte centré', 'mon-theme' ),
            'categories'  => array( 'montheme-hero' ),
            'content'     => '

Bienvenue sur notre site

Découvrez nos services exceptionnels

', ) ); // Pattern CTA register
blockpattern( 'montheme/cta-box', array( 'title' => ( 'Boîte CTA', 'mon-theme' ), 'description' => ( 'Une boîte call-to-action avec fond coloré', 'mon-theme' ), 'categories' => array( 'montheme-cta' ), 'content' => '

Prêt à commencer ?

Rejoignez des milliers d'utilisateurs satisfaits

', ) ); } add
action( 'init', 'monthemeregisterpatterns' );

Accessibilité : Standards WCAG 2025

Créez parts/header.html avec un skip link :




CSS pour l’accessibilité

Ajoutez dans assets/css/blocks.css :

/
  Styles d'accessibilité
 /

/ Skip link /
.skip-link {
    position: absolute;
    left: -9999px;
    top: 2.5em;
    z-index: 999999;
    text-decoration: underline;
    background-color: #fff;
    color: #000;
    padding: 1em;
    border-radius: 4px;
    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
}

.skip-link:focus {
    left: 1em;
}

/ Screen reader text /
.screen-reader-text {
    border: 0;
    clip: rect(1px, 1px, 1px, 1px);
    clip-path: inset(50%);
    height: 1px;
    margin: -1px;
    overflow: hidden;
    padding: 0;
    position: absolute;
    width: 1px;
    word-wrap: normal !important;
}

.screen-reader-text:focus {
    background-color: #fff;
    border-radius: 3px;
    box-shadow: 0 0 2px 2px rgba(0, 0, 0, 0.6);
    clip: auto !important;
    clip-path: none;
    color: #000;
    display: block;
    font-size: 0.875rem;
    font-weight: 700;
    height: auto;
    left: 5px;
    line-height: normal;
    padding: 15px 23px 14px;
    text-decoration: none;
    top: 5px;
    width: auto;
    z-index: 100000;
}

/ Focus visible pour la navigation au clavier /
a:focus-visible,
button:focus-visible,
input:focus-visible,
textarea:focus-visible,
select:focus-visible {
    outline: 2px solid var(--wp--preset--color--primary);
    outline-offset: 2px;
    border-radius: 2px;
}

/ Contraste élevé pour les liens /
a {
    text-decoration-thickness: 1px;
    text-underline-offset: 2px;
}

/ Améliorer la lisibilité /
body {
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

/ Animations respectant prefers-reduced-motion /
@media (prefers-reduced-motion: reduce) {
    ,
    ::before,
    ::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
    }
}

/ Mode sombre /
@media (prefers-color-scheme: dark) {
    :root {
        --wp--preset--color--foreground: #ffffff;
        --wp--preset--color--background: #1a1a1a;
        --wp--preset--color--tertiary: #2a2a2a;
    }
}

/
  Styles de blocs personnalisés
 /

/ Style highlight pour paragraphe /
.is-style-montheme-highlight {
    background-color: var(--wp--preset--color--tertiary);
    padding: var(--wp--preset--spacing--50);
    border-left: 4px solid var(--wp--preset--color--primary);
}

/ Style outline pour bouton /
.is-style-montheme-outline.wp-block-buttonlink {
    background-color: transparent;
    border: 2px solid currentColor;
}

.is-style-montheme-outline.wp-block-buttonlink:hover {
    background-color: var(--wp--preset--color--primary);
    color: var(--wp--preset--color--background);
}

/ Style card pour groupe /
.is-style-montheme-card {
    background-color: var(--wp--preset--color--background);
    border: 1px solid var(--wp--preset--color--tertiary);
    border-radius: 8px;
    padding: var(--wp--preset--spacing--60);
    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
    transition: transform 0.3s ease, box-shadow 0.3s ease;
}

.is-style-montheme-card:hover {
    transform: translateY(-4px);
    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
}

/
  Optimisations pour les performances
 /

/ Lazy loading fade-in /
img[loading="lazy"] {
    opacity: 0;
    transition: opacity 0.3s;
}

img[loading="lazy"].loaded {
    opacity: 1;
}

/ Optimisation des polices /
@font-face {
    font-family: 'Inter';
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url('../fonts/inter-regular.woff2') format('woff2');
}

@font-face {
    font-family: 'Inter';
    font-style: normal;
    font-weight: 700;
    font-display: swap;
    src: url('../fonts/inter-bold.woff2') format('woff2');
}

/ Conteneur responsive /
.wp-block-group.is-layout-constrained >  {
    max-width: 100%;
}

Optimisation des performances

Chargement différé des images JavaScript

Créez assets/js/main.js :

/
  Scripts front-end du thème
 /

(function() {
    'use strict';

    /
      Lazy loading manuel pour images
     /
    const lazyLoadImages = () => {
        const images = document.querySelectorAll('img[loading="lazy"]');

        if ('IntersectionObserver' in window) {
            const imageObserver = new IntersectionObserver((entries, observer) => {
                entries.forEach(entry => {
                    if (entry.isIntersecting) {
                        const img = entry.target;
                        img.classList.add('loaded');
                        observer.unobserve(img);
                    }
                });
            });

            images.forEach(img => imageObserver.observe(img));
        } else {
            // Fallback pour navigateurs anciens
            images.forEach(img => img.classList.add('loaded'));
        }
    };

    /
      Smooth scroll pour les liens d'ancrage
     /
    const initSmoothScroll = () => {
        const links = document.querySelectorAll('a[href^="#"]');

        links.forEach(link => {
            link.addEventListener('click', function(e) {
                const targetId = this.getAttribute('href');

                if (targetId === '#') return;

                const target = document.querySelector(targetId);

                if (target) {
                    e.preventDefault();

                    target.scrollIntoView({
                        behavior: 'smooth',
                        block: 'start'
                    });

                    // Mettre le focus sur l'élément cible (accessibilité)
                    target.focus();

                    // Mettre à jour l'URL
                    if (history.pushState) {
                        history.pushState(null, null, targetId);
                    }
                }
            });
        });
    };

    /
      Améliorer l'accessibilité du menu mobile
     /
    const enhanceMobileMenu = () => {
        const menuToggles = document.querySelectorAll('.wp-block-navigation_responsive-container-open');

        menuToggles.forEach(toggle => {
            toggle.addEventListener('click', function() {
                const isExpanded = this.getAttribute('aria-expanded') === 'true';
                this.setAttribute('aria-expanded', !isExpanded);
            });
        });
    };

    /
      Détecter et signaler les erreurs JavaScript
     /
    const setupErrorTracking = () => {
        window.addEventListener('error', function(e) {
            if (window.console && console.error) {
                console.error('Theme Error:', e.message, e.filename, e.lineno);
            }
        });
    };

    /
      Initialisation au chargement du DOM
     /
    document.addEventListener('DOMContentLoaded', function() {
        lazyLoadImages();
        initSmoothScroll();
        enhanceMobileMenu();
        setupErrorTracking();
    });

})();

Erreurs courantes à éviter

1. Oublier le support REST API

MAUVAIS : Ne pas inclure showin_rest dans theme.json

BON : Toujours activer le support REST pour FSE

2. Hardcoder les couleurs et tailles

MAUVAIS :

.mon-element {
    color: #0066cc;
    font-size: 16px;
}

BON :

.mon-element {
    color: var(--wp--preset--color--primary);
    font-size: var(--wp--preset--font-size--medium);
}

3. Ignorer l’accessibilité

MAUVAIS : Pas de skip link, pas de focus visible

BON : Implémenter tous les standards WCAG 2.1 niveau AA minimum

4. Ne pas tester les performances

Utilisez les outils de test :

  • Google PageSpeed Insights
  • WebPageTest
  • Lighthouse
  • Query Monitor (plugin)
  • Conclusion

    Le développement de thèmes WordPress en 2025 requiert une maîtrise du Full Site Editing, de theme.json, et une attention particulière à l’accessibilité et aux performances. Les block themes représentent l’avenir de WordPress et offrent une flexibilité sans précédent tout en maintenant une expérience utilisateur cohérente.

    Points clés à retenir :

  • Utilisez theme.json pour tous les réglages de design
  • Créez des templates HTML avec des blocs
  • Implémentez des block patterns réutilisables
  • Respectez les standards WCAG 2.1 niveau AA
  • Optimisez les performances (lazy loading, préchargement de polices)
  • Utilisez des variables CSS natives de WordPress
  • Testez sur différents navigateurs et appareils
  • Ressources supplémentaires

  • Block Theme Documentation
  • Theme.json Reference
  • Theme Handbook
  • Accessibility Handbook
  • Performance Best Practices

Mots-clés:* thème WordPress 2025, block theme, Full Site Editing, theme.json, WordPress FSE, développement thème WordPress, accessibilité WordPress WCAG, performances WordPress, WordPress global styles, block patterns WordPress

Une remarque, un retour ?

Cet article est vivant — corrections, contre-arguments et retours de production sont les bienvenus. Trois canaux, choisissez celui qui vous convient.