Open source · Ata
Donnez des ailes à votre plugin WordPress.
Avec une structure MVC-S.
ATA aide les développeurs de plugins WordPress à garder leur code organisé et maintenable à mesure qu’il grandit, grâce au design pattern MVC.
Pour les développeurs de plugins WordPress
Chaque chose à sa place.
ATA donne à chaque plugin la même structure prévisible : votre code reste organisé et maintenable, même quand il grandit.
ATA Folder STRUCTURE
your-plugin-name/
├── app/
│ ├── apis/ # REST API endpoint classes
│ ├── controllers/ # Controller classes
│ ├── helpers/ # Global helper functions
│ ├── models/ # Data logic (database interaction)
│ │ └── structures/ # Optional: DTOs/data structure classes
│ ├── routes/ # API and custom URL definitions
│ ├── services/ # Business logic layer
│ └── views/ # View files (HTML/PHP templates)
│
├── base/ # Base classes your app classes extend
├── config/ # Plugin-wide configuration
├── constants/ # Custom constant definitions
├── inc/ # Bootstrapping and initialization files
├── vendor/ # Composer dependencies (includes the core ATA framework)
│
└── your-plugin-name.php # The main plugin entry file
Les principes fondamentaux d’Ata.
Structuré par défaut
ATA fournit une arborescence prédéfinie qui sépare logiquement les différentes parties de votre plugin.
L’orienté objet d’abord
Il encourage l’écriture de code sous forme de classes plutôt que de fonctions procédurales, pour un code mieux organisé et plus réutilisable.
Une séparation claire des responsabilités
Il met en œuvre une variante du pattern MVC pour garder bien séparées vos couches logique, données et présentation.
Un routage simplifié
ATA intègre un routeur qui rend la déclaration d’endpoints REST API ou d’URL personnalisées simple et déclarative.
Les différences clés
Qu’est-ce que MVC-S ?
ATA promeut une variante du pattern Modèle-Vue-Contrôleur (MVC), que nous appelons MVC-S (Modèle-Vue-Contrôleur-Services).
Contrôleur (le moteur central)
Le Contrôleur est le cœur du fonctionnement de votre plugin. Il traite les requêtes entrantes, enregistre tous les hooks et filtres WordPress et pilote le flux de l’application. Pour un plugin simple, le Contrôleur peut gérer directement toute la logique et l’accès aux données. Dans des applications plus complexes, son rôle évolue vers celui d’un chef d’orchestre : il fait appel à un Service pour la logique métier ou à un Modèle pour les données, puis transmet les résultats à une Vue pour l’affichage.
Vue (la couche de présentation)
La Vue est une couche facultative qui génère le HTML. Elle reçoit les données du Contrôleur et les affiche. Une Vue doit contenir un minimum de logique PHP et se concentrer uniquement sur l’affichage des données qu’on lui transmet.
Modèle (la couche de données)
La seule responsabilité du Modèle est l’interaction directe avec la base de données. Dans une classe Modèle, vous accédez à l’objet de base de données WordPress via $this->db (par ex. $this->db->get_results(...)). Cette couche est facultative : si votre plugin n’interagit pas avec la base de données, vous n’en avez pas besoin.
Service (la couche logique)
La couche Service est l’emplacement facultatif mais recommandé pour la logique métier de votre plugin. Quand la logique devient trop complexe pour un Contrôleur, extrayez-la dans un Service. Vos Contrôleurs restent ainsi légers et centrés sur le traitement des requêtes.
Plugin d’exemple
Polylang RestAPI Helper
Le plugin polylang-restapi-helper est un exemple parfait et ciblé du framework ATA.
Structurer votre plugin WordPress en MVC avec ATA
Documentation
Démarrer avec ATA dans votre plugin, vite et simplement
Le cycle de vie du plugin & le Contrôleur principal
Chaque plugin ATA est piloté par un Contrôleur racine central. Ce contrôleur principal est le point d’entrée de toutes les fonctionnalités du plugin et gère son cycle de vie.
1. Le fichier principal du plugin (your-plugin-name.php) Ce fichier est réduit au strict minimum. Son seul rôle : définir les constantes essentielles, charger le framework ATA et instancier votre contrôleur principal.
// in your-plugin-name.php
namespace YourPluginNamespace;
// ... define constants ...
// Load the framework and all its dependencies
require_once PLUGIN_PATH . '/inc/main.php';
// Instantiate the one and only root controller
$my_plugin = new MainController();
// Hook into WordPress's activation/deactivation events
register_activation_hook(PLUGIN_FILE, [$my_plugin, 'activate']);
register_deactivation_hook(PLUGIN_FILE, [$my_plugin, 'deactivate']);
2. Le Contrôleur principal (app/controllers/main-controller.php) Ce contrôleur contient la logique d’activation/désactivation et, surtout, charge tous les autres contrôleurs. C’est ici que vous pouvez charger des fonctionnalités de manière conditionnelle selon que d’autres plugins sont actifs ou non, pour économiser la mémoire et éviter les erreurs.
// in app/controllers/main-controller.php
namespace YourPluginNamespace;
class MainController extends Controller
{
public function __construct()
{
parent::__construct();
$this->load_features();
}
// Load other controllers for specific features
private function load_features()
{
// Always load the admin UI and asset controllers
(new AdminUiController())->main();
(new AssetsController())->main();
// **Conditionally load features**
// Only load the WooCommerce compatibility layer if WooCommerce is active
if (is_plugin_active('woocommerce/woocommerce.php')) {
(new WooCommerceController())->main();
}
}
// Logic for when the plugin is activated (e.g., create DB tables)
public function activate()
{
// ... your activation code ...
}
// Logic for when the plugin is deactivated (e.g., remove DB tables)
public function deactivate()
{
// ... your deactivation code ...
}
}
Ajouter une page ou un onglet à l’administration WordPress
ATA fournit une interface fluide pour créer facilement des pages d’administration à plusieurs onglets. Le tout se gère depuis un contrôleur.
// in app/controllers/admin-ui-controller.php
namespace YourPluginNamespace;
class AdminUiController extends Controller
{
public function main()
{
$this->add_wp_admin_pages();
}
private function add_wp_admin_pages()
{
// Create a top-level page titled "My Plugin"
$this->admin_page('My Plugin')
// Only users who can 'manage_options' can see it
->permission('manage_options')
// Add a "Dashboard" tab (calls the 'dashboard_page' method)
->add_tab('Dashboard', 'dashboard_page')
// Add a "Settings" tab (calls the 'settings_page' method)
->add_tab('Settings', 'settings_page')
// Register the page and all its tabs
->register();
}
// This method is called when the 'Dashboard' tab is active
public function dashboard_page()
{
$this->view = 'dashboard'; // Renders views/dashboard-view.php
}
// This method is called when the 'Settings' tab is active
public function settings_page()
{
$this->view = 'settings'; // Renders views/settings-view.php
}
}
Se brancher sur un hook WordPress (action)
Le contrôleur de base d’ATA fournit une méthode utilitaire pratique, on() pour enregistrer les hooks d’action. Le constructeur ou une méthode main() de votre contrôleur est l’endroit idéal pour enregistrer tous les hooks.
// in app/controllers/footer-message-controller.php
namespace YourPluginNamespace;
class FooterMessageController extends Controller
{
public function main()
{
// Hook into 'wp_footer' to call the 'add_message' method
$this->on('wp_footer', 'add_message');
}
public function add_message()
{
echo "";
}
}
Utiliser les filtres WordPress
Comme pour les actions, vous pouvez utiliser la méthode utilitaire filter() pour modifier des données.
// in app/controllers/content-controller.php
namespace YourPluginNamespace;
class ContentController extends Controller
{
public function main()
{
// Hook into 'the_content' to modify post content
$this->filter('the_content', 'add_author_bio');
}
public function add_author_bio($content)
{
if (is_single() && in_the_loop() && is_main_query()) {
$author_bio = '';
return $content . $author_bio;
}
return $content;
}
}
Ajouter un endpoint REST API WordPress
Étape 1 : déclarer la route dans app/routes/main-routes.php. Vous indiquez ainsi à WordPress que votre URL existe et quelle méthode doit la traiter.
// in app/routes/main-routes.php
namespace YourPluginNamespace;
$ata_router->api_version('my-plugin/v1');
$ata_router->api_method('GET')->api('/products')->call('ProductsApi::get_all_products');
Étape 2 : créer une classe API dans app/apis/ pour contenir la logique de l’endpoint.
// in app/apis/products-api.php
namespace YourPluginNamespace;
class ProductsApi extends Api {
public function get_all_products() {
// ... logic to get products ...
return $this->send_success('Products retrieved.', ['products' => '...']);
}
}
Comment fonctionne le routage ?
Le fichier de routes (app/routes/main-routes.php) est une fonctionnalité puissante mais facultative. Son seul rôle est de servir d’aiguillage en indiquant à WordPress comment traiter certaines URL personnalisées. Si votre plugin n’a besoin ni d’URL personnalisées ni de REST API, vous n’avez pas à l’utiliser.
- Pour les REST API : utilisez la méthode
api(). Elle enregistre un nouvel endpoint sous/wp-json/.// Registers: example.com/wp-json/my-plugin/v1/orders $ata_router->api_version('my-plugin/v1'); $ata_router->api('/orders')->call('MyOrdersApi::get_orders'); - Pour les URL front-end personnalisées : utilisez la méthode
page(). Elle crée une page virtuelle sans avoir besoin d’une Page WordPress.// Registers: example.com/my-custom-url/ $ata_router->page('/my-custom-url')->call('MyPageController::show_page');
À quoi servent les répertoires principaux facultatifs ?
app/views
Ce répertoire contient vos templates HTML. Il n’est nécessaire que si votre plugin génère une interface utilisateur, comme une page de réglages dans l’administration ou une page front-end personnalisée. Les plugins qui n’offrent qu’une fonctionnalité en arrière-plan ou une REST API n’auront probablement pas de répertoire views.
models/structures (DTO)
Ce répertoire est destiné aux Data Transfer Objects (DTO). Un DTO est une classe simple qui définit la forme des données échangées. Ce répertoire est facultatif et peut s’avérer inutile pour de nombreux plugins. Il est surtout utile lorsque vous devez imposer une structure de données stricte, en particulier pour communiquer avec une API externe.
Votre réussite pourrait être la prochaine.
Des questions ? Nous sommes là pour vous aider à faire le bon choix.