Files

2677 lines
85 KiB
PHP

<?php
/**
* Import / Export.
*
* @link https://plugins360.com
* @since 4.5.2
*
* @package All_In_One_Video_Gallery
*/
// Exit if accessed directly
if ( ! defined( 'WPINC' ) ) {
die;
}
/**
* AIOVG_Admin_Import_Export class.
*
* @since 4.5.2
*/
class AIOVG_Admin_Import_Export {
/**
* Add a settings menu for the plugin.
*
* @since 4.5.2
*/
public function admin_menu() {
add_submenu_page(
'all-in-one-video-gallery',
__( 'All-in-One Video Gallery - Import / Export', 'all-in-one-video-gallery' ),
__( 'Bulk Import / Export', 'all-in-one-video-gallery' ),
'manage_aiovg_options',
'aiovg_import_export',
array( $this, 'display_page' )
);
if ( aiovg_fs()->is_not_paying() ) {
add_submenu_page(
'all-in-one-video-gallery',
'',
'<span class="aiovg-menu-separator"></span>',
'manage_aiovg_options',
'all-in-one-video-gallery-separator-2',
'__return_null'
);
}
}
/**
* Display import / export page.
*
* @since 4.5.2
*/
public function display_page() {
require_once AIOVG_PLUGIN_DIR . 'admin/partials/import-export.php';
}
/**
* AJAX callback to import videos from a folder.
*
* @since 4.5.2
*/
public function ajax_callback_import_folder() {
if ( function_exists( 'set_time_limit' ) ) {
set_time_limit( 1200 );
}
if ( function_exists( 'ignore_user_abort' ) ) {
ignore_user_abort( true );
}
check_ajax_referer( 'aiovg_ajax_nonce', 'security' ); // Verify the nonce for security
if ( ! current_user_can( 'manage_aiovg_options' ) ) {
wp_send_json_error( array( 'error' => esc_html__( 'You do not have sufficient permissions to do this action.', 'all-in-one-video-gallery' ) ) );
}
$response = array();
// Sanitize and extract folder path
$folder = isset( $_POST['folder'] ) ? sanitize_text_field( wp_unslash( $_POST['folder'] ) ) : '';
$resolved_folder_path = $this->resolve_folder_path( $folder );
if ( is_wp_error( $resolved_folder_path ) ) {
wp_send_json_error( array( 'error' => $resolved_folder_path->get_error_message() ) );
}
$base_folder_path = $resolved_folder_path;
// Sanitize options
$include_subfolders = isset( $_POST['include_subfolders'] ) ? (int) $_POST['include_subfolders'] : 0;
$slug_strategy = isset( $_POST['slug_strategy'] ) ? sanitize_key( $_POST['slug_strategy'] ) : 'filename';
$set_featured_image = isset( $_POST['set_featured_image'] ) ? (int) $_POST['set_featured_image'] : 0;
$enable_downloads = isset( $_POST['enable_downloads'] ) ? (int) $_POST['enable_downloads'] : 0;
$enable_comments = isset( $_POST['enable_comments'] ) ? (int) $_POST['enable_comments'] : 0;
$email_capture = isset( $_POST['email_capture'] ) ? (int) $_POST['email_capture'] : -1;
$access_control = isset( $_POST['access_control'] ) ? (int) $_POST['access_control'] : -1;
$restricted_roles = isset( $_POST['restricted_roles'] ) ? array_map( 'sanitize_text_field', $_POST['restricted_roles'] ) : array();
$offset = isset( $_POST['offset'] ) ? (int) $_POST['offset'] : 0;
$limit = isset( $_POST['limit'] ) ? (int) $_POST['limit'] : 20;
// Taxonomies
$categories = array();
if ( isset( $_POST['tax_input'] ) && isset( $_POST['tax_input']['aiovg_categories'] ) ) {
$categories = array_map( 'intval', $_POST['tax_input']['aiovg_categories'] );
}
$tags = array();
if ( isset( $_POST['tax_input'] ) && isset( $_POST['tax_input']['aiovg_tags'] ) ) {
$tags = array_map( 'intval', $_POST['tax_input']['aiovg_tags'] );
}
// Unique ID for this import
$import_id = md5( $folder );
// Find video files
$videos = array();
$matches = array();
$video_extensions = array( 'mp4', 'webm', 'ogv', 'm4v', 'mov' );
$image_extensions = array( 'jpg', 'jpeg', 'png', 'gif', 'webp' );
$current_index = 0;
$processed = 0;
try {
$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator( $base_folder_path, RecursiveDirectoryIterator::SKIP_DOTS ),
RecursiveIteratorIterator::SELF_FIRST
);
foreach ( $iterator as $file ) {
if ( ! $file->isFile() ) {
continue;
}
// Normalize path once per file
$current_folder_path = wp_normalize_path( $file->getPath() );
$file_path = $file->getPathname();
// Skip files from subfolders if not allowed
if ( ! $include_subfolders && $current_folder_path !== $base_folder_path ) {
continue;
}
// Skip early if not a video
$extension = strtolower( $file->getExtension() );
if ( ! in_array( $extension, $video_extensions, true ) ) {
continue;
}
// Respect offset (counting videos only)
if ( $current_index++ < $offset ) {
continue;
}
// Stop when limit is reached
if ( $processed >= $limit ) {
break;
}
// Build base name and title
$file_name = pathinfo( $file_path, PATHINFO_FILENAME );
$post_title = ucwords( preg_replace( '/[-_]+/', ' ', $file_name ) );
// Add video entry
$matches[ $file_name ] = array(
'title' => $post_title,
'video' => $this->make_absolute_url( $file_path )
);
// Try to find matching image in the same folder
foreach ( $image_extensions as $image_extension ) {
$image_path = $current_folder_path. '/' . $file_name . '.' . $image_extension;
if ( file_exists( $image_path ) ) {
$matches[ $file_name ]['image'] = $this->make_absolute_url( $image_path );
$matches[ $file_name ]['image_path'] = $image_path; // Already normalized
break;
}
}
$processed++;
}
} catch ( Exception $e ) {
wp_send_json_error( array( 'error' => $e->getMessage() ) );
}
// Prepare videos for import
foreach ( $matches as $name => $data ) {
if ( empty( $data['video'] ) ) {
continue;
}
$videos[] = array(
'title' => $data['title'],
'src' => $data['video'],
'image' => isset( $data['image'] ) ? $data['image'] : '',
'image_path' => isset( $data['image_path'] ) ? $data['image_path'] : ''
);
}
// Import videos
$imported_data = $this->import_videos_from_folder( $videos, array(
'slug_strategy' => $slug_strategy,
'categories' => $categories,
'tags' => $tags,
'comment_status' => ( ! empty( $enable_comments ) ? 'open' : 'closed' ),
'set_featured_image' => $set_featured_image,
'enable_downloads' => $enable_downloads,
'email_capture' => $email_capture,
'access_control' => $access_control,
'restricted_roles' => $restricted_roles,
'import_id' => $import_id
) );
// Calculate new offset
$new_offset = $offset + $processed;
// Batch processing
if ( $current_index > $new_offset ) {
$message = sprintf(
esc_html__( '%s videos imported, %s excluded as duplicates, and %s failed to import.', 'all-in-one-video-gallery' ),
'%%imported%%',
'%%skipped%%',
'%%failed%%'
);
$response = array(
'step' => 'process',
'message' => $message,
'offset' => $new_offset,
'imported' => $imported_data['imported'],
'skipped' => $imported_data['skipped'],
'failed' => $imported_data['failed']
);
wp_send_json_success( $response );
}
// Build the final response
$message = sprintf(
esc_html__( '%s videos imported, %s excluded as duplicates, and %s failed to import.', 'all-in-one-video-gallery' ),
'%%imported%%',
'%%skipped%%',
'%%failed%%'
);
$message .= sprintf(
' <a href="%s" target="_blank">%s</a>',
esc_url( admin_url( 'edit.php?post_type=aiovg_videos&aiovg_filter=imported&import_id=' . $import_id ) ),
esc_html__( 'Click here to view the imported videos', 'all-in-one-video-gallery' )
);
$response = array(
'step' => 'done',
'message' => $message,
'offset' => $new_offset,
'imported' => $imported_data['imported'],
'skipped' => $imported_data['skipped'],
'failed' => $imported_data['failed']
);
wp_send_json_success( $response ); // Send successful JSON response
}
/**
* AJAX callback to import videos from a csv file.
*
* @since 4.5.2
*/
public function ajax_callback_import_csv() {
if ( function_exists( 'set_time_limit' ) ) {
set_time_limit( 1200 );
}
if ( function_exists( 'ignore_user_abort' ) ) {
ignore_user_abort( true );
}
check_ajax_referer( 'aiovg_ajax_nonce', 'security' ); // Verify the nonce for security
if ( ! current_user_can( 'manage_aiovg_options' ) ) {
wp_send_json_error( array( 'error' => esc_html__( 'You do not have sufficient permissions to do this action.', 'all-in-one-video-gallery' ) ) );
}
// Sanitize and extract parameters
$csv_file = isset( $_POST['csv_file'] ) ? esc_url_raw( $_POST['csv_file'] ) : '';
$zip_file = isset( $_POST['zip_file'] ) ? sanitize_text_field( wp_unslash( $_POST['zip_file'] ) ) : '';
$folder = isset( $_POST['folder'] ) ? sanitize_text_field( wp_unslash( $_POST['folder'] ) ) : '';
$columns_separator = isset( $_POST['columns_separator'] ) ? sanitize_text_field( $_POST['columns_separator'] ) : ',';
$values_separator = isset( $_POST['values_separator'] ) ? sanitize_text_field( $_POST['values_separator'] ) : ';';
$add_new_term = isset( $_POST['add_new_term'] ) ? (int) $_POST['add_new_term'] : 0;
$add_new_user = isset( $_POST['add_new_user'] ) ? (int) $_POST['add_new_user'] : 0;
$set_featured_image = isset( $_POST['set_featured_image'] ) ? (int) $_POST['set_featured_image'] : 0;
$csv_columns = isset( $_POST['csv_columns'] ) ? array_map( 'sanitize_text_field', $_POST['csv_columns'] ) : array();
$offset = isset( $_POST['offset'] ) ? (int) $_POST['offset'] : 0;
$limit = isset( $_POST['limit'] ) ? (int) $_POST['limit'] : 20;
$response = $this->parse_csv( $csv_file, array(
'csv_columns' => $csv_columns,
'columns_separator' => $columns_separator,
'offset' => $offset,
'limit' => $limit
) );
if ( is_wp_error( $response ) ) {
wp_send_json_error( array( 'error' => $response->get_error_message() ) );
}
$videos = $response['videos'];
$has_more = $response['has_more'];
$new_offset = $response['new_offset'];
if ( ! empty( $folder ) ) {
$folder = $this->resolve_folder_path( $folder );
if ( is_wp_error( $folder ) ) {
wp_send_json_error( array( 'error' => $folder->get_error_message() ) );
}
} elseif ( ! empty( $zip_file ) ) {
$folder = $this->resolve_import_directory( $zip_file );
if ( is_wp_error( $folder ) ) {
wp_send_json_error( array( 'error' => $folder->get_error_message() ) );
}
}
// Unique ID for this import
$import_id = md5( $csv_file );
// Import videos
$video_settings = aiovg_get_option( 'aiovg_video_settings' );
$imported_data = $this->import_videos_from_csv( $videos, array(
'folder' => $folder,
'offset' => $offset,
'values_separator' => $values_separator,
'add_new_term' => $add_new_term,
'add_new_user' => $add_new_user,
'set_featured_image' => $set_featured_image,
'comment_status' => ( (int) $video_settings['has_comments'] > 0 ) ? 'open' : 'closed',
'import_id' => $import_id
) );
// Batch processing
if ( $has_more ) {
if ( count( $imported_data['updated'] ) > 0 ) {
$message = sprintf(
esc_html__( '%s videos imported, %s updated, %s excluded as duplicates, and %s failed to import.', 'all-in-one-video-gallery' ),
'%%imported%%',
'%%updated%%',
'%%skipped%%',
'%%failed%%'
);
} else {
$message = sprintf(
esc_html__( '%s videos imported, %s excluded as duplicates, and %s failed to import.', 'all-in-one-video-gallery' ),
'%%imported%%',
'%%skipped%%',
'%%failed%%'
);
}
$response = array(
'step' => 'process',
'message' => $message,
'folder' => $folder,
'offset' => $new_offset,
'imported' => $imported_data['imported'],
'updated' => $imported_data['updated'],
'skipped' => $imported_data['skipped'],
'failed' => $imported_data['failed'],
'errors' => $imported_data['errors']
);
wp_send_json_success( $response );
}
// Delete the attachments before returning the final response
$maybe_attachments = array( $csv_file, $zip_file );
foreach ( $maybe_attachments as $file_path ) {
if ( empty( $file_path ) ) continue;
// Only delete if it's an attachment
$attachment_id = attachment_url_to_postid( $file_path );
if ( $attachment_id ) {
wp_delete_attachment( $attachment_id, true );
}
}
// Build the final response
if ( count( $imported_data['updated'] ) > 0 ) {
$message = sprintf(
esc_html__( '%s videos imported, %s updated, %s excluded as duplicates, and %s failed to import.', 'all-in-one-video-gallery' ),
'%%imported%%',
'%%updated%%',
'%%skipped%%',
'%%failed%%'
);
$message .= sprintf(
' <a href="%s" target="_blank">%s</a>',
esc_url( admin_url( 'edit.php?post_type=aiovg_videos&aiovg_filter=imported&import_id=' . $import_id ) ),
esc_html__( 'Click here to view the imported videos', 'all-in-one-video-gallery' )
);
} else {
$message = sprintf(
esc_html__( '%s videos imported, %s excluded as duplicates, and %s failed to import.', 'all-in-one-video-gallery' ),
'%%imported%%',
'%%skipped%%',
'%%failed%%'
);
$message .= sprintf(
' <a href="%s" target="_blank">%s</a>',
esc_url( admin_url( 'edit.php?post_type=aiovg_videos&aiovg_filter=imported&import_id=' . $import_id ) ),
esc_html__( 'Click here to view the imported videos', 'all-in-one-video-gallery' )
);
}
$response = array(
'step' => 'done',
'message' => $message,
'folder' => $folder,
'offset' => $new_offset,
'imported' => $imported_data['imported'],
'updated' => $imported_data['updated'],
'skipped' => $imported_data['skipped'],
'failed' => $imported_data['failed'],
'errors' => $imported_data['errors']
);
wp_send_json_success( $response ); // Send successful JSON response
}
/**
* AJAX callback to get CSV column mapping fields.
*
* @since 4.5.2
*/
public function ajax_callback_get_csv_columns() {
check_ajax_referer( 'aiovg_ajax_nonce', 'security' ); // Verify the nonce for security
if ( ! current_user_can( 'manage_aiovg_options' ) ) {
wp_send_json_error( array( 'error' => esc_html__( 'You do not have sufficient permissions to do this action.', 'all-in-one-video-gallery' ) ) );
}
// Sanitize and extract parameters.
$csv_file = isset( $_POST['csv_file'] ) ? esc_url_raw( $_POST['csv_file'] ) : '';
$columns_separator = isset( $_POST['columns_separator'] ) ? sanitize_text_field( $_POST['columns_separator'] ) : ',';
$response = $this->parse_csv( $csv_file, array(
'columns_separator' => $columns_separator,
'headers_only' => true
) );
if ( is_wp_error( $response ) ) {
wp_send_json_error( array( 'error' => $response->get_error_message() ) );
}
$csv_headers = $response['headers'];
$csv_columns = $this->get_csv_column_mapping_fields();
$html = '';
foreach ( $csv_headers as $index => $header ) {
$html .= '<div class="aiovg-form-control">';
$html .= sprintf(
'<label for="aiovg-csv_columns-%s" class="aiovg-form-label">%s</label>',
esc_attr( $index ),
esc_html( $header )
);
$html .= sprintf(
'<select name="csv_columns[%s]" id="aiovg-csv_columns-%s" class="widefat">',
esc_attr( $index ),
esc_attr( $index )
);
$html .= sprintf(
'<option value="">— %s —</option>',
esc_html__( 'Select Field', 'all-in-one-video-gallery' )
);
foreach ( $csv_columns as $value => $label ) {
if ( in_array( $value, array( 'post_title', 'video' ), true ) ) {
$label .= ' *'; // Add asterisk for required fields.
}
$html .= sprintf(
'<option value="%s">%s</option>',
esc_attr( $value ),
esc_html( $label )
);
}
$html .= '</select>';
$html .= '</div>';
}
// Send successful JSON response
wp_send_json_success( array( 'html' => $html ) );
}
/**
* AJAX callback to export videos to a CSV file.
*
* @since 4.5.2
*/
public function ajax_callback_export_csv() {
if ( function_exists( 'set_time_limit' ) ) {
set_time_limit( 1200 );
}
if ( function_exists( 'ignore_user_abort' ) ) {
ignore_user_abort( true );
}
check_ajax_referer( 'aiovg_ajax_nonce', 'security' ); // Verify the nonce for security
if ( ! current_user_can( 'manage_aiovg_options' ) ) {
wp_send_json_error( array( 'error' => esc_html__( 'You do not have sufficient permissions to do this action.', 'all-in-one-video-gallery' ) ) );
}
// Sanitize and extract parameters
$offset = isset( $_POST['offset'] ) ? (int) $_POST['offset'] : 0;
$limit = isset( $_POST['limit'] ) ? (int) $_POST['limit'] : 200;
$total = isset( $_POST['total'] ) ? (int) $_POST['total'] : 0;
$timestamp = isset( $_POST['timestamp'] ) ? sanitize_text_field( $_POST['timestamp'] ) : date( 'YmdHis' );
$file_name = isset( $_POST['file_name'] ) ? sanitize_file_name( wp_unslash( $_POST['file_name'] ) ) : '';
$csv_columns = $this->get_csv_column_mapping_fields();
$csv_rows = array();
// Ensure export directory exists
$upload_dir = wp_upload_dir();
$upload_basedir = trailingslashit( $upload_dir['basedir'] );
$upload_baseurl = trailingslashit( $upload_dir['baseurl'] );
$export_dir = $upload_basedir . 'all-in-one-video-gallery/exports/';
$export_url = $upload_baseurl . 'all-in-one-video-gallery/exports/';
if ( ! file_exists( $export_dir ) ) {
if ( ! wp_mkdir_p( $export_dir ) ) {
wp_send_json_error( array( 'error' => __( 'Sorry, we were unable to create the export directory. Please check folder permissions and try again.', 'all-in-one-video-gallery' ) ) );
}
}
// Query videos
$args = array(
'post_type' => 'aiovg_videos',
'post_status' => 'publish',
'posts_per_page' => $limit,
'offset' => $offset,
'orderby' => 'ID',
'order' => 'ASC'
);
if ( $offset > 0 ) {
$args['no_found_rows'] = true; // Only first batch needs total count
}
$aiovg_query = new WP_Query( $args );
if ( ! $aiovg_query->have_posts() ) {
wp_send_json_error( array( 'error' => __( 'Sorry, no videos were found to export.', 'all-in-one-video-gallery' ) ) );
}
// Get total count on first batch
if ( $offset === 0 ) {
$total = $aiovg_query->found_posts;
}
// Loop through videos and build CSV rows
global $post;
while ( $aiovg_query->have_posts() ) {
$aiovg_query->the_post();
$post_id = get_the_ID();
$post_meta = get_post_meta( $post_id );
$row = array();
foreach ( $csv_columns as $field => $column ) {
switch ( $field ) {
case 'post_id':
$row[] = $post_id;
break;
case 'post_title':
$row[] = $post->post_title;
break;
case 'post_content':
$row[] = $post->post_content;
break;
case 'post_excerpt':
$row[] = $post->post_excerpt;
break;
case 'aiovg_categories':
case 'aiovg_tags':
$terms = array();
$terms_ids = wp_get_object_terms( get_the_ID(), $field, array( 'fields' => 'ids' ) );
foreach ( $terms_ids as $term_id ) {
$term_parents_list = get_term_parents_list(
$term_id,
$field,
array(
'separator' => '>',
'link' => false
)
);
$terms[] = rtrim( $term_parents_list, '>' );
}
$row[] = implode( ';', $terms );
break;
case 'video':
$type = isset( $post_meta['type'] ) ? sanitize_text_field( $post_meta['type'][0] ) : 'default';
if ( in_array( $type, array( 'youtube', 'vimeo', 'dailymotion', 'rumble', 'facebook' ) ) ) {
$row[] = isset( $post_meta[ $type ] ) ? aiovg_sanitize_url( $post_meta[ $type ][0] ) : '';
} elseif ( 'adaptive' == $type ) {
$src = isset( $post_meta['hls'] ) ? aiovg_sanitize_url( $post_meta['hls'][0] ) : '';
if ( empty( $src ) ) {
$src = isset( $post_meta['dash'] ) ? aiovg_sanitize_url( $post_meta['dash'][0] ) : '';
}
$row[] = $src;
} elseif ( 'embedcode' == $type ) {
try {
add_filter( 'wp_kses_allowed_html', 'aiovg_allow_iframe_script_tags' );
$row[] = isset( $post_meta['embedcode'] ) ? wp_kses_post( $post_meta['embedcode'][0] ) : '';
} finally {
remove_filter( 'wp_kses_allowed_html', 'aiovg_allow_iframe_script_tags' );
}
} else {
$mp4 = isset( $post_meta['mp4'] ) ? aiovg_sanitize_url( $post_meta['mp4'][0] ) : '';
$sources = isset( $post_meta['sources'] ) ? maybe_unserialize( $post_meta['sources'][0] ) : array();
if ( empty( $sources ) ) {
$row[] = wp_json_encode( array(
'src' => $mp4,
'file' => $this->get_exported_filename( $mp4, $post_id )
) );
} else {
$videos = array();
$videos[] = array(
'src' => $mp4,
'file' => $this->get_exported_filename( $mp4, $post_id ),
'quality' => ( isset( $post_meta['quality_level'] ) ? sanitize_text_field( $post_meta['quality_level'][0] ) : '' )
);
foreach ( $sources as $source ) {
if ( ! empty( $source['src'] ) && ! empty( $source['quality'] ) ) {
$src = aiovg_sanitize_url( $source['src'] );
$videos[] = array(
'src' => $src,
'file' => $this->get_exported_filename( $src, $post_id ),
'quality' => sanitize_text_field( $source['quality'] )
);
}
}
$row[] = wp_json_encode( $videos );
}
}
break;
case 'image':
$image = isset( $post_meta['image'] ) ? aiovg_sanitize_url( $post_meta['image'][0] ) : '';
$image_alt = isset( $post_meta['image_alt'] ) ? sanitize_text_field( $post_meta['image_alt'][0] ) : '';
$row[] = wp_json_encode( array(
'src' => $image,
'file' => $this->get_exported_filename( $image, $post_id ),
'alt' => $image_alt
) );
break;
case 'track':
$tracks = array();
if ( ! empty( $post_meta['track'] ) ) {
foreach ( $post_meta['track'] as $track ) {
$track = maybe_unserialize( $track );
if ( ! empty( $track['src'] ) ) {
$src = aiovg_sanitize_url( $track['src'] );
$tracks[] = array(
'src' => $src,
'file' => $this->get_exported_filename( $src, $post_id ),
'label' => isset( $track['label'] ) ? sanitize_text_field( $track['label'] ) : '',
'srclang' => isset( $track['srclang'] ) ? sanitize_text_field( $track['srclang'] ) : ''
);
}
}
}
$row[] = wp_json_encode( $tracks );
break;
case 'chapter':
$chapters = array();
if ( ! empty( $post_meta['chapter'] ) ) {
foreach ( $post_meta['chapter'] as $chapter ) {
$chapters[] = maybe_unserialize( $chapter );
}
}
$row[] = wp_json_encode( $chapters );
break;
case 'duration':
$row[] = isset( $post_meta['duration'] ) ? sanitize_text_field( $post_meta['duration'][0] ) : '';
break;
case 'views':
case 'likes':
case 'dislikes':
case 'download':
case 'featured':
$row[] = isset( $post_meta[ $field ] ) ? (int) $post_meta[ $field ][0] : 0;
break;
case 'email_capture':
$row[] = isset( $post_meta['email_capture'] ) ? (int) $post_meta['email_capture'][0] : -1;
break;
case 'access_control':
$row[] = isset( $post_meta['access_control'] ) ? (int) $post_meta['access_control'][0] : -1;
break;
case 'restricted_roles':
$restricted_roles = isset( $post_meta['restricted_roles'] ) ? maybe_unserialize( $post_meta['restricted_roles'][0] ) : array();
$restricted_roles = is_array( $restricted_roles ) ? array_map( 'sanitize_text_field', $restricted_roles ) : array();
$row[] = implode( ';', $restricted_roles );
break;
case 'post_date':
$row[] = get_the_date( 'Y-m-d H:i:s' );
break;
case 'post_status':
$row[] = $post->post_status;
break;
case 'comment_status':
$row[] = $post->comment_status;
break;
case 'post_author':
$row[] = get_the_author_meta( 'user_email' );
break;
default:
$row[] = isset( $post_meta[ $field ] ) ? sanitize_text_field( $post_meta[ $field ][0] ) : '';
}
}
$csv_rows[] = $row;
}
wp_reset_postdata();
// Calculate new offset
$new_offset = $offset + count( $aiovg_query->posts );
// Generate file name on first batch
if ( empty( $file_name ) ) {
$file_name = 'aiovg-videos-' . $timestamp . '.csv';
}
$file_path = trailingslashit( $export_dir ) . $file_name;
$file_url = trailingslashit( $export_url ) . $file_name;
// Open file in append mode (or write mode if first batch)
$handle = fopen( $file_path, $offset === 0 ? 'w' : 'a' );
if ( false === $handle ) {
wp_send_json_error( array( 'error' => __( 'Sorry, we were unable to open the CSV file for writing. Please check file permissions and try again.', 'all-in-one-video-gallery' ) ) );
}
// Write header row only for first batch
if ( $offset === 0 ) {
fputcsv( $handle, array_values( $csv_columns ) );
}
// Write CSV rows
foreach ( $csv_rows as $row ) {
fputcsv( $handle, $row );
}
fclose( $handle );
// Batch processing
if ( $new_offset < $total ) {
$message = sprintf(
__( '%d out of %d videos processed', 'all-in-one-video-gallery' ),
$new_offset,
$total
);
$response = array(
'step' => 'process',
'message' => $message,
'offset' => $new_offset,
'total' => $total,
'file_name' => $file_name
);
wp_send_json_success( $response );
}
// Schedule cleanup
$this->schedule_export_directory_cleanup();
// Build the final response
$message = sprintf(
__( 'Your CSV export is complete. %s video records processed successfully. <a href="%s" target="_blank">Click here to download the CSV file</a>.', 'all-in-one-video-gallery' ),
$new_offset,
esc_url( $file_url )
);
$response = array(
'step' => 'done',
'message' => $message,
'offset' => $new_offset,
'total' => $total,
'file_name' => $file_name
);
wp_send_json_success( $response ); // Send successful JSON response
}
/**
* AJAX callback to export videos to ZIP files.
*
* @since 4.5.2
*/
public function ajax_callback_export_zip() {
if ( function_exists( 'set_time_limit' ) ) {
set_time_limit( 1200 );
}
if ( function_exists( 'ignore_user_abort' ) ) {
ignore_user_abort( true );
}
check_ajax_referer( 'aiovg_ajax_nonce', 'security' ); // Verify the nonce for security
if ( ! current_user_can( 'manage_aiovg_options' ) ) {
wp_send_json_error( array( 'error' => esc_html__( 'You do not have sufficient permissions to do this action.', 'all-in-one-video-gallery' ) ) );
}
if ( ! class_exists( 'ZipArchive' ) ) {
wp_send_json_error( array( 'error' => __( 'ZIP creation is not supported on your server. This feature requires the PHP "ZipArchive" class. Please ask your hosting provider to enable the PHP ZIP extension, or upgrade PHP to a version that includes it.', 'all-in-one-video-gallery' ) ) );
}
// Sanitize and extract parameters
$offset = isset( $_POST['offset'] ) ? (int) $_POST['offset'] : 0;
$limit = isset( $_POST['limit'] ) ? (int) $_POST['limit'] : 50;
$total = isset( $_POST['total'] ) ? (int) $_POST['total'] : 0;
$zip_index = isset( $_POST['zip_index'] ) ? (int) $_POST['zip_index'] : 1;
$timestamp = isset( $_POST['timestamp'] ) ? sanitize_text_field( $_POST['timestamp'] ) : date( 'YmdHis' );
$max_size = apply_filters( 'aiovg_export_max_zip_size', 1024 * 1024 * 1024 ); // 1GB default
$zip_files = array();
$skipped = array();
// Ensure export directory exists
$upload_dir = wp_upload_dir();
$upload_basedir = trailingslashit( $upload_dir['basedir'] );
$upload_baseurl = trailingslashit( $upload_dir['baseurl'] );
$export_dir = $upload_basedir . 'all-in-one-video-gallery/exports/';
$export_url = $upload_baseurl . 'all-in-one-video-gallery/exports/';
if ( ! file_exists( $export_dir ) ) {
if ( ! wp_mkdir_p( $export_dir ) ) {
wp_send_json_error( array( 'error' => __( 'Sorry, we were unable to create the export directory. Please check folder permissions and try again.', 'all-in-one-video-gallery' ) ) );
}
}
// Query videos
$args = array(
'post_type' => 'aiovg_videos',
'post_status' => 'publish',
'posts_per_page' => $limit,
'offset' => $offset,
'fields' => 'ids',
'orderby' => 'ID',
'order' => 'ASC',
'update_post_term_cache' => false,
'update_post_meta_cache' => false
);
if ( $offset > 0 ) {
$args['no_found_rows'] = true; // Only first batch needs total count
}
$aiovg_query = new WP_Query( $args );
if ( ! $aiovg_query->have_posts() ) {
wp_send_json_error( array( 'error' => __( 'Sorry, no videos were found to export. Please check your selection and try again.', 'all-in-one-video-gallery' ) ) );
}
// Get total count on first batch
if ( $offset === 0 ) {
$total = $aiovg_query->found_posts;
}
// Process posts and create ZIPs
$added_count = 0;
$added_size = 0;
$zip_name = 'aiovg-videos-' . $timestamp . '-' . $zip_index . '.zip';
$zip_path = trailingslashit( $export_dir ) . $zip_name;
$zip = new ZipArchive();
if ( $zip->open( $zip_path, ZipArchive::CREATE ) !== TRUE ) {
wp_send_json_error( array( 'error' => __( 'Sorry, we were unable to create the ZIP file. Please check folder permissions and try again.', 'all-in-one-video-gallery' ) ) );
}
foreach ( $aiovg_query->posts as $post_id ) {
$files = array();
// Get main video file(s)
$type = get_post_meta( $post_id, 'type', true );
if ( 'default' == $type ) {
$mp4 = get_post_meta( $post_id, 'mp4', true );
if ( ! empty( $mp4 ) && $this->is_file_local( $mp4 ) ) {
$files[] = $mp4;
}
$sources = maybe_unserialize( get_post_meta( $post_id, 'sources', true ) );
if ( ! empty( $sources ) && is_array( $sources ) ) {
foreach ( $sources as $source ) {
if ( ! empty( $source['src'] ) && $this->is_file_local( $source['src'] ) ) {
$files[] = $source['src'];
}
}
}
}
// Get image file
$image = get_post_meta( $post_id, 'image', true );
if ( ! empty( $image ) && $this->is_file_local( $image ) ) {
$files[] = $image;
}
// Get subtitle files
$tracks = get_post_meta( $post_id, 'track' );
if ( ! empty( $tracks ) && is_array( $tracks ) ) {
foreach ( $tracks as $track ) {
$track = maybe_unserialize( $track );
if ( ! empty( $track['src'] ) && $this->is_file_local( $track['src'] ) ) {
$files[] = $track['src'];
}
}
}
// No files found for this video
if ( empty( $files ) ) {
continue;
}
// Move subtitle, image files to the top of the list and video files to the bottom for efficient ZIP compression.
// Remove duplicate entries just in case.
$files = array_reverse( array_unique( $files ) );
// Process each file
foreach ( $files as $file_url ) {
// Convert URL to absolute path
if ( substr( $file_url, 0, strlen( $upload_baseurl ) ) === $upload_baseurl ) {
$file_path = $upload_basedir . substr( $file_url, strlen( $upload_baseurl ) );
} else {
$file_path = ABSPATH . str_replace( site_url( '/' ), '', $file_url );
}
if ( ! file_exists( $file_path ) ) {
continue;
}
$file_size = filesize( $file_path );
// Skip single files larger than max size
if ( $file_size > $max_size ) {
$skipped[] = $file_url;
continue;
}
// If adding this file exceeds max ZIP size, close current ZIP and start a new one
if ( ( $added_size + $file_size ) > $max_size ) {
$zip->close();
$zip_files[] = trailingslashit( $export_url ) . $zip_name;
// Schedule cleanup
$this->schedule_export_directory_cleanup();
// Start new ZIP
$zip_index++;
$added_size = 0;
$zip_name = 'aiovg-videos-' . $timestamp . '-' . $zip_index . '.zip';
$zip_path = trailingslashit( $export_dir ) . $zip_name;
$zip = new ZipArchive();
if ( $zip->open( $zip_path, ZipArchive::CREATE ) !== TRUE ) {
wp_send_json_error( array( 'error' => __( 'Sorry, we were unable to create the ZIP file. Please check folder permissions and try again.', 'all-in-one-video-gallery' ) ) );
}
}
$zip->addFile( $file_path, $this->get_exported_filename( $file_path, $post_id, true ) );
$added_size += $file_size;
$added_count++;
}
}
// Close last ZIP if files were added
if ( $added_count > 0 ) {
$zip->close();
$zip_files[] = trailingslashit( $export_url ) . $zip_name;
// Schedule cleanup
$this->schedule_export_directory_cleanup();
}
wp_reset_postdata();
// Calculate new offset
$new_offset = $offset + count( $aiovg_query->posts );
// Batch processing
if ( $new_offset < $total ) {
$message = sprintf(
__( '%d out of %d videos processed', 'all-in-one-video-gallery' ),
$new_offset,
$total
);
$response = array(
'step' => 'process',
'message' => $message,
'offset' => $new_offset,
'total' => $total,
'zip_index' => $zip_index,
'zip_files' => $zip_files,
'skipped' => $skipped
);
wp_send_json_success( $response );
}
// Build the final response
$message = sprintf(
__( 'Your ZIP export is complete. %s video records processed, and %s skipped.', 'all-in-one-video-gallery' ),
'%%exported%%',
'%%skipped%%'
);
$response = array(
'step' => 'done',
'message' => $message,
'offset' => $new_offset,
'total' => $total,
'zip_index' => $zip_index,
'zip_files' => $zip_files,
'skipped' => $skipped
);
wp_send_json_success( $response ); // Send successful JSON response
}
/**
* AJAX callback to export email leads as a downloadable CSV file.
*
* @since 4.7.6
*/
public function ajax_callback_export_email_leads_csv() {
if ( function_exists( 'set_time_limit' ) ) {
set_time_limit( 1200 );
}
if ( function_exists( 'ignore_user_abort' ) ) {
ignore_user_abort( true );
}
check_ajax_referer( 'aiovg_ajax_nonce', 'security' );
if ( ! current_user_can( 'manage_aiovg_options' ) ) {
wp_send_json_error( array( 'error' => esc_html__( 'You do not have sufficient permissions to do this action.', 'all-in-one-video-gallery' ) ) );
}
$video_id = isset( $_GET['video_id'] ) ? absint( $_GET['video_id'] ) : 0;
$date_from = isset( $_GET['date_from'] ) ? sanitize_text_field( wp_unslash( $_GET['date_from'] ) ) : '';
$date_to = isset( $_GET['date_to'] ) ? sanitize_text_field( wp_unslash( $_GET['date_to'] ) ) : '';
$leads = aiovg_email_capture_get_leads( array(
'video_id' => $video_id,
'date_from' => $date_from,
'date_to' => $date_to
) );
if ( $video_id > 0 ) {
$post = get_post( $video_id );
$slug = ( $post && ! empty( $post->post_name ) ) ? $post->post_name : 'video-' . $video_id;
$file_name = 'aiovg-emails-' . $slug . '-' . date( 'Y-m-d' ) . '.csv';
} else {
$file_name = 'aiovg-emails-' . date( 'Y-m-d' ) . '.csv';
}
aiovg_email_capture_generate_csv( $leads, $file_name );
}
/**
* Hooked cleanup function to delete all files inside the export directory.
*
* @since 4.5.2
*/
public function cleanup_export_directory() {
// Ensure WP_Filesystem is available
if ( ! isset( $GLOBALS['wp_filesystem'] ) || ! is_object( $GLOBALS['wp_filesystem'] ) ) {
require_once ABSPATH . 'wp-admin/includes/file.php';
WP_Filesystem();
}
global $wp_filesystem;
// Path to export directory
$uploads = wp_upload_dir();
$export_dir = trailingslashit( $uploads['basedir'] ) . 'all-in-one-video-gallery/exports/';
if ( $wp_filesystem->is_dir( $export_dir ) ) {
// Get all items (files and subdirectories) inside the folder
$items = $wp_filesystem->dirlist( $export_dir );
foreach ( $items as $item ) {
$path = trailingslashit( $export_dir ) . $item['name'];
// Recursive delete: removes files and subfolders
$wp_filesystem->delete( $path, true );
}
}
}
/**
* Parse CSV data with mapping, offset, and limit support.
*
* @since 4.5.2
* @access private
* @param string $csv_file Path or attachment URL of the CSV file.
* @param array $attributes Import settings.
* @return array|WP_Error Parsed CSV data.
*/
private function parse_csv( $csv_file, $attributes = array() ) {
if ( empty( $csv_file ) ) {
return new WP_Error( 'invalid_csv', __( 'Sorry, the selected file is not a valid CSV. Please upload a valid CSV file.', 'all-in-one-video-gallery' ) );
}
// Default arguments.
$attributes = wp_parse_args( $attributes, array(
'columns_separator' => ',',
'csv_columns' => array(),
'headers_only' => false,
'offset' => 0,
'limit' => 0
) );
$response = array(
'headers' => array(),
'videos' => array(),
'has_more' => false,
'new_offset' => $attributes['offset']
);
$csv_row_number = 0;
// Resolve CSV file path.
$attachment_id = attachment_url_to_postid( $csv_file );
$csv_file_path = $attachment_id ? get_attached_file( $attachment_id ) : '';
if ( ! $csv_file_path || ! file_exists( $csv_file_path ) ) {
return new WP_Error( 'invalid_csv', __( 'Sorry, the selected file is not a valid CSV. Please upload a valid CSV file.', 'all-in-one-video-gallery' ) );
}
if ( ! is_readable( $csv_file_path ) ) {
chmod( $csv_file_path, 0744 );
if ( ! is_readable( $csv_file_path ) ) {
return new WP_Error( 'csv_not_readable', __( 'Sorry, we could not read the selected CSV file. Please check the file and try again.', 'all-in-one-video-gallery' ) );
}
}
if ( function_exists( 'wp_check_filetype' ) ) {
$filetype = wp_check_filetype( $csv_file_path );
if ( empty( $filetype['ext'] ) || 'csv' !== strtolower( $filetype['ext'] ) ) {
return new WP_Error( 'invalid_file_type', __( 'Sorry, this file type is not supported. Please upload a valid CSV file.', 'all-in-one-video-gallery' ) );
}
}
if ( false === ( $handle = fopen( $csv_file_path, 'r' ) ) ) {
return new WP_Error( 'csv_open_failed', __( 'Sorry, we were unable to open the selected CSV file. Please check the file and try again.', 'all-in-one-video-gallery' ) );
}
// Get headers
$headers = fgetcsv( $handle, 0, $attributes['columns_separator'] );
$csv_row_number++;
if ( empty( $headers ) || ! is_array( $headers ) ) {
fclose( $handle );
return new WP_Error( 'invalid_csv_headers', __( 'Sorry, the CSV file does not contain the required column headers. Please check the file and try again.', 'all-in-one-video-gallery' ) );
}
$response['headers'] = array_map( 'trim', $headers );
if ( true === $attributes['headers_only'] ) {
fclose( $handle );
return $response;
}
// Skip until offset
for ( $i = 0; $i < $attributes['offset']; $i++ ) {
if ( feof( $handle ) ) break;
fgetcsv( $handle, 0, $attributes['columns_separator'] );
$csv_row_number++;
}
// Read CSV rows
while ( ! feof( $handle ) ) {
if ( $attributes['limit'] > 0 && count( $response['videos'] ) >= $attributes['limit'] ) {
// Reached limit, stop reading further rows
break;
}
$row = fgetcsv( $handle, 0, $attributes['columns_separator'] );
$csv_row_number++;
if ( $row === false ) {
if ( ! feof( $handle ) ) {
// Malformed row
$response['videos'][] = array(
'number' => $csv_row_number,
'error' => __( 'Malformed CSV row', 'all-in-one-video-gallery' )
);
continue;
} else {
break;
}
}
$post = array( 'number' => $csv_row_number );
// Include empty rows
if ( ! array_filter( $row, 'strlen' ) ) {
$response['videos'][] = $post;
continue;
}
// Map columns
foreach ( $attributes['csv_columns'] as $i => $field ) {
if ( ! empty( $field ) && isset( $row[ $i ] ) ) {
$value = trim( $row[ $i ] );
$decoded = json_decode( $value, true );
if ( json_last_error() === JSON_ERROR_NONE && is_array( $decoded ) ) {
$value = $decoded;
} else {
$value = htmlspecialchars_decode( $value );
}
$post[ $field ] = $value;
}
}
$post = apply_filters( 'aiovg_parse_csv_row', $post, $attributes );
$response['videos'][] = $post;
}
// Peek one extra row to set has_more if needed
if ( ! feof( $handle ) && $attributes['limit'] > 0 ) {
while ( ( $next_row = fgetcsv( $handle, 0, $attributes['columns_separator'] ) ) !== false ) {
if ( array_filter( $next_row, 'strlen' ) ) {
$response['has_more'] = true;
break;
}
}
}
fclose( $handle );
// Calculate next offset for batch import
$response['new_offset'] = $csv_row_number - 1;
return $response;
}
/**
* Resolve import directory from a ZIP file or a folder path.
*
* @since 4.5.2
* @access private
* @param string $zip_file Path or attachment URL of the ZIP file, or folder path.
* @return string|WP_Error Extracted directory path or validated folder path, or WP_Error on failure.
*/
private function resolve_import_directory( $zip_file = '' ) {
if ( empty( $zip_file ) ) {
return new WP_Error( 'invalid_zip', __( 'Sorry, no ZIP file or folder path was provided. Please select a ZIP file or enter a folder path to continue.', 'all-in-one-video-gallery' ) );
}
// CASE 1: Folder path
$folder_path = $this->resolve_folder_path( $zip_file );
if ( ! is_wp_error( $folder_path ) ) {
// Valid folder
return $folder_path;
}
// If folder validation failed with 'invalid_folder', treat it as ZIP
if ( $folder_path->get_error_code() !== 'invalid_folder' ) {
// Any other error (e.g., permissions, invalid location) — stop
return $folder_path;
}
// CASE 2: ZIP attachment
$attachment_id = attachment_url_to_postid( $zip_file );
$zip_file_path = $attachment_id ? get_attached_file( $attachment_id ) : '';
if ( empty( $zip_file_path ) || ! is_file( $zip_file_path ) ) {
return new WP_Error( 'invalid_zip', __( 'Sorry, the selected ZIP file could not be found or read. Please check the file and try again.', 'all-in-one-video-gallery' ) );
}
// Ensure WP_Filesystem is available
if ( ! isset( $GLOBALS['wp_filesystem'] ) || ! is_object( $GLOBALS['wp_filesystem'] ) ) {
require_once ABSPATH . 'wp-admin/includes/file.php';
WP_Filesystem();
}
$uploads = wp_upload_dir();
$zip_file_name = basename( $zip_file_path );
$folder_name = substr( $zip_file_name, 0, strrpos( $zip_file_name, '.' ) );
$default_path = trailingslashit( $uploads['basedir'] ) . 'all-in-one-video-gallery/imports/' . sanitize_file_name( $folder_name );
$extract_path = apply_filters( 'aiovg_import_directory_path', $default_path, array( 'zip_file' => $zip_file ) );
if ( ! wp_mkdir_p( $extract_path ) ) {
return new WP_Error( 'mkdir_failed', __( 'Sorry, we were unable to create the import directory. Please check your folder permissions and try again.', 'all-in-one-video-gallery' ) );
}
// Create protection files safely inside the extract path
$htaccess_file = trailingslashit( $extract_path ) . '.htaccess';
$webconfig_file = trailingslashit( $extract_path ) . 'web.config';
$htaccess_rules = "Deny from all\n";
$webconfig_rules = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
. "<configuration>\n"
. "\t<system.webServer>\n"
. "\t\t<authorization>\n"
. "\t\t\t<deny users=\"*\" />\n"
. "\t\t</authorization>\n"
. "\t</system.webServer>\n"
. "</configuration>";
if ( false === file_put_contents( $htaccess_file, $htaccess_rules ) ) {
return new WP_Error( 'file_write_failed', __( 'We were unable to complete a required file operation. Please make sure your server allows writing files.', 'all-in-one-video-gallery' ) );
}
if ( false === file_put_contents( $webconfig_file, $webconfig_rules ) ) {
return new WP_Error( 'file_write_failed', __( 'We were unable to complete a required file operation. Please make sure your server allows writing files.', 'all-in-one-video-gallery' ) );
}
// Unzip
$unzip_result = unzip_file( $zip_file_path, $extract_path );
if ( is_wp_error( $unzip_result ) ) {
// Remove protection files before returning
unlink( $htaccess_file );
unlink( $webconfig_file );
return $unzip_result;
}
// Keep only files allowed by WordPress MIME validation
$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator( $extract_path, RecursiveDirectoryIterator::SKIP_DOTS ),
RecursiveIteratorIterator::CHILD_FIRST
);
foreach ( $iterator as $file ) {
if ( $file->isFile() ) {
$filetype = wp_check_filetype( $file->getFilename() );
if ( empty( $filetype['type'] ) ) {
unlink( $file->getPathname() );
}
}
}
// Security cleanup
unlink( $htaccess_file );
unlink( $webconfig_file );
return untrailingslashit( $extract_path );
}
/**
* Validate a folder path inside the WordPress directory.
*
* @since 4.5.2
* @access private
* @param string $folder The folder path to validate (relative or absolute).
* @return string|WP_Error Validated and normalized absolute folder path, or WP_Error on failure.
*/
private function resolve_folder_path( $folder ) {
if ( empty( $folder ) ) {
return new WP_Error( 'invalid_folder', __( 'Sorry, the folder path provided is invalid. Please check the path and try again.', 'all-in-one-video-gallery' ) );
}
// Resolve the absolute path
$folder_path = realpath( trailingslashit( ABSPATH ) . ltrim( $folder, '/' ) );
if ( ! $folder_path || ! is_dir( $folder_path ) ) {
return new WP_Error( 'invalid_folder', __( 'Sorry, the folder path provided is invalid. Please check the path and try again.', 'all-in-one-video-gallery' ) );
}
// Normalize and remove trailing slash
$folder_path = untrailingslashit( wp_normalize_path( $folder_path ) );
// Ensure folder is inside the WordPress directory
if ( strpos( $folder_path, wp_normalize_path( ABSPATH ) ) !== 0 ) {
return new WP_Error( 'invalid_folder_location', __( 'Sorry, the folder must be located inside your WordPress directory. Please choose a valid folder and try again.', 'all-in-one-video-gallery' ) );
}
return $folder_path;
}
/**
* Import videos from folder.
*
* @since 4.5.2
* @access private
* @param array $videos Array of videos to import.
* @param array $attributes Import settings.
* @return array $response Array containing import results.
*/
private function import_videos_from_folder( $videos, $attributes = array() ) {
$response = array(
'total' => count( $videos ),
'imported' => array(),
'skipped' => array(),
'failed' => array()
);
if ( empty( $videos ) ) {
return $response;
}
// Pre import
wp_defer_term_counting( true );
wp_defer_comment_counting( true );
// Import videos
foreach ( $videos as $video ) {
// Check if the video post already exists
$post_id = $this->is_video_exists( $video['src'] );
$video_src = aiovg_sanitize_url( $video['src'] );
if ( ! empty( $post_id ) ) {
$response['skipped'][] = $video_src;
continue;
}
// Insert post
$args = array(
'post_type' => 'aiovg_videos',
'post_title' => wp_strip_all_tags( $video['title'] ),
'post_status' => 'publish',
'comment_status' => $attributes['comment_status']
);
if ( 'random' === $attributes['slug_strategy'] ) {
$args['post_name'] = $this->generate_random_video_slug( $video_src );
}
$post_id = wp_insert_post( $args );
// Insert post meta
if ( ! is_wp_error( $post_id ) && ! empty( $post_id ) ) {
// Categories
if ( ! empty( $attributes['categories'] ) ) {
wp_set_object_terms( $post_id, $attributes['categories'], 'aiovg_categories' );
}
// Tags
if ( ! empty( $attributes['tags'] ) ) {
wp_set_object_terms( $post_id, $attributes['tags'], 'aiovg_tags' );
}
// Meta
$meta = array(
'type' => 'default',
'mp4' => $video_src,
'duration' => '',
'featured' => 0,
'views' => 0,
'likes' => 0,
'dislikes' => 0,
'download' => $attributes['enable_downloads'],
'email_capture' => $attributes['email_capture'],
'access_control' => $attributes['access_control'],
'restricted_roles' => $attributes['restricted_roles'],
'import_id' => $attributes['import_id']
);
// Image
if ( ! empty( $video['image'] ) ) {
$meta['image'] = aiovg_sanitize_url( $video['image'] );
if ( ! empty( $attributes['set_featured_image'] ) && ! empty( $video['image_path'] ) ) {
$image_id = $this->create_attachment( $post_id, sanitize_text_field( $video['image_path'] ), $meta['image'] );
if ( ! empty( $image_id ) ) {
$meta['image_id'] = $image_id;
set_post_thumbnail( $post_id, $image_id );
}
}
}
// Insert post meta in bulk
$this->add_post_meta_bulk( $post_id, $meta );
$response['imported'][] = $video_src;
// Hook for developers
do_action( 'aiovg_video_imported', $post_id, $attributes['import_id'] );
} else {
$response['failed'][] = $video_src;
}
}
// Post Import
wp_defer_term_counting( false );
wp_defer_comment_counting( false );
return $response;
}
/**
* Import videos from CSV.
*
* @since 4.5.2
* @access private
* @param array $videos Array of videos to import.
* @param array $attributes Import settings.
* @return array $response Array containing import results.
*/
private function import_videos_from_csv( $videos, $attributes = array() ) {
$response = array(
'total' => count( $videos ),
'imported' => array(),
'updated' => array(),
'skipped' => array(),
'failed' => array(),
'errors' => array()
);
if ( empty( $videos ) ) {
return $response;
}
// Pre import
wp_defer_term_counting( true );
wp_defer_comment_counting( true );
// Import videos
foreach ( $videos as $row ) {
$csv_row_number = (int) $row['number'];
if ( isset( $row['error'] ) && ! empty( $row['error'] ) ) {
$response['failed'][] = $csv_row_number;
$response['errors'][] = sprintf(
__( '<strong>Line #%d:</strong> %s', 'all-in-one-video-gallery' ),
$csv_row_number,
esc_html( $row['error'] )
);
continue;
}
if ( empty( $row['post_title'] ) || empty( $row['video'] ) ) {
$response['failed'][] = $csv_row_number;
$response['errors'][] = sprintf(
__( '<strong>Line #%d:</strong> Invalid video title or source.', 'all-in-one-video-gallery' ),
$csv_row_number
);
continue;
}
// Parse video data
$post_title = wp_strip_all_tags( $row['post_title'] );
$video = $row['video'];
$sources = array();
if ( is_array( $video ) ) {
// Multiple videos array
if ( ! isset( $video['src'] ) ) {
$sources = $video;
$video = array_shift( $sources );
}
} else {
$video = array( 'src' => $video );
}
if ( empty( $video['src'] ) ) {
$response['failed'][] = $csv_row_number;
$response['errors'][] = sprintf(
__( '<strong>Line #%d:</strong> %s - Invalid video source.', 'all-in-one-video-gallery' ),
$csv_row_number,
$post_title
);
continue;
}
// $video['src'] is a simple filename (e.g. video.mp4)
if ( ! empty( $attributes['folder'] ) && preg_match( '/^[a-zA-Z0-9_\-]+\.[a-zA-Z0-9]+$/i', $video['src'] ) ) {
$local_file_path = $attributes['folder'] . '/' . sanitize_file_name( $video['src'] );
if ( file_exists( $local_file_path ) ) {
$video['src'] = $this->make_absolute_url( $local_file_path );
}
}
// Check if the video post already exists
$type = $this->resolve_video_type( $video['src'] );
$post_id = isset( $row['post_id'] ) ? (int) $row['post_id'] : 0;
if ( $post_id > 0 ) {
unset( $row['post_id'] );
$post = get_post( $post_id );
if ( $post && 'aiovg_videos' === $post->post_type ) {
$row['post_id'] = $post_id;
}
}
if ( ! isset( $row['post_id'] ) ) {
$post_id = $this->is_video_exists( $video['src'], $type );
if ( ! empty( $post_id ) ) {
$response['skipped'][] = $csv_row_number;
$response['errors'][] = sprintf(
__( '<strong>Line #%d:</strong> %s - Video already exists.', 'all-in-one-video-gallery' ),
$csv_row_number,
$post_title
);
continue;
}
}
// Insert / Update post
$is_existing_post = false;
$args = array(
'post_type' => 'aiovg_videos',
'post_title' => $post_title
);
if ( isset( $row['post_content'] ) && ! empty( $row['post_content'] ) ) {
$args['post_content'] = wp_kses_post( $row['post_content'] );
}
if ( isset( $row['post_excerpt'] ) && ! empty( $row['post_excerpt'] ) ) {
$args['post_excerpt'] = wp_kses_post( $row['post_excerpt'] );
}
if ( isset( $row['post_date'] ) && ! empty( $row['post_date'] ) ) {
$timestamp = strtotime( $row['post_date'] );
if ( false !== $timestamp ) {
$args['post_date'] = gmdate( 'Y-m-d H:i:s', $timestamp );
}
}
if ( isset( $row['post_status'] ) && ! empty( $row['post_status'] ) ) {
$args['post_status'] = sanitize_text_field( $row['post_status'] );
}
if ( isset( $row['post_author'] ) && ! empty( $row['post_author'] ) ) {
$post_author = $this->resolve_user_id( $row['post_author'], $attributes );
if ( ! is_wp_error( $post_author ) ) {
$args['post_author'] = (int) $post_author;
} else {
$response['errors'][] = sprintf(
__( '<strong>Line #%d:</strong> %s - %s', 'all-in-one-video-gallery' ),
$csv_row_number,
$post_title,
$post_author->get_error_message()
);
}
}
if ( isset( $row['comment_status'] ) && 'open' === strtolower( $row['comment_status'] ) ) {
$args['comment_status'] = 'open';
}
if ( isset( $row['post_id'] ) ) {
// Update the existing video post
$post_id = $row['post_id'];
$args['ID'] = $row['post_id'];
wp_update_post( $args );
$is_existing_post = true;
} else {
if ( ! isset( $row['post_status'] ) || empty( $row['post_status'] ) ) {
$args['post_status'] = 'publish';
}
if ( ! isset( $row['comment_status'] ) || empty( $row['comment_status'] ) ) {
$args['comment_status'] = $attributes['comment_status'];
}
$post_id = wp_insert_post( $args );
}
// Insert post meta
if ( ! is_wp_error( $post_id ) && ! empty( $post_id ) ) {
// Categories
if ( isset( $row['aiovg_categories'] ) ) {
wp_set_object_terms( $post_id, null, 'aiovg_categories' );
if ( ! empty( $row['aiovg_categories'] ) ) {
$categories = $this->resolve_term_ids( $row['aiovg_categories'], 'aiovg_categories', $attributes );
if ( ! is_wp_error( $categories ) ) {
if ( ! empty( $categories ) ) {
wp_set_object_terms( $post_id, $categories, 'aiovg_categories' );
}
} else {
$response['errors'][] = sprintf(
__( '<strong>Line #%d:</strong> %s - %s', 'all-in-one-video-gallery' ),
$csv_row_number,
$post_title,
$categories->get_error_message()
);
}
}
}
// Tags
if ( isset( $row['aiovg_tags'] ) ) {
wp_set_object_terms( $post_id, null, 'aiovg_tags' );
if ( ! empty( $row['aiovg_tags'] ) ) {
$tags = $this->resolve_term_ids( $row['aiovg_tags'], 'aiovg_tags', $attributes );
if ( ! is_wp_error( $tags ) ) {
if ( ! empty( $tags ) ) {
wp_set_object_terms( $post_id, $tags, 'aiovg_tags' );
}
} else {
$response['errors'][] = sprintf(
__( '<strong>Line #%d:</strong> %s - %s', 'all-in-one-video-gallery' ),
$csv_row_number,
$post_title,
$tags->get_error_message()
);
}
}
}
// Subtitles
if ( isset( $row['track'] ) ) {
delete_post_meta( $post_id, 'track' );
if ( is_array( $row['track'] ) ) {
foreach ( $row['track'] as $source ) {
if ( ! empty( $source['src'] ) ) {
$src = $source['src'];
if ( ! empty( $attributes['folder'] ) && preg_match( '/^[a-zA-Z0-9_\-]+\.[a-zA-Z0-9]+$/i', $src ) ) {
// $src is a simple filename (e.g. captions.vtt)
$local_file_path = $attributes['folder'] . '/' . sanitize_file_name( $src );
if ( file_exists( $local_file_path ) ) {
$src = $this->make_absolute_url( $local_file_path );
}
}
if ( ! empty( $attributes['folder'] ) && isset( $source['file'] ) && ! empty( $source['file'] ) ) {
$local_file_path = $attributes['folder'] . '/' . sanitize_file_name( $source['file'] );
if ( file_exists( $local_file_path ) ) {
$src = $this->make_absolute_url( $local_file_path );
}
}
$track = array(
'src' => aiovg_sanitize_url( $src ),
'label' => '',
'srclang' => ''
);
if ( isset( $source['label'] ) && ! empty( $source['label'] ) ) {
$track['label'] = sanitize_text_field( $source['label'] );
}
if ( isset( $source['srclang'] ) && ! empty( $source['srclang'] ) ) {
$track['srclang'] = sanitize_text_field( $source['srclang'] );
}
add_post_meta( $post_id, 'track', $track );
}
}
}
}
// Chapters
if ( isset( $row['chapter'] ) ) {
delete_post_meta( $post_id, 'chapter' );
if ( is_array( $row['chapter'] ) ) {
foreach ( $row['chapter'] as $chapter ) {
if ( ! empty( $chapter['time'] ) && ! empty( $chapter['label'] ) ) {
$chapter = array(
'time' => sanitize_text_field( $chapter['time'] ),
'label' => sanitize_text_field( $chapter['label'] )
);
add_post_meta( $post_id, 'chapter', $chapter );
}
}
}
}
// Import ID
$import_id = sanitize_text_field( $attributes['import_id'] );
if ( ! metadata_exists( 'post', $post_id, 'import_id' ) ) {
add_post_meta( $post_id, 'import_id', $import_id );
} else {
// Meta exists — check if same value
$existing = get_post_meta( $post_id, 'import_id' );
if ( ! in_array( $import_id, $existing ) ) {
add_post_meta( $post_id, 'import_id', $import_id );
}
}
// Meta
$meta = array();
// Type
$meta['type'] = $type;
// Video
if ( in_array( $type, array( 'youtube', 'vimeo', 'dailymotion', 'rumble', 'facebook' ) ) ) {
$meta[ $type ] = aiovg_sanitize_url( $video['src'] );
} elseif ( in_array( $type, array( 'hls', 'dash' ) ) ) {
$meta['type'] = 'adaptive';
$meta[ $type ] = aiovg_sanitize_url( $video['src'] );
} elseif ( 'embedcode' == $type ) {
try {
add_filter( 'wp_kses_allowed_html', 'aiovg_allow_iframe_script_tags' );
$meta[ $type ] = wp_kses_post( $video['src'] );
} finally {
remove_filter( 'wp_kses_allowed_html', 'aiovg_allow_iframe_script_tags' );
}
} else {
$src = $video['src'];
if ( ! empty( $attributes['folder'] ) && isset( $video['file'] ) && ! empty( $video['file'] ) ) {
$local_file_path = $attributes['folder'] . '/' . sanitize_file_name( $video['file'] );
if ( file_exists( $local_file_path ) ) {
$src = $this->make_absolute_url( $local_file_path );
}
}
$meta['mp4'] = aiovg_sanitize_url( $src );
// Quality level
if ( isset( $video['quality'] ) && ! empty( $video['quality'] ) ) {
$meta['quality_level'] = sanitize_text_field( $video['quality'] );
}
}
// Sources
$videos = array();
foreach ( $sources as $source ) {
if ( ! empty( $source['src'] ) && ! empty( $source['quality'] ) ) {
$src = $source['src'];
if ( ! empty( $attributes['folder'] ) && preg_match( '/^[a-zA-Z0-9_\-]+\.[a-zA-Z0-9]+$/i', $src ) ) {
// $src is a simple filename (e.g. video.mp4)
$local_file_path = $attributes['folder'] . '/' . sanitize_file_name( $src );
if ( file_exists( $local_file_path ) ) {
$src = $this->make_absolute_url( $local_file_path );
}
}
if ( ! empty( $attributes['folder'] ) && isset( $source['file'] ) && ! empty( $source['file'] ) ) {
$local_file_path = $attributes['folder'] . '/' . sanitize_file_name( $source['file'] );
if ( file_exists( $local_file_path ) ) {
$src = $this->make_absolute_url( $local_file_path );
}
}
$videos[] = array(
'src' => aiovg_sanitize_url( $src ),
'quality' => sanitize_text_field( $source['quality'] )
);
}
}
$meta['sources'] = $videos;
// Parse image data
$image = '';
$image_path = '';
$image_id = 0;
$image_alt = '';
if ( isset( $row['image'] ) ) {
if ( is_array( $row['image'] ) ) {
if ( isset( $row['image']['src'] ) && ! empty( $row['image']['src'] ) ) {
$image = $row['image']['src'];
}
if ( ! empty( $attributes['folder'] ) && isset( $row['image']['file'] ) && ! empty( $row['image']['file'] ) ) {
$local_file_path = $attributes['folder'] . '/' . sanitize_file_name( $row['image']['file'] );
if ( file_exists( $local_file_path ) ) {
$image = $this->make_absolute_url( $local_file_path );
$image_path = $local_file_path;
}
}
if ( isset( $row['image']['alt'] ) && ! empty( $row['image']['alt'] ) ) {
$image_alt = $row['image']['alt'];
}
} else {
$image = $row['image'];
}
// $image is a simple filename (e.g. image.jpg)
if ( ! empty( $image ) && ! empty( $attributes['folder'] ) && preg_match( '/^[a-zA-Z0-9_\-]+\.[a-zA-Z0-9]+$/i', $image ) ) {
$local_file_path = $attributes['folder'] . '/' . sanitize_file_name( $image );
if ( file_exists( $local_file_path ) ) {
$image = $this->make_absolute_url( $local_file_path );
$image_path = $local_file_path;
}
}
}
$meta['image'] = ! empty( $image ) ? aiovg_sanitize_url( $image ) : '';
$meta['image_alt'] = ! empty( $image_alt ) ? sanitize_text_field( $image_alt ) : '';
// Featured Image
if ( ! empty( $attributes['set_featured_image'] ) ) {
if ( ! empty( $meta['image'] ) ) {
if ( ! empty( $image_path ) ) {
$image_id = $this->create_attachment( $post_id, $image_path, $meta['image'] );
} else {
$image_id = aiovg_create_attachment_from_external_image_url( $meta['image'], $post_id );
}
}
if ( ! empty( $image_id ) ) {
$meta['image_id'] = $image_id;
set_post_thumbnail( $post_id, $image_id );
}
}
// Duration
if ( isset( $row['duration'] ) ) {
$meta['duration'] = '';
if ( ! empty( $row['duration'] ) ) {
$meta['duration'] = sanitize_text_field( $row['duration'] );
}
}
// Views
if ( isset( $row['views'] ) ) {
$meta['views'] = 0;
if ( ! empty( $row['views'] ) ) {
$meta['views'] = (int) $row['views'];
}
}
// Likes
if ( isset( $row['likes'] ) ) {
$meta['likes'] = 0;
if ( ! empty( $row['likes'] ) ) {
$meta['likes'] = (int) $row['likes'];
}
}
// Dislikes
if ( isset( $row['dislikes'] ) ) {
$meta['dislikes'] = 0;
if ( ! empty( $row['dislikes'] ) ) {
$meta['dislikes'] = (int) $row['dislikes'];
}
}
// Download
if ( isset( $row['download'] ) ) {
$meta['download'] = 0;
if ( ! empty( $row['download'] ) ) {
$meta['download'] = (int) $row['download'];
}
}
// Featured
if ( isset( $row['featured'] ) ) {
$meta['featured'] = 0;
if ( ! empty( $row['featured'] ) ) {
$meta['featured'] = (int) $row['featured'];
}
}
// Email Capture
if ( isset( $row['email_capture'] ) ) {
$meta['email_capture'] = -1;
if ( '' !== (string) $row['email_capture'] ) {
$meta['email_capture'] = (int) $row['email_capture'];
}
}
// Access Control
if ( isset( $row['access_control'] ) ) {
$meta['access_control'] = -1;
if ( ! empty( $row['access_control'] ) ) {
$meta['access_control'] = (int) $row['access_control'];
}
}
// Restricted Roles
if ( isset( $row['restricted_roles'] ) ) {
$meta['restricted_roles'] = array();
if ( ! empty( $row['restricted_roles'] ) ) {
$separator = ! empty( $attributes['values_separator'] ) ? $attributes['values_separator'] : ';';
$restricted_roles = array_filter( array_map( 'trim', explode( $separator, $row['restricted_roles'] ) ) );
$meta['restricted_roles'] = array_map( 'sanitize_text_field', $restricted_roles );
}
}
// Insert / Update post meta in bulk
if ( $is_existing_post ) {
$this->update_post_meta_bulk( $post_id, $meta );
$response['updated'][] = $csv_row_number;
} else {
$this->add_post_meta_bulk( $post_id, $meta );
$response['imported'][] = $csv_row_number;
}
// Hook for developers
do_action( 'aiovg_video_imported', $post_id, $attributes['import_id'] );
} else {
$response['failed'][] = $csv_row_number;
$response['errors'][] = sprintf(
__( '<strong>Line #%d:</strong> %s - %s', 'all-in-one-video-gallery' ),
$csv_row_number,
$post_title,
$post_id->get_error_message()
);
}
}
// Post Import
wp_defer_term_counting( false );
wp_defer_comment_counting( false );
return $response;
}
/**
* Check if the video already exists.
*
* @since 4.5.2
* @access private
* @param string $src The video source (URL or embed code).
* @param string $type The video source type.
* @return mixed Video post ID if exists, false if not.
*/
private function is_video_exists( $src, $type = 'default' ) {
if ( empty( $src ) || empty( $type ) ) {
return false;
}
$type = sanitize_key( $type );
$args = array(
'post_type' => 'aiovg_videos',
'post_status' => 'any',
'posts_per_page' => 1,
'fields' => 'ids',
'no_found_rows' => true,
'update_post_term_cache' => false,
'update_post_meta_cache' => false
);
$meta_queries = array();
// Match by video type
$meta_queries[] = array(
'key' => 'type',
'value' => ( in_array( $type, array( 'hls', 'dash' ) ) ? 'adaptive' : $type ),
'compare' => '='
);
// Match by source URL
if ( 'embedcode' === $type ) {
try {
add_filter( 'wp_kses_allowed_html', 'aiovg_allow_iframe_script_tags' );
$meta_queries[] = array(
'key' => 'embedcode',
'value' => wp_kses_post( $src ),
'compare' => '='
);
} finally {
remove_filter( 'wp_kses_allowed_html', 'aiovg_allow_iframe_script_tags' );
}
} else {
$meta_queries[] = array(
'key' => ( 'default' == $type ? 'mp4' : $type ),
'value' => aiovg_sanitize_url( $src ),
'compare' => '='
);
}
// Assign the meta query with 'AND' relation if multiple clauses exist.
if ( count( $meta_queries ) > 1 ) {
$meta_queries['relation'] = 'AND';
}
$args['meta_query'] = $meta_queries;
$aiovg_query = new WP_Query( $args );
if ( $aiovg_query->have_posts() ) {
// Since 'fields' is 'ids', $aiovg_query->posts is an array of post IDs.
return $aiovg_query->posts[0];
}
return false;
}
/**
* Generate a secure, deterministic video post slug.
*
* @since 4.7.0
* @access private
* @param string $video_src Absolute or relative video file path.
* @return string
*/
private function generate_random_video_slug( $video_src ) {
// Normalize path for consistency across environments
$normalized = wp_normalize_path( $video_src );
// Add site-specific salt
$hash = hash( 'sha256', $normalized . '|' . wp_salt( 'aiovg_video_slug' ) );
// Short, URL-safe slug
return substr( $hash, 0, 18 );
}
/**
* Resolve video type.
*
* @since 4.5.2
* @access private
* @param string $src Video source (URL, relative path, or embed code).
* @return string Video type ('default', 'youtube', 'vimeo', etc., or 'embedcode').
*/
private function resolve_video_type( $src ) {
if ( empty( $src ) ) {
return 'default';
}
// Normalize source
$src = trim( $src );
// Check for any HTML markup
if ( preg_match( '/<\s*\w+(?:\b[^>]*)?>/i', $src ) ) {
return 'embedcode';
}
// Check known video platforms
if ( false !== stripos( $src, 'youtube.com' ) || false !== stripos( $src, 'youtu.be' ) ) {
return 'youtube';
} elseif ( false !== stripos( $src, 'vimeo.com' ) ) {
return 'vimeo';
} elseif ( false !== stripos( $src, 'dailymotion.com' ) ) {
return 'dailymotion';
} elseif ( false !== stripos( $src, 'rumble.com' ) ) {
return 'rumble';
} elseif ( false !== stripos( $src, 'facebook.com' ) ) {
return 'facebook';
} else {
$file_type = wp_check_filetype( $src );
if ( 'm3u8' == $file_type['ext'] ) {
return 'hls';
}
if ( 'mpd' == $file_type['ext'] ) {
return 'dash';
}
}
// Default fallback
return 'default';
}
/**
* Resolve term IDs from imported data for a given taxonomy.
*
* Supports hierarchical chains like "Parent > Child > Subchild".
* Can optionally create new terms if they don't exist.
*
* @since 4.5.2
* @access private
* @param array $terms Imported terms array.
* @param string $taxonomy Taxonomy name.
* @param array $attributes Import settings (expects 'values_separator' and 'add_new_term').
* @return array|WP_Error Array of term IDs, or WP_Error on failure.
*/
private function resolve_term_ids( $terms, $taxonomy, $attributes ) {
$term_ids = array();
if ( empty( $terms ) ) {
return $term_ids; // No terms provided, return empty array
}
$separator = ! empty( $attributes['values_separator'] ) ? $attributes['values_separator'] : ';';
$terms_raw = array_filter( array_map( 'trim', explode( $separator, $terms ) ) );
foreach ( $terms_raw as $term_item ) {
// Numeric term IDs
if ( is_numeric( $term_item ) && get_term( (int) $term_item, $taxonomy ) ) {
$term_ids[] = (int) $term_item;
continue;
}
// Hierarchical chain
$chain = array_filter( array_map( 'trim', explode( '>', $term_item ) ) );
if ( empty( $chain ) ) {
continue;
}
$parent_id = 0; // For hierarchy
foreach ( $chain as $term_name ) {
$term_name = htmlspecialchars( sanitize_text_field( $term_name ) ); // Handle &amp; etc.
// Check if term exists
$term = term_exists( $term_name, $taxonomy, $parent_id );
if ( $term ) {
$parent_id = (int) $term['term_id'];
} else {
if ( ! empty( $attributes['add_new_term'] ) ) {
$new_term = wp_insert_term( $term_name, $taxonomy, array( 'parent' => $parent_id ) );
if ( is_wp_error( $new_term ) ) {
return new WP_Error(
'term_insert_failed',
sprintf(
__( 'Failed to create term "%s" in taxonomy "%s".', 'all-in-one-video-gallery' ),
$term_name,
$taxonomy
)
);
}
$parent_id = (int) $new_term['term_id'];
} else {
return new WP_Error(
'term_not_found',
sprintf(
__( 'Term "%s" not found in taxonomy "%s" and adding new terms is disabled.', 'all-in-one-video-gallery' ),
$term_name,
$taxonomy
)
);
}
}
// Append each term in the chain if not already added
if ( $parent_id && ! in_array( $parent_id, $term_ids, true ) ) {
$term_ids[] = $parent_id;
}
}
}
return $term_ids;
}
/**
* Resolve user ID from a username or email, optionally creating a new user.
*
* @since 4.5.2
* @access private
* @param string $post_author WordPress username or email address.
* @param array $attributes Import settings (expects 'add_new_user' boolean).
* @return int|WP_Error User ID on success, WP_Error on failure.
*/
private function resolve_user_id( $post_author, $attributes = array() ) {
if ( empty( $post_author ) ) {
return new WP_Error( 'invalid_user', __( 'No username or email provided.', 'all-in-one-video-gallery' ) );
}
$post_author = sanitize_text_field( $post_author );
// Case 1: Numeric user ID
if ( is_numeric( $post_author ) ) {
$user = get_user_by( 'ID', (int) $post_author );
if ( $user ) {
return $user->ID;
}
return new WP_Error( 'invalid_user', __( 'User ID does not exist.', 'all-in-one-video-gallery' ) );
}
// Case 2: Email
if ( is_email( $post_author ) ) {
$email = sanitize_email( $post_author );
$user = get_user_by( 'email', $email );
if ( $user ) {
return $user->ID;
}
if ( ! empty( $attributes['add_new_user'] ) ) {
$password = wp_generate_password( 12, true );
$new_user_id = wp_create_user( $email, $password, $email );
if ( is_wp_error( $new_user_id ) ) {
return $new_user_id;
}
return $new_user_id;
}
return new WP_Error( 'invalid_user', sprintf( __( 'User with email "%s" does not exist.', 'all-in-one-video-gallery' ), $email ) );
}
// Case 3: Username
$user_id = username_exists( $post_author );
if ( $user_id ) {
return $user_id;
}
return new WP_Error( 'invalid_user', sprintf( __( 'User "%s" does not exist.', 'all-in-one-video-gallery' ), $post_author ) );
}
/**
* Create a WordPress attachment from a local file if it doesn't already exist.
*
* @since 4.5.2
* @access private
* @param int $post_id The post ID to attach the media to (e.g., a video post).
* @param string $file_path Absolute path to the local file.
* @param string $file_url Optional. Public URL of the file (for checking duplicates by URL).
* @return int|false Attachment ID on success, false on failure.
*/
private function create_attachment( $post_id, $file_path, $file_url = '' ) {
if ( ! file_exists( $file_path ) ) {
return false; // File doesn't exist
}
if ( $file_url ) {
// Check via WordPress native function (uploads directory)
if ( $existing_id = attachment_url_to_postid( $file_url ) ) {
return $existing_id;
}
// Check via plugin meta (for external or imported files)
$existing = get_posts( array(
'post_type' => 'attachment',
'post_status' => 'inherit',
'meta_key' => 'aiovg_source_url',
'meta_value' => $file_url,
'fields' => 'ids',
'posts_per_page' => 1
) );
if ( ! empty( $existing ) ) {
return $existing[0];
}
}
// Include required WordPress files
if ( ! function_exists( 'wp_generate_attachment_metadata' ) ) {
require_once ABSPATH . 'wp-admin/includes/image.php';
require_once ABSPATH . 'wp-admin/includes/file.php';
require_once ABSPATH . 'wp-admin/includes/media.php';
}
// Prepare attachment data
$file_name = basename( $file_path );
$file_type = wp_check_filetype( $file_name, null );
// Default to a safe image MIME type if detection fails
$mime_type = ! empty( $file_type['type'] ) ? $file_type['type'] : 'image/jpeg';
$attachment = array(
'guid' => $file_url,
'post_mime_type' => $mime_type,
'post_title' => sanitize_file_name( preg_replace( '/\.[^.]+$/', '', $file_name ) ),
'post_content' => '',
'post_status' => 'inherit'
);
// Insert attachment into WordPress
$attach_id = wp_insert_attachment( $attachment, $file_path, $post_id );
if ( ! $attach_id || is_wp_error( $attach_id ) ) {
return false;
}
// Generate metadata (thumbnails, sizes)
$attach_data = wp_generate_attachment_metadata( $attach_id, $file_path );
wp_update_attachment_metadata( $attach_id, $attach_data );
// Save source URL for plugin-specific imports
if ( $file_url ) {
update_post_meta( $attach_id, 'aiovg_source_url', esc_url_raw( $file_url ) );
}
return $attach_id;
}
/**
* Insert multiple post meta at once.
*
* @since 4.5.2
* @access private
* @param int $post_id Post ID.
* @param array $data Associative array of meta keys and values.
*/
private function add_post_meta_bulk( $post_id, $data ) {
global $wpdb;
$meta_table = _get_meta_table( 'post' );
// Basic sanity check.
if ( empty( $post_id ) || empty( $data ) ) {
return;
}
// Bulk insert all new meta entries.
$placeholders = array();
$values = array();
foreach ( $data as $key => $value ) {
$placeholders[] = "(%d, %s, %s)";
$values[] = $post_id;
$values[] = $key;
$values[] = maybe_serialize( $value );
}
$sql = "INSERT INTO $meta_table (`post_id`, `meta_key`, `meta_value`) VALUES ";
$sql .= implode( ',', $placeholders );
$wpdb->query( $wpdb->prepare( $sql, $values ) );
}
/**
* Update multiple post meta entries at once.
*
* @since 4.5.2
* @access private
* @param int $post_id Post ID.
* @param array $data Associative array of meta keys and values.
* @return void
*/
private function update_post_meta_bulk( $post_id, $data ) {
global $wpdb;
$meta_table = _get_meta_table( 'post' );
// Basic sanity check.
if ( empty( $post_id ) || empty( $data ) ) {
return;
}
// Determine if the DB engine supports transactions (InnoDB).
$supports_transactions = false;
$engine_result = $wpdb->get_row(
$wpdb->prepare( "SHOW TABLE STATUS WHERE Name = %s", $meta_table )
);
if ( $engine_result && isset( $engine_result->Engine ) && strtoupper( $engine_result->Engine ) === 'INNODB' ) {
$supports_transactions = true;
}
// Begin transaction if supported.
if ( $supports_transactions ) {
$wpdb->query( 'START TRANSACTION' );
}
try {
// Step 1: Delete existing meta for the given keys.
$meta_keys = array_keys( $data );
$placeholders = implode( ', ', array_fill( 0, count( $meta_keys ), '%s' ) );
$sql_delete = "DELETE FROM {$meta_table} WHERE post_id = %d AND meta_key IN ($placeholders)";
$wpdb->query( $wpdb->prepare( $sql_delete, array_merge( array( $post_id ), $meta_keys ) ) );
// Step 2: Bulk insert all new meta entries.
$placeholders = array();
$values = array();
foreach ( $data as $key => $value ) {
$placeholders[] = "(%d, %s, %s)";
$values[] = $post_id;
$values[] = $key;
$values[] = maybe_serialize( $value );
}
$sql_insert = "INSERT INTO {$meta_table} (`post_id`, `meta_key`, `meta_value`) VALUES ";
$sql_insert .= implode( ',', $placeholders );
$wpdb->query( $wpdb->prepare( $sql_insert, $values ) );
// Commit if all went well.
if ( $supports_transactions ) {
$wpdb->query( 'COMMIT' );
}
} catch ( Exception $e ) {
// Rollback only works if engine supports transactions.
if ( $supports_transactions ) {
$wpdb->query( 'ROLLBACK' );
}
}
}
/**
* Get CSV column mapping fields.
*
* @since 4.5.2
* @access private
* @return array $fields CSV column mapping fields.
*/
private function get_csv_column_mapping_fields() {
$fields = array(
'post_id' => __( 'Video ID (existing video)', 'all-in-one-video-gallery' ),
'post_title' => __( 'Video Title', 'all-in-one-video-gallery' ),
'video' => __( 'Video File', 'all-in-one-video-gallery' ),
'image' => __( 'Poster Image', 'all-in-one-video-gallery' ),
'post_content' => __( 'Video Description', 'all-in-one-video-gallery' ),
'post_excerpt' => __( 'Video Excerpt', 'all-in-one-video-gallery' ),
'aiovg_categories' => __( 'Video Categories', 'all-in-one-video-gallery' ),
'aiovg_tags' => __( 'Video Tags', 'all-in-one-video-gallery' ),
'track' => __( 'Subtitles', 'all-in-one-video-gallery' ),
'chapter' => __( 'Chapters', 'all-in-one-video-gallery' ),
'duration' => __( 'Video Duration', 'all-in-one-video-gallery' ),
'views' => __( 'Views Count', 'all-in-one-video-gallery' ),
'likes' => __( 'Likes Count', 'all-in-one-video-gallery' ),
'dislikes' => __( 'Dislikes Count', 'all-in-one-video-gallery' ),
'download' => __( 'Enable Download', 'all-in-one-video-gallery' ),
'featured' => __( 'Featured', 'all-in-one-video-gallery' ),
'email_capture' => __( 'Email & Lead Capture', 'all-in-one-video-gallery' ),
'access_control' => __( 'Access Control', 'all-in-one-video-gallery' ),
'restricted_roles' => __( 'Allowed User Roles', 'all-in-one-video-gallery' ),
'comment_status' => __( 'Comment Status', 'all-in-one-video-gallery' ),
'post_status' => __( 'Video Status', 'all-in-one-video-gallery' ),
'post_author' => __( 'Video Author', 'all-in-one-video-gallery' ),
'post_date' => __( 'Published Date', 'all-in-one-video-gallery' )
);
return $fields;
}
/**
* Check if a given URL is local to the WordPress site.
*
* @since 4.5.2
* @access private
* @param string $url The URL to check.
* @return bool True if local, false if external.
*/
private function is_file_local( $url ) {
// Get the hostname of the WordPress site.
$site_host = wp_parse_url( get_home_url(), PHP_URL_HOST );
// Get the hostname from the URL to be checked.
$file_host = wp_parse_url( $url, PHP_URL_HOST );
// If there is no host, it's a relative path and thus local.
if ( null === $file_host ) {
return true;
}
// Compare the hostnames (case-insensitive).
return strcasecmp( $site_host, $file_host ) === 0;
}
/**
* Generate a filename for exported local files.
*
* @since 4.5.2
* @access private
* @param string $file_url The file URL.
* @param int $post_id The post ID.
* @param bool|null $is_local Optional. Whether the file is local. If null, it will be determined automatically.
* @return string|false Generated filename or false if external URL.
*/
private function get_exported_filename( $file_url, $post_id, $is_local = null ) {
if ( $is_local === null ) {
$is_local = $this->is_file_local( $file_url );
}
if ( $is_local ) {
return "$post_id-" . basename( $file_url );
}
return false;
}
/**
* Converts an absolute file system path to a site-relative URL.
*
* @since 4.5.2
* @access private
* @param string $absolute_path Absolute file path.
* @return string File URL or empty string if path is invalid.
*/
private function make_absolute_url( $absolute_path ) {
$absolute_path = wp_normalize_path( $absolute_path );
$abspath = wp_normalize_path( ABSPATH );
if ( stripos( $absolute_path, $abspath ) === 0 ) {
$relative_path = ltrim( substr( $absolute_path, strlen( $abspath ) ), '/' );
return site_url( $relative_path );
}
return '';
}
/**
* Schedule cleanup of the export directory contents.
*
* @since 4.5.2
* @access private
*/
private function schedule_export_directory_cleanup() {
// Unschedule previous cleanup if exists
$timestamp = wp_next_scheduled( 'aiovg_cleanup_export_directory' );
if ( $timestamp ) {
wp_unschedule_event( $timestamp, 'aiovg_cleanup_export_directory' );
}
// Schedule new single-event cleanup
$cleanup_after = apply_filters( 'aiovg_cleanup_export_directory_time', DAY_IN_SECONDS );
wp_schedule_single_event( time() + $cleanup_after, 'aiovg_cleanup_export_directory' );
}
}