Skip to content

Commit 604cb75

Browse files
authored
Merge pull request #1074 from CacheMeOwside/fix/1072
adds TTS generation status polling in Classic Editor
2 parents bc447b8 + 148fc7e commit 604cb75

3 files changed

Lines changed: 189 additions & 22 deletions

File tree

includes/Classifai/Features/TextToSpeech.php

Lines changed: 119 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,41 @@ public function feature_setup() {
105105
add_action( 'add_meta_boxes', [ $this, 'add_meta_box' ] );
106106
add_action( 'admin_notices', [ $this, 'show_error_if' ] );
107107
add_action( 'save_post', [ $this, 'save_post_metadata' ], 5 );
108+
add_action( 'wp_ajax_classifai_get_tts_status', [ $this, 'ajax_get_audio_generation_status' ] );
109+
add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_admin_assets' ] );
110+
}
111+
112+
/**
113+
* Enqueue the Classic Editor polling script. Loaded in Classic Editor only when the feature is enabled.
114+
*
115+
* @param string $hook_suffix The current admin page.
116+
*/
117+
public function enqueue_admin_assets( string $hook_suffix ) {
118+
if ( 'post.php' !== $hook_suffix && 'post-new.php' !== $hook_suffix ) {
119+
return;
120+
}
121+
122+
if ( ! $this->is_feature_enabled() ) {
123+
return;
124+
}
125+
126+
$screen = get_current_screen();
127+
128+
if ( ! $screen || $screen->is_block_editor() ) {
129+
return;
130+
}
131+
132+
if ( ! in_array( $screen->post_type, $this->get_supported_post_types(), true ) ) {
133+
return;
134+
}
135+
136+
wp_enqueue_script(
137+
'classifai-plugin-classic-text-to-speech',
138+
CLASSIFAI_PLUGIN_URL . 'dist/classifai-plugin-classic-text-to-speech.js',
139+
get_asset_info( 'classifai-plugin-classic-text-to-speech', 'dependencies' ),
140+
get_asset_info( 'classifai-plugin-classic-text-to-speech', 'version' ),
141+
true
142+
);
108143
}
109144

110145
/**
@@ -419,6 +454,36 @@ public function add_meta_box( string $post_type ) {
419454
public function render_meta_box( \WP_Post $post ) {
420455
wp_nonce_field( 'classifai_text_to_speech_meta_action', 'classifai_text_to_speech_meta' );
421456

457+
$is_as_scheduled_job =
458+
function_exists( 'as_has_scheduled_action' ) &&
459+
\as_has_scheduled_action(
460+
'classifai_schedule_text_to_speech_job',
461+
[
462+
'post_id' => (int) $post->ID,
463+
'calling_user_id' => get_current_user_id(),
464+
],
465+
'classifai'
466+
);
467+
468+
if ( $is_as_scheduled_job ) :
469+
?>
470+
<p class="classifai-tts-status" data-post-id="<?php echo esc_attr( (string) $post->ID ); ?>" data-nonce="<?php echo esc_attr( wp_create_nonce( 'classifai_tts_status' ) ); ?>">
471+
<?php esc_html_e( 'Audio generation is in progress…', 'classifai' ); ?>
472+
</p>
473+
<?php
474+
else :
475+
$this->render_audio_generation_ui( $post );
476+
endif;
477+
}
478+
479+
/**
480+
* Render the post-generation UI for the TTS meta box. Used both on initial
481+
* render and via AJAX after a queued job completes so the meta box
482+
* matches a fresh page load.
483+
*
484+
* @param \WP_Post $post WP_Post object.
485+
*/
486+
public function render_audio_generation_ui( \WP_Post $post ) {
422487
$source_url = false;
423488
$audio_id = get_post_meta( $post->ID, self::AUDIO_ID_KEY, true );
424489

@@ -445,24 +510,7 @@ public function render_meta_box( \WP_Post $post ) {
445510
if ( $post_type ) {
446511
$post_type_label = $post_type->labels->singular_name;
447512
}
448-
449-
$is_as_scheduled_job =
450-
function_exists( 'as_has_scheduled_action' ) &&
451-
\as_has_scheduled_action(
452-
'classifai_schedule_text_to_speech_job',
453-
[
454-
'post_id' => (int) $post->ID,
455-
'calling_user_id' => get_current_user_id(),
456-
],
457-
'classifai'
458-
);
459-
460-
if ( $is_as_scheduled_job ) : ?>
461-
<p>
462-
<?php esc_html_e( 'Audio generation is in progress…', 'classifai' ); ?>
463-
</p>
464-
<?php else : ?>
465-
513+
?>
466514
<p>
467515
<label for="classifai_synthesize_speech">
468516
<input type="checkbox" value="1" id="classifai_synthesize_speech" name="classifai_synthesize_speech" <?php checked( $process_content ); ?> />
@@ -488,8 +536,6 @@ function_exists( 'as_has_scheduled_action' ) &&
488536
</span>
489537
</p>
490538

491-
<?php endif; ?>
492-
493539
<?php
494540
if ( $source_url ) {
495541
$cache_busting_url = add_query_arg(
@@ -499,15 +545,66 @@ function_exists( 'as_has_scheduled_action' ) &&
499545
$source_url
500546
);
501547
?>
502-
503548
<p>
504549
<audio id="classifai-audio-preview" controls controlslist="nodownload" src="<?php echo esc_url( $cache_busting_url ); ?>"></audio>
505550
</p>
506-
507551
<?php
508552
}
509553
}
510554

555+
/**
556+
* AJAX handler for the Classic Editor meta box's polling. Returns the
557+
* current audio generation status for the given post id.
558+
*/
559+
public function ajax_get_audio_generation_status() {
560+
check_ajax_referer( 'classifai_tts_status', 'nonce' );
561+
562+
$post_id = isset( $_POST['post_id'] ) ? absint( wp_unslash( $_POST['post_id'] ) ) : 0;
563+
564+
if ( ! $post_id || ! current_user_can( 'edit_post', $post_id ) ) {
565+
wp_send_json_error( [ 'message' => __( 'Invalid post.', 'classifai' ) ], 403 );
566+
}
567+
568+
$in_progress =
569+
function_exists( 'as_has_scheduled_action' ) &&
570+
\as_has_scheduled_action(
571+
'classifai_schedule_text_to_speech_job',
572+
[
573+
'post_id' => $post_id,
574+
'calling_user_id' => get_current_user_id(),
575+
],
576+
'classifai'
577+
);
578+
579+
$error_message = '';
580+
$raw_error = get_post_meta( $post_id, '_classifai_text_to_speech_error', true );
581+
582+
if ( ! empty( $raw_error ) ) {
583+
$decoded = (array) json_decode( (string) $raw_error );
584+
if ( ! empty( $decoded['message'] ) ) {
585+
$error_message = (string) $decoded['message'];
586+
}
587+
}
588+
589+
$html = '';
590+
if ( ! $in_progress && ! $error_message ) {
591+
$post = get_post( $post_id );
592+
if ( $post ) {
593+
ob_start();
594+
$this->render_audio_generation_ui( $post );
595+
$html = (string) ob_get_clean();
596+
}
597+
}
598+
599+
wp_send_json_success(
600+
[
601+
'inProgress' => (bool) $in_progress,
602+
'error' => $error_message,
603+
'html' => $html,
604+
]
605+
);
606+
}
607+
511608
/**
512609
* Process the meta box save.
513610
*
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// Poll admin-ajax to update the Classic Editor TTS meta box once audio generation completes.
2+
const init = () => {
3+
const status = document.querySelector( '.classifai-tts-status' );
4+
5+
if ( ! status ) {
6+
return;
7+
}
8+
9+
const postId = parseInt( status.dataset.postId, 10 );
10+
const nonce = status.dataset.nonce;
11+
12+
if ( ! postId || ! nonce ) {
13+
return;
14+
}
15+
16+
const POLL_INTERVAL_MS = 10000;
17+
18+
const renderComplete = ( { error, html } ) => {
19+
if ( error ) {
20+
status.textContent = error;
21+
return;
22+
}
23+
24+
if ( html ) {
25+
status.outerHTML = html;
26+
}
27+
};
28+
29+
const timer = setInterval( async () => {
30+
try {
31+
const body = new URLSearchParams( {
32+
action: 'classifai_get_tts_status',
33+
nonce,
34+
post_id: postId,
35+
} );
36+
37+
const response = await fetch( window.ajaxurl, {
38+
method: 'POST',
39+
credentials: 'same-origin',
40+
body,
41+
} );
42+
43+
if ( ! response.ok ) {
44+
return;
45+
}
46+
47+
const json = await response.json();
48+
49+
if ( ! json || ! json.success || ! json.data ) {
50+
return;
51+
}
52+
53+
if ( json.data.inProgress ) {
54+
return;
55+
}
56+
57+
clearInterval( timer );
58+
renderComplete( json.data );
59+
} catch ( e ) {
60+
// Swallow transient fetch errors and try again next tick.
61+
}
62+
}, POLL_INTERVAL_MS );
63+
};
64+
65+
if ( document.readyState !== 'loading' ) {
66+
init();
67+
} else {
68+
document.addEventListener( 'DOMContentLoaded', init );
69+
}

webpack.config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ module.exports = {
2525
'classifai-plugin-classification-pre-publish': './src/js/features/classification/pre-publish-panel.js',
2626
'classifai-plugin-fill': './src/js/features/slot-fill/index.js',
2727
'classifai-plugin-text-to-speech': './src/js/features/text-to-speech/index.js',
28+
'classifai-plugin-classic-text-to-speech': './src/js/features/text-to-speech/classic/index.js',
2829
'classifai-plugin-text-to-speech-frontend': './src/js/features/text-to-speech/frontend/index.js',
2930
'classifai-plugin-content-resizing': './src/js/features/content-resizing/index.js',
3031
'classifai-plugin-title-generation': './src/js/features/title-generation/index.js',

0 commit comments

Comments
 (0)