post_type && current_user_can( 'edit_post', $post->ID ) ) { $has_summary = AI_Summary_Generator_Core::has_summary( $post->ID ); $needs_regen = AI_Summary_Generator_Core::needs_regeneration( $post->ID ); $url = wp_nonce_url( admin_url( 'admin-ajax.php?action=ai_summary_generator_generate_summary&post_id=' . $post->ID ), 'ai_summary_action' ); if ( $has_summary ) { if ( $needs_regen ) { echo '' . esc_html__( 'Regenerate AI Summary (Outdated)', 'ai-summary-generator' ) . ''; } else { echo '' . esc_html__( 'Regenerate AI Summary', 'ai-summary-generator' ) . ''; } } else { echo '' . esc_html__( 'Generate AI Summary', 'ai-summary-generator' ) . ''; } } } /** * Add action buttons to post list * Show different buttons based on whether summary exists * Only show buttons if user can edit the post * * @param array $actions Existing actions. * @param WP_Post $post Post object. * @return array Modified actions */ public static function ai_summary_generator_add_post_list_buttons( $actions, $post ) { if ( 'post' === $post->post_type && current_user_can( 'edit_post', $post->ID ) ) { $has_summary = AI_Summary_Generator_Core::has_summary( $post->ID ); $needs_regen = AI_Summary_Generator_Core::needs_regeneration( $post->ID ); $generate_url = wp_nonce_url( admin_url( 'admin-ajax.php?action=ai_summary_generator_generate_summary&post_id=' . $post->ID ), 'ai_summary_action' ); $regenerate_url = wp_nonce_url( admin_url( 'admin-ajax.php?action=ai_summary_generator_regenerate_summary&post_id=' . $post->ID ), 'ai_summary_action' ); $clear_url = wp_nonce_url( admin_url( 'admin-ajax.php?action=ai_summary_generator_clear_summary&post_id=' . $post->ID ), 'ai_summary_action' ); if ( $has_summary ) { // Show regenerate and clear options. if ( $needs_regen ) { $actions['regenerate_ai_summary'] = '' . esc_html__( 'Regenerate AI Summary (Outdated)', 'ai-summary-generator' ) . ''; } else { $actions['regenerate_ai_summary'] = '' . esc_html__( 'Regenerate AI Summary', 'ai-summary-generator' ) . ''; } $actions['clear_ai_summary'] = '' . esc_html__( 'Clear AI Summary', 'ai-summary-generator' ) . ''; } else { // Show generate option. $actions['generate_ai_summary'] = '' . esc_html__( 'Generate AI Summary', 'ai-summary-generator' ) . ''; } } return $actions; } /** * Add bulk action for generating summaries * Generates for posts without summaries and regenerates outdated ones * * @param array $bulk_actions Existing bulk actions. * @return array Modified bulk actions */ public static function ai_summary_generator_add_bulk_actions( $bulk_actions ) { $bulk_actions['generate_ai_summaries'] = __( 'Generate/Update AI Summaries', 'ai-summary-generator' ); return $bulk_actions; } /** * Handle bulk action * Generate summaries for posts without them and regenerate outdated ones * * @param string $redirect_to Redirect URL. * @param string $doaction Action being performed. * @param array $post_ids Array of post IDs. * @return string Modified redirect URL */ public static function ai_summary_generator_handle_bulk_action( $redirect_to, $doaction, $post_ids ) { if ( 'generate_ai_summaries' !== $doaction ) { return $redirect_to; } // Clear any existing notice parameters. $notice_params = array( 'single_generated', 'single_regenerated', 'single_cleared', 'single_error', 'bulk_generated', 'bulk_errors', 'bulk_skipped' ); foreach ( $notice_params as $param ) { $redirect_to = remove_query_arg( $param, $redirect_to ); } $generated_count = 0; $error_count = 0; $skipped_count = 0; foreach ( $post_ids as $post_id ) { // Check if user can edit this specific post. if ( ! current_user_can( 'edit_post', $post_id ) ) { $skipped_count++; continue; } $has_summary = AI_Summary_Generator_Core::has_summary( $post_id ); $needs_regen = AI_Summary_Generator_Core::needs_regeneration( $post_id ); // Generate if no summary exists OR if summary is outdated. if ( ! $has_summary || $needs_regen ) { if ( AI_Summary_Generator_Core::generate_summary( $post_id ) ) { $generated_count++; } else { $error_count++; } } else { // Summary exists and is current. $skipped_count++; } } // Add appropriate notice. if ( 0 < $error_count && 0 === $generated_count ) { $redirect_to = add_query_arg( 'single_error', rawurlencode( __( 'Failed to generate any AI summaries. Please check your API settings.', 'ai-summary-generator' ) ), $redirect_to ); } else { $redirect_to = add_query_arg( 'bulk_generated', $generated_count, $redirect_to ); if ( $error_count > 0 ) { $redirect_to = add_query_arg( 'bulk_errors', $error_count, $redirect_to ); } if ( $skipped_count > 0 ) { $redirect_to = add_query_arg( 'bulk_skipped', $skipped_count, $redirect_to ); } } return $redirect_to; } /** * Display admin notices */ public static function ai_summary_generator_admin_notices() { // Only show notices in admin and to users who can edit posts. if ( ! is_admin() || ! current_user_can( 'edit_posts' ) ) { return; } // Error notice (highest priority). // phpcs:disable WordPress.Security.NonceVerification.Recommended -- These are read-only admin notices. if ( ! empty( $_GET['single_error'] ) ) { $error_message = sanitize_text_field( wp_unslash( $_GET['single_error'] ) ); printf( '

%s %s

', esc_html__( 'Error:', 'ai-summary-generator' ), esc_html( $error_message ) ); return; // Don't show other notices when there's an error. } // Success notices. if ( isset( $_GET['bulk_generated'] ) ) { $count = intval( $_GET['bulk_generated'] ); $error_count = ! empty( $_GET['bulk_errors'] ) ? intval( $_GET['bulk_errors'] ) : 0; $skipped_count = ! empty( $_GET['bulk_skipped'] ) ? intval( $_GET['bulk_skipped'] ) : 0; if ( 0 < $count ) { $message = sprintf( /* translators: %1$d is the number of summaries */ _n( 'Successfully generated %1$d AI summary.', 'Successfully generated %1$d AI summaries.', $count, 'ai-summary-generator' ), $count ); if ( 0 < $error_count ) { $message .= ' ' . sprintf( /* translators: %1$d is the number of failed requests */ _n( '%1$d request failed.', '%1$d requests failed.', $error_count, 'ai-summary-generator' ), $error_count ); } if ( 0 < $skipped_count ) { $message .= ' ' . sprintf( /* translators: %1$d is the number of skipped summaries */ _n( '%1$d summary already up-to-date.', '%1$d summaries already up-to-date.', $skipped_count, 'ai-summary-generator' ), $skipped_count ); } printf( '

%s

', esc_html( $message ) ); } elseif ( 0 < $skipped_count ) { $notice_message = sprintf( /* translators: %1$d is the number of summaries */ _n( 'No summaries generated. The %1$d selected summary is already up-to-date.', 'No summaries generated. All %1$d selected summaries are already up-to-date.', $skipped_count, 'ai-summary-generator' ), $skipped_count ); printf( '

%s

', esc_html( $notice_message ) ); } // Note: If both $count and $skipped_count are 0, it means only errors occurred. // and that case is handled above with the single_error message. } if ( ! empty( $_GET['single_generated'] ) ) { printf( '

%s

', esc_html__( 'AI summary generated successfully.', 'ai-summary-generator' ) ); } if ( ! empty( $_GET['single_regenerated'] ) ) { printf( '

%s

', esc_html__( 'AI summary regenerated successfully.', 'ai-summary-generator' ) ); } if ( ! empty( $_GET['single_cleared'] ) ) { printf( '

%s

', esc_html__( 'AI summary cleared successfully.', 'ai-summary-generator' ) ); } // phpcs:enable WordPress.Security.NonceVerification.Recommended } /** * Update summary when post is saved * Only regenerate if summary exists and needs regeneration * * @param int $post_id Post ID. */ public static function ai_summary_generator_update_on_post_save( $post_id ) { $update_enabled = get_option( 'ai_summary_generator_update_on_post_update', 'no' ); if ( 'yes' !== $update_enabled ) { return; } if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) { return; } // Only regenerate if summary not exists or needs regeneration. if ( ! AI_Summary_Generator_Core::has_summary( $post_id ) || AI_Summary_Generator_Core::needs_regeneration( $post_id ) ) { AI_Summary_Generator_Core::generate_summary( $post_id ); } } }