22 min de lecture · 4 822 mots

WordPress : API et fonctions essentielles

WordPress : API et fonctions essentielles
Article · 2025.12.19

Structure et concepts de base

Hiérarchie des templates

Page d'accueil:     front-page.php → home.php → index.php
Article seul:       single-{post-type}.php → single.php → singular.php → index.php
Page:               page-{slug}.php → page-{id}.php → page.php → singular.php → index.php
Archive:            archive-{post-type}.php → archive.php → index.php
Catégorie:          category-{slug}.php → category-{id}.php → category.php → archive.php → index.php
Tag:                tag-{slug}.php → tag-{id}.php → tag.php → archive.php → index.php
Auteur:             author-{nicename}.php → author-{id}.php → author.php → archive.php → index.php
Date:               date.php → archive.php → index.php
Recherche:          search.php → index.php
404:                404.php → index.php
Attachement:        attachment.php → single-attachment-{type}.php → single.php → index.php

Structure d’un thème

mon-theme/
├── style.css              (requis)
├── index.php              (requis)
├── functions.php          (fonctions du thème)
├── header.php
├── footer.php
├── sidebar.php
├── single.php
├── page.php
├── archive.php
├── category.php
├── tag.php
├── search.php
├── 404.php
├── front-page.php
├── home.php
├── comments.php
├── screenshot.png
├── template-parts/
│   ├── content.php
│   ├── content-single.php
│   └── content-page.php
├── inc/
│   ├── customizer.php
│   └── template-functions.php
└── assets/
    ├── css/
    ├── js/
    └── images/

En-tête style.css (thème)

/*
Theme Name: Mon Thème
Theme URI: https://example.com/mon-theme
Author: Votre Nom
Author URI: https://example.com
Description: Description de votre thème
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: blog, two-columns, custom-header, custom-menu
*/

Structure d’un plugin

mon-plugin/
├── mon-plugin.php         (fichier principal)
├── uninstall.php          (désinstallation)
├── readme.txt
├── includes/
│   ├── class-activator.php
│   ├── class-deactivator.php
│   └── class-main.php
├── admin/
│   ├── class-admin.php
│   ├── css/
│   └── js/
└── public/
    ├── class-public.php
    ├── css/
    └── js/

En-tête plugin principal

<?php
/**
 * Plugin Name: Mon Plugin
 * Plugin URI: https://example.com/mon-plugin
 * Description: Description de votre plugin
 * Version: 1.0.0
 * Requires at least: 6.0
 * Requires PHP: 8.0
 * Author: Votre Nom
 * Author URI: https://example.com
 * License: GPL v2 or later
 * License URI: https://www.gnu.org/licenses/gpl-2.0.html
 * Text Domain: mon-plugin
 * Domain Path: /languages
 */

if (!defined('ABSPATH')) {
    exit; // Protection accès direct
}

define('MON_PLUGIN_VERSION', '1.0.0');
define('MON_PLUGIN_PATH', plugin_dir_path(__FILE__));
define('MON_PLUGIN_URL', plugin_dir_url(__FILE__));

Hooks : Actions et Filtres

Actions principales

<?php
// Initialisation WordPress
add_action('init', 'ma_fonction_init');
add_action('admin_init', 'ma_fonction_admin_init');
add_action('wp_loaded', 'ma_fonction_loaded');

// Enqueue scripts et styles
add_action('wp_enqueue_scripts', 'mes_scripts_styles');
add_action('admin_enqueue_scripts', 'mes_scripts_admin');
add_action('login_enqueue_scripts', 'mes_scripts_login');

function mes_scripts_styles() {
    wp_enqueue_style(
        'mon-style',
        get_stylesheet_directory_uri() . '/assets/css/style.css',
        [],
        '1.0.0'
    );

    wp_enqueue_script(
        'mon-script',
        get_template_directory_uri() . '/assets/js/script.js',
        ['jquery'],
        '1.0.0',
        true
    );

    // Localiser script (passer variables PHP à JS)
    wp_localize_script('mon-script', 'monObjet', [
        'ajaxUrl' => admin_url('admin-ajax.php'),
        'nonce' => wp_create_nonce('mon-nonce'),
        'texte' => __('Mon texte', 'mon-theme'),
    ]);
}

// Templates
add_action('wp_head', 'ma_fonction_head');
add_action('wp_footer', 'ma_fonction_footer');
add_action('get_header', 'avant_header');
add_action('get_footer', 'avant_footer');

// Contenu
add_action('the_post', 'ma_fonction_post');
add_action('loop_start', 'debut_loop');
add_action('loop_end', 'fin_loop');

// Enregistrement/Modification
add_action('save_post', 'ma_fonction_save', 10, 2);
add_action('wp_insert_post', 'ma_fonction_insert', 10, 3);
add_action('before_delete_post', 'avant_suppression');
add_action('deleted_post', 'apres_suppression');

// Utilisateurs
add_action('user_register', 'nouvel_utilisateur');
add_action('profile_update', 'maj_profil', 10, 2);
add_action('delete_user', 'suppression_utilisateur');

// Widgets
add_action('widgets_init', 'mes_widgets');

function mes_widgets() {
    register_sidebar([
        'name' => __('Sidebar Principale', 'mon-theme'),
        'id' => 'sidebar-1',
        'before_widget' => '<div class="widget %2$s">',
        'after_widget' => '</div>',
        'before_title' => '<h3 class="widget-title">',
        'after_title' => '</h3>',
    ]);
}

// AJAX
add_action('wp_ajax_mon_action', 'ma_fonction_ajax');
add_action('wp_ajax_nopriv_mon_action', 'ma_fonction_ajax'); // Pour non-connectés

function ma_fonction_ajax() {
    check_ajax_referer('mon-nonce', 'nonce');

    $data = $_POST['data'] ?? '';

    // Traitement...

    wp_send_json_success(['message' => 'Succès']);
    // ou wp_send_json_error(['message' => 'Erreur']);
}

// Activation/Désactivation plugin
register_activation_hook(__FILE__, 'mon_plugin_activation');
register_deactivation_hook(__FILE__, 'mon_plugin_desactivation');

// Cron
add_action('mon_cron_hook', 'ma_tache_cron');

if (!wp_next_scheduled('mon_cron_hook')) {
    wp_schedule_event(time(), 'daily', 'mon_cron_hook');
}

// Priorité et arguments
add_action('init', 'ma_fonction', 10, 1); // 10 = priorité (défaut), 1 = nb args

Filtres principaux

<?php
// Contenu
add_filter('the_content', 'modifier_contenu');
add_filter('the_excerpt', 'modifier_extrait');
add_filter('the_title', 'modifier_titre', 10, 2);

function modifier_contenu($content) {
    // Modifier contenu
    return $content . '<p>Ajout en fin</p>';
}

// Longueur extrait
add_filter('excerpt_length', 'nouvelle_longueur_extrait');
function nouvelle_longueur_extrait($length) {
    return 30; // mots
}

add_filter('excerpt_more', 'nouveau_more');
function nouveau_more($more) {
    return '... <a href="' . get_permalink() . '">Lire plus</a>';
}

// Requêtes
add_filter('pre_get_posts', 'modifier_requete');

function modifier_requete($query) {
    if (!is_admin() && $query->is_main_query() && $query->is_home()) {
        $query->set('posts_per_page', 12);
        $query->set('orderby', 'date');
    }
    return $query;
}

// Upload
add_filter('upload_mimes', 'ajouter_types_mime');
function ajouter_types_mime($mimes) {
    $mimes['svg'] = 'image/svg+xml';
    return $mimes;
}

add_filter('wp_handle_upload_prefilter', 'filtrer_upload');

// Admin
add_filter('admin_footer_text', 'custom_admin_footer');
add_filter('login_redirect', 'ma_redirection_login', 10, 3);

// Email
add_filter('wp_mail_from', 'custom_mail_from');
add_filter('wp_mail_from_name', 'custom_mail_from_name');

function custom_mail_from($email) {
    return 'noreply@monsite.com';
}

// Menu
add_filter('wp_nav_menu_items', 'ajouter_item_menu', 10, 2);

// Body class
add_filter('body_class', 'custom_body_class');

function custom_body_class($classes) {
    if (is_page('contact')) {
        $classes[] = 'page-contact-custom';
    }
    return $classes;
}

// Sanitization
add_filter('sanitize_title', 'custom_sanitize_title');

// Retirer un filtre
remove_filter('the_content', 'wpautop'); // Retire auto-paragraphes

Créer ses propres hooks

<?php
// Créer une action
function ma_fonction() {
    // Avant traitement
    do_action('mon_hook_avant');

    // Traitement
    $resultat = "données";

    // Après traitement
    do_action('mon_hook_apres', $resultat);

    return $resultat;
}

// Utiliser l'action
add_action('mon_hook_avant', 'ma_callback_avant');
add_action('mon_hook_apres', 'ma_callback_apres');

// Créer un filtre
function calculer_prix($prix) {
    $prix = apply_filters('mon_filtre_prix', $prix);
    return $prix;
}

// Utiliser le filtre
add_filter('mon_filtre_prix', function($prix) {
    return $prix * 1.2; // +20%
});

Template Tags (balises de template)

<?php
// header.php
get_header();           // Inclut header.php
get_header('custom');   // Inclut header-custom.php

// footer.php
get_footer();
get_footer('custom');

// sidebar.php
get_sidebar();
get_sidebar('custom');

// Dans header.php
?>
<!DOCTYPE html>
<html <?php language_attributes(); ?>>
<head>
    <meta charset="<?php bloginfo('charset'); ?>">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <?php wp_head(); ?>
</head>
<body <?php body_class(); ?>>
<?php wp_body_open(); ?>

<header>
    <a href="<?php echo esc_url(home_url('/')); ?>">
        <?php bloginfo('name'); ?>
    </a>
    <?php
    wp_nav_menu([
        'theme_location' => 'primary',
        'menu_class' => 'nav-menu',
        'container' => 'nav',
    ]);
    ?>
</header>

<?php
// Dans footer.php
?>
<footer>
    <p>&copy; <?php echo date('Y'); ?> <?php bloginfo('name'); ?></p>
</footer>
<?php wp_footer(); ?>
</body>
</html>

Loop (boucle WordPress)

<?php
// Loop standard
if (have_posts()) :
    while (have_posts()) : the_post();
        ?>
        <article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
            <h2>
                <a href="<?php the_permalink(); ?>">
                    <?php the_title(); ?>
                </a>
            </h2>

            <div class="entry-meta">
                <?php
                echo get_the_date();
                echo ' par ';
                the_author_posts_link();
                ?>
            </div>

            <?php if (has_post_thumbnail()) : ?>
                <div class="post-thumbnail">
                    <?php the_post_thumbnail('large'); ?>
                </div>
            <?php endif; ?>

            <div class="entry-content">
                <?php
                the_excerpt();
                // ou the_content('Lire la suite');
                ?>
            </div>

            <div class="entry-footer">
                <?php
                the_category(', ');
                the_tags('<ul><li>', '</li><li>', '</li></ul>');
                ?>
            </div>
        </article>
        <?php
    endwhile;

    // Pagination
    the_posts_pagination([
        'mid_size' => 2,
        'prev_text' => __('&laquo; Précédent', 'mon-theme'),
        'next_text' => __('Suivant &raquo;', 'mon-theme'),
    ]);

else :
    ?>
    <p><?php _e('Aucun article trouvé.', 'mon-theme'); ?></p>
    <?php
endif;

// Reset query si nécessaire
wp_reset_postdata();

Template Parts

<?php
// Inclure template part
get_template_part('template-parts/content', 'single');
// Cherche: content-single.php, puis content.php

get_template_part('template-parts/content', get_post_type());
// Pour post-type "product": content-product.php

// Passer variables (WP 5.5+)
get_template_part('template-parts/card', null, [
    'title' => 'Mon titre',
    'data' => $data,
]);

// Dans le template part (content.php)
// Accéder aux variables avec $args
$title = $args['title'] ?? '';

Informations du site

<?php
bloginfo('name');           // Nom du site
bloginfo('description');    // Slogan
bloginfo('url');           // URL du site
bloginfo('wpurl');         // URL de WordPress
bloginfo('charset');       // Charset (UTF-8)
bloginfo('language');      // Langue (fr-BE)
bloginfo('version');       // Version WordPress

// Alternatives get_
get_bloginfo('name');
home_url('/');             // URL accueil
admin_url('admin.php');    // URL admin
site_url();                // URL du site

Articles et pages

<?php
// Dans la loop
the_ID();                   // ID du post
the_title();                // Titre
the_permalink();            // URL
the_content();              // Contenu complet
the_excerpt();              // Extrait
the_author();               // Nom auteur
the_author_meta('display_name'); // Meta auteur
the_time('F j, Y');        // Date personnalisée
the_date();                 // Date
the_modified_date();        // Date modification
the_category(', ');        // Catégories
the_tags('Tags: ', ', ');  // Tags
comments_number('0', '1', '%'); // Nombre commentaires

// Versions get_ (retournent, n'affichent pas)
get_the_ID();
get_the_title();
get_the_permalink();
get_the_content();
get_the_excerpt();
get_the_author();
get_the_date('Y-m-d');
get_the_category();
get_the_tags();

// Images
the_post_thumbnail('thumbnail');     // 150x150
the_post_thumbnail('medium');        // 300x300
the_post_thumbnail('large');         // 1024x1024
the_post_thumbnail('full');          // Taille originale
the_post_thumbnail([200, 300]);      // Taille personnalisée

get_the_post_thumbnail_url($post_id, 'large');

if (has_post_thumbnail()) {
    the_post_thumbnail();
}

// Custom fields
get_post_meta($post_id, 'cle', true);   // true = valeur unique
update_post_meta($post_id, 'cle', 'valeur');
delete_post_meta($post_id, 'cle');
add_post_meta($post_id, 'cle', 'valeur');

Taxonomies

<?php
// Catégories
the_category(', ');                     // Affiche
get_the_category();                     // Retourne array

// Tags
the_tags('Tags: ', ', ', '<br>');
get_the_tags();

// Termes personnalisés
the_terms($post_id, 'ma-taxonomie', 'Prefix: ', ', ');
get_the_terms($post_id, 'ma-taxonomie');

// Récupérer termes
$terms = get_terms([
    'taxonomy' => 'category',
    'hide_empty' => false,
]);

foreach ($terms as $term) {
    echo $term->name;
    echo $term->slug;
    echo $term->term_id;
    echo $term->count;
}

// URL terme
get_term_link($term);
get_category_link($cat_id);
get_tag_link($tag_id);

WP_Query : Requêtes personnalisées

Exemples de requêtes

<?php
// Requête basique
$args = [
    'post_type' => 'post',
    'posts_per_page' => 10,
];
$query = new WP_Query($args);

if ($query->have_posts()) :
    while ($query->have_posts()) : $query->the_post();
        the_title();
    endwhile;
    wp_reset_postdata(); // Important !
endif;

// Requête avancée
$args = [
    'post_type' => 'product',
    'posts_per_page' => 12,
    'orderby' => 'date',
    'order' => 'DESC',
    'post_status' => 'publish',
    'author' => 1,
    'category_name' => 'actualites',
    'tag' => 'featured',
    'meta_query' => [
        'relation' => 'AND',
        [
            'key' => 'prix',
            'value' => 100,
            'compare' => '<',
            'type' => 'NUMERIC',
        ],
        [
            'key' => 'disponible',
            'value' => '1',
            'compare' => '=',
        ],
    ],
    'tax_query' => [
        'relation' => 'AND',
        [
            'taxonomy' => 'product_cat',
            'field' => 'slug',
            'terms' => 'electronics',
        ],
        [
            'taxonomy' => 'product_tag',
            'field' => 'slug',
            'terms' => ['featured', 'new'],
            'operator' => 'IN',
        ],
    ],
    'date_query' => [
        [
            'after' => '2024-01-01',
            'before' => '2024-12-31',
            'inclusive' => true,
        ],
    ],
];

$query = new WP_Query($args);

// Paramètres utiles
$args = [
    // Post Type
    'post_type' => 'post',          // post, page, custom-post-type, any
    'post_type' => ['post', 'page'],

    // Nombre
    'posts_per_page' => 10,         // -1 pour tous
    'nopaging' => true,             // Ignore pagination

    // Ordre
    'orderby' => 'date',            // date, title, name, modified, rand, meta_value, meta_value_num
    'order' => 'DESC',              // ASC ou DESC

    // Pagination
    'paged' => get_query_var('paged') ?: 1,
    'offset' => 5,                  // Sauter X posts

    // Statut
    'post_status' => 'publish',     // publish, draft, pending, private, trash, any

    // Auteur
    'author' => 1,                  // ID
    'author_name' => 'john',        // Slug

    // Inclusion/Exclusion
    'post__in' => [1, 2, 3],       // IDs à inclure
    'post__not_in' => [4, 5, 6],   // IDs à exclure

    // Taxonomie simple
    'category_name' => 'news',      // Slug catégorie
    'cat' => 5,                     // ID catégorie
    'tag' => 'featured',            // Slug tag
    'tag_id' => 10,                 // ID tag

    // Recherche
    's' => 'mot clé',

    // Post parent
    'post_parent' => 10,            // ID du parent
    'post_parent__in' => [1, 2],
    'post_parent__not_in' => [3, 4],

    // Cache
    'cache_results' => true,
    'update_post_meta_cache' => true,
    'update_post_term_cache' => true,
];

// Informations sur la requête
$query->found_posts;        // Total posts trouvés
$query->max_num_pages;      // Nombre de pages
$query->post_count;         // Posts dans page actuelle

Meta Query avancée

<?php
$args = [
    'meta_query' => [
        'relation' => 'AND', // AND ou OR
        [
            'key' => 'couleur',
            'value' => 'bleu',
            'compare' => '=',    // =, !=, >, >=, <, <=, LIKE, NOT LIKE, IN, NOT IN, BETWEEN, NOT BETWEEN, EXISTS, NOT EXISTS
        ],
        [
            'key' => 'prix',
            'value' => [10, 100],
            'compare' => 'BETWEEN',
            'type' => 'NUMERIC', // NUMERIC, BINARY, CHAR, DATE, DATETIME, DECIMAL, SIGNED, TIME, UNSIGNED
        ],
        [
            'relation' => 'OR',
            [
                'key' => 'promo',
                'value' => '1',
                'compare' => '=',
            ],
            [
                'key' => 'nouveau',
                'value' => '1',
                'compare' => '=',
            ],
        ],
    ],
];

// Ordonner par meta
$args = [
    'meta_key' => 'prix',
    'orderby' => 'meta_value_num',
    'order' => 'ASC',
];

// Meta query avec clause nommée (pour orderby)
$args = [
    'meta_query' => [
        'prix_clause' => [
            'key' => 'prix',
            'type' => 'NUMERIC',
        ],
        'note_clause' => [
            'key' => 'note',
            'type' => 'NUMERIC',
        ],
    ],
    'orderby' => [
        'prix_clause' => 'ASC',
        'note_clause' => 'DESC',
    ],
];

Tax Query avancée

<?php
$args = [
    'tax_query' => [
        'relation' => 'AND',
        [
            'taxonomy' => 'category',
            'field' => 'slug',      // slug, term_id, name
            'terms' => 'news',
            'operator' => 'IN',     // IN, NOT IN, AND, EXISTS, NOT EXISTS
        ],
        [
            'taxonomy' => 'post_tag',
            'field' => 'slug',
            'terms' => ['featured', 'popular'],
            'operator' => 'IN',
        ],
        [
            'relation' => 'OR',
            [
                'taxonomy' => 'product_cat',
                'field' => 'slug',
                'terms' => 'electronics',
            ],
            [
                'taxonomy' => 'product_cat',
                'field' => 'slug',
                'terms' => 'clothing',
            ],
        ],
    ],
];

Fonctions alternatives

<?php
// get_posts() - Retourne array de posts
$posts = get_posts([
    'numberposts' => 5,
    'post_type' => 'post',
]);

foreach ($posts as $post) {
    setup_postdata($post); // Important pour template tags
    the_title();
}
wp_reset_postdata();

// get_pages()
$pages = get_pages([
    'sort_column' => 'menu_order',
    'parent' => 0,
]);

// Query principale
global $wp_query;
$wp_query->is_home();
$wp_query->is_single();
$wp_query->is_page();

Custom Post Types et Taxonomies

Register Post Type

<?php
function mon_custom_post_type() {
    $labels = [
        'name' => _x('Produits', 'Post type general name', 'mon-theme'),
        'singular_name' => _x('Produit', 'Post type singular name', 'mon-theme'),
        'menu_name' => _x('Produits', 'Admin Menu text', 'mon-theme'),
        'add_new' => __('Ajouter nouveau', 'mon-theme'),
        'add_new_item' => __('Ajouter un nouveau produit', 'mon-theme'),
        'edit_item' => __('Modifier le produit', 'mon-theme'),
        'new_item' => __('Nouveau produit', 'mon-theme'),
        'view_item' => __('Voir le produit', 'mon-theme'),
        'search_items' => __('Rechercher des produits', 'mon-theme'),
        'not_found' => __('Aucun produit trouvé', 'mon-theme'),
        'not_found_in_trash' => __('Aucun produit dans la corbeille', 'mon-theme'),
        'all_items' => __('Tous les produits', 'mon-theme'),
    ];

    $args = [
        'labels' => $labels,
        'description' => __('Gestion des produits', 'mon-theme'),
        'public' => true,
        'publicly_queryable' => true,
        'show_ui' => true,
        'show_in_menu' => true,
        'query_var' => true,
        'rewrite' => ['slug' => 'produits'],
        'capability_type' => 'post',
        'has_archive' => true,
        'hierarchical' => false,        // false = comme post, true = comme page
        'menu_position' => 5,
        'menu_icon' => 'dashicons-products',
        'supports' => ['title', 'editor', 'thumbnail', 'excerpt', 'comments', 'custom-fields'],
        'show_in_rest' => true,         // Active Gutenberg
        'taxonomies' => ['category', 'post_tag'],
    ];

    register_post_type('product', $args);
}
add_action('init', 'mon_custom_post_type');

// Flush rewrite rules après activation
register_activation_hook(__FILE__, function() {
    mon_custom_post_type();
    flush_rewrite_rules();
});

register_deactivation_hook(__FILE__, function() {
    flush_rewrite_rules();
});

Register Taxonomy

<?php
function ma_custom_taxonomy() {
    $labels = [
        'name' => _x('Catégories Produits', 'taxonomy general name', 'mon-theme'),
        'singular_name' => _x('Catégorie Produit', 'taxonomy singular name', 'mon-theme'),
        'search_items' => __('Rechercher catégories', 'mon-theme'),
        'all_items' => __('Toutes les catégories', 'mon-theme'),
        'parent_item' => __('Catégorie parente', 'mon-theme'),
        'parent_item_colon' => __('Catégorie parente:', 'mon-theme'),
        'edit_item' => __('Modifier la catégorie', 'mon-theme'),
        'update_item' => __('Mettre à jour', 'mon-theme'),
        'add_new_item' => __('Ajouter nouvelle catégorie', 'mon-theme'),
        'new_item_name' => __('Nom nouvelle catégorie', 'mon-theme'),
        'menu_name' => __('Catégories', 'mon-theme'),
    ];

    $args = [
        'labels' => $labels,
        'description' => __('Catégories de produits', 'mon-theme'),
        'hierarchical' => true,         // true = comme catégorie, false = comme tag
        'public' => true,
        'publicly_queryable' => true,
        'show_ui' => true,
        'show_in_menu' => true,
        'show_in_nav_menus' => true,
        'show_admin_column' => true,
        'query_var' => true,
        'rewrite' => ['slug' => 'categorie-produit'],
        'show_in_rest' => true,
    ];

    register_taxonomy('product_cat', ['product'], $args);

    // Taxonomie non-hiérarchique (comme tags)
    register_taxonomy('product_tag', ['product'], [
        'labels' => [
            'name' => 'Tags Produits',
            'singular_name' => 'Tag Produit',
        ],
        'hierarchical' => false,
        'show_admin_column' => true,
        'rewrite' => ['slug' => 'tag-produit'],
    ]);
}
add_action('init', 'ma_custom_taxonomy');
<?php
// functions.php - Enregistrer emplacements
function mes_menus() {
    register_nav_menus([
        'primary' => __('Menu Principal', 'mon-theme'),
        'footer' => __('Menu Footer', 'mon-theme'),
        'mobile' => __('Menu Mobile', 'mon-theme'),
    ]);
}
add_action('after_setup_theme', 'mes_menus');

// Afficher menu
wp_nav_menu([
    'theme_location' => 'primary',
    'menu_class' => 'nav-menu',
    'container' => 'nav',
    'container_class' => 'primary-navigation',
    'fallback_cb' => 'wp_page_menu',
    'depth' => 2,
]);

// Options avancées
wp_nav_menu([
    'theme_location' => 'primary',
    'menu' => 'Main Menu',              // Nom du menu
    'menu_id' => 'primary-menu',
    'menu_class' => 'nav-menu',
    'container' => 'nav',
    'container_id' => 'site-navigation',
    'container_class' => 'primary-navigation',
    'before' => '<span>',
    'after' => '</span>',
    'link_before' => '<span>',
    'link_after' => '</span>',
    'items_wrap' => '<ul id="%1$s" class="%2$s">%3$s</ul>',
    'depth' => 0,                       // 0 = tous les niveaux
    'walker' => new Mon_Custom_Walker(),
]);

// Walker personnalisé
class Mon_Custom_Walker extends Walker_Nav_Menu {
    function start_el(&$output, $item, $depth = 0, $args = [], $id = 0) {
        $classes = empty($item->classes) ? [] : (array) $item->classes;
        $class_names = join(' ', apply_filters('nav_menu_css_class', array_filter($classes), $item));

        $output .= '<li class="' . esc_attr($class_names) . '">';

        $attributes = '';
        $attributes .= !empty($item->url) ? ' href="' . esc_attr($item->url) . '"' : '';

        $item_output = $args->before ?? '';
        $item_output .= '<a' . $attributes . '>';
        $item_output .= ($args->link_before ?? '') . apply_filters('the_title', $item->title, $item->ID) . ($args->link_after ?? '');
        $item_output .= '</a>';
        $item_output .= $args->after ?? '';

        $output .= apply_filters('walker_nav_menu_start_el', $item_output, $item, $depth, $args);
    }
}

Base de données WordPress

Tables principales

wp_posts            - Articles, pages, custom post types
wp_postmeta         - Meta données posts
wp_users            - Utilisateurs
wp_usermeta         - Meta données utilisateurs
wp_comments         - Commentaires
wp_commentmeta      - Meta données commentaires
wp_terms            - Termes (catégories, tags, taxonomies)
wp_term_taxonomy    - Relations taxonomie
wp_term_relationships - Relations posts/termes
wp_options          - Options du site
wp_links            - Liens (déprécié)

wpdb – Requêtes SQL

<?php
global $wpdb;

// SELECT
$results = $wpdb->get_results("SELECT * FROM {$wpdb->posts} WHERE post_type = 'post'");

foreach ($results as $post) {
    echo $post->post_title;
}

// Récupérer une ligne
$post = $wpdb->get_row("SELECT * FROM {$wpdb->posts} WHERE ID = 1");

// Récupérer une colonne
$titles = $wpdb->get_col("SELECT post_title FROM {$wpdb->posts}");

// Récupérer une valeur
$count = $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->posts}");

// Préparation sécurisée (IMPORTANT)
$post_id = 1;
$post_type = 'product';
$sql = $wpdb->prepare(
    "SELECT * FROM {$wpdb->posts} WHERE ID = %d AND post_type = %s",
    $post_id,
    $post_type
);
$post = $wpdb->get_row($sql);

// Placeholders: %d (int), %f (float), %s (string)

// INSERT
$wpdb->insert(
    $wpdb->posts,
    [
        'post_title' => 'Mon titre',
        'post_content' => 'Mon contenu',
        'post_status' => 'publish',
        'post_type' => 'post',
    ],
    ['%s', '%s', '%s', '%s']
);
$insert_id = $wpdb->insert_id;

// UPDATE
$wpdb->update(
    $wpdb->posts,
    ['post_title' => 'Nouveau titre'],      // Data
    ['ID' => 1],                             // Where
    ['%s'],                                  // Format data
    ['%d']                                   // Format where
);
$affected = $wpdb->rows_affected;

// DELETE
$wpdb->delete(
    $wpdb->posts,
    ['ID' => 1],
    ['%d']
);

// Requête directe
$wpdb->query("DELETE FROM {$wpdb->posts} WHERE post_type = 'trash'");

// Préfixe des tables
$table_name = $wpdb->prefix . 'ma_table_custom';

// Créer table custom
$charset_collate = $wpdb->get_charset_collate();
$sql = "CREATE TABLE $table_name (
    id mediumint(9) NOT NULL AUTO_INCREMENT,
    name varchar(100) NOT NULL,
    email varchar(100) NOT NULL,
    created_at datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
    PRIMARY KEY  (id)
) $charset_collate;";

require_once ABSPATH . 'wp-admin/includes/upgrade.php';
dbDelta($sql);

// Erreurs
$wpdb->show_errors();
$wpdb->print_error();
$wpdb->last_error;
$wpdb->last_query;

Options API

<?php
// Ajouter/Récupérer option
add_option('mon_option', 'valeur', '', 'yes'); // yes = autoload
$valeur = get_option('mon_option', 'défaut');

// Mettre à jour (crée si n'existe pas)
update_option('mon_option', 'nouvelle valeur');

// Supprimer
delete_option('mon_option');

// Options réseau (multisite)
add_site_option('mon_option', 'valeur');
get_site_option('mon_option', 'défaut');
update_site_option('mon_option', 'valeur');
delete_site_option('mon_option');

// Vérifier existence
if (get_option('mon_option') !== false) {
    // Option existe
}

Conditional Tags

<?php
// Types de pages
is_home();              // Page d'accueil du blog
is_front_page();        // Page d'accueil du site
is_single();            // Article seul
is_single(123);         // Article ID 123
is_single('hello');     // Article slug "hello"
is_page();              // Page
is_page(456);           // Page ID 456
is_page('contact');     // Page slug "contact"
is_page_template('template-custom.php');
is_archive();           // Archive
is_category();          // Archive catégorie
is_category('news');    // Catégorie "news"
is_tag();               // Archive tag
is_tag('featured');     // Tag "featured"
is_tax();               // Archive taxonomie custom
is_tax('product_cat');  // Taxonomie product_cat
is_author();            // Archive auteur
is_author(1);           // Auteur ID 1
is_date();              // Archive date
is_year();              // Archive année
is_month();             // Archive mois
is_day();               // Archive jour
is_time();              // Archive heure
is_search();            // Résultats recherche
is_404();               // Page 404
is_attachment();        // Page attachement
is_singular();          // Article ou page seule
is_post_type_archive('product');

// Contexte
is_admin();             // Backoffice
is_user_logged_in();    // Utilisateur connecté
is_sticky();            // Article épinglé
has_post_thumbnail();   // A une image mise en avant
has_excerpt();          // A un extrait
has_tag('news');        // A le tag "news"
has_category('tech');   // A la catégorie "tech"
has_term('blue', 'color'); // A le terme "blue" de taxonomie "color"
is_multi_author();      // Site avec plusieurs auteurs
is_paged();             // Page paginée (page 2+)
in_category('news');    // Dans catégorie "news"

// Template
is_main_query();        // Dans requête principale
is_active_sidebar('sidebar-1'); // Sidebar active

// Multisite
is_multisite();
is_main_site();

Shortcodes

<?php
// Créer shortcode simple
function mon_shortcode() {
    return '<p>Contenu du shortcode</p>';
}
add_shortcode('mon_shortcode', 'mon_shortcode');
// Utilisation: [mon_shortcode]

// Avec attributs
function shortcode_bouton($atts) {
    $atts = shortcode_atts([
        'url' => '#',
        'texte' => 'Cliquez ici',
        'couleur' => 'blue',
    ], $atts, 'bouton');

    return sprintf(
        '<a href="%s" class="btn btn-%s">%s</a>',
        esc_url($atts['url']),
        esc_attr($atts['couleur']),
        esc_html($atts['texte'])
    );
}
add_shortcode('bouton', 'shortcode_bouton');
// Utilisation: [bouton url="https://example.com" texte="Voir plus" couleur="red"]

// Avec contenu
function shortcode_box($atts, $content = null) {
    $atts = shortcode_atts([
        'titre' => '',
        'couleur' => 'blue',
    ], $atts);

    $content = do_shortcode($content); // Parse shortcodes imbriqués

    $output = '<div class="box box-' . esc_attr($atts['couleur']) . '">';
    if ($atts['titre']) {
        $output .= '<h3>' . esc_html($atts['titre']) . '</h3>';
    }
    $output .= '<div class="box-content">' . $content . '</div>';
    $output .= '</div>';

    return $output;
}
add_shortcode('box', 'shortcode_box');
// Utilisation: [box titre="Mon titre" couleur="red"]Contenu[/box]

// Retirer shortcode
remove_shortcode('mon_shortcode');

// Vérifier si shortcode existe
if (shortcode_exists('mon_shortcode')) {
    // ...
}

// Parser shortcodes dans texte
$content = do_shortcode('[mon_shortcode]');

// Échapper shortcodes (afficher sans exécuter)
// [[mon_shortcode]] affichera [mon_shortcode]

Internationalisation (i18n)

<?php
// Traduction simple
__('Texte à traduire', 'mon-theme');
_e('Texte affiché directement', 'mon-theme');
esc_html__('Texte échappé HTML', 'mon-theme');
esc_html_e('Texte échappé et affiché', 'mon-theme');
esc_attr__('Texte pour attribut', 'mon-theme');

// Contexte (pour différencier même texte)
_x('Post', 'nom', 'mon-theme');
_x('Post', 'verbe', 'mon-theme');

// Pluriel
_n('1 commentaire', '%s commentaires', $nombre, 'mon-theme');
printf(_n('1 commentaire', '%s commentaires', $count, 'mon-theme'), $count);

// Contexte + pluriel
_nx('1 produit', '%s produits', $nombre, 'e-commerce', 'mon-theme');

// Variables
sprintf(__('Bonjour %s', 'mon-theme'), $nom);

// Charger traductions (functions.php)
function mon_theme_load_textdomain() {
    load_theme_textdomain('mon-theme', get_template_directory() . '/languages');
}
add_action('after_setup_theme', 'mon_theme_load_textdomain');

// Pour plugin
load_plugin_textdomain('mon-plugin', false, dirname(plugin_basename(__FILE__)) . '/languages');

// Structure fichiers traduction
// mon-theme/languages/fr_BE.po
// mon-theme/languages/fr_BE.mo
// mon-theme/languages/en_US.po
// mon-theme/languages/en_US.mo

Sécurité WordPress

Nonces

<?php
// Créer nonce
$nonce = wp_create_nonce('mon-action');

// Champ nonce dans formulaire
wp_nonce_field('mon-action', 'mon_nonce_field');

// URL avec nonce
$url = wp_nonce_url('admin.php?page=ma-page&action=supprimer', 'supprimer-action');

// Vérifier nonce
if (isset($_POST['mon_nonce_field']) && wp_verify_nonce($_POST['mon_nonce_field'], 'mon-action')) {
    // Traitement sécurisé
}

// Vérifier nonce dans URL
if (isset($_GET['_wpnonce']) && wp_verify_nonce($_GET['_wpnonce'], 'supprimer-action')) {
    // OK
}

// AJAX nonce
check_ajax_referer('mon-action', 'nonce');

// Admin nonce
check_admin_referer('mon-action', 'mon_nonce_field');

Sanitization et Validation

<?php
// Sanitize (nettoyage)
sanitize_text_field($_POST['champ']);       // Texte simple
sanitize_email($_POST['email']);             // Email
sanitize_url($_POST['url']);                 // URL
sanitize_title($_POST['titre']);             // Titre/slug
sanitize_key($_POST['cle']);                 // Clé (lettres, chiffres, tirets)
sanitize_html_class($_POST['classe']);       // Classe CSS
sanitize_textarea_field($_POST['texte']);    // Textarea

// Validation
is_email($email);                            // Email valide
filter_var($email, FILTER_VALIDATE_EMAIL);
filter_var($url, FILTER_VALIDATE_URL);
filter_var($int, FILTER_VALIDATE_INT);

// Échappement sortie
esc_html($text);                             // Texte HTML
esc_attr($text);                             // Attribut
esc_url($url);                               // URL
esc_js($text);                               // JavaScript
esc_textarea($text);                         // Textarea

// Données complexes
wp_kses($html, $allowed_tags);              // HTML avec tags autorisés
wp_kses_post($html);                        // HTML autorisé dans posts

// Exemple complet
if (isset($_POST['submit']) && wp_verify_nonce($_POST['_wpnonce'], 'mon-formulaire')) {
    $nom = sanitize_text_field($_POST['nom']);
    $email = sanitize_email($_POST['email']);
    $url = esc_url_raw($_POST['url']);
    $message = sanitize_textarea_field($_POST['message']);

    if (is_email($email)) {
        // Traiter données
    }
}

Capabilities (Capacités)

<?php
// Vérifier capacité utilisateur
if (current_user_can('edit_posts')) {
    // Utilisateur peut éditer posts
}

// Capacités courantes
'read'                  // Lecture
'edit_posts'            // Éditer ses posts
'edit_others_posts'     // Éditer posts des autres
'publish_posts'         // Publier posts
'delete_posts'          // Supprimer ses posts
'delete_others_posts'   // Supprimer posts des autres
'manage_options'        // Gérer options (admin)
'manage_categories'     // Gérer catégories
'upload_files'          // Upload fichiers
'edit_theme_options'    // Modifier thème
'install_plugins'       // Installer plugins
'activate_plugins'      // Activer plugins
'edit_users'            // Éditer utilisateurs
'delete_users'          // Supprimer utilisateurs

// Par post type
current_user_can('edit_post', $post_id);
current_user_can('delete_post', $post_id);

// Obtenir utilisateur courant
$current_user = wp_get_current_user();
echo $current_user->user_login;
echo $current_user->user_email;
echo $current_user->ID;

// Vérifier rôle
if (in_array('administrator', $current_user->roles)) {
    // Est admin
}

Performance et optimisation

<?php
// Transients (cache temporaire)
set_transient('ma_donnee', $valeur, 12 * HOUR_IN_SECONDS);
$data = get_transient('ma_donnee');
if ($data === false) {
    // Calculer/récupérer données
    $data = fonction_couteuse();
    set_transient('ma_donnee', $data, 12 * HOUR_IN_SECONDS);
}
delete_transient('ma_donnee');

// Object cache
wp_cache_set('ma_cle', $valeur, 'mon_groupe', 3600);
$data = wp_cache_get('ma_cle', 'mon_groupe');
wp_cache_delete('ma_cle', 'mon_groupe');
wp_cache_flush(); // Vider tout

// Désactiver updates pour tests
define('AUTOMATIC_UPDATER_DISABLED', true);
define('WP_AUTO_UPDATE_CORE', false);

// Désactiver révisions
define('WP_POST_REVISIONS', false);
// Ou limiter
define('WP_POST_REVISIONS', 3);

// Augmenter memory limit
define('WP_MEMORY_LIMIT', '256M');
define('WP_MAX_MEMORY_LIMIT', '512M');

// Debug
define('WP_DEBUG', true);
define('WP_DEBUG_LOG', true);
define('WP_DEBUG_DISPLAY', false);

// Heartbeat API (réduit charge serveur)
add_action('init', function() {
    wp_deregister_script('heartbeat');
});

Version: WordPress 6.4+ | Documentation: developer.wordpress.org

Une remarque, un retour ?

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

Laisser un commentaire