settings = $settings; $this->sync_service = $sync_service; $this->scheduler = $scheduler; $this->debug_history = $debug_history; add_action( 'admin_menu', array( $this, 'add_menu' ) ); add_action( 'admin_init', array( $this, 'register_settings' ) ); add_action( 'admin_notices', array( $this, 'render_admin_notice' ) ); add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_assets' ) ); add_action( 'admin_post_' . self::MANUAL_SYNC_ACTION, array( $this, 'handle_manual_sync' ) ); add_action( 'admin_post_' . self::REGENERATE_TOKEN_ACTION, array( $this, 'handle_regenerate_token' ) ); add_action( 'admin_post_' . self::CLEAR_HISTORY_ACTION, array( $this, 'handle_clear_debug_history' ) ); add_action( 'update_option_' . Settings::OPTION_NAME, array( $this, 'after_settings_saved' ), 10, 2 ); } /** * Enqueues plugin CSS and JS on plugin admin pages only. * * @param string $hook_suffix Current admin page hook suffix. */ public function enqueue_assets( $hook_suffix ) { $plugin_pages = array( 'toplevel_page_' . self::PAGE_SLUG, 'ai-blog-poster_page_' . self::SETTINGS_PAGE_SLUG, 'ai-blog-poster_page_' . self::IMPORTED_POSTS_SLUG, 'ai-blog-poster_page_' . self::DEBUG_PAGE_SLUG, 'ai-blog-poster_page_' . self::HELP_PAGE_SLUG, ); if ( ! in_array( $hook_suffix, $plugin_pages, true ) ) { return; } wp_enqueue_style( 'aibp-admin', AIBP_PLUGIN_URL . 'assets/css/admin.css', array(), AIBP_VERSION ); // Only load JS on the Settings page where the cron toggle is needed. if ( 'ai-blog-poster_page_' . self::SETTINGS_PAGE_SLUG === $hook_suffix ) { wp_enqueue_script( 'aibp-admin', AIBP_PLUGIN_URL . 'assets/js/admin.js', array(), AIBP_VERSION, true ); wp_localize_script( 'aibp-admin', 'aibpAdmin', array( 'optionName' => Settings::OPTION_NAME, ) ); } } /** * Registers the plugin admin menu and subpages. */ public function add_menu() { add_menu_page( __( 'AI Blog Poster', 'ai-blog-poster' ), __( 'AI Blog Poster', 'ai-blog-poster' ), 'manage_options', self::PAGE_SLUG, array( $this, 'render_dashboard_page' ), 'dashicons-edit-page', 80 ); add_submenu_page( self::PAGE_SLUG, __( 'Dashboard', 'ai-blog-poster' ), __( 'Dashboard', 'ai-blog-poster' ), 'manage_options', self::PAGE_SLUG, array( $this, 'render_dashboard_page' ) ); add_submenu_page( self::PAGE_SLUG, __( 'Settings', 'ai-blog-poster' ), __( 'Settings', 'ai-blog-poster' ), 'manage_options', self::SETTINGS_PAGE_SLUG, array( $this, 'render_page' ) ); add_submenu_page( self::PAGE_SLUG, __( 'Imported Posts', 'ai-blog-poster' ), __( 'Imported Posts', 'ai-blog-poster' ), 'manage_options', self::IMPORTED_POSTS_SLUG, array( $this, 'render_imported_posts_page' ) ); add_submenu_page( self::PAGE_SLUG, __( 'Debug History', 'ai-blog-poster' ), __( 'Debug History', 'ai-blog-poster' ), 'manage_options', self::DEBUG_PAGE_SLUG, array( $this, 'render_debug_history_page' ) ); add_submenu_page( self::PAGE_SLUG, __( 'Help', 'ai-blog-poster' ), __( 'Help', 'ai-blog-poster' ), 'manage_options', self::HELP_PAGE_SLUG, array( $this, 'render_help_page' ) ); } /** * Registers plugin settings with the WordPress Settings API. */ public function register_settings() { $this->settings->register(); } /** * Renders the plugin dashboard page. */ public function render_dashboard_page() { if ( ! current_user_can( 'manage_options' ) ) { return; } $settings = $this->settings->get_all(); $manual_sync_url = wp_nonce_url( admin_url( 'admin-post.php?action=' . self::MANUAL_SYNC_ACTION ), self::MANUAL_SYNC_ACTION ); $last_sync = ! empty( $settings['last_sync'] ) ? $this->format_timestamp( (int) $settings['last_sync'] ) : __( 'Never', 'ai-blog-poster' ); $last_run = ! empty( $settings['last_run'] ) ? $this->format_timestamp( (int) $settings['last_run'] ) : __( 'Never', 'ai-blog-poster' ); $sync_mode = 'manual_cron' === $settings['sync_mode'] ? __( 'Manual Server Cron', 'ai-blog-poster' ) : __( 'WordPress Cron', 'ai-blog-poster' ); $imported_count = $this->get_imported_post_count(); $debug_entries = $this->debug_history->get_entries(); $latest_entry = ! empty( $debug_entries[0] ) ? $debug_entries[0] : array(); $imported_url = admin_url( 'admin.php?page=' . self::IMPORTED_POSTS_SLUG ); $help_url = admin_url( 'admin.php?page=' . self::HELP_PAGE_SLUG ); ?>

settings->get_all(); $manual_sync_url = wp_nonce_url( admin_url( 'admin-post.php?action=' . self::MANUAL_SYNC_ACTION ), self::MANUAL_SYNC_ACTION ); $regenerate_token_url = wp_nonce_url( admin_url( 'admin-post.php?action=' . self::REGENERATE_TOKEN_ACTION ), self::REGENERATE_TOKEN_ACTION ); $last_sync = ! empty( $settings['last_sync'] ) ? $this->format_timestamp( (int) $settings['last_sync'] ) : __( 'Never', 'ai-blog-poster' ); $last_run = ! empty( $settings['last_run'] ) ? $this->format_timestamp( (int) $settings['last_run'] ) : __( 'Never', 'ai-blog-poster' ); $manual_cron_url = $this->scheduler->get_manual_cron_url(); $sync_mode = isset( $settings['sync_mode'] ) ? $settings['sync_mode'] : 'wp_cron'; $example_cron_cmd = 'curl -s "' . $manual_cron_url . '"'; $hourly_cron_cmd = '0 * * * * curl -s "' . $manual_cron_url . '" >/dev/null 2>&1'; $is_manual_cron = 'manual_cron' === $sync_mode; $masked_api_key = $this->settings->mask_api_key( $settings['api_key'] ); $api_key_set = ! empty( $settings['api_key'] ); ?>


'post', 'post_status' => 'any', 'posts_per_page' => $per_page, 'paged' => $paged, 'meta_key' => Sync_Service::REMOTE_ID_META_KEY, 'orderby' => 'date', 'order' => 'DESC', 'ignore_sticky_posts' => true, 'update_post_meta_cache' => true, 'update_post_term_cache' => false, ) ); ?>

have_posts() ) : ?> have_posts() ) : $query->the_post(); $post_id = get_the_ID(); $blog_id = get_post_meta( $post_id, Sync_Service::REMOTE_ID_META_KEY, true ); $status = get_post_status_object( get_post_status( $post_id ) ); $author = get_userdata( (int) get_post_field( 'post_author', $post_id ) ); $edit_url = get_edit_post_link( $post_id, '' ); $view_url = get_permalink( $post_id ); ?>
label : get_post_status( $post_id ) ); ?> display_name : '-' ); ?>
max_num_pages > 1 ) : ?>
add_query_arg( 'paged', '%#%', admin_url( 'admin.php?page=' . self::IMPORTED_POSTS_SLUG ) ), 'format' => '', 'current' => $paged, 'total' => $query->max_num_pages, 'prev_text' => __( '«', 'ai-blog-poster' ), 'next_text' => __( '»', 'ai-blog-poster' ), ) ) ); ?>
debug_history->get_entries(); $clear_url = wp_nonce_url( admin_url( 'admin-post.php?action=' . self::CLEAR_HISTORY_ACTION ), self::CLEAR_HISTORY_ACTION ); ?>

format_timestamp( (int) $entry['time'] ) : '-' ); ?>
format_debug_context( ! empty( $entry['context'] ) ? $entry['context'] : array() ) ); ?>
scheduler->get_manual_cron_url(); $hourly_cron_cmd = '0 * * * * curl -s "' . $manual_cron_url . '" >/dev/null 2>&1'; $api_key_img = AIBP_PLUGIN_URL . 'assets/api.png'; ?>

<?php esc_attr_e( 'AI Blog Poster API key generation screen showing the APIs menu and Create API Key button.', 'ai-blog-poster' ); ?>

  1. AI Blog Poster > Settings and paste the key.', 'ai-blog-poster' ); ?>

—

—

sync_service->sync( 'manual' ); if ( is_wp_error( $result ) ) { $this->add_admin_message( $result->get_error_message(), 'error' ); } else { $message = sprintf( /* translators: 1: returned count, 2: created count, 3: duplicate count, 4: failed count */ __( 'Sync complete. API Returned: %1$d, Created: %2$d, Already Imported: %3$d, Failed: %4$d.', 'ai-blog-poster' ), (int) $result['fetched'], (int) $result['created'], (int) $result['skipped'], (int) $result['failed'] ); $this->add_admin_message( $message, 'updated' ); } wp_safe_redirect( admin_url( 'admin.php?page=' . self::SETTINGS_PAGE_SLUG ) ); exit; } /** * Handles the cron token regeneration action. */ public function handle_regenerate_token() { if ( ! current_user_can( 'manage_options' ) ) { wp_die( esc_html__( 'You do not have permission to perform this action.', 'ai-blog-poster' ) ); } check_admin_referer( self::REGENERATE_TOKEN_ACTION ); $this->settings->regenerate_cron_token(); $this->add_admin_message( __( 'Cron token regenerated. Update your server cron job with the new URL.', 'ai-blog-poster' ), 'updated' ); wp_safe_redirect( admin_url( 'admin.php?page=' . self::SETTINGS_PAGE_SLUG ) ); exit; } /** * Handles the clear debug history action. */ public function handle_clear_debug_history() { if ( ! current_user_can( 'manage_options' ) ) { wp_die( esc_html__( 'You do not have permission to perform this action.', 'ai-blog-poster' ) ); } check_admin_referer( self::CLEAR_HISTORY_ACTION ); $this->debug_history->clear(); $this->add_admin_message( __( 'Debug history cleared.', 'ai-blog-poster' ), 'updated' ); wp_safe_redirect( admin_url( 'admin.php?page=' . self::DEBUG_PAGE_SLUG ) ); exit; } /** * Refreshes the cron schedule after settings are saved. * * @param mixed $old_value Previous option value. * @param mixed $value New option value. */ public function after_settings_saved( $old_value, $value ) { $this->scheduler->register_schedule(); $message = $this->scheduler->is_wp_cron_enabled() ? __( 'Settings saved and WP-Cron schedule updated.', 'ai-blog-poster' ) : __( 'Settings saved. Use the Manual Cron URL in your server cron job.', 'ai-blog-poster' ); $this->add_admin_message( $message, 'updated' ); } /** * Prints the stored one-time admin notice. */ public function render_admin_notice() { $notice = get_transient( 'aibp_admin_notice' ); if ( empty( $notice['message'] ) ) { return; } delete_transient( 'aibp_admin_notice' ); $class = 'error' === $notice['type'] ? 'notice notice-error' : 'notice notice-success'; ?>

$message, 'type' => $type, ), 60 ); } /** * Returns the total number of posts imported by the plugin. * * @return int */ private function get_imported_post_count() { $query = new \WP_Query( array( 'post_type' => 'post', 'post_status' => 'any', 'posts_per_page' => 1, 'fields' => 'ids', 'meta_key' => Sync_Service::REMOTE_ID_META_KEY, 'no_found_rows' => false, 'ignore_sticky_posts' => true, 'update_post_meta_cache' => false, 'update_post_term_cache' => false, ) ); return (int) $query->found_posts; } /** * Formats a Unix timestamp using the site timezone. * * @param int $timestamp Unix timestamp. * @return string */ private function format_timestamp( $timestamp ) { if ( function_exists( 'wp_date' ) ) { return wp_date( 'Y-m-d H:i:s', $timestamp ); } return date_i18n( 'Y-m-d H:i:s', $timestamp ); } /** * Formats debug context as indented JSON for the admin table. * * @param array $context Debug context array. * @return string */ private function format_debug_context( array $context ) { if ( empty( $context ) ) { return '{}'; } $json = wp_json_encode( $context, JSON_PRETTY_PRINT ); return false === $json ? '{}' : $json; } }