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)
Header et Footer
<?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>© <?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' => __('« Précédent', 'mon-theme'),
'next_text' => __('Suivant »', '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');
Menus de navigation
<?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