'Security verification failed']); return; } if ( ! current_user_can( 'manage_options' ) ) { wp_send_json_error( array( 'message' => __( 'You do not have permission to access this page.', '2coders-integration-mux-video' ) ), 403 ); return; } try { $api = muxvideo_api_client_init_playback_restrictions(); if (!$api) { wp_send_json_error(['message' => 'Unable to initialize Mux API']); return; } // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- JSON payload; structure validated and individual fields are sanitized below. $request_data = isset( $_POST['form_data'] ) ? wp_unslash( $_POST['form_data'] ) : ''; $input = json_decode( $request_data, true ); if ( is_array( $input ) ) { if ( isset( $input['allowed_domains'] ) && is_array( $input['allowed_domains'] ) ) { $input['allowed_domains'] = array_values( array_filter( array_map( 'sanitize_text_field', $input['allowed_domains'] ) ) ); // Always include the WordPress site's own host so the admin // preview and the plugin's own Gutenberg block can play // signed assets. Without this the user's `home_url` host // would not match Mux's referer check and playback would // fail right after saving any restriction. if ( ! empty( $input['allowed_domains'] ) ) { $site_host = wp_parse_url( home_url(), PHP_URL_HOST ); if ( $site_host && ! in_array( $site_host, $input['allowed_domains'], true ) ) { $input['allowed_domains'][] = $site_host; } if ( ! in_array( 'stream.mux.com', $input['allowed_domains'], true ) ) { $input['allowed_domains'][] = 'stream.mux.com'; } } } $input['allow_no_referrer'] = ! empty( $input['allow_no_referrer'] ); } if ( empty( $input['allowed_domains'] ) || ! is_array( $input['allowed_domains'] ) ) { $response = $api->listPlaybackRestrictions(); $all_restrictions = method_exists($response, 'getData') ? $response->getData() : ($response->data ?? []); if (!empty($all_restrictions)) { $restriction_id = method_exists($all_restrictions[0], 'getId') ? $all_restrictions[0]->getId() : ($all_restrictions[0]->id ?? ''); if ($restriction_id) { $api->deletePlaybackRestriction($restriction_id); delete_transient('muxvideo_playback_restrictions'); } } wp_send_json_success(['message' => 'All playback restrictions removed']); return; } $response = $api->listPlaybackRestrictions(); $all_restrictions = method_exists($response, 'getData') ? $response->getData() : ($response->data ?? []); $restriction_id = ''; if (!empty($all_restrictions)) { $first_restriction = $all_restrictions[0]; $restriction_id = method_exists($first_restriction, 'getId') ? $first_restriction->getId() : ($first_restriction->id ?? ''); } $referrer_request = new \MuxPhp\Models\UpdateReferrerDomainRestrictionRequest([ 'allowed_domains' => $input['allowed_domains'], 'allow_no_referrer' => $input['allow_no_referrer'] ?? false, ]); if ($restriction_id) { $result = $api->updateReferrerDomainRestriction($restriction_id, $referrer_request); } else { $create_request = new \MuxPhp\Models\CreatePlaybackRestrictionRequest([ 'referrer' => [ 'allowed_domains' => $input['allowed_domains'], 'allow_no_referrer' => $input['allow_no_referrer'] ?? false, ] ]); $result = $api->createPlaybackRestriction($create_request); if (method_exists($result, 'getData') && $result->getData() instanceof \MuxPhp\Models\PlaybackRestriction) { $restriction_id = $result->getData()->getId(); } } $obj = new stdClass(); $obj->id = $restriction_id; $obj->allowed_domains = $input['allowed_domains']; $obj->allow_no_referrer = $input['allow_no_referrer'] ?? false; set_transient('muxvideo_playback_restrictions', $obj, HOUR_IN_SECONDS); wp_send_json_success([ 'message' => 'Playback restriction saved', 'restriction_id' => $restriction_id, ]); } catch (Exception $e) { if (defined('WP_DEBUG') && WP_DEBUG) { // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- guarded by WP_DEBUG, intended for plugin debugging. error_log('Error updating playback restriction: ' . $e->getMessage()); } wp_send_json_error(['message' => 'Error updating playback restriction']); } wp_die(); } /** * Display the content to Customize shortcode */ add_action( 'wp_ajax_muxvideo_display_modal_customize_shortcode', 'muxvideo_display_modal_customize_shortcode' ); function muxvideo_display_modal_customize_shortcode() { if (!isset($_POST['nonce']) || !wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'mux_token_nonce' )) { wp_send_json_error(array('message' => 'Security verification failed')); return; } if ( ! current_user_can( 'manage_options' ) ) { wp_send_json_error( array( 'message' => __( 'You do not have permission to access this page.', '2coders-integration-mux-video' ) ), 403 ); return; } try { include_once MUXVIDEO_PLUGIN_DIR . '/views/template-parts/customize-shortcode.php'; wp_die(); } catch (\Throwable $th) { if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- guarded by WP_DEBUG, intended for plugin debugging. error_log( "Error: muxvideo_display_modal_customize_shortcode"); } echo '
' . esc_html__('error_try_again', '2coders-integration-mux-video') . '
'; } } /** * Display the content to Customize shortcode */ add_action( 'wp_ajax_muxvideo_get_jwt_dinamically', 'muxvideo_get_jwt_dinamically' ); function muxvideo_get_jwt_dinamically() { if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'mux_token_nonce' ) ) { wp_send_json_error( array( 'message' => 'Security verification failed' ) ); return; } if ( ! current_user_can( 'manage_options' ) ) { wp_send_json_error( array( 'message' => __( 'You do not have permission to access this page.', '2coders-integration-mux-video' ) ), 403 ); return; } // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- JSON payload; individual fields are sanitized below before use. $json_string = isset( $_POST['formated_data'] ) ? wp_unslash( $_POST['formated_data'] ) : ''; $asset_data = json_decode( $json_string, true ); $time = isset( $_POST['time'] ) ? absint( $_POST['time'] ) : 0; if ( empty( $asset_data ) || ! is_array( $asset_data ) ) { wp_send_json_error( 'No valid data' ); return; } $playback_id = isset( $asset_data['playback_id'] ) ? sanitize_text_field( $asset_data['playback_id'] ) : ''; $playback_restriction = isset( $asset_data['playback_restriction_id'] ) ? sanitize_text_field( $asset_data['playback_restriction_id'] ) : ''; if ( empty( $playback_id ) ) { wp_send_json_error( 'No valid data' ); return; } $signing_options = get_option( 'muxvideo_options', array() ); $signing_id = isset( $signing_options['muxvideo_signing_data']['id'] ) ? $signing_options['muxvideo_signing_data']['id'] : ''; $signing_key = isset( $signing_options['muxvideo_signing_data']['private_key'] ) ? $signing_options['muxvideo_signing_data']['private_key'] : ''; if ( empty( $signing_id ) || empty( $signing_key ) ) { wp_send_json_error( 'Signing key not configured' ); return; } try { $jwt_t = muxvideo_get_json_web_token( $playback_id, $signing_id, $signing_key, 't', $playback_restriction, $time ); wp_send_json( $jwt_t ); } catch ( \Throwable $th ) { if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- guarded by WP_DEBUG, intended for plugin debugging. error_log( 'Error: muxvideo_get_jwt_dinamically' ); } wp_send_json_error( __( 'An error occurred. Please try again.', '2coders-integration-mux-video' ) ); } } /** * Function called from ajax to get next page of assets */ add_action( 'wp_ajax_muxvideo_load_more_assets', 'muxvideo_load_more_assets' ); function muxvideo_load_more_assets() { if (!isset($_POST['nonce']) || !wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'mux_token_nonce' )) { wp_send_json_error(array('message' => 'Security verification failed')); return; } if ( ! current_user_can( 'manage_options' ) ) { wp_die( esc_html__( 'You do not have permission to access this page.', '2coders-integration-mux-video' ) ); } muxvideo_display_assets_list(); wp_die(); } /** * Create a delete request and remove the asset in Mux */ add_action( 'wp_ajax_muxvideo_delete_asset', 'muxvideo_delete_asset' ); function muxvideo_delete_asset() { require_once MUXVIDEO_PLUGIN_DIR . '/includes/functions.php'; if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'mux_token_nonce' ) ) { wp_send_json_error( array( 'message' => 'Security verification failed' ) ); return; } if ( ! current_user_can( 'manage_options' ) ) { wp_send_json_error( array( 'message' => __( 'You do not have permission to access this page.', '2coders-integration-mux-video' ) ), 403 ); return; } $asset_id = isset( $_REQUEST['asset_id'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['asset_id'] ) ) : ''; if ( empty( $asset_id ) ) { wp_send_json_error( array( 'message' => 'Missing asset_id' ) ); return; } try { $assetsApi = muxvideo_api_client_init(); $assetsApi->deleteAsset( $asset_id ); global $wpdb; // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange $wpdb->delete( $wpdb->prefix . 'mux_caption_queue', array( 'asset_id' => $asset_id ), array( '%s' ) ); } catch ( Exception $e ) { if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- guarded by WP_DEBUG, intended for plugin debugging. error_log( 'Exception when calling AssetsApi->deleteAsset' ); } echo '
' . esc_html__( 'error_delete', '2coders-integration-mux-video' ) . '
'; } wp_die(); } /** * Create a new upload url to upload a new asset */ add_action( 'wp_ajax_muxvideo_reset_upload_url', 'muxvideo_reset_upload_url' ); function muxvideo_reset_upload_url() { if (!isset($_POST['nonce']) || !wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'mux_token_nonce' )) { wp_send_json_error(array('message' => 'Security verification failed')); return; } if ( ! current_user_can( 'manage_options' ) ) { wp_send_json_error( array( 'message' => __( 'You do not have permission to access this page.', '2coders-integration-mux-video' ) ), 403 ); return; } require_once MUXVIDEO_PLUGIN_DIR . '/includes/functions.php'; $asset_privacy_raw = isset( $_REQUEST['asset_privacy'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['asset_privacy'] ) ) : ''; $asset_privacy = ( 'signed' === $asset_privacy_raw ) ? [ MuxPhp\Models\PlaybackPolicy::SIGNED ] : [ MuxPhp\Models\PlaybackPolicy::_PUBLIC ]; $upload_id = isset($_REQUEST['upload_id']) ? sanitize_text_field( wp_unslash( $_REQUEST['upload_id'] ) ) : ''; $caption_type = isset($_REQUEST['caption_type']) ? sanitize_text_field( wp_unslash( $_REQUEST['caption_type'] ) ) : ''; $language_code = isset($_REQUEST['language_code']) ? sanitize_text_field( wp_unslash( $_REQUEST['language_code'] ) ) : ''; $closed_captions_raw = isset( $_REQUEST['closed_captions'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['closed_captions'] ) ) : ''; $closed_captions = ( 'true' === $closed_captions_raw ); $title = isset($_POST['title']) ? sanitize_text_field( wp_unslash( $_POST['title'] ) ) : ''; muxvideo_save_caption_request_handler($upload_id, $caption_type, $language_code, $closed_captions); try { $uploadsApi = muxvideo_api_client_init_upload(); $createAssetRequest = new MuxPhp\Models\CreateAssetRequest([ "playback_policies" => $asset_privacy, "meta" => [ "title" => $title ], ]); $createUploadRequest = new MuxPhp\Models\CreateUploadRequest([ "timeout" => 3600, "new_asset_settings" => $createAssetRequest, "cors_origin" => "*" ]); $upload = $uploadsApi->createDirectUpload($createUploadRequest); $data = $upload->getData(); $new_upload_id = $data->getId(); // Iniciar proceso de actualización con reintento automático (empieza en intento 1) // muxvideo_update_asset_metadata_later($new_upload_id, $title, 1); wp_send_json([ 'data' => [ 'url' => $data->getUrl(), 'id' => $new_upload_id ] ]); } catch (Exception $e) { if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- guarded by WP_DEBUG, intended for plugin debugging. error_log('Exception when creating upload'); } echo '
' . esc_html__('error_upload', '2coders-integration-mux-video') . '
'; } wp_die(); } add_action('wp_ajax_muxvideo_start_metadata_polling', 'muxvideo_start_metadata_polling'); function muxvideo_start_metadata_polling() { if (!isset($_POST['nonce']) || !wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'mux_token_nonce' )) { wp_send_json_error(array('message' => 'Security verification failed')); return; } if ( ! current_user_can( 'manage_options' ) ) { wp_send_json_error( array( 'message' => __( 'You do not have permission to access this page.', '2coders-integration-mux-video' ) ), 403 ); return; } require_once MUXVIDEO_PLUGIN_DIR . '/includes/functions.php'; $upload_id = isset( $_POST['upload_id'] ) ? sanitize_text_field( wp_unslash( $_POST['upload_id'] ) ) : ''; $title = isset( $_POST['title'] ) ? sanitize_text_field( wp_unslash( $_POST['title'] ) ) : ''; $apiInstance = muxvideo_api_client_init(); $assets = $apiInstance->listAssets(25, 1, null, $upload_id); $asset = $assets->getData()[0]; $asset_id = $asset->getId(); $update_asset_request = [ 'meta' => [ 'title' => $title ] ]; $apiInstance->updateAsset($asset_id, $update_asset_request); if (!$upload_id || !$title) { wp_send_json_error(['message' => 'Faltan parámetros']); } muxvideo_update_asset_metadata_later($upload_id, $title, 1); wp_send_json_success(['message' => 'Intento de actualización programado.']); } /** * Refresh asset list dynamically */ add_action( 'wp_ajax_muxvideo_refresh_asset_list', 'muxvideo_refresh_asset_list' ); function muxvideo_refresh_asset_list() { if ( ! isset( $_REQUEST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_REQUEST['nonce'] ) ), 'mux_token_nonce' ) ) { wp_send_json_error( array( 'message' => 'Security verification failed' ) ); return; } if ( ! current_user_can( 'manage_options' ) ) { wp_send_json_error( array( 'message' => __( 'You do not have permission to access this page.', '2coders-integration-mux-video' ) ), 403 ); return; } try { muxvideo_display_assets_list(); wp_die(); } catch (\Exception $e) { if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- guarded by WP_DEBUG, intended for plugin debugging. error_log( 'Exception when calling muxvideo_refresh_asset_list'); } echo '
' . esc_html__('error_displaying_list', '2coders-integration-mux-video') . '
'; } } /** * Display the delete caption modal content */ function muxvideo_display_modal_delete_caption() { if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'mux_token_nonce' ) ) { wp_send_json_error( array( 'message' => __( 'Invalid security token. Please refresh and try again.', '2coders-integration-mux-video' ) ) ); return; } if ( ! current_user_can( 'manage_options' ) ) { wp_send_json_error( array( 'message' => __( 'You do not have permission to access this page.', '2coders-integration-mux-video' ) ), 403 ); return; } if ( ! isset( $_POST['track_id'] ) || ! isset( $_POST['asset_id'] ) ) { wp_send_json_error( array( 'message' => __( 'delete_caption_error_missing_data', '2coders-integration-mux-video' ) ) ); return; } ob_start(); include_once MUXVIDEO_PLUGIN_DIR . '/views/template-parts/delete-caption-modal.php'; $content = ob_get_clean(); echo wp_kses_post( $content ); wp_die(); } add_action( 'wp_ajax_muxvideo_display_modal_delete_caption', 'muxvideo_display_modal_delete_caption' ); /** * Delete a caption track */ function muxvideo_delete_caption_track() { if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'mux_token_nonce' ) ) { wp_send_json_error( array( 'message' => 'Security verification failed' ) ); return; } if ( ! current_user_can( 'manage_options' ) ) { wp_send_json_error( array( 'message' => __( 'You do not have permission to access this page.', '2coders-integration-mux-video' ) ), 403 ); return; } if (!isset($_POST['track_id']) || !isset($_POST['asset_id'])) { wp_send_json_error(array('message' => __('delete_caption_error_missing_data', '2coders-integration-mux-video'))); return; } $track_id = sanitize_text_field( wp_unslash( $_POST['track_id'] ) ); $asset_id = sanitize_text_field( wp_unslash( $_POST['asset_id'] ) ); try { $assetsApi = muxvideo_api_client_init(); $assetsApi->deleteAssetTrack($asset_id, $track_id); wp_send_json_success(array( 'message' => __('caption_deleted_success', '2coders-integration-mux-video'), 'track_id' => $track_id )); } catch (\Exception $e) { if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- guarded by WP_DEBUG, intended for plugin debugging. error_log('Exception when calling AssetsApi->deleteTrack'); } wp_send_json_error(array( 'message' => __('caption_delete_error', '2coders-integration-mux-video'), )); } wp_die(); } add_action('wp_ajax_muxvideo_delete_caption_track', 'muxvideo_delete_caption_track'); /** * Display the content to manage captions */ add_action('wp_ajax_muxvideo_display_modal_manage_captions', 'muxvideo_display_modal_manage_captions'); function muxvideo_display_modal_manage_captions() { if (!isset($_POST['nonce']) || !wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'mux_token_nonce' )) { wp_send_json_error(array('message' => 'Security verification failed')); return; } if ( ! current_user_can( 'manage_options' ) ) { wp_send_json_error( array( 'message' => __( 'You do not have permission to access this page.', '2coders-integration-mux-video' ) ), 403 ); return; } try { $asset_id = isset( $_POST['asset_id'] ) ? sanitize_text_field( wp_unslash( $_POST['asset_id'] ) ) : ''; $used_languages = isset( $_POST['used_languages'] ) ? json_decode( sanitize_text_field( wp_unslash( $_POST['used_languages'] ) ), true ) : []; if (empty($asset_id)) { wp_send_json_error(array('message' => __('captions_manager_error_missing_asset', '2coders-integration-mux-video'))); return; } include_once MUXVIDEO_PLUGIN_DIR . '/views/template-parts/customize-captions-modal.php'; wp_die(); } catch (\Throwable $th) { if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- guarded by WP_DEBUG, intended for plugin debugging. error_log("Error: muxvideo_display_modal_manage_captions"); } echo '
' . esc_html__('error_try_again', '2coders-integration-mux-video') . '
'; } } /** * Ajax handler for loading asset captions */ add_action('wp_ajax_muxvideo_get_asset_captions', 'muxvideo_get_asset_captions'); function muxvideo_get_asset_captions() { if (!isset($_POST['nonce']) || !wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'mux_token_nonce' )) { wp_send_json_error(array('message' => 'Security verification failed')); return; } if ( ! current_user_can( 'manage_options' ) ) { wp_send_json_error( array( 'message' => __( 'You do not have permission to access this page.', '2coders-integration-mux-video' ) ), 403 ); return; } if (!isset($_POST['asset_id'])) { wp_send_json_error(array('message' => __('Missing asset ID', '2coders-integration-mux-video'))); return; } $asset_id = sanitize_text_field( wp_unslash( $_POST['asset_id'] ) ); $upload_id = isset( $_POST['upload_id'] ) ? sanitize_text_field( wp_unslash( $_POST['upload_id'] ) ) : ''; $caption_page = isset($_POST['caption_page']) ? intval($_POST['caption_page']) : 1; try { // Check for pending captions for this asset global $wpdb; $table_name = $wpdb->prefix . 'mux_caption_queue'; // Only proceed if we have an upload_id if (!empty($upload_id) && !empty($asset_id)) { // First check if the asset is ready try { $assetsApi = muxvideo_api_client_init(); $asset = $assetsApi->getAsset($asset_id); $asset_data = $asset->getData(); // If asset is not ready, just update the timestamp and exit if ($asset_data->getStatus() === 'ready') { // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange $pending_requests = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM `{$wpdb->prefix}mux_caption_queue` WHERE upload_id = %s AND status = %s ORDER BY created_at ASC", $upload_id, 'pending' ) ); // Update the asset_id for these requests if we have pending requests if (!empty($pending_requests)) { // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange $wpdb->update( $table_name, array( 'asset_id' => $asset_id, 'updated_at' => current_time('mysql') ), array('upload_id' => $upload_id) ); // Process pending captions foreach ($pending_requests as $request) { // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange $wpdb->update( $table_name, array( 'attempts' => $request->attempts + 1, 'updated_at' => current_time('mysql') ), array('id' => $request->id) ); $original_filename = isset($request->original_filename) ? $request->original_filename : ''; if ($request->caption_type === 'auto') { $result = muxvideo_generate_captions($asset_id, $request->language_code); if ($result['success']) { // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange $wpdb->update( $table_name, array( 'status' => 'completed', 'updated_at' => current_time('mysql'), 'error_message' => null ), array('id' => $request->id) ); } else { $is_permanent_error = strpos($result['message'], 'already has auto-generated captions') !== false; // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange $wpdb->update( $table_name, array( 'status' => $is_permanent_error ? 'failed' : 'pending', 'error_message' => $result['message'], 'updated_at' => current_time('mysql') ), array('id' => $request->id) ); } } else if ($request->caption_type === 'custom' && !empty($request->caption_file_url)) { $result = muxvideo_upload_captions( $asset_id, $request->language_code, $request->caption_file_url, (bool)$request->closed_captions, $original_filename ); if ($result['success']) { // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange $wpdb->update( $table_name, array( 'status' => 'completed', 'updated_at' => current_time('mysql'), 'error_message' => null ), array('id' => $request->id) ); } else { // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange $wpdb->update( $table_name, array( 'status' => 'pending', 'error_message' => $result['message'], 'updated_at' => current_time('mysql') ), array('id' => $request->id) ); } } } } } } catch (\Exception $e) { if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- guarded by WP_DEBUG, intended for plugin debugging. error_log('Error checking asset status: ' . $e->getMessage()); } return; } } // Now get the asset data and display captions $assetsApi = muxvideo_api_client_init(); $asset = $assetsApi->getAsset($asset_id); $asset_data = $asset->getData(); if (!$asset) { echo '
' . esc_html__('error_asset_not_found', '2coders-integration-mux-video') . '
'; wp_die(); } $has_valid_captions = false; if (isset($asset_data['tracks']) && !empty($asset_data['tracks'])) { foreach ($asset_data['tracks'] as $track) { if ($track->getType() === 'text' && $track->getLanguageCode()) { $has_valid_captions = true; break; } } } if ($has_valid_captions) { // Set up variables for the template $all_languages = array_merge( muxvideo_get_auto_caption_languages()['stable'], muxvideo_get_auto_caption_languages()['beta'], muxvideo_get_custom_caption_languages() ); // Pass the caption_page to your template $_GET['caption_page'] = $caption_page; // Include the template file with the captions content. ob_start(); include MUXVIDEO_PLUGIN_DIR . '/views/template-parts/asset-captions.php'; $captions_html = ob_get_clean(); echo wp_kses_post( $captions_html ); } else { echo '
' . esc_html__('asset_list_no_captions', '2coders-integration-mux-video') . '
'; } wp_die(); } catch (\Throwable $th) { wp_send_json_error(__('An error occurred. Please try again.', '2coders-integration-mux-video')); } } add_action('wp_ajax_muxvideo_generate_captions', 'muxvideo_ajax_generate_captions'); function muxvideo_ajax_generate_captions() { if (!isset($_POST['nonce']) || !wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'mux_token_nonce' )) { wp_send_json_error(array('message' => 'Security verification failed')); return; } if ( ! current_user_can( 'manage_options' ) ) { wp_send_json_error( array( 'message' => __( 'You do not have permission to access this page.', '2coders-integration-mux-video' ) ), 403 ); return; } try { $asset_id = isset( $_POST['asset_id'] ) ? sanitize_text_field( wp_unslash( $_POST['asset_id'] ) ) : ''; $language_code = isset( $_POST['language_code'] ) ? sanitize_text_field( wp_unslash( $_POST['language_code'] ) ) : ''; if (empty($asset_id) || empty($language_code)) { wp_send_json_error(__('missing_required_parameters', '2coders-integration-mux-video')); return; } $result = muxvideo_generate_captions($asset_id, $language_code); if ($result === true || (is_array($result) && isset($result['success']) && $result['success'])) { wp_send_json_success($result); } else { $error_message = is_array($result) && isset($result['message']) ? $result['message'] : __('captions_generation_failed', '2coders-integration-mux-video'); wp_send_json_error($error_message); } } catch (\Exception $e) { wp_send_json_error(__('An error occurred. Please try again.', '2coders-integration-mux-video')); } wp_die(); } /** * AJAX handler for uploading custom captions */ function muxvideo_ajax_upload_captions() { if (!isset($_POST['nonce']) || !wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'mux_token_nonce' )) { wp_send_json_error(array('message' => 'Security verification failed')); return; } if ( ! current_user_can( 'manage_options' ) ) { wp_send_json_error( __( 'captions_manager_error_permission_denied', '2coders-integration-mux-video' ), 403 ); return; } $asset_id = isset( $_POST['asset_id'] ) ? sanitize_text_field( wp_unslash( $_POST['asset_id'] ) ) : ''; $language_code = isset( $_POST['language_code'] ) ? sanitize_text_field( wp_unslash( $_POST['language_code'] ) ) : ''; $closed_captions = isset($_POST['closed_captions']) && $_POST['closed_captions'] === 'true'; if ( empty( $asset_id ) || empty( $language_code ) ) { wp_send_json_error( esc_html__( 'captions_manager_error_missing_parameters', '2coders-integration-mux-video' ) ); return; } // Check that the file upload arrived with no transport-level error. $caption_file_error = isset( $_FILES['caption_file']['error'] ) ? (int) $_FILES['caption_file']['error'] : -1; if ( ! isset( $_FILES['caption_file'] ) || UPLOAD_ERR_OK !== $caption_file_error ) { wp_send_json_error( sprintf( /* translators: %s: upload error code or message */ esc_html__( 'captions_manager_error_upload_failed', '2coders-integration-mux-video' ), ( -1 === $caption_file_error ) ? esc_html__( 'captions_manager_error_no_file', '2coders-integration-mux-video' ) : $caption_file_error ) ); return; } // Get the original filename and extension. $original_filename = isset( $_FILES['caption_file']['name'] ) ? sanitize_file_name( wp_unslash( $_FILES['caption_file']['name'] ) ) : ''; $file_extension = strtolower( pathinfo( $original_filename, PATHINFO_EXTENSION ) ); if ( ! in_array( $file_extension, array( 'srt', 'vtt' ), true ) ) { wp_send_json_error( esc_html__( 'captions_manager_error_format', '2coders-integration-mux-video' ) ); return; } // wp_handle_upload() reads $_FILES directly and performs its own MIME / size // validation. The phpcs:ignore is intentional because we cannot pre-sanitize // a $_FILES array without breaking the upload API. // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized,WordPress.Security.ValidatedSanitizedInput.InputNotValidated -- delegated to wp_handle_upload(). $upload = wp_handle_upload( $_FILES['caption_file'], array( 'test_form' => false ) ); if (isset($upload['error'])) { wp_send_json_error(__('An error occurred. Please try again.', '2coders-integration-mux-video')); return; } // Create custom directory for captions $upload_dir = wp_upload_dir(); $asset_id = preg_replace('/[^a-zA-Z0-9_-]/', '', $asset_id); $caption_dir = $upload_dir['basedir'] . '/mux-captions/' . $asset_id; if (!file_exists($caption_dir)) { wp_mkdir_p($caption_dir); } $unique_filename = $language_code . '.' . $file_extension; $file_path = $caption_dir . '/' . $unique_filename; if ( ! function_exists( 'WP_Filesystem' ) ) { require_once ABSPATH . 'wp-admin/includes/file.php'; } WP_Filesystem(); global $wp_filesystem; if ( $wp_filesystem instanceof WP_Filesystem_Base && $wp_filesystem->copy( $upload['file'], $file_path, true ) ) { $wp_filesystem->delete( $upload['file'] ); $caption_file_url = $upload_dir['baseurl'] . '/mux-captions/' . $asset_id . '/' . $unique_filename; $result = muxvideo_upload_captions( $asset_id, $language_code, $caption_file_url, $closed_captions, $original_filename ); if ( $result['success'] ) { wp_send_json_success( $result ); } else { $wp_filesystem->delete( $file_path ); wp_send_json_error( esc_html__( 'An error occurred. Please try again.', '2coders-integration-mux-video' ) ); } } else { wp_send_json_error( esc_html__( 'Error uploading captions', '2coders-integration-mux-video' ) ); } } add_action('wp_ajax_muxvideo_upload_captions', 'muxvideo_ajax_upload_captions'); function update_mux_asset_callback() { if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'mux_token_nonce' ) ) { wp_send_json_error( array( 'message' => 'Security verification failed' ) ); return; } if ( ! current_user_can( 'manage_options' ) ) { wp_send_json_error( array( 'message' => __( 'You do not have permission to access this page.', '2coders-integration-mux-video' ) ), 403 ); return; } if ( !isset($_POST['asset_id']) || !isset($_POST['mp4_support']) ) { wp_send_json_error(array('message' => 'Invalid parameters')); return; } $apiInstance = muxvideo_api_client_init(); $asset_id = sanitize_text_field( wp_unslash( $_POST['asset_id'] ) ); $mp4_support = sanitize_text_field( wp_unslash( $_POST['mp4_support'] ) ); $update_asset_request = array('mp4_support' => $mp4_support); try { $clean_mp4_support = array('mp4_support' => 'none'); $apiInstance->updateAssetMp4Support($asset_id, $clean_mp4_support); $result = $apiInstance->updateAssetMp4Support($asset_id, $update_asset_request); $result; wp_send_json_success(array('message' => 'Asset updated successfully')); } catch (Exception $e) { wp_send_json_error(array('message' => 'Error updating asset')); } } add_action('wp_ajax_update_mux_asset', 'update_mux_asset_callback'); function muxvideo_update_asset_settings() { if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'mux_token_nonce' ) ) { wp_send_json_error( array( 'message' => 'Security verification failed' ) ); return; } if ( ! current_user_can( 'manage_options' ) ) { wp_send_json_error( array( 'message' => __( 'You do not have permission to access this page.', '2coders-integration-mux-video' ) ), 403 ); return; } if (!isset($_POST['upload_id'])) { wp_send_json_error(['message' => 'Missing upload ID']); return; } try { $video_quality = isset( $_POST['video_quality'] ) ? sanitize_text_field( wp_unslash( $_POST['video_quality'] ) ) : 'plus'; $mp4_support = isset( $_POST['mp4_support'] ) ? sanitize_text_field( wp_unslash( $_POST['mp4_support'] ) ) : ''; $asset_privacy = isset( $_POST['asset_privacy'] ) ? sanitize_text_field( wp_unslash( $_POST['asset_privacy'] ) ) : 'protected'; $title = isset( $_POST['title'] ) ? sanitize_text_field( wp_unslash( $_POST['title'] ) ) : ''; // Create asset settings $createAssetRequest = new MuxPhp\Models\CreateAssetRequest([ "playback_policy" => $asset_privacy === 'protected' ? [MuxPhp\Models\PlaybackPolicy::SIGNED] : [MuxPhp\Models\PlaybackPolicy::_PUBLIC], "mp4_support" => $mp4_support ?: 'none', "video_quality" => $video_quality, "meta" => [ "title" => $title ] ]); // Create upload request $createUploadRequest = new MuxPhp\Models\CreateUploadRequest([ "timeout" => 6000, "new_asset_settings" => $createAssetRequest, "cors_origin" => "*" ]); $uploadsApi = muxvideo_api_client_init_upload(); $upload = $uploadsApi->createDirectUpload($createUploadRequest); $data = $upload->getData(); wp_send_json_success([ 'url' => $data->getUrl(), 'id' => $data->getId() ]); } catch (Exception $e) { wp_send_json_error([ 'message' => 'Error creating upload' ]); } } add_action('wp_ajax_muxvideo_update_asset_settings', 'muxvideo_update_asset_settings'); // CREATE TABLE IN THE DATABASE FOR MUX ASSETS add_action('wp_ajax_save_mux_asset', 'handle_save_mux_asset'); function handle_save_mux_asset() { if (!isset($_POST['nonce']) || !wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'mux_token_nonce' )) { wp_send_json_error(array('message' => 'Security verification failed')); return; } require_once MUXVIDEO_PLUGIN_DIR . '/includes/functions.php'; if ( ! current_user_can( 'manage_options' ) ) { wp_send_json_error( 'Insufficient permissions', 403 ); return; } $title = isset($_POST['title']) ? sanitize_text_field( wp_unslash( $_POST['title'] ) ) : ''; if (empty($title)) { wp_send_json_error('Empty title.'); } if ( isset( $_FILES['file'] ) ) { // wp_handle_upload() and finfo_file() handle a raw upload struct; we // sanitize the displayable name separately. The fields we read are // either checked against an allow-list or sanitized below. // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- handled below. $file = $_FILES['file']; $tmp_name = isset( $file['tmp_name'] ) ? $file['tmp_name'] : ''; if ( ! $tmp_name || ! is_uploaded_file( $tmp_name ) ) { wp_send_json_error( 'Invalid upload.' ); return; } $finfo = finfo_open( FILEINFO_MIME_TYPE ); $mime_type = $finfo ? finfo_file( $finfo, $tmp_name ) : ''; if ( $finfo ) { finfo_close( $finfo ); } $allowed_mimes = array( 'video/mp4','video/x-m4v','video/avi','video/quicktime','video/mpeg','video/x-ms-wmv', 'video/x-flv','video/webm','video/x-matroska','video/ogg','video/3gpp','video/3gpp2', 'audio/mpeg','audio/mp3','audio/wav','audio/ogg','audio/mp4','audio/flac','audio/amr', 'audio/x-m4a','audio/x-m4r', ); if ( ! in_array( $mime_type, $allowed_mimes, true ) ) { wp_send_json_error( 'Invalid file type.' ); return; } $raw_name = isset( $file['name'] ) ? sanitize_file_name( wp_unslash( $file['name'] ) ) : ''; $extension = strtolower( pathinfo( $raw_name, PATHINFO_EXTENSION ) ); $allowed_extensions = array( 'mp4','m4v','avi','mov','mpeg','wmv','flv','webm','mkv','ogg','3gp','3g2', 'mp3','wav','flac','amr','m4a','m4r', ); if ( ! in_array( $extension, $allowed_extensions, true ) ) { wp_send_json_error( 'Invalid extension.' ); return; } // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- delegated to wp_handle_upload(). $upload = wp_handle_upload( $_FILES['file'], array( 'test_form' => false ) ); if ( isset( $upload['error'] ) ) { wp_send_json_error( esc_html__( 'An error occurred. Please try again.', '2coders-integration-mux-video' ) ); return; } $file_url = $upload['url']; } $uploadsApi = muxvideo_api_client_init(); $data = $uploadsApi->listAssets(1, 1); $playback_restrictions_data = muxvideo_get_data_playback_restrictions(); $ID = ""; createMuxDatabaseTable(); foreach ($data->getData() as $asset) { $asset_data = muxvideo_get_asset_data($asset, $playback_restrictions_data); $ID .= $asset_data['id']; } insertMuxAsset($title, $ID, isset($file_url) ? $file_url : ''); wp_send_json_success([ 'message' => 'Asset saved!', 'title' => $title, 'mux_id' => $ID, 'file_url' => isset($file_url) ? $file_url : '' ]); } add_action('wp_ajax_save_mux_asset_title', 'handle_save_mux_asset_title'); function handle_save_mux_asset_title() { if (!isset($_POST['nonce']) || !wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'mux_token_nonce' )) { wp_send_json_error(array('message' => 'Security verification failed')); return; } require_once MUXVIDEO_PLUGIN_DIR . '/includes/functions.php'; if ( ! current_user_can( 'manage_options' ) ) { wp_send_json_error( 'Insufficient permissions', 403 ); return; } if (empty($_POST['title']) || empty($_POST['mux_id'])) { wp_send_json_error('Uncomplete data.'); } $apiInstance = muxvideo_api_client_init(); $title = sanitize_text_field( wp_unslash( $_POST['title'] ) ); $mux_id = sanitize_text_field( wp_unslash( $_POST['mux_id'] ) ); global $wpdb; // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange $exists = $wpdb->get_var( $wpdb->prepare("SELECT COUNT(*) FROM `{$wpdb->prefix}mux_assets` WHERE mux_id = %s", $mux_id) ); if ($exists) { updateMuxAssetTitle($title, $mux_id); } else { insertMuxAsset($title, $mux_id); } $update_asset_request = [ 'meta' => [ 'title' => $title ] ]; $apiInstance->updateAsset($mux_id, $update_asset_request); wp_send_json_success('Asset guardado'); } function createMuxDatabaseTable() { global $wpdb; $table = $wpdb->prefix . 'mux_assets'; $charset_collate = $wpdb->get_charset_collate(); $sql = "CREATE TABLE $table ( id mediumint(9) NOT NULL AUTO_INCREMENT, title varchar(255) NOT NULL, mux_id varchar(255) NOT NULL, PRIMARY KEY (id) ) $charset_collate;"; require_once(ABSPATH . 'wp-admin/includes/upgrade.php'); dbDelta($sql); } function insertMuxAsset($title, $mux_id) { global $wpdb; $table = $wpdb->prefix . 'mux_assets'; // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange $wpdb->insert( $table, [ 'title' => sanitize_text_field($title), 'mux_id' => sanitize_text_field($mux_id), ], ['%s', '%s'] ); } function updateMuxAssetTitle($title, $mux_id) { global $wpdb; $table = $wpdb->prefix . 'mux_assets'; // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange $wpdb->update( $table, [ 'title' => sanitize_text_field($title),], [ 'mux_id' => sanitize_text_field($mux_id),], ['%s'], ['%s'] ); }