filtres poses une seule fois.
add_action( 'plugins_loaded', array( 'Aiforya_Multi_AI_Marking', 'init' ) );
// =============================================================================
// 2bis. Services métier internes (DB, workflow, AJAX).
// =============================================================================
require_once AIFORYA_MA_DIR . 'includes/class-aiforya-multi-author-db.php';
require_once AIFORYA_MA_DIR . 'includes/class-aiforya-multi-author-workflow.php';
require_once AIFORYA_MA_DIR . 'includes/class-aiforya-multi-author-ajax.php';
require_once AIFORYA_MA_DIR . 'includes/class-aiforya-multi-author-notifier.php';
require_once AIFORYA_MA_DIR . 'public/class-aiforya-multi-author-frontend.php';
// =============================================================================
// 3. Activator — DOIT être chargé AVANT register_activation_hook.
// =============================================================================
require_once AIFORYA_MA_DIR . 'includes/class-aiforya-multi-author-activator.php';
register_activation_hook( __FILE__, [ 'Aiforya_Ma_Activator', 'activate' ] );
// La migration de schéma NE se déclenche pas à l'activation : WordPress ne rejoue pas
// register_activation_hook lors d'une MISE À JOUR. On compare donc la version stockée
// au chargement (voir maybe_upgrade dans l'activateur, 28/08/2026).
add_action( 'plugins_loaded', static function (): void {
if ( method_exists( 'Aiforya_Ma_Activator', 'maybe_upgrade' ) ) {
Aiforya_Ma_Activator::maybe_upgrade();
}
}, 1 );
register_deactivation_hook( __FILE__, [ 'Aiforya_Ma_Activator', 'deactivate' ] );
// =============================================================================
// 4bis. Enqueue défensif des assets du shell + de l'interface commune.
// =============================================================================
add_action( 'admin_enqueue_scripts', static function ( string $hook ): void {
if ( class_exists( 'AIFORYA_MULTI_Shell' ) && method_exists( 'AIFORYA_MULTI_Shell', 'maybe_enqueue_assets' ) ) {
AIFORYA_MULTI_Shell::maybe_enqueue_assets( $hook );
}
}, 5 );
add_action( 'admin_enqueue_scripts', static function ( string $hook ): void {
$vendor_url = AIFORYA_MA_URL . 'vendor-aiforya/assets/';
wp_enqueue_style(
'aiforya-ui-bbf8d166',
$vendor_url . 'aiforya-ui.css',
[],
AIFORYA_MA_VERSION
);
wp_enqueue_script(
'aiforya-ui-bbf8d166',
$vendor_url . 'aiforya-ui.js',
[],
AIFORYA_MA_VERSION,
true
);
wp_localize_script( 'aiforya-ui-bbf8d166', 'aiforyaUiI18n', [
'confirm' => __( 'OK', 'aiforya-multi-author' ),
'cancel' => __( 'Cancel', 'aiforya-multi-author' ),
] );
}, 5 );
// =============================================================================
// 5. Boot du moteur (menu admin + onglets).
// =============================================================================
add_action( 'plugins_loaded', static function (): void {
if ( ! class_exists( 'Aiforya_Multi_Engine' ) ) {
return;
}
Aiforya_Multi_Engine::boot( AIFORYA_MA_DIR, [
'slug' => AIFORYA_MA_SLUG,
'requires_activation' => false, // Extension gratuite .org : aucun ecran d'activation licence.
'title' => 'AIFORYA Multi Author',
'description' => 'A multi-author editorial workflow: roles, post assignment, statuses, co-authors and bylines — with no API key and no external service.',
'icon' => 'dashicons-groups',
'category' => 'Editorial',
'capability' => 'manage_options',
'position' => 20,
'plugin_basename' => AIFORYA_MA_BASENAME,
'plugin_image' => plugins_url( 'assets/images/cover.png', __FILE__ ),
'faq' => static function () {
return [
[
'q' => __( 'Which roles does this plugin add?', 'aiforya-multi-author' ),
'a' => __( 'Three editorial roles are created on activation: Writer (writes and submits their posts), Editor (edits and approves writers\' posts) and Publisher (publishes the approved posts). Each role has granular permissions matching its place in the flow.', 'aiforya-multi-author' ),
],
[
'q' => __( 'How does the status workflow work?', 'aiforya-multi-author' ),
'a' => __( 'Every assigned post follows a clear cycle: Drafting, In review, Revision requested, Approved, then Published. You move a post from one status to the next in the Posts tab; switching to Published publishes it automatically in WordPress.', 'aiforya-multi-author' ),
],
[
'q' => __( 'Do I need an API key or an external account?', 'aiforya-multi-author' ),
'a' => __( 'No. The free version runs entirely on your own server, with no API key and no external service. Roles, assignments, statuses, co-authors and statistics are all handled locally.', 'aiforya-multi-author' ),
],
[
'q' => __( 'How do I assign a post to an author?', 'aiforya-multi-author' ),
'a' => __( 'In the Posts tab, choose a post and the author to assign it to. The WordPress post author is updated and a tracking row is created, so you can steer its status through the editorial workflow.', 'aiforya-multi-author' ),
],
[
'q' => __( 'Is there a version with AI review?', 'aiforya-multi-author' ),
'a' => __( 'Yes. The advanced version adds automatic post review (quality, style, SEO) with improvement suggestions, through a personal API key at the AI provider of your choice. See aiforya.fr.', 'aiforya-multi-author' ),
],
];
},
] );
// 5b. Instanciation des services métier (singleton).
Aiforya_Multi_Author_Workflow::get_instance();
Aiforya_Multi_Author_Ajax::get_instance();
Aiforya_Multi_Author_Notifier::get_instance()->register_hooks();
Aiforya_Multi_Author_Frontend::get_instance();
}, 5 );
// =============================================================================
// 6. Liens dans la liste des extensions WordPress.
// =============================================================================
add_filter( 'plugin_row_meta', static function ( array $links, string $file ): array {
if ( $file !== AIFORYA_MA_BASENAME ) {
return $links;
}
$links[] = '' . esc_html__( 'User guide', 'aiforya-multi-author' ) . '';
return $links;
}, 10, 2 );
add_filter( 'plugin_action_links_' . AIFORYA_MA_BASENAME, static function ( array $links ): array {
$settings_link = '' . esc_html__( 'Settings', 'aiforya-multi-author' ) . '';
array_unshift( $links, $settings_link );
return $links;
} );