* @since 4.0.0 */ namespace Beyondwords\Wordpress\Component\Post\SelectVoice; use Beyondwords\Wordpress\Core\CoreUtils; use Beyondwords\Wordpress\Component\Settings\SettingsUtils; use Beyondwords\Wordpress\Core\ApiClient; /** * SelectVoice * * @since 4.0.0 */ class SelectVoice { /** * Init. * * @since 4.0.0 * @since 6.0.0 Make static. */ public static function init() { add_action('rest_api_init', [self::class, 'restApiInit']); add_action('admin_enqueue_scripts', [self::class, 'adminEnqueueScripts']); add_action('wp_loaded', function (): void { $postTypes = SettingsUtils::getCompatiblePostTypes(); if (is_array($postTypes)) { foreach ($postTypes as $postType) { add_action("save_post_{$postType}", [self::class, 'save'], 10); } } }); } /** * HTML output for this component. * * @since 4.0.0 * @since 4.5.1 Hide element if no language data exists. * @since 5.4.0 Always display all languages and associated voices. * @since 6.0.0 Make static. * * @param \WP_Post $post The post object. * * @return string|null */ public static function element($post) { $languageCode = self::getLanguageCode($post->ID); $voiceId = self::getVoiceId($post->ID); $languages = ApiClient::getLanguages(); $voices = self::getVoicesForLanguage($languageCode); wp_nonce_field('beyondwords_select_voice', 'beyondwords_select_voice_nonce'); self::renderLanguageSelect($languages, $languageCode); self::renderVoiceSelect($voices, $voiceId, $languageCode); self::renderLoadingSpinner(); } /** * Get the language code for a post. * * @since 6.0.0 * * @param int $postId The post ID. * @return string|false The language code or false if not set. */ private static function getLanguageCode(int $postId) { $postLanguageCode = get_post_meta($postId, 'beyondwords_language_code', true); return $postLanguageCode ?: get_option('beyondwords_project_language_code'); } /** * Get the voice ID for a post. * * @since 6.0.0 * * @param int $postId The post ID. * @return string|false The voice ID or false if not set. */ private static function getVoiceId(int $postId) { $postVoiceId = get_post_meta($postId, 'beyondwords_body_voice_id', true); return $postVoiceId ?: get_option('beyondwords_project_body_voice_id'); } /** * Get voices for a language code. * * @since 6.0.0 * * @param string|false $languageCode The language code. * @return array The voices array. */ private static function getVoicesForLanguage($languageCode): array { if ($languageCode === false || $languageCode === '') { return []; } $voices = ApiClient::getVoices($languageCode); return is_array($voices) ? $voices : []; } /** * Render the language select dropdown. * * @since 6.0.0 * * @param array $languages The languages array. * @param string|false $selectedLanguageCode The selected language code. */ private static function renderLanguageSelect(array $languages, $selectedLanguageCode): void { ?>

\WP_REST_Server::READABLE, 'callback' => [self::class, 'languagesRestApiResponse'], 'permission_callback' => fn() => current_user_can('edit_posts'), ]); // Voices endpoint register_rest_route('beyondwords/v1', '/languages/(?P[a-zA-Z0-9-_]+)/voices', [ 'methods' => \WP_REST_Server::READABLE, 'callback' => [self::class, 'voicesRestApiResponse'], 'permission_callback' => fn() => current_user_can('edit_posts'), ]); } /** * "Languages" WP REST API response (required for the Gutenberg editor). * * @since 4.0.0 * @since 5.4.0 No longer filter by "Languages" plugin setting. * @since 6.0.0 Make static. * * @return \WP_REST_Response */ public static function languagesRestApiResponse() { $languages = ApiClient::getLanguages(); return new \WP_REST_Response($languages); } /** * "Voices" WP REST API response (required for the Gutenberg editor * and Block Editor). * * @since 4.0.0 * @since 6.0.0 Make static. * * @return \WP_REST_Response */ public static function voicesRestApiResponse(\WP_REST_Request $data) { $params = $data->get_url_params(); $voices = ApiClient::getVoices($params['languageCode']); return new \WP_REST_Response($voices); } /** * Register the component scripts. * * @since 4.0.0 * @since 6.0.0 Make static. * * @param string $hook Page hook * * @return void */ public static function adminEnqueueScripts($hook) { if (! CoreUtils::isGutenbergPage() && ( $hook === 'post.php' || $hook === 'post-new.php')) { wp_register_script( 'beyondwords-metabox--select-voice', BEYONDWORDS__PLUGIN_URI . 'src/Component/Post/SelectVoice/classic-metabox.js', ['jquery', 'underscore'], BEYONDWORDS__PLUGIN_VERSION, true ); /** * Localize the script to handle ajax requests */ wp_localize_script( 'beyondwords-metabox--select-voice', 'beyondwordsData', [ 'nonce' => wp_create_nonce('wp_rest'), 'root' => esc_url_raw(rest_url()), ] ); wp_enqueue_script('beyondwords-metabox--select-voice'); } } }