init();
}
public static function onboarding_is_done() {
return ! self::DEV_ONBOARDING_IS_UNRESTRICTED && (bool) get_option( self::ONBOARDING_DONE_OPTION, false );
}
public static function onboarding_can_prompt_gpt() {
if ( self::DEV_ONBOARDING_IS_UNRESTRICTED ) {
return true;
}
$gpt_prompt_count = (int) get_option( self::ONBOARDING_GPT_PROMPT_COUNT_OPTION, 0 );
return $gpt_prompt_count < self::ONBOARDING_GPT_PROMPT_MAX_COUNT;
}
public static function clear_onboarding_settings() {
update_option( 'blogname', 'VideoPress.tv' );
update_option( 'blogdescription', '' );
delete_option( VideoPressHQAdmin::CATEGORIES_SUGGESTION_OPTION );
delete_option( 'vphq-custom-colors' );
update_option( VideoPressHQAdmin::ONBOARDING_DONE_OPTION, true );
}
public static function onboarding_get_last_gpt_prompt() {
$last_gpt_prompt = get_option( self::ONBOARDING_GPT_LAST_PROMPT_OPTION, '' );
if ( ! is_string( $last_gpt_prompt ) ) {
$last_gpt_prompt = '';
}
return trim( wp_unslash( $last_gpt_prompt ) );
}
private function onboarding_increment_gpt_prompt() {
$prompt_count = get_option( self::ONBOARDING_GPT_PROMPT_COUNT_OPTION, 0 );
if ( ! is_numeric( $prompt_count ) ) {
$prompt_count = 0;
}
$prompt_count++;
update_option( self::ONBOARDING_GPT_PROMPT_COUNT_OPTION, $prompt_count );
}
private function init() {
if ( ! $this->has_videopress_library() ) {
return;
}
$this->init_admin_ajax();
$this->init_admin_menus();
}
private function has_videopress_library() {
return function_exists( 'videopress_is_valid_guid' ) && function_exists( 'videopress_get_video_details' );
}
private function init_admin_ajax() {
add_action( 'wp_ajax_videopress_hq_new_video', array( $this, 'videopress_hq_new_video' ) );
add_action( 'wp_ajax_videopress_hq_add_guid_to_post', array( $this, 'videopress_hq_add_guid_to_post' ) );
add_action( 'wp_ajax_videopress_hq_edit_video', array( $this, 'videopress_hq_edit_video' ) );
add_action( 'wp_ajax_videopress_hq_create_category', array( $this, 'videopress_hq_create_category' ) );
add_action( 'wp_ajax_videopress_hq_delete_video', array( $this, 'videopress_hq_delete_video' ) );
add_action( 'wp_ajax_videopress_hq_toggle_featured_video', array( $this, 'videopress_hq_toggle_featured_video' ) );
add_action( 'wp_ajax_videopress_hq_edit_playlist', array( $this, 'videopress_hq_edit_playlist' ) );
add_action( 'wp_ajax_videopress_hq_delete_playlist', array( $this, 'videopress_hq_delete_playlist' ) );
add_action( 'wp_ajax_videopress_hq_search_videos', array( $this, 'videopress_hq_search_videos' ) );
add_action( 'wp_ajax_videopress_hq_save_appearance', array( $this, 'videopress_hq_save_appearance' ) );
add_action( 'wp_ajax_videopress_hq_onboarding_customize', array( $this, 'videopress_hq_onboarding_customize' ) );
add_action( 'wp_ajax_videopress_hq_onboarding_gpt_prompt', array( $this, 'videopress_hq_onboarding_gpt_prompt' ) );
add_action( 'wp_ajax_videopress_hq_add_category', array( $this, 'videopress_hq_add_category' ) );
add_action( 'wp_ajax_videopress_hq_delete_category', array( $this, 'videopress_hq_delete_category' ) );
add_action( 'wp_ajax_videopress_hq_update_comment_status', array( $this, 'videopress_hq_update_comment_status' ) );
}
private function init_admin_menus() {
add_filter( self::FILTER_ADMIN_TOP_MENUS, array( $this, 'add_top_menus' ) );
add_filter( self::FILTER_ADMIN_BOTTOM_MENUS, array( $this, 'add_bottom_menus' ) );
}
public function add_top_menus( array $menus ) {
if ( current_user_can( VideoPressHQCaps::CAP_READ_DASHBOARD ) ) {
$menus[] = array(
'name' => __( 'Dashboard', 'videopress-hq' ),
'icon' => 'grid',
'pages' => array( 'dashboard' ),
'url' => vphq_admin_page_link( 'dashboard' ),
);
}
if ( current_user_can( VideoPressHQCaps::CAP_EDIT_VIDEOS ) ) {
$menus[] = array(
'name' => __( 'Videos', 'videopress-hq' ),
'icon' => 'capture-video',
'pages' => array( 'manage-videos', 'edit' ),
'url' => vphq_admin_page_link( 'videos' ),
'cap' => VideoPressHQCaps::CAP_EDIT_VIDEOS,
);
}
if ( current_user_can( VideoPressHQCaps::CAP_EDIT_PLAYLISTS ) ) {
$menus[] = array(
'name' => __( 'Playlists', 'videopress-hq' ),
'icon' => 'playlist',
'pages' => array( 'manage-playlists', 'edit-playlist' ),
'url' => vphq_admin_page_link( 'playlists' ),
);
}
if ( current_user_can( 'manage_categories' ) ) {
$menus[] = array(
'name' => __( 'Categories', 'videopress-hq' ),
'icon' => 'file',
'pages' => array( 'manage-categories' ),
'url' => vphq_admin_page_link( 'categories' ),
);
}
if ( current_user_can( 'moderate_comments' ) ) {
$menus[] = array(
'name' => __( 'Comments', 'videopress-hq' ),
'icon' => 'comment',
'pages' => array( 'manage-comments' ),
'url' => vphq_admin_page_link( 'comments' ),
);
}
return $menus;
}
public function add_bottom_menus( array $menus ) {
if ( current_user_can( 'list_users' ) ) {
$menus[] = array(
'name' => __( 'Users', 'videopress-hq' ),
'icon' => 'people',
'url' => admin_url( 'users.php' ),
'ext' => true,
);
}
if ( current_user_can( 'edit_theme_options' ) ) {
$menus[] = array(
'name' => __( 'Appearance', 'videopress-hq' ),
'icon' => 'styles',
'pages' => array( 'appearance' ),
'url' => vphq_admin_page_link( 'appearance' ),
);
}
$is_wpcom = defined( 'IS_WPCOM' ) && IS_WPCOM;
$wpcom_blog_url = '';
if ( $is_wpcom ) {
$wpcom_blog_url = wpcom_get_blog_url( get_blog_details() );
}
if ( ! empty( $wpcom_blog_url ) && current_user_can( 'manage_options' ) ) {
$menus[] = array(
'name' => __( 'Billing', 'videopress-hq' ),
'icon' => 'payment',
'url' => 'https://wordpress.com/purchases/subscriptions/' . urlencode( $wpcom_blog_url ),
'ext' => true,
);
}
if ( current_user_can( 'manage_options' ) ) {
$site_settings_link = admin_url( 'options-general.php' );
if ( ! empty( $wpcom_blog_url ) ) {
$site_settings_link = 'https://wordpress.com/settings/general/' . urlencode( $wpcom_blog_url );
}
$menus[] = array(
'name' => __( 'Site settings', 'videopress-hq' ),
'icon' => 'cog',
'url' => $site_settings_link,
'ext' => true,
);
}
$menus[] = array(
'name' => __( 'Log out', 'videopress-hq' ),
'icon' => '',
'url' => wp_logout_url(),
);
return $menus;
}
public function videopress_hq_new_video() {
if ( ! current_user_can( VideoPressHQCaps::CAP_EDIT_VIDEOS ) ) {
return $this->ajax_response( new WP_Error( 'invalid_permissions', 'You do not have permission to add videos.' ) );
}
if ( ! $this->check_posted_nonce( 'add_video_nonce', 'videopress-hq-add-video' ) ) {
return $this->ajax_response( new WP_Error( 'invalid_nonce', 'Nonce is invalid.' ) );
}
$new_video_details = array(
'post_status' => VideoPressHQPostStatus::STATUS_DRAFT,
'post_type' => 'vp_video',
);
$new_video_id = wp_insert_post( $new_video_details );
if ( is_wp_error( $new_video_id ) ) {
return $this->ajax_response( $new_video_id );
}
$video_link = get_edit_video_link( $new_video_id );
return $this->ajax_response( $video_link );
}
public function videopress_hq_add_guid_to_post() {
if ( ! current_user_can( VideoPressHQCaps::CAP_EDIT_VIDEOS ) ) {
return $this->ajax_response( new WP_Error( 'invalid_permissions', 'You do not have permission to edit videos.' ) );
}
$create_post = ! empty( $_POST['create_post'] );
$post_id = null;
if ( $create_post ) {
if ( ! $this->check_posted_nonce( 'add_video_with_guid_nonce', 'videopress-hq-video-add-guid-new' ) ) {
return $this->ajax_response( new WP_Error( 'invalid_nonce', 'Nonce is invalid.' ) );
}
$new_video_details = array(
'post_status' => VideoPressHQPostStatus::STATUS_PUBLISHED,
'post_type' => 'vp_video',
);
$post_id = wp_insert_post( $new_video_details );
if ( is_wp_error( $post_id ) ) {
return $this->ajax_response( $post_id );
}
} else {
if ( ! isset( $_POST['post_id'] ) ) {
return $this->ajax_response( new WP_Error( 'invalid_post_id', 'Post ID is missing' ) );
}
$post_id = sanitize_text_field( $_POST['post_id'] );
if ( ! $this->check_posted_nonce( 'add_guid_nonce', 'videopress-hq-video-add-guid-' . $post_id ) ) {
return $this->ajax_response( new WP_Error( 'invalid_nonce', 'Nonce is invalid.' ) );
}
$post = get_post( $post_id );
if ( ! $post ) {
return $this->ajax_response( new WP_Error( 'invalid_post_id', 'Post does not exist' ) );
}
}
if ( ! isset( $_POST['guid'] ) ) {
return $this->ajax_response( new WP_Error( 'invalid_guid', 'Invalid GUID' ) );
}
$guid = sanitize_text_field( $_POST['guid'] );
if ( ! videopress_is_valid_guid( $guid ) ) {
return $this->ajax_response( new WP_Error( 'invalid_guid', 'Invalid GUID' ) );
}
$video_details = videopress_hq_get_video_details( $guid );
if ( is_wp_error( $video_details ) ) {
return $this->ajax_response( new WP_Error( 'invalid_guid', 'Invalid GUID' ) );
}
$result = update_post_meta( $post_id, 'guid', $guid );
if ( is_wp_error( $result ) ) {
return $this->ajax_response( $result );
}
if ( $create_post ) {
$title = $video_details->title ?? '';
if ( ! empty( $title ) ) {
wp_update_post(
array(
'ID' => $post_id,
'post_title' => $title,
)
);
}
}
$options = array();
$token = vphq_get_metadata_token_if_required( $guid );
if ( false !== $token ) {
$options['metadata_token'] = $token;
}
$embed_url = generate_embed_url( $guid, $options );
$video_embed = "";
return $this->ajax_response(
array(
'success' => true,
'video_embed' => $video_embed,
'post_id' => $post_id,
)
);
}
/**
* Helper to send a JSON response to an AJAX request.
* @param WP_Error|mixed $data
*/
private function ajax_response( $data ) {
$is_error = is_wp_error( $data );
$data = array(
'success' => ! $is_error,
'data' => $is_error ? $data->get_error_message() : $data,
);
$data = json_encode( $data );
header( 'Content-Type: application/json' );
echo $data;
wp_die();
}
private function check_posted_nonce( $post_name, $nonce_action ) {
if ( ! isset( $_POST[ $post_name ] ) ) {
return false;
}
$nonce = sanitize_text_field( $_POST[ $post_name ] );
return false !== wp_verify_nonce( $nonce, $nonce_action );
}
private function check_geted_nonce( $get_name, $nonce_action ) {
if ( ! isset( $_GET[ $get_name ] ) ) {
return false;
}
$nonce = sanitize_text_field( $_GET[ $get_name ] );
return false !== wp_verify_nonce( $nonce, $nonce_action );
}
public function videopress_hq_edit_video() {
if ( ! current_user_can( VideoPressHQCaps::CAP_EDIT_VIDEOS ) ) {
return $this->ajax_response( new WP_Error( 'invalid_permissions', __( 'You do not have permission to edit videos.', 'videopress-hq' ) ) );
}
if ( ! isset( $_POST['post_id'] ) ) {
return $this->ajax_response( new WP_Error( 'invalid_post_id', __( 'Post ID is missing', 'videopress-hq' ) ) );
}
$post_id = sanitize_text_field( $_POST['post_id'] );
if ( ! $this->check_posted_nonce( 'nonce', 'videopress-hq-video-edit-' . $post_id ) ) {
return $this->ajax_response( new WP_Error( 'invalid_nonce', __( 'Nonce is invalid.', 'videopress-hq' ) ) );
}
$post = get_post( $post_id );
if ( ! $post || 'vp_video' !== $post->post_type ) {
return $this->ajax_response( new WP_Error( 'invalid_post_id', __( 'Post does not exist', 'videopress-hq' ) ) );
}
$publish_status = sanitize_text_field( $_POST['post_status'] ?? '' );
$title = sanitize_text_field( $_POST['title'] );
$content = wp_kses_post( $_POST['content'] );
$post_categories = array();
$categories = @json_decode( stripslashes( $_POST['categories'] ?? '' ), true );
if ( is_array( $categories ) ) {
foreach ( $categories as $category ) {
$category = sanitize_text_field( $category );
if ( ! is_numeric( $category ) ) {
continue;
}
$term = get_term( $category, 'category' );
if ( $term ) {
$post_categories[] = $term->term_id;
}
}
}
$post_updates = array(
'ID' => $post_id,
'post_title' => $title,
);
if ( ! empty( $publish_status ) && current_user_can( VideoPressHQCaps::CAP_PUBLISH_VIDEO, $post_id ) ) {
if ( ! VideoPressHQPostStatus::is_valid_post_status( $publish_status ) ) {
return $this->ajax_response( new WP_Error( 'invalid_post_status', __( 'Invalid post status.', 'videopress-hq' ) ) );
}
$video_guid = get_post_meta( $post_id, 'guid', true );
if ( $video_guid ) {
$this->update_remote_privacy_setting( $video_guid, $publish_status );
}
$post_updates['post_status'] = $publish_status;
}
$post_updates['post_content'] = $content;
$result = wp_update_post( $post_updates, true );
if ( is_wp_error( $result ) ) {
return $this->ajax_response( $result );
}
wp_set_post_categories( $post_id, $post_categories );
$permalink = get_permalink( $post_id );
return $this->ajax_response( $permalink );
}
private function update_remote_privacy_setting( $video_guid, $publish_status ) {
$video_post_id = videopress_get_post_id_by_guid( $video_guid );
if ( ! $video_post_id ) {
return;
}
$post_data = array(
'id' => $video_post_id,
'privacy_setting' => VideoPressHQPostStatus::video_privacy_from_post_status( $publish_status ),
);
if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
$post_data['guid'] = $video_guid;
return Automattic\Jetpack\Connection\Client::wpcom_json_api_request_as_blog(
'videos',
'2',
array(
'method' => 'POST',
'headers' => array( 'content-type' => 'application/json' ),
),
wp_json_encode( $post_data ),
'wpcom'
);
}
$request = new WP_REST_Request( 'POST', '/wpcom/v2/videopress/meta' );
$request->set_header( 'Content-Type', 'application/json' );
$request->set_body( wp_json_encode( $post_data ) );
return rest_do_request( $request );
}
public function videopress_hq_create_category() {
if ( ! current_user_can( 'manage_categories' ) ) {
return $this->ajax_response( new WP_Error( 'invalid_permissions', 'You do not have permission to create categories.' ) );
}
if ( ! $this->check_posted_nonce( 'nonce', 'videopress-hq-create-category' ) ) {
return $this->ajax_response( new WP_Error( 'invalid_nonce', 'Nonce is invalid.' ) );
}
$category_name = filter_input( INPUT_POST, 'category_name' ) ?? '';
$category_name = sanitize_text_field( $category_name );
if ( empty( $category_name ) ) {
return $this->ajax_response( new WP_Error( 'invalid_category_name', 'Category name is empty.' ) );
}
$parent_id = filter_input( INPUT_POST, 'parent', FILTER_VALIDATE_INT );
if ( ! is_numeric( $parent_id ) || $parent_id < 0 ) {
return $this->ajax_response( new WP_Error( 'invalid_parent_id', 'Parent ID is invalid.' ) );
}
$category_id = wp_create_category( $category_name, intval( $parent_id ) );
if ( is_wp_error( $category_id ) ) {
return $this->ajax_response( $category_id );
}
return $this->ajax_response( get_category( $category_id ) );
}
public function videopress_hq_delete_video() {
$post_id = filter_input( INPUT_POST, 'post_id', FILTER_VALIDATE_INT );
if ( ! is_numeric( $post_id ) || $post_id <= 0 ) {
return $this->ajax_response( new WP_Error( 'invalid_post_id', 'Post ID is invalid.' ) );
}
if ( ! current_user_can( VideoPressHQCaps::CAP_DELETE_VIDEO, $post_id ) ) {
return $this->ajax_response( new WP_Error( 'invalid_permissions', 'You do not have permission to delete this video.' ) );
}
if ( ! $this->check_posted_nonce( 'nonce', 'videopress-hq-delete-video_' . $post_id ) ) {
return $this->ajax_response( new WP_Error( 'invalid_nonce', 'Nonce is invalid.' ) );
}
$post = get_post( $post_id );
if ( ! $post ) {
return $this->ajax_response( new WP_Error( 'invalid_post_id', 'Post does not exist' ) );
}
$video_guid = get_post_meta( $post_id, 'guid', true );
if ( $video_guid && preg_match( '/^[a-z0-9]{8,}$/i', $video_guid ) ) {
$video_post_id = videopress_get_post_id_by_guid( $video_guid );
if ( $video_post_id ) {
wp_delete_attachment( $video_post_id );
wp_delete_post( $video_post_id );
}
}
$result = wp_delete_post( $post_id, true );
return $this->ajax_response( is_wp_error( $result ) ? $result : true );
}
public function videopress_hq_toggle_featured_video() {
$post_id = filter_input( INPUT_POST, 'post_id', FILTER_VALIDATE_INT );
if ( ! is_numeric( $post_id ) || $post_id <= 0 ) {
return $this->ajax_response( new WP_Error( 'invalid_post_id', 'Post ID is invalid.' ) );
}
if ( ! current_user_can( VideoPressHQCaps::CAP_EDIT_VIDEO, $post_id ) ) {
return $this->ajax_response( new WP_Error( 'invalid_permissions', 'You do not have permission to edit this video.' ) );
}
if ( ! $this->check_posted_nonce( 'nonce', 'videopress-hq-toggle-featured-video_' . $post_id ) ) {
return $this->ajax_response( new WP_Error( 'invalid_nonce', 'Nonce is invalid.' ) );
}
$post = get_post( $post_id );
if ( ! $post || 'vp_video' !== $post->post_type ) {
return $this->ajax_response( new WP_Error( 'invalid_post_id', 'Post does not exist' ) );
}
$currently_featured_video = (int) get_option( self::FEATURED_VIDEO_OPTION, 0 );
if ( $currently_featured_video === $post_id ) {
delete_option( self::FEATURED_VIDEO_OPTION );
return $this->ajax_response( array( 'is_featured' => false ) );
}
update_option( self::FEATURED_VIDEO_OPTION, $post->ID );
return $this->ajax_response( array( 'is_featured' => true ) );
}
public function videopress_hq_edit_playlist() {
$playlist_id = filter_input( INPUT_POST, 'id', FILTER_VALIDATE_INT );
if ( ! is_numeric( $playlist_id ) || $playlist_id < 0 ) {
return $this->ajax_response( new WP_Error( 'invalid_playlist_id', 'Playlist ID is invalid.' ) );
}
if ( ! $this->check_posted_nonce( 'nonce', 'videopress_hq_save_playlist-' . $playlist_id ) ) {
return $this->ajax_response( new WP_Error( 'invalid_nonce', 'Nonce is invalid.' ) );
}
if ( ! current_user_can( VideoPressHQCaps::CAP_EDIT_PLAYLIST, $playlist_id ) ) {
return $this->ajax_response( new WP_Error( 'invalid_permissions', 'You do not have permission to edit this playlist.' ) );
}
$playlist_name = filter_input( INPUT_POST, 'name' ) ?? '';
$playlist_name = sanitize_text_field( $playlist_name );
if ( empty( $playlist_name ) ) {
return $this->ajax_response( new WP_Error( 'invalid_playlist_name', 'Playlist name is empty.' ) );
}
$playlist_visibility = filter_input( INPUT_POST, 'visibility', FILTER_VALIDATE_INT ) ?? -1;
if ( ! VideoPressHQPlaylist::is_valid_visibility( $playlist_visibility ) ) {
return $this->ajax_response( new WP_Error( 'invalid_playlist_visibility', 'Playlist visibility is invalid.' ) );
}
$playlist_description = filter_input( INPUT_POST, 'description' ) ?? '';
$playlist_description = sanitize_text_field( $playlist_description );
$videos_order = explode( ',', filter_input( INPUT_POST, 'videos' ) );
$videos_order = array_map( 'intval', $videos_order );
$playlist = null;
if ( 0 === $playlist_id ) {
$playlist = VideoPressHQPlaylist::create( $playlist_name, $playlist_description );
} else {
$term = get_term( $playlist_id, VideoPressHQPlaylist::TAXONOMY_NAME );
if ( ! $term ) {
return $this->ajax_response( new WP_Error( 'invalid_playlist_id', 'Playlist does not exist.' ) );
}
$playlist = VideoPressHQPlaylist::from_term( $term );
}
if ( ! $playlist || is_wp_error( $playlist ) ) {
return $this->ajax_response(
is_wp_error( $playlist )
? $playlist
: new WP_Error( 'invalid_playlist', 'Playlist could not be created or updated.' )
);
}
$playlist->term->name = $playlist_name;
$playlist->term->description = $playlist_description;
$playlist->term->term_group = $playlist_visibility;
$playlist->set_items( $videos_order );
$result = $playlist->update();
if ( is_wp_error( $result ) ) {
return $this->ajax_response( $result );
}
return $this->ajax_response( array( 'redirect_uri' => vphq_admin_page_link( 'playlists' ) ) );
}
public function videopress_hq_delete_playlist() {
$playlist_id = filter_input( INPUT_POST, 'id', FILTER_VALIDATE_INT );
if ( ! is_numeric( $playlist_id ) || $playlist_id < 0 ) {
return $this->ajax_response( new WP_Error( 'invalid_playlist_id', 'Playlist ID is invalid.' ) );
}
if ( ! $this->check_posted_nonce( 'nonce', 'videopress_hq_delete_playlist-' . $playlist_id ) ) {
return $this->ajax_response( new WP_Error( 'invalid_nonce', 'Nonce is invalid.' ) );
}
$redirect_uri = vphq_admin_page_link( 'playlists' );
if ( 0 === $playlist_id ) {
return $this->ajax_response( array( 'redirect_uri' => $redirect_uri ) );
}
if ( ! current_user_can( VideoPressHQCaps::CAP_DELETE_PLAYLIST, $playlist_id ) ) {
return $this->ajax_response( new WP_Error( 'invalid_permissions', 'You do not have permission to delete this playlist.' ) );
}
$term = get_term( $playlist_id, VideoPressHQPlaylist::TAXONOMY_NAME );
if ( ! $term ) {
return $this->ajax_response( new WP_Error( 'invalid_playlist_id', 'Playlist does not exist.' ) );
}
$result = VideoPressHQPlaylist::delete( $term );
if ( is_wp_error( $result ) ) {
return $this->ajax_response( $result );
}
return $this->ajax_response( array( 'redirect_uri' => $redirect_uri ) );
}
public function videopress_hq_search_videos() {
$query = filter_input( INPUT_POST, 'query' );
if ( ! $query ) {
return $this->ajax_response( new WP_Error( 'invalid_query', 'Query is empty.' ) );
}
$playlist_id = filter_input( INPUT_POST, 'playlist_id', FILTER_VALIDATE_INT );
if ( ! is_numeric( $playlist_id ) || $playlist_id < 0 ) {
return $this->ajax_response( new WP_Error( 'invalid_playlist_id', 'Playlist ID is invalid.' ) );
}
if ( ! $this->check_posted_nonce( 'nonce', 'videopress_hq_search_videos' ) ) {
return $this->ajax_response( new WP_Error( 'invalid_nonce', 'Nonce is invalid.' ) );
}
if ( ! current_user_can( VideoPressHQCaps::CAP_EDIT_PLAYLIST, $playlist_id ) ) {
return $this->ajax_response( new WP_Error( 'invalid_permissions', 'You do not have permission to edit this playlist.' ) );
}
$videos = array();
// Get all results not in playlist
$post_query = new WP_Query(
array(
'post_type' => 'vp_video',
'posts_per_page' => -1,
's' => $query,
'tax_query' => array(
array(
'taxonomy' => VideoPressHQPlaylist::TAXONOMY_NAME,
'field' => 'term_id',
'terms' => $playlist_id,
'operator' => 'NOT IN',
),
),
)
);
foreach ( $post_query->posts as $post ) {
$videos[] = array(
'id' => $post->ID,
'title' => $post->post_title,
'description' => $post->post_content,
'thumbnail' => get_video_post_thumbnail( $post->ID, 'small' ),
'url' => get_permalink( $post->ID ),
);
}
return $this->ajax_response( array( 'videos' => $videos ) );
}
public function videopress_hq_save_appearance() {
if ( ! current_user_can( 'edit_theme_options' ) ) {
return $this->ajax_response( new WP_Error( 'invalid_permissions', 'You do not have permission to edit theme options.' ) );
}
if ( ! $this->check_posted_nonce( 'nonce', 'videopress_hq_save_appearance' ) ) {
return $this->ajax_response( new WP_Error( 'invalid_nonce', 'Nonce is invalid.' ) );
}
$colors = json_decode( trim( wp_unslash( $_POST['colors'] ?? '' ) ), true );
if ( ! is_array( $colors ) || empty( $colors ) ) {
return $this->ajax_response( new WP_Error( 'invalid_colors', 'Colors are invalid.' ) );
}
$theme_json = WP_Theme_JSON_Resolver::get_theme_data();
$theme_data = $theme_json->get_data();
$theme_colors = $theme_data['settings']['color']['palette'] ?? array();
$available_colors = array();
foreach ( $theme_colors as $color ) {
$available_colors[ $color['slug'] ] = $color['color'];
}
$colors = array_intersect_key( $colors, $available_colors );
if ( empty( $colors ) ) {
return $this->ajax_response( new WP_Error( 'invalid_colors', 'Colors are invalid.' ) );
}
$custom_colors_option = vphq_get_site_custom_colors();
if ( ! is_array( $custom_colors_option ) ) {
$custom_colors_option = array();
}
$new_colors = array_map( 'sanitize_hex_color_with_alpha', $colors );
foreach ( $new_colors as $slug => $color ) {
if ( empty( $color ) ) {
continue;
}
$custom_colors_option[ $slug ] = $color;
}
$custom_colors_option = array_intersect_key( $custom_colors_option, $available_colors );
vphq_update_site_custom_colors( $custom_colors_option );
return $this->ajax_response( array( 'colors' => $custom_colors_option ) );
}
public function videopress_hq_onboarding_customize() {
if ( ! $this->check_posted_nonce( 'nonce', 'videopress_hq_onboarding_customize' ) ) {
return $this->ajax_response( new WP_Error( 'invalid_nonce', 'Nonce is invalid.' ) );
}
$site_title = sanitize_text_field( trim( $_POST['site_title'] ?? '' ) );
if ( empty( $site_title ) ) {
return $this->ajax_response( new WP_Error( 'invalid_site_title', 'Site title is empty.' ) );
}
$site_description = sanitize_text_field( trim( $_POST['site_description'] ?? '' ) );
$categories = @json_decode( stripslashes( $_POST['categories'] ?? '' ), true );
if ( ! is_array( $categories ) ) {
$categories = array();
}
update_option( 'blogname', $site_title );
update_option( 'blogdescription', $site_description );
if ( ! empty( $categories ) ) {
$categories = array_map( 'sanitize_text_field', $categories );
foreach ( $categories as $category ) {
if ( ! is_string( $category ) ) {
continue;
}
$category = trim( $category );
if ( empty( $category ) ) {
continue;
}
if ( category_exists( $category ) ) {
continue;
}
wp_create_category( $category );
}
}
update_option( self::ONBOARDING_DONE_OPTION, true );
return $this->ajax_response( array( 'ok' => true ) );
}
public function videopress_hq_onboarding_gpt_prompt() {
if ( ! defined( 'IS_WPCOM' ) || ! IS_WPCOM ) {
return $this->ajax_response( new WP_Error( 'invalid_permissions', 'This feature is only available on WordPress.com.' ) );
}
if ( ! current_user_can( 'manage_options' ) ) {
return $this->ajax_response( new WP_Error( 'invalid_permissions', 'You do not have permission to edit theme options.' ) );
}
if ( ! $this->check_posted_nonce( 'nonce', 'videopress_hq_onboarding_gpt_prompt' ) ) {
return $this->ajax_response( new WP_Error( 'invalid_nonce', 'Nonce is invalid.' ) );
}
if ( ! self::onboarding_can_prompt_gpt() ) {
return $this->ajax_response( new WP_Error( 'invalid_prompt_count', 'Onboarding prompts are disabled.' ) );
}
$prompt = sanitize_text_field( trim( $_POST['prompt'] ?? '' ) );
$prompt = str_replace( '##STARTTAG##', '', $prompt );
$prompt = str_replace( '##ENDTAG##', '', $prompt );
if ( empty( $prompt ) ) {
return $this->ajax_response( new WP_Error( 'invalid_prompt', 'Prompt is empty.' ) );
}
$prompt_template = $this->get_gpt_prompt();
$prompt = substr( $prompt, 0, 500 );
update_option( self::ONBOARDING_GPT_LAST_PROMPT_OPTION, $prompt );
$prompt = str_replace( '##PROMPT##', $prompt, $prompt_template );
require_lib( 'openai' );
$ai = new OpenAI( 'videopress_tv_onboarding' );
$results = $ai->request_chat_completion(
array(
array(
'role' => 'user',
'content' => $prompt,
),
),
null,
'gpt-4'
);
if ( is_wp_error( $results ) ) {
return $this->ajax_response( $results );
}
$response = $results->choices[0]->message->content ?? '';
if ( empty( $response ) ) {
return $this->ajax_response( new WP_Error( 'invalid_response', 'Response is empty.' ) );
}
$response = @json_decode( $response, true );
if ( ! is_array( $response ) ) {
$response = array();
} else {
$this->onboarding_increment_gpt_prompt();
}
$result = array(
'site_title' => $response['site_title'] ?? '',
'description' => $response['description'] ?? '',
'categories' => $response['categories'] ?? array(),
'primary_color' => $response['primary_color'] ?? '',
'text_color' => $response['text_color'] ?? '',
'accent_color' => $response['accent_color'] ?? '',
'accent_color_light' => $response['accent_color_light'] ?? '',
'border_color' => $response['border_color'] ?? '',
'border_color_light' => $response['border_color_light'] ?? '',
'text_over_accent_color' => $response['text_over_accent_color'] ?? '',
'text_light' => $response['text_light'] ?? '',
'background_ultralight' => $response['background_ultralight'] ?? '',
'text_over_light_background' => $response['text_over_light_background'] ?? '',
'background_transparent' => $response['background_transparent'] ?? '',
);
if ( ! empty( $result['site_title'] ) ) {
$site_title = sanitize_text_field( $result['site_title'] );
update_option( 'blogname', $site_title );
}
if ( ! empty( $result['description'] ) ) {
$description = sanitize_text_field( $result['description'] );
update_option( 'blogdescription', $description );
}
$colors = array();
$this->add_custom_color( $colors, $result['primary_color'], 'custom-page-background-color' );
$this->add_custom_color( $colors, $result['accent_color'], 'custom-accent-color' );
$this->add_custom_color( $colors, $result['accent_color_light'], 'custom-accent-color-light' );
$this->add_custom_color( $colors, $result['border_color'], 'custom-border-color' );
$this->add_custom_color( $colors, $result['border_color_light'], 'custom-border-color-light' );
$this->add_custom_color( $colors, $result['text_color'], 'custom-text-color' );
$this->add_custom_color( $colors, $result['text_over_accent_color'], 'custom-text-over-accent-background' );
$this->add_custom_color( $colors, $result['text_light'], 'custom-text-color-light' );
$this->add_custom_color( $colors, $result['background_ultralight'], 'custom-background-ultralight' );
$this->add_custom_color( $colors, $result['text_over_light_background'], 'custom-text-color-over-light-background' );
$this->add_custom_color( $colors, $result['background_transparent'], 'custom-background-color-dark-transparent' );
if ( ! empty( $result['categories'] ) ) {
$categories = array_map( 'sanitize_text_field', $result['categories'] );
update_option( self::CATEGORIES_SUGGESTION_OPTION, $categories );
}
if ( ! empty( $colors ) ) {
vphq_update_site_custom_colors( $colors );
}
return $this->ajax_response( $result );
}
private function add_custom_color( &$colors, $color, $slug ) {
$color = sanitize_hex_color_with_alpha( $color );
if ( ! empty( $color ) ) {
$colors[ $slug ] = $color;
}
}
private function get_gpt_prompt() {
return <<check_posted_nonce( '_wpnonce_add-category', 'videopress_hq_add_category' ) ) {
wp_die( 'Nonce is invalid.' );
}
$taxonomy_meta = get_taxonomy( 'category' );
if ( ! current_user_can( $taxonomy_meta->cap->manage_terms ) ) {
wp_die( 'The taxonomy does not exist' );
}
$term = get_term_by( 'name', $category_name, 'category' );
if ( $term ) {
// the same name is allowed as long as the parents are different.
if ( $parent_id === $term->parent ) {
wp_die( 'A category with that name already exists' );
}
}
$category = [
'taxonomy' => 'category',
'post_type' => 'vp_video',
'cat_name' => $category_name,
'category_description' => $category_description,
'category_parent' => $parent_id,
];
$result = wp_insert_category( $category );
if ( is_wp_error( $result ) || ! $result ) {
wp_die(
is_wp_error( $result ) ? $result->get_error_message() : $result
);
}
$redirect_uri = vphq_admin_page_link( 'categories' );
return wp_redirect( add_query_arg( 'message', 1, $redirect_uri ) );
}
public function videopress_hq_delete_category() {
$category_id = filter_input( INPUT_GET, 'category_id', FILTER_VALIDATE_INT );
if ( ! is_numeric( $category_id ) || $category_id <= 0 ) {
wp_die( 'Category ID is invalid.' );
}
if ( ! $this->check_geted_nonce( '_wpnonce', 'videopress_hq_delete_category-' . $category_id ) ) {
wp_die( 'Nonce is invalid.' );
}
if ( ! current_user_can( 'delete_term', $category_id ) ) {
wp_die( 'You do not have permission to delete this category.' );
}
$category = get_category( $category_id );
if ( ! $category ) {
wp_die( 'Category does not exist.' );
}
$result = wp_delete_category( $category_id );
if ( is_wp_error( $result ) || ! $result ) {
wp_die(
is_wp_error( $result ) ? $result->get_error_message() : $result
);
}
$redirect_uri = vphq_admin_page_link( 'categories' );
return wp_redirect( add_query_arg( 'message', 2, $redirect_uri ) );
}
public function videopress_hq_update_comment_status() {
$comment_id = filter_input( INPUT_GET, 'comment_id', FILTER_VALIDATE_INT );
$doaction = trim( $_GET['doaction'] ?? '' );
if ( ! is_numeric( $comment_id ) || $comment_id <= 0 ) {
wp_die( 'Comment ID is invalid.' );
}
if ( ! $this->check_geted_nonce( '_wpnonce', 'videopress_hq_update_comment_status-' . $comment_id ) ) {
wp_die( 'Nonce is invalid.' );
}
$redirect_uri = vphq_admin_page_link( 'comments' );
if ( ! current_user_can( 'moderate_comments' ) ) {
wp_die( 'You do not have permission to update this comment.' );
}
$comment = get_comment( $comment_id );
if ( ! $comment ) {
wp_die( 'Comment does not exist.' );
}
$result = null;
// cases replicated from https://github.com/WordPress/wordpress-develop/blob/3bacfc9f978876549ee0e2b5068be02e006d956c/src/wp-admin/edit-comments.php#L84C18-L84C18
switch ( $doaction ) {
case 'approve':
$result = wp_set_comment_status( $comment_id, 'approve' );
break;
case 'unapprove':
$result = wp_set_comment_status( $comment_id, 'hold' );
break;
case 'spam':
$result = wp_spam_comment( $comment_id );
break;
case 'unspam':
$result = wp_unspam_comment( $comment_id );
break;
case 'trash':
$result = wp_trash_comment( $comment_id );
break;
case 'untrash':
$result = wp_untrash_comment( $comment_id );
break;
case 'delete':
$result = wp_delete_comment( $comment_id );
break;
default:
wp_die( "Action is not valid" );
}
if ( is_wp_error( $result ) || ! $result ) {
wp_die(
is_wp_error( $result ) ? $result->get_error_message() : $result
);
}
return wp_redirect( $redirect_uri );
}
}