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; } );