From 4332bb08e4e9b51524b521c3a65800c0f26de992 Mon Sep 17 00:00:00 2001 From: CacheMeOwside Date: Fri, 8 May 2026 01:50:17 +0530 Subject: [PATCH 1/3] adds TTS generation status polling in Classic Editor --- includes/Classifai/Features/TextToSpeech.php | 107 +++++++++++++++---- src/js/admin.js | 54 ++++++++++ 2 files changed, 139 insertions(+), 22 deletions(-) diff --git a/includes/Classifai/Features/TextToSpeech.php b/includes/Classifai/Features/TextToSpeech.php index 868ca5763..494d953a4 100644 --- a/includes/Classifai/Features/TextToSpeech.php +++ b/includes/Classifai/Features/TextToSpeech.php @@ -105,6 +105,7 @@ public function feature_setup() { add_action( 'add_meta_boxes', [ $this, 'add_meta_box' ] ); add_action( 'admin_notices', [ $this, 'show_error_if' ] ); add_action( 'save_post', [ $this, 'save_post_metadata' ], 5 ); + add_action( 'wp_ajax_classifai_get_tts_status', [ $this, 'ajax_get_audio_generation_status' ] ); } /** @@ -419,6 +420,36 @@ public function add_meta_box( string $post_type ) { public function render_meta_box( \WP_Post $post ) { wp_nonce_field( 'classifai_text_to_speech_meta_action', 'classifai_text_to_speech_meta' ); + $is_as_scheduled_job = + function_exists( 'as_has_scheduled_action' ) && + \as_has_scheduled_action( + 'classifai_schedule_text_to_speech_job', + [ + 'post_id' => (int) $post->ID, + 'calling_user_id' => get_current_user_id(), + ], + 'classifai' + ); + + if ( $is_as_scheduled_job ) : + ?> +

+ +

+ render_audio_generation_ui( $post ); + endif; + } + + /** + * Render the post-generation UI for the TTS meta box. Used both on initial + * render and via AJAX after a queued job completes so the meta box + * matches a fresh page load. + * + * @param \WP_Post $post WP_Post object. + */ + public function render_audio_generation_ui( \WP_Post $post ) { $source_url = false; $audio_id = get_post_meta( $post->ID, self::AUDIO_ID_KEY, true ); @@ -445,24 +476,7 @@ public function render_meta_box( \WP_Post $post ) { if ( $post_type ) { $post_type_label = $post_type->labels->singular_name; } - - $is_as_scheduled_job = - function_exists( 'as_has_scheduled_action' ) && - \as_has_scheduled_action( - 'classifai_schedule_text_to_speech_job', - [ - 'post_id' => (int) $post->ID, - 'calling_user_id' => get_current_user_id(), - ], - 'classifai' - ); - - if ( $is_as_scheduled_job ) : ?> -

- -

- - + ?>

- - -

- __( 'Invalid post.', 'classifai' ) ], 403 ); + } + + $in_progress = + function_exists( 'as_has_scheduled_action' ) && + \as_has_scheduled_action( + 'classifai_schedule_text_to_speech_job', + [ + 'post_id' => $post_id, + 'calling_user_id' => get_current_user_id(), + ], + 'classifai' + ); + + $error_message = ''; + $raw_error = get_post_meta( $post_id, '_classifai_text_to_speech_error', true ); + + if ( ! empty( $raw_error ) ) { + $decoded = (array) json_decode( (string) $raw_error ); + if ( ! empty( $decoded['message'] ) ) { + $error_message = (string) $decoded['message']; + } + } + + $html = ''; + if ( ! $in_progress && ! $error_message ) { + $post = get_post( $post_id ); + if ( $post ) { + ob_start(); + $this->render_audio_generation_ui( $post ); + $html = (string) ob_get_clean(); + } + } + + wp_send_json_success( + [ + 'inProgress' => (bool) $in_progress, + 'error' => $error_message, + 'html' => $html, + ] + ); + } + /** * Process the meta box save. * diff --git a/src/js/admin.js b/src/js/admin.js index ab1b69d89..5f155b350 100644 --- a/src/js/admin.js +++ b/src/js/admin.js @@ -445,6 +445,60 @@ document.addEventListener( 'DOMContentLoaded', function () { } ); } )( jQuery ); +// Poll admin-ajax to update the Classic Editor TTS meta box once audio generation completes. +( function ( $ ) { + $( function () { + const $status = $( '.classifai-tts-status' ); + + if ( ! $status.length ) { + return; + } + + const postId = parseInt( $status.data( 'post-id' ), 10 ); + const nonce = $status.data( 'nonce' ); + + if ( ! postId || ! nonce ) { + return; + } + + const POLL_INTERVAL_MS = 5000; + + const renderComplete = ( { error, html } ) => { + if ( error ) { + $status.text( error ); + return; + } + + if ( html ) { + $status.replaceWith( html ); + } + }; + + const timer = setInterval( () => { + $.ajax( { + url: ajaxurl, // eslint-disable-line no-undef + type: 'POST', + data: { + action: 'classifai_get_tts_status', + nonce, + post_id: postId, + }, + } ).done( ( response ) => { + if ( ! response || ! response.success || ! response.data ) { + return; + } + + if ( response.data.inProgress ) { + return; + } + + clearInterval( timer ); + renderComplete( response.data ); + } ); + }, POLL_INTERVAL_MS ); + } ); +} )( jQuery ); + // Update the Term Cleanup status. ( function ( $ ) { const statusWrapper = $( '.classifai-term-cleanup-process-status' ); From 09cd584f11919f0b236fd01b9b85916f8e6aa72c Mon Sep 17 00:00:00 2001 From: CacheMeOwside Date: Fri, 8 May 2026 02:09:06 +0530 Subject: [PATCH 2/3] adds 10s TTS generation status polling in Classic Editor --- src/js/admin.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/js/admin.js b/src/js/admin.js index 5f155b350..699a7a55c 100644 --- a/src/js/admin.js +++ b/src/js/admin.js @@ -461,7 +461,7 @@ document.addEventListener( 'DOMContentLoaded', function () { return; } - const POLL_INTERVAL_MS = 5000; + const POLL_INTERVAL_MS = 10000; const renderComplete = ( { error, html } ) => { if ( error ) { From 828a08d02233c8c40fbea36f956d6ff3fdec89db Mon Sep 17 00:00:00 2001 From: CacheMeOwside Date: Tue, 12 May 2026 00:33:52 +0530 Subject: [PATCH 3/3] scope polling JS to TTS feature --- includes/Classifai/Features/TextToSpeech.php | 36 +++++++++- src/js/admin.js | 54 --------------- .../features/text-to-speech/classic/index.js | 69 +++++++++++++++++++ webpack.config.js | 1 + 4 files changed, 105 insertions(+), 55 deletions(-) create mode 100644 src/js/features/text-to-speech/classic/index.js diff --git a/includes/Classifai/Features/TextToSpeech.php b/includes/Classifai/Features/TextToSpeech.php index 494d953a4..968ac0ba3 100644 --- a/includes/Classifai/Features/TextToSpeech.php +++ b/includes/Classifai/Features/TextToSpeech.php @@ -106,6 +106,40 @@ public function feature_setup() { add_action( 'admin_notices', [ $this, 'show_error_if' ] ); add_action( 'save_post', [ $this, 'save_post_metadata' ], 5 ); add_action( 'wp_ajax_classifai_get_tts_status', [ $this, 'ajax_get_audio_generation_status' ] ); + add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_admin_assets' ] ); + } + + /** + * Enqueue the Classic Editor polling script. Loaded in Classic Editor only when the feature is enabled. + * + * @param string $hook_suffix The current admin page. + */ + public function enqueue_admin_assets( string $hook_suffix ) { + if ( 'post.php' !== $hook_suffix && 'post-new.php' !== $hook_suffix ) { + return; + } + + if ( ! $this->is_feature_enabled() ) { + return; + } + + $screen = get_current_screen(); + + if ( ! $screen || $screen->is_block_editor() ) { + return; + } + + if ( ! in_array( $screen->post_type, $this->get_supported_post_types(), true ) ) { + return; + } + + wp_enqueue_script( + 'classifai-plugin-classic-text-to-speech', + CLASSIFAI_PLUGIN_URL . 'dist/classifai-plugin-classic-text-to-speech.js', + get_asset_info( 'classifai-plugin-classic-text-to-speech', 'dependencies' ), + get_asset_info( 'classifai-plugin-classic-text-to-speech', 'version' ), + true + ); } /** @@ -525,7 +559,7 @@ public function render_audio_generation_ui( \WP_Post $post ) { public function ajax_get_audio_generation_status() { check_ajax_referer( 'classifai_tts_status', 'nonce' ); - $post_id = isset( $_POST['post_id'] ) ? absint( $_POST['post_id'] ) : 0; + $post_id = isset( $_POST['post_id'] ) ? absint( wp_unslash( $_POST['post_id'] ) ) : 0; if ( ! $post_id || ! current_user_can( 'edit_post', $post_id ) ) { wp_send_json_error( [ 'message' => __( 'Invalid post.', 'classifai' ) ], 403 ); diff --git a/src/js/admin.js b/src/js/admin.js index 699a7a55c..ab1b69d89 100644 --- a/src/js/admin.js +++ b/src/js/admin.js @@ -445,60 +445,6 @@ document.addEventListener( 'DOMContentLoaded', function () { } ); } )( jQuery ); -// Poll admin-ajax to update the Classic Editor TTS meta box once audio generation completes. -( function ( $ ) { - $( function () { - const $status = $( '.classifai-tts-status' ); - - if ( ! $status.length ) { - return; - } - - const postId = parseInt( $status.data( 'post-id' ), 10 ); - const nonce = $status.data( 'nonce' ); - - if ( ! postId || ! nonce ) { - return; - } - - const POLL_INTERVAL_MS = 10000; - - const renderComplete = ( { error, html } ) => { - if ( error ) { - $status.text( error ); - return; - } - - if ( html ) { - $status.replaceWith( html ); - } - }; - - const timer = setInterval( () => { - $.ajax( { - url: ajaxurl, // eslint-disable-line no-undef - type: 'POST', - data: { - action: 'classifai_get_tts_status', - nonce, - post_id: postId, - }, - } ).done( ( response ) => { - if ( ! response || ! response.success || ! response.data ) { - return; - } - - if ( response.data.inProgress ) { - return; - } - - clearInterval( timer ); - renderComplete( response.data ); - } ); - }, POLL_INTERVAL_MS ); - } ); -} )( jQuery ); - // Update the Term Cleanup status. ( function ( $ ) { const statusWrapper = $( '.classifai-term-cleanup-process-status' ); diff --git a/src/js/features/text-to-speech/classic/index.js b/src/js/features/text-to-speech/classic/index.js new file mode 100644 index 000000000..c7678aeca --- /dev/null +++ b/src/js/features/text-to-speech/classic/index.js @@ -0,0 +1,69 @@ +// Poll admin-ajax to update the Classic Editor TTS meta box once audio generation completes. +const init = () => { + const status = document.querySelector( '.classifai-tts-status' ); + + if ( ! status ) { + return; + } + + const postId = parseInt( status.dataset.postId, 10 ); + const nonce = status.dataset.nonce; + + if ( ! postId || ! nonce ) { + return; + } + + const POLL_INTERVAL_MS = 10000; + + const renderComplete = ( { error, html } ) => { + if ( error ) { + status.textContent = error; + return; + } + + if ( html ) { + status.outerHTML = html; + } + }; + + const timer = setInterval( async () => { + try { + const body = new URLSearchParams( { + action: 'classifai_get_tts_status', + nonce, + post_id: postId, + } ); + + const response = await fetch( window.ajaxurl, { + method: 'POST', + credentials: 'same-origin', + body, + } ); + + if ( ! response.ok ) { + return; + } + + const json = await response.json(); + + if ( ! json || ! json.success || ! json.data ) { + return; + } + + if ( json.data.inProgress ) { + return; + } + + clearInterval( timer ); + renderComplete( json.data ); + } catch ( e ) { + // Swallow transient fetch errors and try again next tick. + } + }, POLL_INTERVAL_MS ); +}; + +if ( document.readyState !== 'loading' ) { + init(); +} else { + document.addEventListener( 'DOMContentLoaded', init ); +} diff --git a/webpack.config.js b/webpack.config.js index 4783d5d3b..d813e4e6a 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -25,6 +25,7 @@ module.exports = { 'classifai-plugin-classification-pre-publish': './src/js/features/classification/pre-publish-panel.js', 'classifai-plugin-fill': './src/js/features/slot-fill/index.js', 'classifai-plugin-text-to-speech': './src/js/features/text-to-speech/index.js', + 'classifai-plugin-classic-text-to-speech': './src/js/features/text-to-speech/classic/index.js', 'classifai-plugin-text-to-speech-frontend': './src/js/features/text-to-speech/frontend/index.js', 'classifai-plugin-content-resizing': './src/js/features/content-resizing/index.js', 'classifai-plugin-title-generation': './src/js/features/title-generation/index.js',