'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']
);
}