| @@ -9,26 +9,13 @@ | ||
| 9 | 9 | * @package Wpstream |
| 10 | 10 | * @subpackage Wpstream/admin |
| 11 | 11 | */ |
| 12 | 12 | |
| 13 | - | |
| 14 | -// Exit if accessed directly. | |
| 15 | -if ( ! defined( 'ABSPATH' ) ) { | |
| 16 | - exit; | |
| 17 | -} | |
| 18 | - | |
| 19 | 13 | /** |
| 20 | 14 | * The admin-specific functionality of the plugin. |
| 21 | 15 | * |
| 22 | - * This is the admin "god class": it wires up the whole wp-admin surface of the | |
| 23 | - * plugin. Responsibilities include registering admin CSS/JS, building the | |
| 24 | - * top-level WpStream menu and its sub-pages (Credentials, Channels, Recordings, | |
| 25 | - * Settings, Quick Start), rendering channel/settings/onboarding screens and | |
| 26 | - * their modal dialogs, defining the per-event global streaming options, hooking | |
| 27 | - * into WooCommerce to register the custom stream/VOD product types and their | |
| 28 | - * pricing/metabox behaviour, rendering post metaboxes, driving the multipart S3 | |
| 29 | - * upload AJAX endpoints, and emitting the various admin notices (plugin update, | |
| 30 | - * cache flush, theme, etc.). Many methods echo HTML directly. | |
| 16 | + * Defines the plugin name, version, and two examples hooks for how to | |
| 17 | + * enqueue the admin-specific stylesheet and JavaScript. | |
| 31 | 18 | * |
| 32 | 19 | * @package Wpstream |
| 33 | 20 | * @subpackage Wpstream/admin |
| 34 | 21 | * @author wpstream <office@wpstream.net> |
| @@ -33,20 +20,11 @@ | ||
| 33 | 20 | * @subpackage Wpstream/admin |
| 34 | 21 | * @author wpstream <office@wpstream.net> |
| 35 | 22 | */ |
| 36 | 23 | class Wpstream_Admin { |
| 37 | - | |
| 24 | + | |
| 25 | + | |
| 38 | 26 | /** |
| 39 | - * Most parts a multipart VOD upload may be split into. | |
| 40 | - * | |
| 41 | - * The storage backend assembles at most this many parts, so a larger | |
| 42 | - * split uploads every byte and still can never complete. | |
| 43 | - * | |
| 44 | - * @var int | |
| 45 | - */ | |
| 46 | - const MULTIPART_MAX_PARTS = 1000; | |
| 47 | - | |
| 48 | - /** | |
| 49 | 27 | * Store plugin main class to allow public access. |
| 50 | 28 | * |
| 51 | 29 | * @since 20180622 |
| 52 | 30 | * @var object The main class. |
| @@ -53,1391 +31,646 @@ | ||
| 53 | 31 | */ |
| 54 | 32 | public $main; |
| 55 | 33 | |
| 56 | 34 | |
| 57 | - /** | |
| 58 | - * The ID of this plugin. | |
| 59 | - * | |
| 60 | - * @since 3.0.1 | |
| 61 | - * @access private | |
| 62 | - * @var string $plugin_name The ID of this plugin. | |
| 63 | - */ | |
| 64 | - private $plugin_name; | |
| 35 | + /** | |
| 36 | + * The ID of this plugin. | |
| 37 | + * | |
| 38 | + * @since 3.0.1 | |
| 39 | + * @access private | |
| 40 | + * @var string $plugin_name The ID of this plugin. | |
| 41 | + */ | |
| 42 | + private $plugin_name; | |
| 65 | 43 | |
| 66 | - /** | |
| 67 | - * The version of this plugin. | |
| 68 | - * | |
| 69 | - * @since 3.0.1 | |
| 70 | - * @access private | |
| 71 | - * @var string $version The current version of this plugin. | |
| 72 | - */ | |
| 73 | - private $version; | |
| 44 | + /** | |
| 45 | + * The version of this plugin. | |
| 46 | + * | |
| 47 | + * @since 3.0.1 | |
| 48 | + * @access private | |
| 49 | + * @var string $version The current version of this plugin. | |
| 50 | + */ | |
| 51 | + private $version; | |
| 74 | 52 | |
| 75 | - /** | |
| 76 | - * @var array Definitions of the per-event "global" streaming options (record, | |
| 77 | - * view count, autoplay, encryption, etc.). Each entry holds a | |
| 78 | - * translated label, a help "details" string, and a default value. | |
| 79 | - * Populated lazily on `init` by load_global_event_options(). | |
| 80 | - */ | |
| 81 | - public $global_event_options ; | |
| 53 | + /** | |
| 54 | + * Initialize the class and set its properties. | |
| 55 | + * | |
| 56 | + * @since 3.0.1 | |
| 57 | + * @param string $plugin_name The name of this plugin. | |
| 58 | + * @param string $version The version of this plugin. | |
| 59 | + */ | |
| 60 | + public function __construct( $plugin_name, $version,$plugin_main ) { | |
| 82 | 61 | |
| 62 | + $this->plugin_name = $plugin_name; | |
| 63 | + $this->version = $version; | |
| 64 | + $this->main = $plugin_main; | |
| 83 | 65 | |
| 66 | + } | |
| 84 | 67 | |
| 68 | + /** | |
| 69 | + * Register the stylesheets for the admin area. | |
| 70 | + * | |
| 71 | + * @since 3.0.1 | |
| 72 | + */ | |
| 73 | + public function enqueue_styles() { | |
| 85 | 74 | |
| 75 | + /** | |
| 76 | + * This function is provided for demonstration purposes only. | |
| 77 | + * | |
| 78 | + * An instance of this class should be passed to the run() function | |
| 79 | + * defined in Wpstream_Loader as all of the hooks are defined | |
| 80 | + * in that particular class. | |
| 81 | + * | |
| 82 | + * The Wpstream_Loader will then create the relationship | |
| 83 | + * between the defined hooks and the functions defined in this | |
| 84 | + * class. | |
| 85 | + */ | |
| 86 | + wp_enqueue_style( 'wpestate-roboto', "https://fonts.googleapis.com/css?family=Roboto:300,400,500,600,700,900&display=swap&subset=latin-ext" ); | |
| 87 | + wp_enqueue_style( $this->plugin_name, plugin_dir_url( __FILE__ ) . 'css/wpstream-admin.css', array(), WPSTREAM_PLUGIN_VERSION, 'all' ); | |
| 88 | + | |
| 89 | + } | |
| 86 | 90 | |
| 87 | - /** | |
| 88 | - * Initialize the class and set its properties. | |
| 89 | - * | |
| 90 | - * @since 3.0.1 | |
| 91 | - * @param string $plugin_name The name (ID) of this plugin. | |
| 92 | - * @param string $version The version of this plugin. | |
| 93 | - * @param object $plugin_main The main plugin class instance, kept for public access. | |
| 94 | - * @return void | |
| 95 | - */ | |
| 96 | - public function __construct( $plugin_name, $version,$plugin_main ) { | |
| 91 | + /** | |
| 92 | + * Register the JavaScript for the admin area. | |
| 93 | + * | |
| 94 | + * @since 3.0.1 | |
| 95 | + */ | |
| 96 | + public function enqueue_scripts() { | |
| 97 | 97 | |
| 98 | - // Remember the plugin identity and the main class for later use. | |
| 99 | - $this->plugin_name = $plugin_name; | |
| 100 | - $this->version = $version; | |
| 101 | - $this->main = $plugin_main; | |
| 102 | - | |
| 103 | - // Build the translatable global event options once WP (and its i18n) is ready. | |
| 104 | - add_action('init', array($this, 'load_global_event_options')); | |
| 105 | - } | |
| 106 | - | |
| 107 | - /** | |
| 108 | - * Populate $global_event_options with the translatable per-event settings. | |
| 109 | - * | |
| 110 | - * Deferred to the `init` hook so the esc_html__() translations resolve | |
| 111 | - * against a loaded text domain. | |
| 112 | - * | |
| 113 | - * @return void | |
| 114 | - */ | |
| 115 | - public function load_global_event_options() { | |
| 116 | - // Each key maps to a label/details/default triple used when rendering the event option toggles. | |
| 117 | - $this->global_event_options = array( | |
| 118 | - 'record' => array( | |
| 119 | - 'name' => esc_html__('Record Live Stream','wpstream'), | |
| 120 | - 'details' => esc_html__('If enabled, live streams will be recorded and saved to your library.','wpstream'), | |
| 121 | - 'defaults' => 'no', | |
| 122 | - ), | |
| 123 | - 'view_count' => array( | |
| 124 | - 'name' => esc_html__('Display Viewer Count','wpstream'), | |
| 125 | - 'details' => esc_html__('If enabled, the live viewer count will show up in the player.','wpstream'), | |
| 126 | - 'defaults' => 'yes', | |
| 127 | - ), | |
| 128 | - 'domain_lock' => array( | |
| 129 | - 'name' => esc_html__('Lock To Website','wpstream'), | |
| 130 | - 'details' => sprintf ( esc_html__('If enabled, live video will only display on %1$s, otherwise it can show up on any website.','wpstream'),get_bloginfo('wpurl') ), | |
| 131 | - 'defaults' => 'no', | |
| 132 | - ), | |
| 133 | - 'autoplay' => array( | |
| 134 | - 'name' => esc_html__('Autoplay','wpstream'), | |
| 135 | - 'details' => esc_html__('If enabled, live video will attempt to start playing automatically. This is only achievable in some browsers.','wpstream'), | |
| 136 | - 'defaults' => 'yes', | |
| 137 | - ), | |
| 138 | - 'mute' => array( | |
| 139 | - 'name' => esc_html__('Start Muted','wpstream'), | |
| 140 | - 'details' => esc_html__('If enabled, live video will start muted. This may increase the rate of autoplay in some browsers. ','wpstream'), | |
| 141 | - 'defaults' => 'no', | |
| 142 | - ), | |
| 143 | - 'low_latency' => array( | |
| 144 | - 'name' => esc_html__('Low Latency (beta)','wpstream'), | |
| 145 | - 'details' => esc_html__('Shortens the live delay between streamer and viewers. Useful for interactive applications like gaming, auctions, trading etc. Low latency may worsen the viewer experience on some devices.','wpstream'), | |
| 146 | - 'defaults' => 'no', | |
| 147 | - ), | |
| 148 | - 'adaptive_bitrate' => array( | |
| 149 | - 'name' => esc_html__('Adaptive Bitrate (beta)','wpstream'), | |
| 150 | - 'details' => esc_html__('Ensures a smooth and uninterrupted viewing experience by adjusting video quality for viewers with reduced network speed or device capabilities.','wpstream'), | |
| 151 | - 'defaults' => 'no', | |
| 152 | - ), | |
| 153 | - 'encrypt' =>array( | |
| 154 | - 'name' => esc_html__('Encrypt Live Stream','wpstream'), | |
| 155 | - 'details' => esc_html__('If enabled, video data will be encrypted. Enabling encryption may lead to reduced website performance under certain configurations. Encrypted video may not display in all browsers.','wpstream'), | |
| 156 | - 'defaults' => 'no', | |
| 157 | - ), | |
| 158 | - 'ses_encrypt'=>array( | |
| 159 | - 'name' => esc_html__('Use Sessions with Encryption','wpstream'), | |
| 160 | - 'details' => esc_html__('If enabled, encryption key distribution will be checked against valid user sessions. Setting may malfunction or lead to reduced website performance under certain configurations. ','wpstream'), | |
| 161 | - 'defaults' => 'no', | |
| 162 | - ), | |
| 163 | - ); | |
| 164 | - | |
| 165 | - /** | |
| 166 | - * Filter the catalog of per-channel options shown as toggles. | |
| 167 | - * | |
| 168 | - * Each entry is `key => array( name, details, defaults )`. An added key | |
| 169 | - * renders a toggle on the settings and channel screens; it is stored | |
| 170 | - * only if the Channel Settings Module knows the key. | |
| 171 | - * | |
| 172 | - * @since 4.14.0 | |
| 173 | - * | |
| 174 | - * @param array $options Option catalog keyed by setting. | |
| 175 | - */ | |
| 176 | - $this->global_event_options = (array) apply_filters( 'wpstream_default_event_options', $this->global_event_options ); | |
| 177 | - } | |
| 178 | - | |
| 179 | - /** | |
| 180 | - * Register and enqueue the plugin's admin-area stylesheets. | |
| 181 | - * | |
| 182 | - * Hooked (via Wpstream_Loader) to admin_enqueue_scripts. | |
| 183 | - * | |
| 184 | - * @since 3.0.1 | |
| 185 | - * @return void | |
| 186 | - */ | |
| 187 | - public function enqueue_styles() { | |
| 188 | - | |
| 189 | - /** | |
| 190 | - * This function is provided for demonstration purposes only. | |
| 191 | - * | |
| 192 | - * An instance of this class should be passed to the run() function | |
| 193 | - * defined in Wpstream_Loader as all of the hooks are defined | |
| 194 | - * in that particular class. | |
| 195 | - * | |
| 196 | - * The Wpstream_Loader will then create the relationship | |
| 197 | - * between the defined hooks and the functions defined in this | |
| 198 | - * class. | |
| 199 | - */ | |
| 200 | - // No external webfont: the admin UI falls back to the system font stack | |
| 201 | - // declared in the stylesheets, so no request leaves the site for fonts. | |
| 202 | - // Main admin stylesheet; filemtime() is used as the cache-busting version. | |
| 203 | - wp_enqueue_style( | |
| 204 | - $this->plugin_name, | |
| 205 | - plugin_dir_url( __FILE__ ) . 'css/wpstream-admin.css', | |
| 206 | - array(), | |
| 207 | - filemtime(plugin_dir_path(__FILE__) . 'css/wpstream-admin.css' ), | |
| 208 | - 'all' | |
| 209 | - ); | |
| 210 | - | |
| 211 | - // Ensure the WP media library scripts/styles are available (for logo/image pickers) if not already loaded. | |
| 212 | - if (!did_action('wp_enqueue_media')) { | |
| 213 | - wp_enqueue_media(); | |
| 214 | - } | |
| 215 | - } | |
| 216 | - | |
| 217 | - /** | |
| 218 | - * Register, enqueue and localize the plugin's admin-area JavaScript. | |
| 219 | - * | |
| 220 | - * Enqueues jQuery UI helpers, the fileupload lib, the admin control/upload | |
| 221 | - * scripts, the start-streaming and settings scripts, and the onboarding | |
| 222 | - * bundles. Each script is fed a localized vars array (translated strings, | |
| 223 | - * URLs, nonces, feature flags). Some bundles are only loaded on specific | |
| 224 | - * admin screens. Hooked (via Wpstream_Loader) to admin_enqueue_scripts. | |
| 225 | - * | |
| 226 | - * @since 3.0.1 | |
| 227 | - * @return void | |
| 228 | - */ | |
| 229 | - public function enqueue_scripts() { | |
| 230 | - | |
| 231 | - // jQuery UI widgets used by the settings/date pickers and sliders. | |
| 232 | 98 | wp_enqueue_script("jquery-ui-slider"); |
| 233 | - wp_enqueue_script("jquery-ui-datepicker"); | |
| 234 | - // Blueimp-style file upload library backing the recordings/VOD uploader. | |
| 235 | - wp_enqueue_script('jquery.fileupload', plugin_dir_url( __FILE__ ) .'js/jquery.fileupload.js?v='.time(),array(), WPSTREAM_PLUGIN_VERSION, true); | |
| 99 | + wp_enqueue_script("jquery-ui-datepicker"); | |
| 100 | + wp_enqueue_script('jquery.fileupload', plugin_dir_url( __FILE__ ) .'js/jquery.fileupload.js',array(), WPSTREAM_PLUGIN_VERSION, true); | |
| 101 | + wp_enqueue_script('wpstream-admin-control', plugin_dir_url( __FILE__ ) .'js/admin_control.js',array(), WPSTREAM_PLUGIN_VERSION, true); | |
| 102 | + wp_localize_script('wpstream-admin-control', 'wpstream_admin_control_vars', | |
| 103 | + array( | |
| 104 | + 'admin_url' => get_admin_url(), | |
| 105 | + 'loading_url' => WPSTREAM_PLUGIN_DIR_URL.'/img/loading.gif', | |
| 106 | + 'download_mess' => esc_html__('Click to download!','wpstream'), | |
| 107 | + 'uploading' => esc_html('We are uploading your file.Do not close this window!','wpstream'), | |
| 108 | + 'upload_complete2' => esc_html('Upload Complete! You can upload another file!','wpstream'), | |
| 109 | + 'not_accepted' => esc_html('The file is not an accepted video format','wpstream'), | |
| 110 | + 'upload_complete' => esc_html('Upload Complete!','wpstream'), | |
| 111 | + 'no_band' => esc_html('Not enough bandwidth.','wpsteam'), | |
| 112 | + 'no_band_no_store' => esc_html('Not enough bandwidth or storage.','wpsteam') | |
| 236 | 113 | |
| 237 | - // Shared admin utility helpers, then the main admin control script that drives uploads and channel actions. | |
| 238 | - wp_enqueue_script( 'wpstream-admin-utils', plugin_dir_url( __FILE__ ) .'js/utils/admin_utils.js?v='.time(),array(), WPSTREAM_PLUGIN_VERSION, true); | |
| 239 | - wp_enqueue_script('wpstream-admin-control', plugin_dir_url( __FILE__ ) .'js/admin_control.js?v='.time(),array(), WPSTREAM_PLUGIN_VERSION, true); | |
| 240 | - // Hand the control script all of its translated status strings, the admin URL, and the multipart upload nonce. | |
| 241 | - wp_localize_script('wpstream-admin-control', 'wpstream_admin_control_vars', | |
| 114 | + )); | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + wp_enqueue_script('wpstream-start-streaming_admin', plugin_dir_url( __DIR__ ) .'/public/js/start_streaming.js',array(), WPSTREAM_PLUGIN_VERSION, true); | |
| 119 | + wp_localize_script('wpstream-start-streaming_admin', 'wpstream_start_streaming_vars', | |
| 242 | 120 | array( |
| 243 | - 'admin_url' => get_admin_url(), | |
| 244 | - 'multipart_upload_nonce' => wp_create_nonce( 'wpstream_multipart_upload_nonce' ), | |
| 245 | - 'recordings_nonce' => wp_create_nonce( 'wpstream_recordings_nonce' ), | |
| 246 | - 'loading_url' => WPSTREAM_PLUGIN_DIR_URL.'/img/loading.gif', | |
| 247 | - 'download_mess' => esc_html__('Click to download!','wpstream'), | |
| 248 | - 'uploading' => esc_html__('We are uploading your file. Do not close this window!','wpstream'), | |
| 249 | - 'upload_complete2' => esc_html__('Upload Complete! You can upload another file!','wpstream'), | |
| 250 | - 'not_accepted' => esc_html__('The file is not an accepted video format','wpstream'), | |
| 251 | - 'upload_complete' => esc_html__('Upload Complete!','wpstream'), | |
| 252 | - 'no_band' => esc_html__('Not enough streaming data.','wpstream'), | |
| 253 | - 'no_band_no_store' => esc_html__('Not enough streaming data or storage.','wpstream'), | |
| 254 | - 'no_streaming_hours' => esc_html__('Not enough streaming hours.','wpstream'), | |
| 255 | - 'exceeding_limit' => esc_html__('File size exceeds 5GB. Initiating multipart upload...','wpstream'), | |
| 256 | - 'upload_failed' => esc_html__('Upload Failed!','wpstream'), | |
| 257 | - 'upload_failed2' => esc_html__('Upload Failed! Please Try again!','wpstream'), | |
| 258 | - 'choose_a_file' => esc_html__('Choose a file…','wpstream'), | |
| 259 | - 'preparing_multipart' => esc_html__('Preparing multipart upload...','wpstream'), | |
| 260 | - 'uploading_part' => esc_html__('Uploading part {part} of {total}...','wpstream'), | |
| 261 | - 'upload_failed_part' => esc_html__('Failed to upload part {part}. Please try again.','wpstream'), | |
| 262 | - 'completing_upload' => esc_html__('Completing upload. Please wait...','wpstream'), | |
| 263 | - 'upload_failed_part_retry' => esc_html__('Failed to upload part {part}. Retrying...','wpstream'), | |
| 264 | - 'choose_recording' => esc_html__( 'Choose Recording', 'wpstream' ), | |
| 265 | - 'select_recording' => esc_html__( 'Please select a recording from the list', 'wpstream' ), | |
| 266 | - 'invalid_response' => esc_html__('Invalid response from server. Missing required upload data.', 'wpstream'), | |
| 267 | - 'video_processing' => esc_html__( 'The video is still processing', 'wpstream' ), | |
| 268 | - 'file_name_text' => esc_html__('File Name:','wpstream'), | |
| 269 | - 'channel_create_error' => esc_html__('Something did not work. Please try again.', 'wpstream'), | |
| 270 | - 'select_caption_file' => esc_html__('Select .vtt Captions File', 'wpstream'), | |
| 271 | - 'select_button' => esc_html__('Select', 'wpstream'), | |
| 272 | - 'remove_button' => esc_html__('Remove', 'wpstream'), | |
| 273 | - 'use_streaming_hours' => $this->main->quota_manager->get_streaming_ui_flags_from_cache()['use_streaming_hours'], | |
| 121 | + 'admin_url' => get_admin_url(), | |
| 122 | + 'loading_url' => WPSTREAM_PLUGIN_DIR_URL.'/img/loading.gif', | |
| 123 | + 'download_mess' => esc_html__('Click to download!','wpstream'), | |
| 124 | + 'uploading' => esc_html('We are uploading your file.Do not close this window!','wpstream'), | |
| 125 | + 'upload_complete2' => esc_html('Upload Complete! You can upload another file!','wpstream'), | |
| 126 | + 'not_accepted' => esc_html('The file is not an accepted video format','wpstream'), | |
| 127 | + 'upload_complete' => esc_html('Upload Complete!','wpstream'), | |
| 128 | + 'no_band' => esc_html('Not enough bandwidth.','wpsteam'), | |
| 129 | + 'no_band_no_store' => esc_html('Not enough bandwidth or storage.','wpsteam') | |
| 130 | + | |
| 274 | 131 | )); |
| 275 | 132 | |
| 276 | - // Recordings list script + its localized labels and the "create VOD from recording" links (free vs paid depending on WooCommerce). | |
| 277 | - wp_enqueue_script('wpstream-recordings-videos-list', plugin_dir_url( __FILE__ ) .'js/recordings_videos_list.js?v='.time(),array(), WPSTREAM_PLUGIN_VERSION, true); | |
| 278 | - wp_localize_script( 'wpstream-recordings-videos-list', 'wpstream_recordings_videos_list_vars', | |
| 279 | - array( | |
| 280 | - 'delete_file' => esc_html__('Delete file', 'wpstream'), | |
| 281 | - 'download' => esc_html__( 'Download', 'wpstream'), | |
| 282 | - 'download_available' => esc_html__( 'Click to download! The url will work for the next 20 minutes!', 'wpstream'), | |
| 283 | - 'add_free_video_url' => esc_url( admin_url( 'post-new.php?post_type=wpstream_product_vod') . '&new_video_name=' ), | |
| 284 | - 'create_ftv_vod' => esc_html__( 'Create new Free-To-View VOD from this recording' , 'wpstream' ), | |
| 285 | - 'woocommerce_exists' => class_exists( 'WooCommerce' ), | |
| 286 | - 'add_paid_video_url' => esc_url( admin_url( 'post-new.php?post_type=product').'&new_video_name=' ), | |
| 287 | - 'create_ptv_vod' => esc_html__( 'Create new Pay-Per-View VOD from this recording' , 'wpstream' ), | |
| 288 | - ) | |
| 289 | - ); | |
| 290 | - | |
| 291 | - | |
| 292 | - // Settings-page script with its save/logo-picker strings and the broadcaster page URL. | |
| 293 | - wp_enqueue_script('wpstream-settings', plugin_dir_url( __DIR__ ) .'/admin/js/wpstream_settings.js?v='.time(),array(), WPSTREAM_PLUGIN_VERSION, true); | |
| 294 | - wp_localize_script('wpstream-settings', 'wpstream_settings_vars', array( | |
| 295 | - 'error_message' => esc_html__( 'Failed to save settings. Please try again.', 'wpstream'), | |
| 296 | - 'choose_image_text' => esc_html__( 'Choose Logo Image', 'wpstream'), | |
| 297 | - 'select_image_text' => esc_html__( 'Select Image', 'wpstream'), | |
| 298 | - 'update_successful' => esc_html__( 'Update Successful.', 'wpstream'), | |
| 299 | - 'update_failed' => esc_html__( 'Something went wrong. Try again.', 'wpstream'), | |
| 300 | - 'broadcaster_url' => esc_url( esc_url(home_url('/broadcaster-page/') ) ), | |
| 301 | - )); | |
| 302 | - | |
| 303 | - | |
| 304 | - // Identify the current admin screen so screen-specific bundles load only where needed. | |
| 305 | - $current_screen=get_current_screen(); | |
| 306 | - | |
| 307 | - // On the credentials/channels/recordings/onboard screens, load the quota widget updater. | |
| 308 | - if ( in_array( $current_screen->base, ['toplevel_page_wpstream_credentials', 'wpstream_page_wpstream_live_channels', 'wpstream_page_wpstream_recordings', 'wpstream_page_wpstream_onboard'] ) ) { | |
| 309 | - wp_enqueue_script( 'wpstream-user-quota-update', plugin_dir_url( __DIR__ ) . 'admin/js/wpstream-user-quota.js', array(), WPSTREAM_PLUGIN_VERSION, true ); | |
| 310 | - wp_localize_script( 'wpstream-user-quota-update', 'wpstream_user_quota_vars', array( | |
| 311 | - 'admin_url' => get_admin_url() | |
| 312 | - )); | |
| 313 | - } | |
| 314 | - | |
| 315 | - // Add localized variables for broadcaster | |
| 316 | - // Provide the broadcaster script (registered elsewhere) with its AJAX URL and nonce. | |
| 317 | - wp_localize_script('wpstream-broadcaster', 'wpstream_broadcaster_vars', array( | |
| 318 | - 'ajax_url' => admin_url('admin-ajax.php'), | |
| 319 | - 'nonce' => wp_create_nonce('wpstream_broadcaster_nonce'), | |
| 320 | - 'plugin_url' => plugin_dir_url(__FILE__), | |
| 321 | - // Gates the broadcaster's diagnostic console logging (see broadcaster.js). | |
| 322 | - 'debug' => defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG, | |
| 323 | - )); | |
| 324 | - | |
| 325 | 133 | } |
| 326 | 134 | |
| 327 | 135 | |
| 328 | 136 | /** |
| 329 | - * Add Plugin Administation menu | |
| 330 | - * | |
| 331 | - * Registers the top-level "WpStream" menu and its sub-pages (Credentials, | |
| 332 | - * All Channels, Recordings, Settings, Quick Start), each mapped to a render | |
| 333 | - * callback on this class and gated to the `administrator` capability. | |
| 334 | - * | |
| 335 | - * @since 3.0.1 | |
| 336 | - * @return void | |
| 337 | - */ | |
| 137 | + * Add Plugin Administation menu | |
| 138 | + * | |
| 139 | + * @since 3.0.1 | |
| 140 | + */ | |
| 141 | + | |
| 338 | 142 | public function wpstream_manage_admin_menu() { |
| 339 | - | |
| 340 | - // Top-level menu; its page defaults to the Credentials screen and uses the WpStream icon at position 20. | |
| 341 | - add_menu_page( __('WpStream','wpstream'), __('WpStream ','wpstream'), 'administrator', 'wpstream_credentials', array($this,'wpstream_set_wpstream_credentials'), WPSTREAM_PLUGIN_DIR_URL.'img/wpstream-icon-menu_2.png',20 ); | |
| 342 | - // Credentials sub-page (same slug as the parent so it is the default view). | |
| 343 | - add_submenu_page( 'wpstream_credentials', __('WpStream Credentials','wpstream'), __('Credentials','wpstream'), 'administrator', 'wpstream_credentials', array($this,'wpstream_set_wpstream_credentials') ); | |
| 344 | - // All Channels listing. | |
| 345 | - add_submenu_page( 'wpstream_credentials', __('WpStream Live Channels','wpstream'), __('All Channels','wpstream'), 'administrator', 'wpstream_live_channels', array( $this,'wpstream_new_general_set')); | |
| 346 | - // Recordings / media management. | |
| 347 | - add_submenu_page( 'wpstream_credentials', __('WpStream Recordings','wpstream'), __('Recordings','wpstream'), 'administrator', 'wpstream_recordings', array($this,'wpstream_media_management')); | |
| 348 | - // Global plugin settings. | |
| 349 | - add_submenu_page( 'wpstream_credentials', __('WpStream Settings','wpstream'), __('Settings','wpstream'), 'administrator', 'wpstream_settings', array($this,'wpstream_settings')); | |
| 350 | - | |
| 351 | - // Quick Start / onboarding entry point. | |
| 352 | - add_submenu_page( 'wpstream_credentials', __('WpStream Quick Start','wpstream'), __('WpStream Quick Start','wpstream'), 'administrator', 'wpstream_onboard', array($this,'wpstream_pre_onboard_display')); | |
| 353 | - | |
| 354 | - | |
| 355 | - | |
| 356 | - | |
| 143 | + | |
| 144 | + add_menu_page( __('WpStream','wpestream'), __('WpStream ','wpstream'), 'administrator', 'wpstream_plugin_options', array($this,'wpstream_set_wpstream_credentials') ); | |
| 145 | + add_submenu_page( 'wpstream_plugin_options', __('WpStream Credentials','wpestream'), __('WpStream Credentials','wpestream'), 'administrator', 'wpstream_plugin_options', array($this,'wpstream_set_wpstream_credentials') ); | |
| 146 | + add_submenu_page( 'wpstream_plugin_options', __('WpStream Channels','wpestream'), __('WpStream Channels','wpestream'), 'administrator', 'wpstream_new_general_set', array( $this,'wpstream_new_general_set')); | |
| 147 | + add_submenu_page( 'wpstream_plugin_options', __('WpStream Media Management','wpestream'), __('WpStream Media Management','wpestream'), 'administrator', 'wpstream_media_management', array($this,'wpstream_media_management')); | |
| 148 | + add_submenu_page( 'wpstream_plugin_options', __('WpStream Settings','wpestream'), __('WpStream Settings','wpestream'), 'administrator', 'wpstream_settings', array($this,'wpstream_settings')); | |
| 149 | + | |
| 357 | 150 | } |
| 358 | 151 | |
| 359 | - | |
| 360 | - | |
| 361 | 152 | |
| 153 | + | |
| 362 | 154 | /** |
| 363 | 155 | * Shows events wpstream |
| 364 | 156 | * |
| 365 | - * Renders the "All Channels" admin screen: the Pay-Per-View (WooCommerce | |
| 366 | - * `product`) channel list, the Free-To-View (`wpstream_product`) list, the | |
| 367 | - * quota/pack summary, and the "no channels" call-to-action. Each channel is | |
| 368 | - * drawn via wpstream_live_stream_unit(). Echoes HTML directly. | |
| 369 | - * | |
| 370 | - * @since 3.0.1 | |
| 371 | - * @return void | |
| 157 | + * @since 3.0.1 | |
| 372 | 158 | */ |
| 373 | - public function wpstream_new_general_set() { | |
| 374 | - return $this->main->get_live_channel_presentation()->render_channels_page(); | |
| 375 | - } | |
| 376 | - public function wpstream_social_share($the_id){ | |
| 377 | - return $this->main->get_live_channel_presentation()->render_part( 'social_share', array( $the_id ) ); | |
| 378 | - } | |
| 379 | - public function wpstream_live_stream_unit($the_id,$is_front=''){ | |
| 380 | - $context = '' === $is_front ? 'admin' : $is_front; | |
| 381 | - return $this->main->get_live_channel_presentation()->render_channel( $the_id, $context ); | |
| 382 | - } | |
| 383 | - public function wpstream_live_stream_unit_for_theme($the_id,$is_front=''){ | |
| 384 | - return $this->main->get_live_channel_presentation()->render_part( 'theme_channel', array( $the_id, $is_front ) ); | |
| 385 | - } | |
| 386 | - public function wpstream_close_modal_button(){ | |
| 387 | - return $this->main->get_live_channel_presentation()->render_part( 'close_modal_button' ); | |
| 388 | - } | |
| 389 | - public function wpstream_local_event_options_toggle( $is_basic_stream_mode = false ) { | |
| 390 | - return $this->main->get_live_channel_presentation()->render_part( 'local_event_options_toggle', array( $is_basic_stream_mode ) ); | |
| 391 | - } | |
| 392 | - public function wpstream_basic_stream_mode_message() { | |
| 393 | - return $this->main->get_live_channel_presentation()->render_part( 'basic_stream_mode_message' ); | |
| 394 | - } | |
| 395 | - public function wpstream_display_modal_seetings($the_id){ | |
| 396 | - return $this->main->get_live_channel_presentation()->render_part( 'settings_modal', array( $the_id ) ); | |
| 397 | - } | |
| 398 | - public function wpstream_display_modal_share($the_id){ | |
| 399 | - return $this->main->get_live_channel_presentation()->render_part( 'share_modal', array( $the_id ) ); | |
| 400 | - } | |
| 401 | - public function wpstream_display_modal_broadcast($the_id,$external_software_streaming_class,$obs_uri,$obs_stream){ | |
| 402 | - return $this->main->get_live_channel_presentation()->render_part( | |
| 403 | - 'broadcast_modal', | |
| 404 | - array( $the_id, $external_software_streaming_class, $obs_uri, $obs_stream ) | |
| 159 | + | |
| 160 | + public function wpstream_new_general_set() { | |
| 161 | + | |
| 162 | + $no_channel=1; | |
| 163 | + | |
| 164 | + if(class_exists ('WC_Subscription')){ | |
| 165 | + | |
| 166 | + } | |
| 167 | + | |
| 168 | + //event_passed | |
| 169 | + $args = array( | |
| 170 | + 'posts_per_page' => -1, | |
| 171 | + 'post_type' => 'product', | |
| 172 | + 'post_status' => 'publish', | |
| 173 | + 'meta_query' => array( | |
| 174 | + array( | |
| 175 | + 'key' => 'event_passed', | |
| 176 | + 'value' => 1, | |
| 177 | + 'compare' => '!=', | |
| 178 | + ) | |
| 179 | + ), | |
| 180 | + | |
| 181 | + 'tax_query' => array( | |
| 182 | + 'relation' => 'AND', | |
| 183 | + array( | |
| 184 | + 'taxonomy' => 'product_type', | |
| 185 | + 'field' => 'slug', | |
| 186 | + 'terms' => array('live_stream','subscription') | |
| 187 | + ) | |
| 188 | + ), | |
| 405 | 189 | ); |
| 406 | - } | |
| 407 | - public function wpstream_encoder_table(){ | |
| 408 | - return $this->main->get_live_channel_presentation()->render_part( 'encoder_table' ); | |
| 409 | - } | |
| 410 | - public function wpstream_encoder_panel( $encoder, $obs_uri, $obs_stream, $visible = false ){ | |
| 411 | - return $this->main->get_live_channel_presentation()->render_part( | |
| 412 | - 'encoder_panel', | |
| 413 | - array( $encoder, $obs_uri, $obs_stream, $visible ) | |
| 414 | - ); | |
| 415 | - } | |
| 416 | - private function wpstream_settings_fields(){ | |
| 417 | - // Definition of every settings field, keyed and grouped by 'tab' (general, subscription, messages, default options, VOD defaults, support). | |
| 418 | - return array( | |
| 419 | - 1 => array( | |
| 420 | - 'tab' => 'general_options', | |
| 421 | - 'label' => esc_html__('Slug for free video/channel pages ','wpstream'), | |
| 422 | - 'name' => 'free_media_slug', | |
| 423 | - 'type' => 'text', | |
| 424 | - 'details' => esc_html__('This will replace the default "wpstream" of all your free video/channel urls. Special characters like "&" are not permitted. To have your new slug show up you need to re-save the "Permalinks Settings" under Settings -> Permalinks, even if not making any changes.','wpstream'), | |
| 425 | - ), | |
| 426 | 190 | |
| 427 | - 'free_vod_slug' => array( | |
| 428 | - 'tab' => 'general_options', | |
| 429 | - 'label' => esc_html__('Slug for free VOD pages ','wpstream'), | |
| 430 | - 'name' => 'free_media_slug_vod', | |
| 431 | - 'type' => 'text', | |
| 432 | - 'details' => esc_html__('This will replace the default "wpstream_vod" of all your free VOD urls. Special characters like "&" are not permitted. To have your new slug show up you need to re-save the "Permalinks Settings" under Settings -> Permalinks, even if not making any changes.','wpstream'), | |
| 433 | - ), | |
| 434 | - | |
| 435 | - 2 => array( | |
| 436 | - 'tab' => 'general_options', | |
| 437 | - 'label' => esc_html__('Non-Admin User Roles Allowed to Broadcast','wpstream'), | |
| 438 | - 'name' => 'stream_role', | |
| 439 | - 'type' => 'user_roles', | |
| 440 | - 'details' => esc_html__('These types of users can stream via frontend shortcodes / blocks. Single individual channels are automaticlally created for streaming by non-admins.','wpstream'), | |
| 441 | - | |
| 442 | - ), | |
| 443 | - 3 => array( | |
| 444 | - 'tab' => 'general_options', | |
| 445 | - 'label' => esc_html__('Non Admin Streamers Channel Type.','wpstream'), | |
| 446 | - 'name' => 'user_streaming_channel_type', | |
| 447 | - 'type' => 'select', | |
| 448 | - 'select_values'=>array( | |
| 449 | - 'free' => esc_html__('Free Live Channel','wpstream'), | |
| 450 | - 'paid' => esc_html__('Pay-Per-View','wpstream') | |
| 451 | - ), | |
| 452 | - 'details' => esc_html__('Choose whether the channels assigned to non-admins are free-for-all or pay-per-view (WooCommerce product).','wpstream'), | |
| 453 | - ), | |
| 454 | - | |
| 455 | - 4 => array( | |
| 456 | - 'tab' => 'general_options', | |
| 457 | - 'label' => esc_html__('Default Pay-Per-View Price','wpstream'), | |
| 458 | - 'name' => 'user_streaming_default_price', | |
| 459 | - 'type' => 'text', | |
| 460 | - 'details' => esc_html__('Default price of pay-per-view channels assigned to non-admins.','wpstream'), | |
| 461 | - ), | |
| 462 | - | |
| 463 | - | |
| 464 | - | |
| 465 | - 6 => array( | |
| 466 | - 'tab' => 'subscription_options', | |
| 467 | - 'label' => esc_html__('Use Global Subscription Mode','wpstream'), | |
| 468 | - 'name' => 'global_sub', | |
| 469 | - 'type' => 'slidertoogle', | |
| 470 | - 'details' => esc_html__('If enabled, a client can access all the media products (live and VOD) by purchasing a single subscription. The "WooCommerce Subscriptions" plugin is required.','wpstream'), | |
| 471 | - ), | |
| 472 | - | |
| 473 | - 7 => array( | |
| 474 | - 'tab' => 'subscription_options', | |
| 475 | - 'label' => esc_html__('Subscription ID for Global Subscription Mode','wpstream'), | |
| 476 | - 'name' => 'global_sub_id', | |
| 477 | - 'type' => 'text', | |
| 478 | - 'details' => esc_html__('ID of the subscription product to be purchased for global access to media. All non-subscription video products that are not already attached to a subscription will be accessible to users that have purchased it.','wpstream'), | |
| 479 | - ), | |
| 480 | - 8 => array( | |
| 481 | - 'tab' => 'messages_options', | |
| 482 | - 'label' => esc_html__('PPV not logged in message','wpstream'), | |
| 483 | - 'name' => 'product_not_login', | |
| 484 | - 'type' => 'text', | |
| 485 | - 'details' => esc_html__('This message will be displayed on top of the media player for pay-per-view items when user is not logged in.','wpstream'), | |
| 486 | - 'default' => esc_html__('You must be logged in to watch this video.','wpstream'), | |
| 487 | - ), | |
| 488 | - 9 => array( | |
| 489 | - 'tab' => 'messages_options', | |
| 490 | - 'label' => esc_html__('PPV not purchased message','wpstream'), | |
| 491 | - 'name' => 'product_not_bought', | |
| 492 | - 'type' => 'text', | |
| 493 | - 'details' => esc_html__('This message will be displayed on top of the media player for common pay-per-view items that have not been purchased.','wpstream'), | |
| 494 | - 'default' => esc_html__('You did not yet purchase this item.','wpstream'), | |
| 495 | - ), | |
| 496 | - 10 => array( | |
| 497 | - 'tab' => 'messages_options', | |
| 498 | - 'label' => esc_html__('Subscription not purchased message','wpstream'), | |
| 499 | - 'name' => 'product_not_subscribe', | |
| 500 | - 'type' => 'text', | |
| 501 | - 'details' => esc_html__('This message will be displayed on top of the media player for subscription-type pay-per-view items that have not been purchased.','wpstream'), | |
| 502 | - 'default' => esc_html__(' You did not yet subscribe to this item.','wpstream'), | |
| 503 | - ), | |
| 504 | - 11 => array( | |
| 505 | - 'tab' => 'messages_options', | |
| 506 | - 'label' => esc_html__('Thank you message','wpstream'), | |
| 507 | - 'name' => 'product_thankyou', | |
| 508 | - 'type' => 'text', | |
| 509 | - 'details' => esc_html__('This message will be displayed on the thank you page (after purchase) and the confirmation email.','wpstream'), | |
| 510 | - 'default' => esc_html__('Thanks for your purchase. You can access your item at any time by visiting the following page: {item_link}','wpstream'), | |
| 511 | - ), | |
| 512 | - | |
| 513 | - 12 => array( | |
| 514 | - 'tab' => 'messages_options', | |
| 515 | - 'label' => esc_html__('Subscription Active message','wpstream'), | |
| 516 | - 'name' => 'subscription_active', | |
| 517 | - 'type' => 'text', | |
| 518 | - 'details' => esc_html__('This message will be displayed on subscription product page.','wpstream'), | |
| 519 | - 'default' => esc_html__('Your Subscription is Active','wpstream'), | |
| 520 | - ), | |
| 521 | - 13 => array( | |
| 522 | - 'tab' => 'messages_options', | |
| 523 | - 'label' => esc_html__('You are not live message','wpstream'), | |
| 524 | - 'name' => 'you_are_not_live', | |
| 525 | - 'type' => 'text', | |
| 526 | - 'details' => esc_html__('This message will be displayed in player.','wpstream'), | |
| 527 | - 'default' => esc_html__('We are not live at this moment','wpstream'), | |
| 528 | - ), | |
| 529 | 191 | |
| 530 | - 14 => array( | |
| 531 | - 'tab' => 'general_options', | |
| 532 | - 'label' => esc_html__('Video player theme','wpstream'), | |
| 533 | - 'name' => 'video_player_theme', | |
| 534 | - 'type' => 'select', | |
| 535 | - 'select_values'=>array( | |
| 536 | - 'default' => esc_html__('Default','wpstream'), | |
| 537 | - 'city' => esc_html__('City','wpstream'), | |
| 538 | - 'forest' => esc_html__('Forest','wpstream'), | |
| 539 | - 'fantasy' => esc_html__('Fantasy','wpstream'), | |
| 540 | - 'sea' => esc_html__('Sea','wpstream'), | |
| 541 | - ), | |
| 542 | - 'details' => esc_html__('Choose the video player theme to have a different look for the player.','wpstream'), | |
| 543 | - ), | |
| 544 | - 'wpstream_player_logo' => array( | |
| 545 | - 'tab' => 'general_options', | |
| 546 | - 'name' => 'player_logo', | |
| 547 | - 'label' => esc_html__('Logo for the video player','wpstream'), | |
| 548 | - 'type' => 'image', | |
| 549 | - 'details' => esc_html__('This logo will be displayed on the the video player.','wpstream'), | |
| 550 | - 'default' => '', | |
| 551 | - 'image_size' => 'thumbnail', | |
| 552 | - ), | |
| 553 | - // hide the video player logo opacity for now | |
| 554 | -// 'wpstream_player_logo_opacity' => array( | |
| 555 | -// 'tab' => 'general_options', | |
| 556 | -// 'name' => 'player_logo_opacity', | |
| 557 | -// 'label' => esc_html__('Opacity of the video player logo','wpstream'), | |
| 558 | -// 'type' => 'range', | |
| 559 | -// 'details' => esc_html__('Set the opacity of the logo','wpstream'), | |
| 560 | -// 'default' => '', | |
| 561 | -// 'image_size' => 'thumbnail', | |
| 562 | -// ), | |
| 563 | - 'wpsteram_player_logo_position' => array( | |
| 564 | - 'tab' => 'general_options', | |
| 565 | - 'name' => 'player_logo_position', | |
| 566 | - 'label' => esc_html__('Position of the video player logo','wpstream'), | |
| 567 | - 'type' => 'select', | |
| 568 | - 'select_values'=>array( | |
| 569 | - 'top-left' => esc_html__('Top Left','wpstream'), | |
| 570 | - 'top-right' => esc_html__('Top Right','wpstream'), | |
| 571 | - 'bottom-left' => esc_html__('Bottom Left','wpstream'), | |
| 572 | - 'bottom-right' => esc_html__('Bottom Right','wpstream'), | |
| 573 | - ), | |
| 574 | - 'details' => esc_html__('Choose the position of the logo on the video player.','wpstream'), | |
| 575 | - 'default' => '', | |
| 576 | - ), | |
| 577 | 192 | |
| 193 | + $event_list = new WP_Query($args); | |
| 194 | + global $live_event_for_user; | |
| 195 | + $live_event_for_user = $this->main->wpstream_live_connection->wpstream_get_live_event_for_user(); | |
| 196 | + $pack_details = $this->main->wpstream_live_connection->wpstream_request_pack_data_per_user(); | |
| 578 | 197 | |
| 579 | - | |
| 580 | - 99 => array( | |
| 581 | - 'tab' => 'default_options', | |
| 582 | - 'label' => esc_html__('Events Options ','wpstream'), | |
| 583 | - 'name' => 'user_streaming_global_channel_options', | |
| 584 | - 'type' => 'user_streaming_global_channel_options', | |
| 585 | - 'details' => esc_html__('Global Options for live events.','wpstream'), | |
| 586 | - ), | |
| 198 | + $this->main->show_user_data($pack_details); | |
| 587 | 199 | |
| 588 | - 100 => array( | |
| 589 | - 'tab' => 'default_options_vod', | |
| 590 | - 'label' => esc_html__('Autoplay','wpstream'), | |
| 591 | - 'name' => 'vod_autoplay', | |
| 592 | - 'type' => 'slidertoogle', | |
| 593 | - 'details' => esc_html__('If enabled, video will attempt to start playing automatically. This is only achievable in some browsers.','wpstream'), | |
| 594 | - ), | |
| 595 | 200 | |
| 201 | + | |
| 202 | + | |
| 203 | + if( $event_list->have_posts()){ | |
| 596 | 204 | |
| 597 | - 101 => array( | |
| 598 | - 'tab' => 'default_options_vod', | |
| 599 | - 'label' => esc_html__('Start Muted','wpstream'), | |
| 600 | - 'name' => 'vod_start_muted', | |
| 601 | - 'type' => 'slidertoogle', | |
| 602 | - 'details' => esc_html__('If enabled, video will start muted. This may increase the rate of autoplay in some browsers.','wpstream'), | |
| 603 | - ), | |
| 205 | + | |
| 206 | + print '<div class="pack_details_wrapper_transparent"> | |
| 207 | + <h3>'.__('Your Pay-Per-View Channel List','wpstream').'</h3>'; | |
| 208 | + | |
| 209 | + | |
| 210 | + $link_new = admin_url('post-new.php?post_type=product').'&new_stream='. rawurlencode('new'); | |
| 604 | 211 | |
| 605 | - 102 => array( | |
| 606 | - 'tab' => 'default_options_vod', | |
| 607 | - 'label' => esc_html__('Lock To Website','wpstream'), | |
| 608 | - 'name' => 'vod_domain_lock', | |
| 609 | - 'type' => 'slidertoogle', | |
| 610 | - 'details' =>sprintf ( esc_html__('If enabled, video will only display on %1$s, otherwise it can show up on any website.','wpstream'),get_bloginfo('wpurl') ), | |
| 611 | - ), | |
| 612 | - | |
| 613 | - 103 => array( | |
| 614 | - 'tab' => 'default_options_vod', | |
| 615 | - 'label' => esc_html__('Encrypt Video','wpstream'), | |
| 616 | - 'name' => 'vod_encrypt', | |
| 617 | - 'type' => 'slidertoogle', | |
| 618 | - 'details' => esc_html__('If enabled, video data will be encrypted. Enabling encryption may lead to reduced website performance under certain configurations. Encrypted video may not display in all browsers.','wpstream'), | |
| 619 | - ), | |
| 620 | - | |
| 621 | - /* 'vod_domain_lock' =>array( | |
| 622 | - 'name' => esc_html__('Video On Demand - Lock To Website','wpstream'), | |
| 623 | - 'details' => sprintf ( esc_html__('If enabled, VODS will only display on %1$s, otherwise they can show up on any website.','wpstream'),get_bloginfo('wpurl') ), | |
| 624 | - 'defaults' => 'no', | |
| 625 | - ), | |
| 626 | - 'vod_encrypt' =>array( | |
| 627 | - 'name' => esc_html__('Encrypt Video on Demand','wpstream'), | |
| 628 | - 'details' => esc_html__('If enabled, video data will be encrypted. Enabling encryption may lead to reduced website performance under certain configurations. Encrypted video may not display in all browsers.','wpstream'), | |
| 629 | - 'defaults' => 'no', | |
| 630 | - ),*/ | |
| 212 | + print '<a href="'.esc_url($link_new).'" class="wpstream_create_new_product_link">'.esc_html__('Create new pay-per-view channel.','wpstream').'</a>'; | |
| 213 | + print '</div>'; | |
| 631 | 214 | |
| 632 | - 104 => array( | |
| 633 | - 'tab' => 'support_tab', | |
| 634 | - 'label' => esc_html__('Logs','wpstream'), | |
| 635 | - 'name' => 'logs', | |
| 636 | - 'type' => 'logs_table', | |
| 637 | - 'details' => esc_html__('This is the error log of the plugin.','wpstream'), | |
| 638 | - ) | |
| 639 | - | |
| 640 | - ); | |
| 641 | - } | |
| 215 | + print '<div style="clear: both;"></div><div class="event_list_wrapper">'; | |
| 642 | 216 | |
| 643 | - /** | |
| 644 | - * Stop the request unless the current user may manage plugin settings. | |
| 645 | - * | |
| 646 | - * Shared by the settings and credentials screens so both enforce the | |
| 647 | - * same capability (`manage_options`). | |
| 648 | - * | |
| 649 | - * @return void | |
| 650 | - */ | |
| 651 | - private function wpstream_require_settings_capability(){ | |
| 652 | - if ( ! current_user_can( 'manage_options' ) ) { | |
| 653 | - wp_die( esc_html__( 'Not enough permissions to make this change', 'wpstream' ) ); | |
| 654 | - } | |
| 655 | - } | |
| 217 | + while ($event_list->have_posts()): $event_list->the_post(); | |
| 656 | 218 | |
| 657 | - /** | |
| 658 | - * Render the WpStream Settings admin screen and persist submitted values. | |
| 659 | - * | |
| 660 | - * On POST it verifies the nonce, then stores only the fields declared for | |
| 661 | - * the active tab as `wpstream_*` options (the streamer role is checked | |
| 662 | - * against the site's roles, the "default options" tab folds its checkboxes | |
| 663 | - * into one map), and flushes rewrite rules. It then renders the tabbed | |
| 664 | - * form from the same field definitions. Echoes HTML. | |
| 665 | - * | |
| 666 | - * @return void | |
| 667 | - */ | |
| 668 | - public function wpstream_settings(){ | |
| 219 | + $the_id = get_the_ID(); | |
| 220 | + $is_subscription_live_event = esc_html(get_post_meta($the_id,'_subscript_live_event',true)); | |
| 221 | + $term_list = wp_get_post_terms($the_id, 'product_type'); | |
| 669 | 222 | |
| 670 | - // Admin-only screen. | |
| 671 | - $this->wpstream_require_settings_capability(); | |
| 223 | + if( $term_list[0]->name=='subscription' && $is_subscription_live_event=='no'){ | |
| 224 | + continue; | |
| 225 | + } | |
| 672 | 226 | |
| 227 | + $this->wpstream_live_stream_unit($the_id); | |
| 673 | 228 | |
| 674 | - $active_tab = isset( $_GET['tab'] ) ? sanitize_key( $_GET['tab'] ) : 'general_options'; | |
| 229 | + endwhile; | |
| 675 | 230 | |
| 676 | - /** | |
| 677 | - * Filter the settings field definitions. | |
| 678 | - * | |
| 679 | - * Field definitions drive both the save allow-list and the rendered | |
| 680 | - * form, so an added field (`tab`, `label`, `name`, `type`, `details`) | |
| 681 | - * is rendered on its tab and saved as the `wpstream_{name}` option | |
| 682 | - * through sanitize_text_field(). | |
| 683 | - * | |
| 684 | - * @since 4.14.0 | |
| 685 | - * | |
| 686 | - * @param array $fields Field definitions. | |
| 687 | - * @param string $active_tab Tab being rendered or saved. | |
| 688 | - */ | |
| 689 | - $wpstream_settings_array = (array) apply_filters( 'wpstream_settings_fields', $this->wpstream_settings_fields(), $active_tab ); | |
| 231 | + print'</div>'; | |
| 232 | + $no_channel=1; | |
| 233 | + }else{ | |
| 234 | + $no_channel=0; | |
| 235 | + } | |
| 690 | 236 | |
| 691 | - /** | |
| 692 | - * Filter the settings tabs. | |
| 693 | - * | |
| 694 | - * Added tabs render their fields from `wpstream_settings_fields` | |
| 695 | - * and fire `wpstream_settings_tab_{slug}` for a custom body. | |
| 696 | - * | |
| 697 | - * @since 4.14.0 | |
| 698 | - * | |
| 699 | - * @param array $tabs Tab slug => label. | |
| 700 | - * @param string $active_tab Tab being rendered or saved. | |
| 701 | - */ | |
| 702 | - $tabs = (array) apply_filters( | |
| 703 | - 'wpstream_settings_tabs', | |
| 704 | - array( | |
| 705 | - 'general_options' => esc_html__( 'General Options', 'wpstream' ), | |
| 706 | - 'default_options' => esc_html__( 'Default Channel Settings', 'wpstream' ), | |
| 707 | - 'default_options_vod' => esc_html__( 'VOD Settings', 'wpstream' ), | |
| 708 | - 'subscription_options' => esc_html__( 'Subscription Options', 'wpstream' ), | |
| 709 | - 'messages_options' => esc_html__( 'Customize Messages', 'wpstream' ), | |
| 710 | - 'support_tab' => esc_html__( 'Support', 'wpstream' ), | |
| 711 | - ), | |
| 712 | - $active_tab | |
| 713 | - ); | |
| 714 | 237 | |
| 715 | - // Handle a settings submission. | |
| 716 | - if($_SERVER['REQUEST_METHOD'] === 'POST'){ | |
| 717 | - // CSRF protection. | |
| 718 | - check_admin_referer( 'wpstream-settings-nonce', 'wpstream-settings-nonce' ); | |
| 238 | + $ajax_nonce = wp_create_nonce( "wpstream_start_event_nonce" ); | |
| 239 | + print '<input type="hidden" id="wpstream_start_event_nonce" value="'.$ajax_nonce.'">'; | |
| 240 | + $current_user = wp_get_current_user(); | |
| 241 | + $allowded_html = array(); | |
| 242 | + $userID = $current_user->ID; | |
| 243 | + $user_live_streams = get_user_meta($userID,'live_shows'); | |
| 719 | 244 | |
| 720 | - // Only the fields declared for the active tab may be persisted. | |
| 721 | - $allowed = array(); | |
| 722 | - foreach ( $wpstream_settings_array as $field ) { | |
| 723 | - if ( isset( $field['tab'], $field['name'] ) && $field['tab'] === $active_tab ) { | |
| 724 | - $allowed[] = $field['name']; | |
| 725 | - } | |
| 726 | - } | |
| 727 | 245 | |
| 728 | - // Option values as they were before this submission, and as written by it | |
| 729 | - // (both keyed by option name) — announced together once the save is complete. | |
| 730 | - $previous_options = array(); | |
| 731 | - $saved_options = array(); | |
| 246 | + wp_reset_postdata(); | |
| 732 | 247 | |
| 733 | - // If the "channel type" section was shown but no streamer role was chosen, clear the stored role. | |
| 734 | - if( isset($_POST['user_streaming_channel_type_hidden']) && intval($_POST['user_streaming_channel_type_hidden'])==1 && !isset($_POST['stream_role']) ){ | |
| 735 | - $previous_options['wpstream_stream_role'] = get_option( 'wpstream_stream_role' ); | |
| 736 | - $saved_options['wpstream_stream_role'] = ''; | |
| 737 | - update_option( sanitize_key('wpstream_stream_role'), '' ); | |
| 738 | - } | |
| 739 | 248 | |
| 740 | - // Persist each declared field as a sanitized wpstream_* option; anything else is ignored. | |
| 741 | - foreach ( $allowed as $variable ) { | |
| 742 | - if ( ! isset( $_POST[ $variable ] ) ) { | |
| 743 | - continue; | |
| 744 | - } | |
| 745 | - $value = $_POST[ $variable ]; | |
| 746 | 249 | |
| 747 | - // Streamer role is a list of role slugs; keep only the roles the form offers | |
| 748 | - // (editable roles minus administrator, who can always broadcast). | |
| 749 | - if ( 'stream_role' === $variable ) { | |
| 750 | - $known = array_diff( array_keys( get_editable_roles() ), array( 'administrator' ) ); | |
| 751 | - $roles = array_values( array_intersect( (array) $value, $known ) ); | |
| 752 | - $previous_options['wpstream_stream_role'] = get_option( 'wpstream_stream_role' ); | |
| 753 | - $saved_options['wpstream_stream_role'] = $roles; | |
| 754 | - update_option( 'wpstream_stream_role', $roles ); | |
| 755 | - continue; | |
| 756 | - } | |
| 757 | 250 | |
| 758 | - $option_name = sanitize_key( 'wpstream_' . $variable ); | |
| 759 | - $previous_options[ $option_name ] = get_option( $option_name ); | |
| 760 | - $saved_options[ $option_name ] = sanitize_text_field( $value ); | |
| 761 | - update_option( $option_name, $saved_options[ $option_name ] ); | |
| 762 | - } | |
| 251 | + // free | |
| 763 | 252 | |
| 253 | + $args_free = array( | |
| 254 | + 'posts_per_page' => -1, | |
| 255 | + 'post_type' => 'wpstream_product', | |
| 256 | + 'post_status' => 'publish', | |
| 257 | + 'meta_query' => array( | |
| 258 | + 'relation' => 'AND', | |
| 259 | + array( | |
| 260 | + 'key' => 'wpstream_product_type', | |
| 261 | + 'value' => 1, | |
| 262 | + 'compare' => '==', | |
| 263 | + ), | |
| 764 | 264 | |
| 765 | - // On the "default options" tab, fold the per-option checkboxes into a single 1/0 map. | |
| 766 | - if ( 'default_options' === $active_tab ) { | |
| 767 | - $event_settings=array(); | |
| 768 | - foreach($this->global_event_options as $key=>$option){ | |
| 769 | - $event_settings[$key]=''; | |
| 770 | - if(isset($_POST['wpstream_event_set_'.$key]) && $_POST['wpstream_event_set_'.$key]=='on'){ | |
| 771 | - $event_settings[$key]=1; | |
| 772 | - }else{ | |
| 773 | - $event_settings[$key]=0; | |
| 774 | - } | |
| 775 | - } | |
| 776 | - $this->main->channel_settings->apply( | |
| 777 | - array( | |
| 778 | - 'type' => 'save_defaults', | |
| 779 | - 'options' => $event_settings, | |
| 780 | - ) | |
| 781 | - ); | |
| 782 | - } | |
| 265 | + ), | |
| 783 | 266 | |
| 784 | 267 | |
| 268 | + ); | |
| 269 | + $event_list_free = new WP_Query($args_free); | |
| 785 | 270 | |
| 786 | 271 | |
| 787 | - // reset permalinkgs | |
| 788 | - // Slug settings can change permalinks, so drop and rebuild the rewrite rules. | |
| 789 | - global $wp_rewrite; | |
| 272 | + if( $event_list_free->have_posts()){ | |
| 273 | + print '<div class="pack_details_wrapper_transparent"> | |
| 274 | + <h3>'.__('Your Free Channel List','wpestate').'</h3>'; | |
| 790 | 275 | |
| 791 | - update_option( "rewrite_rules", FALSE ); | |
| 792 | - $wp_rewrite->flush_rules( true ); | |
| 276 | + $link_new = admin_url('post-new.php?post_type=wpstream_product'); | |
| 277 | + print '<a href="'.esc_url($link_new).'" class="wpstream_create_new_product_link">'.esc_html__('Create new free channel.','wpstream').'</a>'; | |
| 278 | + print '</div>'; | |
| 279 | + print '<div style="clear: both;"></div><div class="event_list_wrapper">'; | |
| 793 | 280 | |
| 794 | - /** | |
| 795 | - * Fires after a WpStream Settings tab was saved and the rewrite | |
| 796 | - * rules rebuilt. Default Channel Settings saved from the | |
| 797 | - * "default options" tab are announced separately by | |
| 798 | - * wpstream_default_channel_settings_saved. | |
| 799 | - * | |
| 800 | - * @since 4.14.0 | |
| 801 | - * | |
| 802 | - * @param string $active_tab Settings tab that was submitted. | |
| 803 | - * @param array $saved Option values written, keyed by option name. | |
| 804 | - * @param array $previous The values those options held before. | |
| 805 | - */ | |
| 806 | - do_action( 'wpstream_settings_saved', $active_tab, $saved_options, $previous_options ); | |
| 281 | + while ($event_list_free->have_posts()): $event_list_free->the_post(); | |
| 807 | 282 | |
| 808 | - } | |
| 809 | 283 | |
| 284 | + $the_id = get_the_ID(); | |
| 810 | 285 | |
| 286 | + if( get_post_meta ($the_id,'event_passed',true)!=1){ | |
| 287 | + $this->wpstream_live_stream_unit($the_id); | |
| 288 | + } | |
| 811 | 289 | |
| 290 | + endwhile; | |
| 812 | 291 | |
| 813 | - // Open the settings panel and the form. | |
| 814 | - print '<div class="theme_options_tab_wpstream" style="display:block;" > | |
| 815 | - <h1>'.__('WpStream Settings','wpstream').'</h1> | |
| 816 | - <form method="post" action="" >'; | |
| 292 | + print'</div>'; | |
| 293 | + $no_channel=1; | |
| 294 | + }else{ | |
| 295 | + $no_channel=0; | |
| 296 | + } | |
| 817 | 297 | |
| 818 | - // Tab navigation bar; the current tab gets the nav-tab-active class. | |
| 819 | - print '<h2 class="nav-tab-wrapper">'; | |
| 820 | - foreach ( $tabs as $tab_slug => $tab_label ) { | |
| 821 | - $tab_slug = sanitize_key( $tab_slug ); | |
| 822 | - print '<a href="' . esc_url( add_query_arg( array( 'page' => 'wpstream_settings', 'tab' => $tab_slug ), admin_url( 'admin.php' ) ) ) . '" class="nav-tab ' . ( $active_tab === $tab_slug ? 'nav-tab-active' : '' ) . '">' . esc_html( $tab_label ) . '</a>'; | |
| 823 | - } | |
| 824 | - print '</h2>'; | |
| 825 | - $help_link=''; | |
| 826 | 298 | |
| 827 | - // Basic-stream mode disables/annotates some default-channel controls. | |
| 828 | - $is_basic_stream_mode = $this->wpstream_is_basic_streaming_mode(); | |
| 829 | - print '<div class="wpstream_option_wrapper">'; | |
| 830 | 299 | |
| 831 | - // Pick the contextual "Video Help" docs link for the active tab. | |
| 832 | - switch ($active_tab) { | |
| 833 | - case 'general_options': | |
| 834 | - $help_link='https://docs.wpstream.net/docs/general-settings/'; | |
| 835 | - break; | |
| 836 | - case 'default_options': | |
| 837 | - $help_link='https://docs.wpstream.net/docs/default-channel-settings/'; | |
| 838 | - break; | |
| 839 | - case 'default_options_vod': | |
| 840 | - $help_link='https://docs.wpstream.net/docs/vod-settings/'; | |
| 841 | - break; | |
| 842 | - case 'subscription_options': | |
| 843 | - $help_link='https://docs.wpstream.net/docs/subscription-options/'; | |
| 844 | - break; | |
| 845 | - case 'messages_options': | |
| 846 | - $help_link='https://docs.wpstream.net/docs/customize-messages/'; | |
| 847 | - break; | |
| 848 | - } | |
| 300 | + if($no_channel==0){ | |
| 301 | + $link_new_paid = admin_url('post-new.php?post_type=product').'&new_stream='. rawurlencode('new'); | |
| 302 | + $link_new_free = admin_url('post-new.php?post_type=wpstream_product'); | |
| 303 | + print '<div class="no_events_warning"> '.__('* You don\'t have any live channels!','wpstream'); | |
| 849 | 304 | |
| 850 | - print '<div class="options_wrapper">'; | |
| 851 | - // Render each field that belongs to the active tab. | |
| 852 | - foreach ($wpstream_settings_array as $key=>$option){ | |
| 853 | - // Skip fields from other tabs. | |
| 854 | - if($option['tab']!=$active_tab){ | |
| 855 | - continue; | |
| 856 | - } | |
| 305 | + print '<a href="'.esc_url($link_new_free).'" class="wpstream_no_chanel_add_channel">'.esc_html__('Add new free channel ','wpstream').'</a>'; | |
| 306 | + print '<a href="'.esc_url($link_new_paid).'" class="wpstream_no_chanel_add_channel">'.esc_html__('Add new pay-per-view channel ','wpstream').'</a>'; | |
| 857 | 307 | |
| 858 | - // Intro blurb (and basic-mode notice) shown above the global channel options control. | |
| 859 | - if ( $option['type']=='user_streaming_global_channel_options' ) { | |
| 860 | - print '<div class="default-channel-settings-info">'; | |
| 861 | - print esc_html__( 'These settings will apply to newly created channels; existing channels will not change settings if you change them here', 'wpstream'); | |
| 862 | - if ( $is_basic_stream_mode ) { | |
| 863 | - $this->wpstream_basic_stream_mode_message(); | |
| 864 | - } | |
| 865 | - print '</div>'; | |
| 308 | + print '</div>'; | |
| 309 | + } | |
| 866 | 310 | |
| 867 | - } | |
| 868 | - print '<div class="wpstream_option">'; | |
| 869 | - // Load this option's stored value. | |
| 870 | - $options_value = get_option('wpstream_'.$option['name']) ; | |
| 871 | 311 | |
| 872 | 312 | |
| 873 | - // Render the appropriate control for this field's type. | |
| 874 | - switch( $option['type'] ) { | |
| 875 | - // Multi-select of WordPress user roles allowed to broadcast. | |
| 876 | - case 'user_roles': | |
| 877 | - print '<label for="'.esc_attr( $option['name'] ).'">'.wp_kses_post( $option['label'] ).'</label>'; | |
| 878 | - print $this->wpstream_select_user_roles(esc_attr( $option['name'] ),$options_value); | |
| 879 | - print '<div class="settings_details">'.wp_kses_post( $option['details'] ).'</div>'; | |
| 880 | - break; | |
| 881 | - // The grid of default per-event streaming options. | |
| 882 | - case 'user_streaming_global_channel_options': | |
| 883 | - $exclude_array=array(); | |
| 884 | - $this->user_streaming_global_channel_options( | |
| 885 | - $option['name'], | |
| 886 | - $options_value, | |
| 887 | - $exclude_array, | |
| 888 | - $is_basic_stream_mode | |
| 889 | - ); | |
| 890 | - break; | |
| 891 | - // Plain text input; falls back to the field's default when unset. | |
| 892 | - case 'text': | |
| 893 | - if($options_value==''){ | |
| 894 | - $options_value=''; | |
| 895 | - if(isset($option['default'])){ | |
| 896 | - $options_value=$option['default']; | |
| 897 | - } | |
| 898 | - } | |
| 899 | 313 | |
| 900 | - print '<label for="'.esc_attr( $option['name'] ).'">'.wp_kses_post( $option['label'] ).'</label>'; | |
| 901 | - print '<input class="wpstream-text-input-setting" id="'.esc_attr( $option['name'] ).'" type="'.$option['type'].'" size="36" name="'.esc_attr( $option['name'] ).'" value="'.esc_attr($options_value).'" />'; | |
| 902 | - print '<div class="settings_details">'.wp_kses_post( $option['details'] ).'</div>'; | |
| 903 | - break; | |
| 904 | - // Dropdown built from the field's select_values map; a hidden mirror marks the field as present. | |
| 905 | - case 'select': | |
| 906 | - print '<label for="'.esc_attr( $option['name'] ).'">'.wp_kses_post( $option['label'] ).'</label>'; | |
| 907 | - print '<select id="'.esc_attr( $option['name'] ).'" name="'.esc_attr( $option['name'] ).'" >'; | |
| 908 | - foreach($option['select_values'] as $key=>$value){ | |
| 909 | - print '<option value="'.$key.'" '; | |
| 910 | - // Pre-select the currently stored value. | |
| 911 | - if( $key == esc_html($options_value) ){ | |
| 912 | - print ' selected '; | |
| 913 | - } | |
| 914 | - print '>'.$value.'</option>'; | |
| 915 | - } | |
| 916 | - print '</select>'; | |
| 917 | - print '<input type="hidden" name="'.esc_attr( $option['name'] ).'_hidden" value="1" >'; | |
| 918 | - print '<div class="settings_details">'.wp_kses_post( $option['details'] ).'</div>'; | |
| 919 | - break; | |
| 920 | - // On/off switch; a hidden 0-valued twin ensures "off" posts a value. | |
| 921 | - case 'slidertoogle': | |
| 922 | - print '<label for="'.esc_attr( $option['name'] ).'">'.wp_kses_post( $option['label'] ).'</label>'; | |
| 923 | - print '<div style="display: flex; gap: 25px; justify-content: space-between;">'; | |
| 924 | - print '<div class="settings_details">'.wp_kses_post( $option['details'] ).'</div>'; | |
| 925 | - print '<label class="wpstream_switch"> | |
| 926 | - <input type="hidden" class="wpstream_event_option_itemc" value="0" name="'.esc_attr( $option['name'] ).'" > | |
| 927 | - <input type="checkbox" class="wpstream_event_option_itemc" value="1" name="'.esc_attr( $option['name'] ).'" '; | |
| 928 | - if( intval($options_value) !==0 ){ | |
| 929 | - print ' checked '; | |
| 930 | - } | |
| 931 | - print '> <span class="wpstream_slider round"></span>'; | |
| 932 | - print '</label>'; | |
| 933 | - print '</div>'; | |
| 934 | - break; | |
| 935 | - // Media-library image picker with preview + upload/remove buttons. | |
| 936 | - case 'image': | |
| 937 | - $image_url = $options_value ? esc_url($options_value) : ''; | |
| 938 | - $has_image = !empty($image_url); | |
| 314 | + } | |
| 315 | + // end wpstream_new_general_set | |
| 939 | 316 | |
| 940 | - print '<label for="' . esc_attr( $option['name'] ) . '">' . wp_kses_post( $option['label'] ) . '</label>'; | |
| 941 | - print '<div class="wpstream-image-upload-wrapper">'; | |
| 942 | - print '<input type="hidden" id="' . esc_attr( $option['name'] ) . '" name="' . esc_attr( $option['name'] ) . '" value="' . $image_url . '" />'; | |
| 943 | 317 | |
| 944 | - // Preview area | |
| 945 | - print '<div class="wpstream-image-preview" style="' . (!$has_image ? 'display:none;' : '') . '">'; | |
| 946 | - print '<img src="' . $image_url . '" alt="Preview" />'; | |
| 947 | - print '</div>'; | |
| 318 | + | |
| 319 | + | |
| 320 | + | |
| 321 | + | |
| 322 | + /** | |
| 323 | + * Shows event unit card in admin | |
| 324 | + * | |
| 325 | + * @since 3.0.1 | |
| 326 | + */ | |
| 327 | + public function wpstream_live_stream_unit($the_id,$is_front=''){ | |
| 328 | + global $live_event_for_user; | |
| 329 | + $current_user = wp_get_current_user(); | |
| 330 | + | |
| 331 | + if(!current_user_can('administrator')){ | |
| 332 | + if($is_front=='' ){ | |
| 333 | + print '<div class="event_list_unit">'; | |
| 334 | + esc_html_e('You are not allowed to broadcast.','wpstream'); | |
| 335 | + print '</div>'; | |
| 336 | + return; | |
| 337 | + } | |
| 338 | + | |
| 339 | + } | |
| 340 | + | |
| 341 | + if( !$this->main->wpstream_check_user_can_stream() ){ | |
| 342 | + print '<div class="event_list_unit">'; | |
| 343 | + esc_html_e('You are not allowed to broadcast','wpstream'); | |
| 344 | + print '</div>'; | |
| 345 | + return; | |
| 346 | + | |
| 347 | + } | |
| 348 | + | |
| 349 | + | |
| 350 | + $live_class=''; | |
| 351 | + if(isset($live_event_for_user[$the_id])) { | |
| 352 | + $live_class=" wpstream_show_started"; | |
| 353 | + } | |
| 948 | 354 | |
| 949 | - // Upload/remove buttons | |
| 950 | - print '<div class="wpstream-image-upload-buttons">'; | |
| 951 | - print '<button type="button" class="wpstream-upload-image button">' . esc_html__('Upload Image', 'wpstream') . '</button>'; | |
| 952 | - print '<button type="button" class="wpstream-remove-image button" style="' . (!$has_image ? 'display:none;' : '') . '">' . esc_html__('Remove Image', 'wpstream') . '</button>'; | |
| 953 | - print '</div>'; | |
| 954 | 355 | |
| 955 | - print '</div>'; | |
| 956 | - print '<div class="settings_details">' . wp_kses_post( $option['details'] ) . '</div>'; | |
| 957 | - break; | |
| 958 | - // 0-100 range slider. | |
| 959 | - case 'range': | |
| 960 | - print '<label for="'.esc_attr( $option['name'] ).'">'.wp_kses_post( $option['label'] ).'</label>'; | |
| 961 | - print '<input class="wpstream-range-input" type="range" id="'.esc_attr( $option['name'] ).'" name="'.esc_attr( $option['name'] ).'" min="0" max="100" step="10" value="'.esc_attr($options_value).'" />'; | |
| 962 | - print '<div class="settings_details">'.wp_kses_post( $option['details'] ).'</div>'; | |
| 963 | - break; | |
| 964 | - // Delegates to the Support tab renderer (plugin error log table). | |
| 965 | - case 'logs_table': | |
| 966 | - $this->wpstream_support_tab(); | |
| 967 | - break; | |
| 968 | - } | |
| 969 | - print '</div>'; | |
| 970 | - } | |
| 356 | + print '<div class="event_list_unit '.$live_class.' event_unit_style_'.esc_attr($is_front).'">'; | |
| 357 | + if(has_post_thumbnail($the_id)){ | |
| 358 | + $thumb = get_the_post_thumbnail_url($the_id,'thumbnail'); | |
| 359 | + }else{ | |
| 360 | + $thumb= plugin_dir_url( dirname( __FILE__ ) ). 'img/default_150.jpg'; | |
| 361 | + } | |
| 971 | 362 | |
| 972 | - /** | |
| 973 | - * Fires inside the options wrapper of a settings tab, after its fields. | |
| 974 | - * | |
| 975 | - * The dynamic part is the tab slug. Callbacks echo their own markup | |
| 976 | - * and own its escaping; fields they add to the form are saved only | |
| 977 | - * when declared through `wpstream_settings_fields`. | |
| 978 | - * | |
| 979 | - * @since 4.14.0 | |
| 980 | - * | |
| 981 | - * @param string $active_tab Tab being rendered. | |
| 982 | - */ | |
| 983 | - do_action( 'wpstream_settings_tab_' . $active_tab, $active_tab ); | |
| 984 | - print '</div>'; // options wrapper | |
| 985 | - // Contextual help link for tabs that have one. | |
| 986 | - if($help_link!==''){ | |
| 987 | - print '<div class="wpstream_options_help"><a href="'.esc_url($help_link).'" target="_blank" >'.esc_html__('Video Help','wpstream').'</a></div>'; | |
| 988 | - } | |
| 989 | - print '</div>'; | |
| 363 | + global $wpstream_plugin; | |
| 364 | + | |
| 365 | + | |
| 366 | + print '<div class="event_thumb_wrapper"><img class="event_thumb" src="'.$thumb.'" alt="show_imagge"></div>'; | |
| 367 | + print '<h3 data-prodid="'.$the_id.'">'.get_the_title($the_id).' - '.esc_html__('Id','wpstream').': '.$the_id.'<a class="view_channel" href="'.get_permalink($the_id).'" target="_blank">'.esc_html__('View Channel','wprentals').'</a></h3> '; | |
| 990 | 368 | |
| 369 | + | |
| 370 | + | |
| 371 | + $live_event_stream_name = get_post_meta($the_id,'live_event_stream_name',true); | |
| 372 | + $live_event_array = get_post_meta($the_id,'live_event_uri',true); | |
| 373 | + $live_event_uri = ''; | |
| 991 | 374 | |
| 992 | - // Save button (hidden on the read-only Support tab). | |
| 993 | - if ( $active_tab != 'support_tab') { | |
| 994 | - print '<div class="wpstream-save-settings">'; | |
| 995 | - print '<input type="submit" name="submit" class="wpstream_button wpstream_button_action" value="'.__('Save Changes','wpstream').'" />'; | |
| 996 | - print '<div class="spinner"></div>'; | |
| 997 | - print '</div>'; | |
| 998 | - } | |
| 999 | 375 | |
| 1000 | - // CSRF nonce for the submission handled at the top of this method. | |
| 1001 | - print '<input id="wpstream-settings-nonce" name="wpstream-settings-nonce" type="hidden" value="'.wp_create_nonce('wpstream-settings-nonce').'" /> '; | |
| 1002 | - print '</form>'; | |
| 1003 | - print '</div>'; | |
| 376 | + $pending_streaming_class = ''; | |
| 377 | + $wpstream_ready_to_stream_class = ''; | |
| 378 | + $external_software_streaming_class = ''; | |
| 379 | + $wpstream_no_stream_class = ''; | |
| 380 | + $carnat_key1 = ''; | |
| 381 | + $carnat_key2 = ''; | |
| 382 | + $uri = ''; | |
| 383 | + $webcaster_url = ''; | |
| 384 | + $rtmp_ip_uri = ''; | |
| 385 | + $uri_ip = ''; | |
| 386 | + $server_id = ''; | |
| 387 | + $obs_uri = ''; | |
| 388 | + $obs_stream = ''; | |
| 389 | + $webCasterUrl = ''; | |
| 390 | + | |
| 391 | + if( $live_event_for_user=='' && $is_front=='front' ){ | |
| 392 | + $live_event_for_user = $this->main->wpstream_live_connection->wpstream_get_live_event_for_user(); | |
| 393 | + } | |
| 394 | + | |
| 395 | + | |
| 396 | + | |
| 397 | + if(is_array($live_event_for_user) && isset($live_event_for_user[$the_id])) { | |
| 1004 | 398 | |
| 1005 | - } | |
| 399 | + $pending_streaming_class = 'show_stream_data pending_trigger'; | |
| 400 | + $wpstream_ready_to_stream_class = 'hide_stream_data'; | |
| 401 | + $external_software_streaming_class = 'show_stream_data'; | |
| 402 | + $wpstream_no_stream_class = 'hide_stream_data'; | |
| 403 | + if(isset($live_event_for_user[$the_id]['live_uri'])){ | |
| 404 | + $explode = explode('wpstream.net/', $live_event_for_user[$the_id]['live_uri']); | |
| 405 | + $uri = $explode[0].'wpstream.net/wpstream/'; | |
| 406 | + $stream_name = get_post_meta($the_id,'live_event_stream_name',true); | |
| 407 | + $carnat_key1 = $live_event_for_user[$the_id]['carnat1']; | |
| 408 | + $carnat_key2 = $live_event_for_user[$the_id]['carnat2']; | |
| 409 | + $webcaster_url = 'https://'.$live_event_for_user[$the_id]['subdomain_key'].'.live.streamer.wpstream.net:8443/'.$live_event_for_user[$the_id]['carnat2']; | |
| 1006 | 410 | |
| 1007 | - /** | |
| 1008 | - * Get system information for support tab | |
| 1009 | - * | |
| 1010 | - * @return array System information | |
| 1011 | - */ | |
| 1012 | - private function get_system_info() { | |
| 1013 | - global $wp_version; | |
| 411 | + $rtmp_ip_uri = 'http://'.$live_event_for_user[$the_id]['ip'].':8444'; | |
| 412 | + $uri_ip= 'rtmp://'.$live_event_for_user[$the_id]['ip'].'/wpstream/'; | |
| 413 | + | |
| 414 | + // starting from 2.0 | |
| 415 | + $server_id = get_post_meta($the_id,'server_id',true); | |
| 416 | + $obs_uri = get_post_meta($the_id,'obs_uri',true); | |
| 417 | + $obs_stream = get_post_meta($the_id,'obs_stream',true); | |
| 418 | + $webCasterUrl= get_post_meta($the_id,'webCasterUrl',true); | |
| 419 | + | |
| 420 | + // if local server id diffrens than wpstream server id it means call was made via api and we use wpstream ip | |
| 421 | + if( $server_id != $live_event_for_user[$the_id]['api20_event_id'] && $live_event_for_user[$the_id]['api20_event_id']!='' ){ | |
| 422 | + | |
| 423 | + $server_id=esc_html($live_event_for_user[$the_id]['api20_event_id']); | |
| 424 | + } | |
| 425 | + | |
| 426 | + } | |
| 1014 | 427 | |
| 1015 | - // Environment facts: PHP/WP version, debug flag, memory limit and the plugin version. | |
| 1016 | - $php_version = phpversion(); | |
| 1017 | - $wp_version_info = $wp_version; | |
| 1018 | - $site_debug_mode = (defined('WP_DEBUG') && WP_DEBUG); | |
| 1019 | - $wp_memory_limit = WP_MEMORY_LIMIT; | |
| 428 | + }else{ | |
| 1020 | 429 | |
| 1021 | - $wpstream_version = WPSTREAM_PLUGIN_VERSION; | |
| 1022 | - $wpstream_plugin_outdated = false; | |
| 430 | + $pending_streaming_class = 'hide_stream_data'; | |
| 431 | + $wpstream_ready_to_stream_class = 'hide_stream_data'; | |
| 432 | + $external_software_streaming_class = 'hide_stream_data'; | |
| 433 | + $wpstream_no_stream_class = 'show_stream_data'; | |
| 434 | + } | |
| 1023 | 435 | |
| 1024 | - // Check if plugin is outdated | |
| 1025 | - // Mark the plugin outdated if WP's update transient lists an available update for it. | |
| 1026 | - $update_plugins = get_site_transient('update_plugins'); | |
| 1027 | - if (isset($update_plugins->response['plugin/wpstream.php'])) { | |
| 1028 | - $wpstream_plugin_outdated = true; | |
| 1029 | - } | |
| 1030 | 436 | |
| 1031 | - // Check API status | |
| 1032 | - // API is "connected" when a WpStream cloud token can be obtained. | |
| 1033 | - $api_status = false; | |
| 1034 | - if (method_exists($this->main->wpstream_live_connection, 'is_connected')) { | |
| 1035 | - $api_status = $this->main->wpstream_live_connection->is_connected(); | |
| 1036 | - } | |
| 1037 | 437 | |
| 1038 | - // Return the collected diagnostics for the Support tab to render. | |
| 1039 | - return array( | |
| 1040 | - 'php_version' => $php_version, | |
| 1041 | - 'wp_version' => $wp_version_info, | |
| 1042 | - 'site_debug_mode' => $site_debug_mode, | |
| 1043 | - 'wp_memory_limit' => $wp_memory_limit, | |
| 1044 | - 'wpstream_version' => $wpstream_version, | |
| 1045 | - 'wpstream_plugin_outdated' => $wpstream_plugin_outdated, | |
| 1046 | - 'api_status' => $api_status | |
| 1047 | - ); | |
| 1048 | - } | |
| 1049 | 438 | |
| 1050 | - /** | |
| 1051 | - * Render system information HTML | |
| 1052 | - * | |
| 1053 | - * Prints the Support-tab diagnostics table (PHP/WP versions, debug mode, | |
| 1054 | - * memory limit, plugin version + update button, API connection) with a | |
| 1055 | - * warning/OK dashicon per row. Echoes HTML. | |
| 1056 | - * | |
| 1057 | - * @return void | |
| 1058 | - */ | |
| 1059 | - private function render_system_info() { | |
| 1060 | - // Pull the current environment diagnostics. | |
| 1061 | - $system_info = $this->get_system_info(); | |
| 1062 | - // Below: diagnostics table; each row shows a value and a warning/OK indicator based on recommended thresholds. | |
| 1063 | - ?> | |
| 439 | + print' <div class="pending_streaming '.$pending_streaming_class.' " data-show-id="'.$the_id.'" data-server-id="'.$server_id.'" data-server-url="'.$rtmp_ip_uri.'">'; | |
| 440 | + print'<div class="wpstream_channel_status not_ready_to_stream"><span class="dashicons dashicons-dismiss"></span>'.esc_html__('Your Event is starting. Please wait...','wprentals').' '; | |
| 441 | + print '<img class="server_loading_new" src="'.plugin_dir_url( dirname( __FILE__ ) ).'img/loading.gif" alt="loading" /></div>'; | |
| 442 | + print '<div class="multiple_warning_events"> '.esc_html__('To go Live on a Channel, you need to start an Event. It will stop automatically after an hour of inactivity.','wpstream').'</div>'; | |
| 443 | + print '</div>'; | |
| 1064 | 444 | |
| 1065 | - <div class="wpstream-system-info"> | |
| 1066 | - <h3><?php esc_html_e('System Information', 'wpstream'); ?></h3> | |
| 1067 | - <table class="widefat"> | |
| 1068 | - <tbody> | |
| 1069 | - <tr> | |
| 1070 | - <td><strong><?php esc_html_e('PHP Version', 'wpstream'); ?></strong></td> | |
| 1071 | - <td><?php echo esc_html($system_info['php_version']); ?></td> | |
| 1072 | - <td> | |
| 1073 | - <?php if (version_compare($system_info['php_version'], '7.4', '<')): ?> | |
| 1074 | - <span class="dashicons dashicons-warning" style="color: #ffb900;"></span> | |
| 1075 | - <?php esc_html_e('We recommend PHP 7.4 or higher', 'wpstream'); ?> | |
| 1076 | - <?php else: ?> | |
| 1077 | - <span class="dashicons dashicons-yes-alt" style="color: #46b450;"></span> | |
| 1078 | - <?php endif; ?> | |
| 1079 | - </td> | |
| 1080 | - </tr> | |
| 1081 | - <tr> | |
| 1082 | - <td><strong><?php esc_html_e('WordPress Version', 'wpstream'); ?></strong></td> | |
| 1083 | - <td><?php echo esc_html($system_info['wp_version']); ?></td> | |
| 1084 | - <td> | |
| 1085 | - <?php if (version_compare($system_info['wp_version'], '5.6', '<')): ?> | |
| 1086 | - <span class="dashicons dashicons-warning" style="color: #ffb900;"></span> | |
| 1087 | - <?php esc_html_e('We recommend WordPress 5.6 or higher', 'wpstream'); ?> | |
| 1088 | - <?php else: ?> | |
| 1089 | - <span class="dashicons dashicons-yes-alt" style="color: #46b450;"></span> | |
| 1090 | - <?php endif; ?> | |
| 1091 | - </td> | |
| 1092 | - </tr> | |
| 1093 | - <tr> | |
| 1094 | - <td><strong><?php esc_html_e('WP Debug Mode', 'wpstream'); ?></strong></td> | |
| 1095 | - <td><?php echo $system_info['site_debug_mode'] ? esc_html__('Enabled', 'wpstream') : esc_html__('Disabled', 'wpstream'); ?></td> | |
| 1096 | - <td> | |
| 1097 | - <?php if ($system_info['site_debug_mode']): ?> | |
| 1098 | - <span class="dashicons dashicons-info" style="color: #00a0d2;"></span> | |
| 1099 | - <?php esc_html_e('Debug mode should be disabled on production sites', 'wpstream'); ?> | |
| 1100 | - <?php else: ?> | |
| 1101 | - <span class="dashicons dashicons-yes-alt" style="color: #46b450;"></span> | |
| 1102 | - <?php endif; ?> | |
| 1103 | - </td> | |
| 1104 | - </tr> | |
| 1105 | - <tr> | |
| 1106 | - <td><strong><?php esc_html_e('WP Memory Limit', 'wpstream'); ?></strong></td> | |
| 1107 | - <td><?php echo esc_html($system_info['wp_memory_limit']); ?></td> | |
| 1108 | - <td> | |
| 1109 | - <?php | |
| 1110 | - $memory_limit = wp_convert_hr_to_bytes($system_info['wp_memory_limit']); | |
| 1111 | - if ($memory_limit < 64 * 1024 * 1024): // 64MB | |
| 1112 | - ?> | |
| 1113 | - <span class="dashicons dashicons-warning" style="color: #ffb900;"></span> | |
| 1114 | - <?php esc_html_e('We recommend at least 64MB', 'wpstream'); ?> | |
| 1115 | - <?php else: ?> | |
| 1116 | - <span class="dashicons dashicons-yes-alt" style="color: #46b450;"></span> | |
| 1117 | - <?php endif; ?> | |
| 1118 | - </td> | |
| 1119 | - </tr> | |
| 1120 | - <tr> | |
| 1121 | - <td><strong><?php esc_html_e('WpStream Version', 'wpstream'); ?></strong></td> | |
| 1122 | - <td><?php echo esc_html($system_info['wpstream_version']); ?></td> | |
| 1123 | - <td style="display: flex; align-items: center; gap: 5px;"> | |
| 1124 | - <?php if ($system_info['wpstream_plugin_outdated']): ?> | |
| 1125 | - <span class="dashicons dashicons-warning" style="color: #ffb900;"></span> | |
| 1126 | - <?php esc_html_e('Update available', 'wpstream'); ?> | |
| 1127 | - <div class="update-button-wrapper"> | |
| 1128 | - <button class="wpstream-update-plugin-button button button-primary" data-plugin="wpstream/wpstream.php"> | |
| 1129 | - <?php esc_html_e('Update Now', 'wpstream'); ?> | |
| 1130 | - </button> | |
| 1131 | - </div> | |
| 1132 | - <?php else: ?> | |
| 1133 | - <span class="dashicons dashicons-yes-alt" style="color: #46b450;"></span> | |
| 1134 | - <?php endif; ?> | |
| 1135 | - </td> | |
| 1136 | - </tr> | |
| 1137 | - <tr> | |
| 1138 | - <td><strong><?php esc_html_e('API Connection', 'wpstream'); ?></strong></td> | |
| 1139 | - <td><?php echo $system_info['api_status'] ? esc_html__('Connected', 'wpstream') : esc_html__('Disconnected', 'wpstream'); ?></td> | |
| 1140 | - <td> | |
| 1141 | - <?php if (!$system_info['api_status']): ?> | |
| 1142 | - <span class="dashicons dashicons-warning" style="color: #ffb900;"></span> | |
| 1143 | - <?php esc_html_e('API connection issue', 'wpstream'); ?> | |
| 1144 | - <?php else: ?> | |
| 1145 | - <span class="dashicons dashicons-yes-alt" style="color: #46b450;"></span> | |
| 1146 | - <?php endif; ?> | |
| 1147 | - </td> | |
| 1148 | - </tr> | |
| 1149 | - </tbody> | |
| 1150 | - </table> | |
| 1151 | - </div> | |
| 1152 | - <?php | |
| 1153 | - } | |
| 1154 | 445 | |
| 1155 | - /** | |
| 1156 | - * Render support tab content | |
| 1157 | - * | |
| 1158 | - * Prints the Support tab: the system-info table, a table of relevant active | |
| 1159 | - * plugins with update tooltips, and a table of the plugin's recent logs. | |
| 1160 | - * Echoes HTML. | |
| 1161 | - * | |
| 1162 | - * @return void | |
| 1163 | - */ | |
| 1164 | - public function wpstream_support_tab() { | |
| 1165 | - // Below: Support tab markup (system info, active plugins table, recent logs table). | |
| 1166 | - ?> | |
| 1167 | - <div class="wrap"> | |
| 1168 | - <div class="wpstream-support-tab-root"> | |
| 1169 | - <?php $this->render_system_info(); ?> | |
| 446 | + print '<div class="wpstream_ready_to_stream '.$wpstream_ready_to_stream_class.'">'; | |
| 447 | + print '<div class="wpstream_channel_status"><span class="dashicons dashicons-yes"></span>'.esc_html__('Ready to Go Live !','wpstream').'</div>'; | |
| 448 | + print '<div class="start_webcaster wpstream_button" data-webcaster-url="'.$webCasterUrl.'" >'.esc_html__('Go Live from Browser','wpstream').'</div>'; | |
| 449 | + print '<div class="start_external wpstream_button" >'.esc_html__('Go Live with External Broadcaster','wpstream').'</div>'; | |
| 450 | + print '<div class="stop_server wpstream_button" data-show-id="'.$the_id.'">'.esc_html__('Turn Off Channel','wpstream').'</div>'; | |
| 451 | + $ajax_nonce_stop = wp_create_nonce( "wpstream_stop_event_nonce" ); | |
| 452 | + print '<input type="hidden" id="wpstream_stop_event_nonce" value="'.$ajax_nonce_stop.'">'; | |
| 453 | + print '</div>'; | |
| 1170 | 454 | |
| 1171 | - <div class="wpstream-plugins-table-container"> | |
| 1172 | - <h3><?php esc_html_e('Active Plugins', 'wpstream'); ?></h3> | |
| 1173 | - <table class="widefat wpstream-plugins-table"> | |
| 1174 | - <thead> | |
| 1175 | - <tr> | |
| 1176 | - <th><?php esc_html_e('Plugin', 'wpstream'); ?></th> | |
| 1177 | - <th><?php esc_html_e('Version', 'wpstream'); ?></th> | |
| 1178 | - </tr> | |
| 1179 | - </thead> | |
| 1180 | - <tbody> | |
| 1181 | - <?php | |
| 1182 | - // Build the relevant-plugins list; show a placeholder row when none are found. | |
| 1183 | - $plugins_data = $this->wpstream_get_plugins_data(); | |
| 1184 | - if (empty($plugins_data)) { | |
| 1185 | - echo '<tr><td colspan="3">' . esc_html__('No WPStream plugins found.', 'wpstream') . '</td></tr>'; | |
| 1186 | - } else { | |
| 1187 | - // One row per plugin; append an "update available" tooltip when a newer version exists. | |
| 1188 | - foreach ($plugins_data as $plugin) { | |
| 1189 | - echo '<tr>'; | |
| 1190 | - echo '<td>' . esc_html($plugin['name']) . '</td>'; | |
| 1191 | - echo '<td>'; | |
| 1192 | - echo esc_html($plugin['version']); | |
| 1193 | - if ( isset($plugin['new_version']) ) { | |
| 1194 | - echo '<div class="wpstream-tooltip-container">'; | |
| 1195 | - echo '<span class="dashicons dashicons-info wpstream-tooltip" title="' . esc_attr($plugin['new_version']) . '">'; | |
| 1196 | - echo '</span>'; | |
| 1197 | - echo '<div class="wpstream-custom-tooltip">' . sprintf( | |
| 1198 | - esc_html__('A new version is available: %s', 'wpstream'), | |
| 1199 | - esc_html($plugin['new_version']) | |
| 1200 | - ) . '</div>'; | |
| 1201 | - echo '</div>'; | |
| 1202 | - } | |
| 1203 | - echo '</td>'; | |
| 1204 | - echo '</tr>'; | |
| 1205 | - } | |
| 1206 | - } | |
| 1207 | - ?> | |
| 1208 | - </tbody> | |
| 1209 | - </table> | |
| 1210 | - </div> | |
| 1211 | 455 | |
| 1212 | - <div class="wpstream-logs-table-container"> | |
| 1213 | - <h3><?php esc_html_e('Recent Logs', 'wpstream'); ?></h3> | |
| 1214 | - <table class="widefat wpstream-logs-table"> | |
| 1215 | - <thead> | |
| 1216 | - <tr> | |
| 1217 | - <th><?php esc_html_e('Time', 'wpstream'); ?></th> | |
| 1218 | - <th><?php esc_html_e('Type', 'wpstream'); ?></th> | |
| 1219 | - <th><?php esc_html_e('Description', 'wpstream'); ?></th> | |
| 1220 | - </tr> | |
| 1221 | - </thead> | |
| 1222 | - <tbody> | |
| 1223 | - <?php | |
| 1224 | - // Load the stored plugin logs; show a placeholder row when empty. | |
| 1225 | - $logs = get_option('wpstream_logs'); | |
| 1226 | - if ( !is_array($logs) || empty($logs) ) { | |
| 1227 | - echo '<tr><td colspan="3">' . esc_html__('No logs found.', 'wpstream') . '</td></tr>'; | |
| 1228 | - } else { | |
| 1229 | - // One row per log entry (time, type, description). | |
| 1230 | - foreach ($logs as $log) { | |
| 1231 | - echo '<tr>'; | |
| 1232 | - echo '<td>' . esc_html(date('Y-m-d H:i:s', $log['timestamp'] ) ) . '</td>'; | |
| 1233 | - echo '<td>' . esc_html($log['type']) . '</td>'; | |
| 1234 | - echo '<td>' . esc_html($log['description']) . '</td>'; | |
| 1235 | - echo '</tr>'; | |
| 1236 | - } | |
| 1237 | - } | |
| 1238 | - ?> | |
| 1239 | - </tbody> | |
| 1240 | - </table> | |
| 1241 | - </div> | |
| 1242 | - </div> | |
| 1243 | - </div> | |
| 1244 | - <?php | |
| 1245 | - } | |
| 1246 | 456 | |
| 1247 | - /** | |
| 1248 | - * Get plugins data. | |
| 1249 | - * | |
| 1250 | - * Collects name/version/active/update info for a fixed allow-list of plugins | |
| 1251 | - * relevant to WpStream (WpStream, WooCommerce, Meta Box, One Click Demo | |
| 1252 | - * Import, Better Messages), used by the Support tab. | |
| 1253 | - * | |
| 1254 | - * @return array List of plugin info arrays (name, version, path, active, needs_update, [new_version]). | |
| 1255 | - */ | |
| 1256 | - public function wpstream_get_plugins_data() { | |
| 1257 | - // Ensure get_plugins() is available in non-admin contexts. | |
| 1258 | - if (!function_exists('get_plugins')) { | |
| 1259 | - require_once ABSPATH . 'wp-admin/includes/plugin.php'; | |
| 1260 | - } | |
| 457 | + print '<div class="external_software_streaming '. $external_software_streaming_class.' ">'; | |
| 458 | + print '<div class="event_list_unit_notificationx"><strong>'.__('Server:').' </strong> <div class="wpstream_live_uri_text">' . $obs_uri.'</div><div class="copy_live_uri">'.__('copy to clipboard','wpstream').'</div>'; | |
| 459 | + print '<div class="event_list_stream_key_wrap"><strong>'.__('Stream Key:').' </strong><div class="wpstream_live_key_text">'. $obs_stream.'</div><div class="copy_live_key">'.__('copy to clipboard','wpstream').'</div></div>'; | |
| 460 | + print '<div class="warning_stream">'. | |
| 461 | + sprintf(esc_html__('Use %s on your Windows or Mac computer, or the Larix Broadcaster app on your %s or %s smartphone/tablet. Various other Apps and devices are compatible. See %s for more details.','wpstream'),'<a href="https://obsproject.com/download" target="_blank">OBS Studio</a>','<a href="https://apps.apple.com/us/app/larix-broadcaster/id1042474385" target="_blank"> iOS</a>','<a href="https://play.google.com/store/apps/details?id=com.wmspanel.larix_broadcaster&hl=en" target="_blank">Android</a>','<a href="https://wpstream.net/external-broadcasters/" target="_blank">this page</a>').'</div>'; | |
| 462 | + print ' <img class="how_to" src="'.plugin_dir_url( dirname( __FILE__ ) ).'img/how_to_obs.jpg" alt="show_imagge">'; | |
| 463 | + print'</div>'; | |
| 464 | + print'</div>'; | |
| 1261 | 465 | |
| 1262 | - // Get all installed plugins | |
| 1263 | - $all_plugins = get_plugins(); | |
| 1264 | - $update_data = get_site_transient('update_plugins'); | |
| 1265 | - $all_plugins_info = []; | |
| 1266 | 466 | |
| 1267 | - // We want to get data only for the WpStream plugins | |
| 1268 | - $wpstream_plugins = array( | |
| 1269 | - 'WpStream' => array( | |
| 1270 | - 'path' => 'wpstream/wpstream.php', | |
| 1271 | - ), | |
| 1272 | - 'WooCommerce' => array( | |
| 1273 | - 'path' => 'woocommerce/woocommerce.php', | |
| 1274 | - ), | |
| 1275 | - 'Meta Box' => array( | |
| 1276 | - 'path' => 'meta-box/meta-box.php', | |
| 1277 | - ), | |
| 1278 | - 'One Click Demo Import' => array( | |
| 1279 | - 'path' => 'one-click-demo-import/one-click-demo-import.php', | |
| 1280 | - ), | |
| 1281 | - 'Better Messages' => array( | |
| 1282 | - 'path' => 'bp-better-messages/bp-better-messages.php', | |
| 1283 | - ), | |
| 1284 | 467 | |
| 1285 | - ); | |
| 1286 | 468 | |
| 1287 | - // Build an info array for every installed plugin (filtered down afterwards). | |
| 1288 | - foreach ($all_plugins as $plugin_path => $plugin_data) { | |
| 1289 | - $is_active = is_plugin_active( $plugin_path ); | |
| 1290 | - $has_update = isset( $update_data->response[$plugin_path] ); | |
| 469 | + print '<div class="wpstream_no_stream '.$wpstream_no_stream_class.' ">'; | |
| 470 | + print '<div class="event_list_unit_notificationx"><span class="server_notification">'.__('Broadcast Offline.','wpestream').' <img class="server_loading" src="'.plugins_url().'/wpstream/img/loading.gif" alt="loading" /></span></div>'; | |
| 471 | + print '<div class="record_wrapper">Record ? <input type="checkbox" name="record_event" class="record_event"/>Yes</div>'; | |
| 472 | + print '<div class="encrypt_wrapper">Encrypt ? <input type="checkbox" name="encrypt_event" class="encrypt_event"/>Yes</div>'; | |
| 473 | + | |
| 474 | + print '<input class="start_event wpstream_button" type="button" data-show-id="'.$the_id.'" value="'.esc_html__('Start Live Event','wpstream').'">'; | |
| 475 | + | |
| 476 | + if($is_front==''){ | |
| 477 | + print '<input class="close_event wpstream_button" type="button" data-show-id="'.$the_id.'" value="'.esc_html__('Delete Channel','wpstream').'">'; | |
| 478 | + } | |
| 479 | + | |
| 480 | + print '<div class="multiple_warning_events"> '.esc_html__('To go Live on a Channel, you need to start an Event. It will stop automatically after an hour of inactivity.','wpstream').'</div>'; | |
| 481 | + | |
| 482 | + | |
| 483 | + print '<div class="wpstream_social_media_broadcast">'; | |
| 484 | + | |
| 485 | + print '<div class="wpstream_social_media_unit"><input type="checkbox" class="wpstream_on_facebook" id="wpstream_on_facebook'.$the_id.'"><label for="wpstream_on_facebook'.$the_id.'">'.esc_html__('Stream on Facebook','wpstream').'</label>'; | |
| 486 | + print '</div>'; | |
| 1291 | 487 | |
| 1292 | - $plugin_info = [ | |
| 1293 | - 'name' => $plugin_data['Name'], | |
| 1294 | - 'version' => $plugin_data['Version'], | |
| 1295 | - 'path' => $plugin_path, | |
| 1296 | - 'active' => $is_active ? 'Yes' : 'No', | |
| 1297 | - 'needs_update' => $has_update ? 'Yes' : 'No' | |
| 1298 | - ]; | |
| 488 | + print '<div class="wpstream_social_media_unit"><input type="checkbox" class="wpstream_on_youtube" id="wpstream_on_youtube'.$the_id.'"><label for="wpstream_on_youtube'.$the_id.'">'.esc_html__('Stream on Youtube','wpstream').'</label>'; | |
| 489 | + print '</div>'; | |
| 1299 | 490 | |
| 1300 | - // Record the offered version when an update is pending. | |
| 1301 | - if ($has_update) { | |
| 1302 | - $plugin_info['new_version'] = $update_data->response[$plugin_path]->new_version; | |
| 1303 | - } | |
| 1304 | 491 | |
| 1305 | - $all_plugins_info[] = $plugin_info; | |
| 1306 | - } | |
| 492 | + print '<div class="wpstream_social_media_unit"><input type="checkbox" class="wpstream_on_twich" id="wpstream_on_twich'.$the_id.'"><label for="wpstream_on_twich'.$the_id.'">'.esc_html__('Stream on Twich','wpstream').'</label>'; | |
| 493 | + print '</div>'; | |
| 494 | + | |
| 495 | + print '<div class="wpstream_on_facebook_container wpstream_social_stream_container">'; | |
| 496 | + print 'Some Facebook Settings for event '.$the_id; | |
| 497 | + print '</div>'; | |
| 498 | + | |
| 499 | + print '<div class="wpstream_on_youtube_container wpstream_social_stream_container">'; | |
| 500 | + print '<label for="wpstream_youtube_rtmp'.$the_id.'">'.esc_html__('Youtube RTMP','wpstream').'</label>'; | |
| 501 | + print '<input type="text" class="wpstream_youtube_rtmp" id="wpstream_youtube_rtmp'.$the_id.'" value="'.esc_html(get_post_meta($the_id,'wpstream_youtube_rtmp',true )).'">'; | |
| 502 | + print '</div>'; | |
| 503 | + | |
| 504 | + print '<div class="wpstream_on_twich_container wpstream_social_stream_container">'; | |
| 505 | + print '<label for="wpstream_twich_rtmp'.$the_id.'">'.esc_html__('Twich RTMP','wpstream').'</label>'; | |
| 506 | + print '<input type="text" class="wpstream_twich_rtmp" id="wpstream_twich_rtmp'.$the_id.'" value="'.esc_html(get_post_meta($the_id,'wpstream_twich_rtmp',true )).'">'; | |
| 507 | + print '</div>'; | |
| 1307 | 508 | |
| 1308 | - // Filter out the elements from $all_plugins_info that are not in $wpstream_plugins | |
| 1309 | - foreach ( $all_plugins_info as $key => $plugin_info ) { | |
| 1310 | - // compare $plugin_info['path'] against the path property on each $wpstream_plugins element item | |
| 1311 | - // if the path is not in $wpstream_plugins, unset the element | |
| 1312 | - if ( !in_array( $plugin_info['path'], array_column( $wpstream_plugins, 'path' ) ) ) { | |
| 1313 | - unset( $all_plugins_info[$key] ); | |
| 1314 | - } | |
| 1315 | - } | |
| 509 | + | |
| 510 | + print '</div>'; | |
| 511 | + print '</div>'; | |
| 1316 | 512 | |
| 1317 | - return $all_plugins_info; | |
| 1318 | - } | |
| 1319 | 513 | |
| 1320 | - /** | |
| 1321 | - * Print a dismissible admin notice when a WpStream plugin update is pending. | |
| 1322 | - * | |
| 1323 | - * @return void | |
| 1324 | - */ | |
| 1325 | - public function wpstream_render_outdated_plugin_notice() { | |
| 1326 | - // Only render when WP's update transient lists an update for the plugin. | |
| 1327 | - $has_update = get_site_transient('update_plugins'); | |
| 1328 | - if (isset($has_update->response['plugin/wpstream.php'])) { | |
| 1329 | - // Below: warning notice linking to the WP updates page. | |
| 1330 | - ?> | |
| 1331 | - <div class="notice notice-warning is-dismissible"> | |
| 1332 | - <p> | |
| 1333 | - <?php | |
| 1334 | - printf( | |
| 1335 | - /* translators: 1: Link to update page */ | |
| 1336 | - esc_html__('A new version of WpStream is available. Please update to the latest version for the best experience. Go to the %1$s to update now.', 'wpstream'), | |
| 1337 | - '<a href="' . esc_url(admin_url('update-core.php')) . '">' . esc_html__('updates page', 'wpstream') . '</a>' | |
| 1338 | - ); | |
| 1339 | - ?> | |
| 1340 | - </p> | |
| 1341 | - </div> | |
| 1342 | - <?php | |
| 514 | + print '</div>'; | |
| 1343 | 515 | } |
| 1344 | - } | |
| 1345 | 516 | |
| 1346 | 517 | |
| 518 | + | |
| 519 | + | |
| 520 | + | |
| 1347 | 521 | /** |
| 1348 | - * Set user roles | |
| 1349 | - * | |
| 1350 | - * Render the grid of per-event streaming option switches (from | |
| 1351 | - * $global_event_options). Reused for both the site-wide default settings | |
| 1352 | - * and the per-channel settings modal. Echoes HTML. | |
| 1353 | - * | |
| 1354 | - * @param string $name Field name prefix/context (unused in body; kept for callers). | |
| 1355 | - * @param array|string $value Stored 1/0 map of option states (empty falls back to defaults). | |
| 1356 | - * @param array|string $local_array Option keys to EXCLUDE from this render (per-channel context). | |
| 1357 | - * @param bool $disabled True to render the switches disabled. | |
| 1358 | - * @param bool $is_basic_stream_mode True to disable switches for basic-streaming accounts. | |
| 1359 | - * @return void | |
| 1360 | - */ | |
| 1361 | - public function user_streaming_global_channel_options( | |
| 1362 | - $name, | |
| 1363 | - $value, | |
| 1364 | - $local_array='', | |
| 1365 | - $disabled = false, | |
| 1366 | - $is_basic_stream_mode = false | |
| 1367 | - ) { | |
| 522 | + * Set Settings | |
| 523 | + * | |
| 524 | + * | |
| 525 | + */ | |
| 1368 | 526 | |
| 1369 | - // Render one switch per defined global event option. | |
| 1370 | - foreach($this->global_event_options as $key=>$option){ | |
| 527 | + public function wpstream_settings(){ | |
| 528 | + | |
| 529 | + if($_SERVER['REQUEST_METHOD'] === 'POST'){ | |
| 530 | + $allowed_html = array(); | |
| 531 | + $exclude_array = array(); | |
| 532 | + $allowed_html = array(); | |
| 1371 | 533 | |
| 1372 | - // Skip options listed in the exclude array (used by the per-channel modal). | |
| 1373 | - if( is_array($local_array) && !in_array($key,$local_array)){ | |
| 1374 | - print '<div class="wpstream_setting_event_unit_wrapper wpstream-setting-'.esc_attr($key).' ">'; | |
| 1375 | - | |
| 1376 | - print '<label for="'.$option['name'].'">'.$option['name'].'</label>'; | |
| 1377 | - | |
| 1378 | - print '<div style="display: flex; gap: 25px; justify-content: space-between;">'; | |
| 1379 | - print '<div class="settings_details">'.$option['details'].'</div>'; | |
| 1380 | - print ' | |
| 1381 | - <label class="wpstream_switch"> | |
| 1382 | - <input type="checkbox" class="wpstream_event_option_item" data-attr-ajaxname="'.esc_attr($key).'" name="wpstream_event_set_'.esc_attr($key).'" '; | |
| 1383 | - // Check state: only a stored value of 1 renders the switch on. | |
| 1384 | - // An absent key resolves to off everywhere the settings are | |
| 1385 | - // consumed, so the screen must not promise otherwise. | |
| 1386 | - if( isset($value[$key]) && intval($value[$key]) !== 0 ){ | |
| 1387 | - print ' checked '; | |
| 534 | + | |
| 535 | + if( isset($_POST['user_streaming_channel_type_hidden']) && intval($_POST['user_streaming_channel_type_hidden'])==1 && !isset($_POST['stream_role']) ){ | |
| 536 | + update_option( sanitize_key('wpstream_stream_role'), '' ); | |
| 537 | + } | |
| 538 | + | |
| 539 | + | |
| 540 | + foreach($_POST as $variable=>$value){ | |
| 541 | + if ($variable!='submit'){ | |
| 542 | + if (!in_array($variable, $exclude_array) ){ | |
| 543 | + update_option( sanitize_key('wpstream_'.$variable), sanitize_text_field ($value) ); | |
| 1388 | 544 | } |
| 1389 | - // Disable the switch when requested or in basic-streaming mode. | |
| 1390 | - if ( $disabled || $is_basic_stream_mode ) { | |
| 1391 | - print ' disabled '; | |
| 545 | + | |
| 546 | + if($variable=='stream_role'){ | |
| 547 | + update_option( sanitize_key('wpstream_stream_role'), $value ); | |
| 1392 | 548 | } |
| 549 | + | |
| 550 | + } | |
| 551 | + } | |
| 552 | + | |
| 553 | + // reset permalinkgs | |
| 554 | + global $wp_rewrite; | |
| 555 | + | |
| 556 | + update_option( "rewrite_rules", FALSE ); | |
| 557 | + $wp_rewrite->flush_rules( true ); | |
| 558 | + | |
| 559 | + } | |
| 560 | + | |
| 561 | + $wpstream_settings_array =array( | |
| 562 | + 1 => array( | |
| 563 | + 'label' => esc_html__('Slug for wpstream free videos/channels','wpstream'), | |
| 564 | + 'name' => 'free_media_slug', | |
| 565 | + 'type' => 'text', | |
| 566 | + 'details' => esc_html__('It will replace wpstream in the free videos/channels url with your new slug. You cannot use special characters like "&". After changing the url go to Settings - Permalinks and Save again the "Permalinks Settings" - option "Post name" ','wpstream'), | |
| 567 | + ), | |
| 568 | + | |
| 569 | + 2 => array( | |
| 570 | + 'label' => esc_html__('Extra roles who can stream via wpstream shortcodes / blocks','wpstream'), | |
| 571 | + 'name' => 'stream_role', | |
| 572 | + 'type' => 'user_roles', | |
| 573 | + 'details' => esc_html__('A non admin user will be able to stream only on one channel only that will be automaticaly created.','wpstream'), | |
| 574 | + | |
| 575 | + ), | |
| 576 | + 3 => array( | |
| 577 | + 'label' => esc_html__('Type channel on wich non admin users can stream ','wpstream'), | |
| 578 | + 'name' => 'user_streaming_channel_type', | |
| 579 | + 'type' => 'select', | |
| 580 | + 'select_values'=>array( | |
| 581 | + 'free' => esc_html__('Free Live Channels','wpstream'), | |
| 582 | + 'paid' => esc_html__('Pay per view (WooCommerce product)','wpstream') | |
| 583 | + ), | |
| 584 | + 'details' => esc_html__('The product type channel is a WooCommerce product (pay per view) while Free Channels is visible to all types of visitors ','wpstream'), | |
| 585 | + ), | |
| 586 | + | |
| 587 | + 4 => array( | |
| 588 | + 'label' => esc_html__('Default Price ','wpstream'), | |
| 589 | + 'name' => 'user_streaming_default_price', | |
| 590 | + 'type' => 'text', | |
| 591 | + 'details' => esc_html__('If non admins can stream on a product channel then you can set here the default price here.','wpstream'), | |
| 592 | + ), | |
| 593 | + ); | |
| 594 | + | |
| 595 | + | |
| 596 | + | |
| 597 | + print '<form method="post" action="" >'; | |
| 598 | + print '<div class="theme_options_tab_wpstream" style="display:block;" > | |
| 599 | + <h1>'.__('WpStream Settings','wpstream').'</h1>'; | |
| 1393 | 600 | |
| 1394 | 601 | |
| 1395 | - print '> <span class="wpstream_slider round"></span>'; | |
| 1396 | - print '</label>'; | |
| 1397 | - print '</div>'; | |
| 1398 | 602 | |
| 603 | + print '<div class="wpstream_option_wrapper">'; | |
| 604 | + foreach ($wpstream_settings_array as $key=>$option){ | |
| 605 | + print '<div class="wpstream_option">'; | |
| 606 | + $options_value = get_option('wpstream_'.$option['name']) ; | |
| 607 | + | |
| 608 | + | |
| 609 | + | |
| 610 | + if($option['type']=='user_roles'){ | |
| 611 | + | |
| 612 | + print '<label for="'.$option['name'].'">'.$option['label'].'</label>'; | |
| 613 | + print $this->wpstream_select_user_roles($option['name'],$options_value); | |
| 614 | + print '<div class="settings_details">'.$option['details'].'</div>'; | |
| 1399 | 615 | |
| 1400 | - print '</div>'; | |
| 1401 | - } | |
| 1402 | - } | |
| 1403 | 616 | |
| 617 | + }else if($option['type']=='text'){ | |
| 1404 | 618 | |
| 1405 | - } | |
| 1406 | - | |
| 619 | + print '<label for="'.$option['name'].'">'.$option['label'].'</label>'; | |
| 620 | + print '<input id="'.$option['name'].'" type="'.$option['type'].'" size="36" name="'.$option['name'].'" value="'.esc_attr($options_value).'" />'; | |
| 621 | + print '<div class="settings_details">'.$option['details'].'</div>'; | |
| 622 | + | |
| 623 | + } else if($option['type']=='select'){ | |
| 624 | + | |
| 625 | + print '<label for="'.$option['name'].'">'.$option['label'].'</label>'; | |
| 626 | + print '<select id="'.$option['name'].'" name="'.$option['name'].'" >'; | |
| 627 | + foreach($option['select_values'] as $key=>$value){ | |
| 628 | + print '<option value="'.$key.'" '; | |
| 629 | + if( $key == esc_html($options_value) ){ | |
| 630 | + print ' selected '; | |
| 631 | + } | |
| 632 | + print '>'.$value.'</option>'; | |
| 633 | + } | |
| 634 | + print '</select>'; | |
| 635 | + print '<input type="hidden" name="'.$option['name'].'_hidden" value="1" >'; | |
| 636 | + print '<div class="settings_details">'.$option['details'].'</div>'; | |
| 637 | + | |
| 638 | + } | |
| 639 | + | |
| 640 | + print '</div>'; | |
| 641 | + } | |
| 642 | + print '</div>'; | |
| 1407 | 643 | |
| 1408 | - | |
| 1409 | - | |
| 1410 | 644 | |
| 645 | + print '<input type="submit" name="submit" class="wpstream_button" value="'.__('Save Changes','wpstream').'" />'; | |
| 1411 | 646 | |
| 1412 | 647 | |
| 648 | + | |
| 649 | + print '</div>'; | |
| 650 | + print '</form>'; | |
| 651 | + } | |
| 652 | + | |
| 1413 | 653 | |
| 1414 | 654 | |
| 1415 | - /* | |
| 1416 | - * Set user roles | |
| 1417 | - * | |
| 1418 | - * @since 3.0.1 | |
| 1419 | - */ | |
| 655 | + | |
| 656 | + | |
| 657 | + | |
| 658 | + | |
| 1420 | 659 | /** |
| 1421 | - * Build a multi-select of editable user roles (administrator excluded) | |
| 1422 | - * for the "roles allowed to broadcast" setting. | |
| 1423 | - * | |
| 1424 | - * @param string $name Field name (rendered as name="{name}[]"). | |
| 1425 | - * @param array|string $value Currently selected role keys ('' becomes an empty array). | |
| 1426 | - * @return string HTML <select> markup. | |
| 1427 | - */ | |
| 660 | + * Set user roles | |
| 661 | + * | |
| 662 | + * @since 3.0.1 | |
| 663 | + */ | |
| 1428 | 664 | public function wpstream_select_user_roles($name,$value){ |
| 1429 | - // Normalize an empty stored value to an array for in_array() below. | |
| 1430 | 665 | if($value==''){ |
| 1431 | 666 | $value=array(); |
| 1432 | 667 | } |
| 1433 | - | |
| 1434 | - // All editable roles minus administrator (admins always can broadcast). | |
| 668 | + | |
| 1435 | 669 | $roles = get_editable_roles(); |
| 1436 | 670 | $return = '<select id="wpstream_user_roles" name="'.esc_html($name).'[]" multiple>'; |
| 1437 | 671 | unset( $roles['administrator'] ); |
| 1438 | - | |
| 1439 | - // One option per role, pre-selecting those already chosen. | |
| 672 | + | |
| 1440 | 673 | foreach ($roles as $key=>$role){ |
| 1441 | 674 | $return .= '<option value="'.$key.'" '; |
| 1442 | 675 | if( in_array($key, $value) ){ |
| 1443 | 676 | $return .= ' selected '; |
| @@ -1444,129 +677,48 @@ | ||
| 1444 | 677 | } |
| 1445 | 678 | $return .= '>'.$role['name'].'</option>'; |
| 1446 | 679 | } |
| 1447 | 680 | $return .= '</select>'; |
| 1448 | - | |
| 1449 | - | |
| 681 | + | |
| 682 | + | |
| 1450 | 683 | return $return; |
| 1451 | 684 | } |
| 1452 | 685 | |
| 1453 | - | |
| 1454 | - /* | |
| 1455 | - * Set credential admin function | |
| 1456 | - * | |
| 1457 | - * @since 3.0.1 | |
| 1458 | - */ | |
| 686 | + | |
| 1459 | 687 | /** |
| 1460 | - * Render the Credentials admin screen and save submitted API credentials. | |
| 1461 | - * | |
| 1462 | - * On POST it stores the WpStream username/password options and clears the | |
| 1463 | - * cached token/quota transients so the next request re-authenticates. It | |
| 1464 | - * then shows the connection status and the credentials form. Echoes HTML. | |
| 1465 | - * | |
| 1466 | - * @return void | |
| 1467 | - */ | |
| 688 | + * Set credential admin function | |
| 689 | + * | |
| 690 | + * @since 3.0.1 | |
| 691 | + */ | |
| 1468 | 692 | public function wpstream_set_wpstream_credentials(){ |
| 1469 | - $credentials_from_constants = wpstream_api_credentials_from_constants(); | |
| 1470 | - | |
| 1471 | - // Handle a credentials submission. | |
| 1472 | - if($_SERVER['REQUEST_METHOD'] === 'POST'){ | |
| 1473 | - // CSRF/permission gate: only an admin submitting the credentials | |
| 1474 | - // form (with its nonce) may overwrite the stored API credentials. | |
| 1475 | - $this->wpstream_require_settings_capability(); | |
| 1476 | - check_admin_referer( 'wpstream_save_credentials', 'wpstream_credentials_nonce' ); | |
| 1477 | - | |
| 1478 | - // wp-config owns the complete pair. A forged/manual POST must be the | |
| 1479 | - // same no-op as the disabled form presented to the administrator. | |
| 1480 | - if ( ! $credentials_from_constants ) { | |
| 1481 | - | |
| 693 | + | |
| 694 | + if($_SERVER['REQUEST_METHOD'] === 'POST'){ | |
| 1482 | 695 | $allowed_html = array(); |
| 1483 | 696 | $exclude_array = array(); |
| 1484 | 697 | $allowed_html = array(); |
| 1485 | 698 | |
| 1486 | - // Username before this submission: tells a cleared form apart from a new account. | |
| 1487 | - $previous_username = (string) get_option( 'wpstream_api_username', '' ); | |
| 1488 | - | |
| 1489 | - // Persist only the recognised credential fields. | |
| 1490 | - foreach($_POST as $variable=>$value){ | |
| 699 | + foreach($_POST as $variable=>$value){ | |
| 1491 | 700 | if ($variable!='submit'){ |
| 1492 | 701 | if (!in_array($variable, $exclude_array) ){ |
| 1493 | - switch ( $variable ) { | |
| 1494 | - case 'api_username': | |
| 1495 | - // Unslashed first: WordPress slashes every $_POST value, | |
| 1496 | - // so a username containing a quote would otherwise be | |
| 1497 | - // stored with a stray backslash and never authenticate. | |
| 1498 | - // Then sanitized as text. | |
| 1499 | - update_option( sanitize_key('wpstream_api_username'), sanitize_text_field( wp_unslash( $value ) ) ); | |
| 1500 | - break; | |
| 1501 | - case 'api_password': | |
| 1502 | - // Only unslashed, never sanitized: the password is a secret | |
| 1503 | - // sent verbatim to the API, and sanitizing would silently | |
| 1504 | - // change it. Unslashing undoes the escaping WordPress adds | |
| 1505 | - // to every $_POST value, without which a password holding a | |
| 1506 | - // quote or a backslash is stored — and sent — wrong, so the | |
| 1507 | - // customer is told their correct password is incorrect. | |
| 1508 | - // Not autoloaded: it is only needed when authenticating. | |
| 1509 | - // An empty submission keeps the current password, since the | |
| 1510 | - // form never pre-fills the field with the stored secret. | |
| 1511 | - $password = wp_unslash( $value ); | |
| 1512 | - if ( $password !== '' ) { | |
| 1513 | - update_option( 'wpstream_api_password', $password, false ); | |
| 1514 | - } elseif ( | |
| 1515 | - array_key_exists( 'api_username', $_POST ) | |
| 1516 | - && '' === sanitize_text_field( wp_unslash( $_POST['api_username'] ) ) | |
| 1517 | - ) { | |
| 1518 | - // Clearing the account is an explicit disconnect, not a | |
| 1519 | - // password-only edit. Do not retain an orphaned secret. | |
| 1520 | - delete_option( 'wpstream_api_password' ); | |
| 1521 | - } | |
| 1522 | - break; | |
| 1523 | - } | |
| 1524 | - } | |
| 1525 | - } | |
| 702 | + update_option( sanitize_key('wpstream_'.$variable), wp_kses ($value,$allowed_html) ); | |
| 703 | + } | |
| 704 | + } | |
| 1526 | 705 | } |
| 706 | + | |
| 707 | + | |
| 1527 | 708 | |
| 1528 | 709 | |
| 710 | + update_option('wp_estate_token_expire',0); | |
| 711 | + update_option('wp_estate_curent_token',' '); | |
| 712 | + delete_transient( 'wpstream_token_request'); | |
| 1529 | 713 | |
| 1530 | - // Invalidate any cached token/quota so the new credentials are used immediately. | |
| 1531 | - update_option('wpstream_token_expire',0); | |
| 1532 | - update_option('wpstream_current_token',' '); | |
| 1533 | - delete_transient( 'wpstream_token_api'); | |
| 1534 | - delete_transient('wpstream_token_request_30'); | |
| 1535 | - $this->main->quota_manager->invalidate(); | |
| 1536 | - | |
| 1537 | - // Announce the account change. Only the username travels: the | |
| 1538 | - // password and any token stay server-side. | |
| 1539 | - $username = (string) get_option( 'wpstream_api_username', '' ); | |
| 1540 | - if ( '' !== $username ) { | |
| 1541 | - /** | |
| 1542 | - * Fires after WpStream account credentials were saved and the | |
| 1543 | - * cached token/quota dropped; the connection itself is verified | |
| 1544 | - * on the next API call. | |
| 1545 | - * | |
| 1546 | - * @since 4.14.0 | |
| 1547 | - * | |
| 1548 | - * @param string $username WpStream.net username or e-mail. | |
| 1549 | - */ | |
| 1550 | - do_action( 'wpstream_account_connected', $username ); | |
| 1551 | - } elseif ( '' !== $previous_username ) { | |
| 1552 | - /** | |
| 1553 | - * Fires after the WpStream account username was cleared. | |
| 1554 | - * | |
| 1555 | - * @since 4.14.0 | |
| 1556 | - * | |
| 1557 | - * @param string $username The username that was removed. | |
| 1558 | - */ | |
| 1559 | - do_action( 'wpstream_account_disconnected', $previous_username ); | |
| 1560 | - } | |
| 1561 | - } | |
| 1562 | 714 | } |
| 1563 | 715 | |
| 1564 | 716 | |
| 1565 | 717 | $allowed_html = array(); |
| 718 | + $api_key = esc_html( get_option('wpstream_api_key','') ); | |
| 1566 | 719 | |
| 1567 | 720 | |
| 1568 | - // Field definitions for the credentials form (username + password). | |
| 1569 | 721 | $wpstream_options_array =array( |
| 1570 | 722 | 2 => array( |
| 1571 | 723 | 'label' => 'WpStream.net Username or Email', |
| 1572 | 724 | 'name' => 'api_username', |
| @@ -1580,67 +732,34 @@ | ||
| 1580 | 732 | |
| 1581 | 733 | ); |
| 1582 | 734 | |
| 1583 | 735 | |
| 1584 | - // Existing installs saved the password as an autoloaded option; flip it | |
| 1585 | - // to non-autoloaded so the secret is not loaded on every request. | |
| 1586 | - if ( function_exists( 'wp_set_option_autoload' ) ) { | |
| 1587 | - wp_set_option_autoload( 'wpstream_api_password', false ); | |
| 1588 | - } | |
| 1589 | - | |
| 1590 | - // Connectivity and quota data drive the connection-status banner below. | |
| 1591 | - $connected = $this->main->wpstream_live_connection->is_connected(); | |
| 1592 | - $pack_details = $this->main->quota_manager->get_live_quota_data( 'wpstream_set_wpstream_credentials' ); | |
| 1593 | - | |
| 736 | + $token = $this->main->wpstream_live_connection->wpstream_get_token(); | |
| 737 | + $pack_details = $this->main->wpstream_live_connection->wpstream_request_pack_data_per_user(); | |
| 738 | + | |
| 1594 | 739 | $this->main->show_user_data($pack_details); |
| 1595 | 740 | |
| 1596 | 741 | print '<form method="post" action="" >'; |
| 1597 | - // CSRF nonce for the credentials save handled at the top of this method. | |
| 1598 | - wp_nonce_field( 'wpstream_save_credentials', 'wpstream_credentials_nonce' ); | |
| 1599 | 742 | print '<div class="theme_options_tab_wpstream" style="display:block;" > |
| 1600 | 743 | <h1>'.__('WpStream Credentials','wpstream').'</h1>'; |
| 1601 | 744 | |
| 1602 | - // Credentials supplied via wp-config.php constants take | |
| 1603 | - // precedence over anything saved here — tell the admin. | |
| 1604 | - if( $credentials_from_constants ){ | |
| 1605 | - echo '<div class="api_conected">'.esc_html__('Your WpStream credentials are defined in wp-config.php; values saved on this screen are ignored.','wpstream').'</div>'; | |
| 1606 | - } | |
| 1607 | - | |
| 1608 | - // Connection status banner: no credentials, bad credentials, connected, or CURL failure. | |
| 1609 | - if( wpstream_get_api_username()=='' || wpstream_get_api_password()== '' ){ | |
| 1610 | - echo '<div class="api_not_conected wpstream_orange">'; | |
| 1611 | - $admin_url_onboard=get_admin_url().'admin.php?page=wpstream_onboard'; | |
| 1612 | - printf ( __('To connect your plugin, enter your WpStream credentials below or go <a href="%s" target="_blank">here</a> to create an account.','wpstream'),$admin_url_onboard); | |
| 1613 | - echo '</div>'; | |
| 1614 | - | |
| 1615 | - }else if(!$connected){ | |
| 1616 | - // Translate the literals at definition — gettext cannot extract variable strings. | |
| 1617 | - $text = get_option('wpstream_curl_failed') === "0" ? | |
| 1618 | - __( ' Incorrect username or password. Please check your credentials or go <a href="https://wpstream.net/my-account/edit-account/" target="_blank">here</a> to reset your password.', 'wpstream' ) : | |
| 1619 | - __( 'Not connected to WpStream. Please note the errors above and contact support.', 'wpstream' ); | |
| 1620 | - echo '<div class="api_not_conected">'.wp_kses_post($text).'</div>'; | |
| 745 | + | |
| 746 | + if( get_option('wpstream_api_username')=='' || get_option('wpstream_api_password')== ' '){ | |
| 747 | + echo '<div class="api_not_conected wpstream_orange">'.__('To connect your plugin, enter your WpStream credentials below or go <a href="https://wpstream.net/my-account/" target="_blank">here</a> to create an account.','wpstream').'</div>'; | |
| 748 | + }else if($token==''){ | |
| 749 | + echo '<div class="api_not_conected">'.__(' Incorrect username or password. Please check your credentials or go <a href="https://wpstream.net/my-account/edit-account/" target="_blank">here</a> to reset your password.','wpstream').'</div>'; | |
| 750 | + }else if( $this->main->wpstream_live_connection->wpstream_client_check_api_status() ){ | |
| 751 | + echo '<div class="api_conected">'.__('Conected to WpStream.net!','wpstream').'</div>'; | |
| 1621 | 752 | }else{ |
| 1622 | - // Credentials present and a token was obtained: connected. | |
| 1623 | - echo '<div class="api_conected">'.__('Connected to WpStream.net!','wpstream').'</div>'; | |
| 753 | + echo '<div class="api_not_conected wpstream_brown">'.__('Failed to connect to WpStream.net. Please address CURL connectivity with your hosting provider.','wpstream').'</div>'; | |
| 1624 | 754 | } |
| 1625 | - // Render the credential inputs. The username is pre-filled; | |
| 1626 | - // the password field is always left blank so the stored | |
| 1627 | - // secret is never echoed into the page source (an empty | |
| 1628 | - // submission keeps the saved password). Inputs are disabled | |
| 1629 | - // when the wp-config constants are in charge. | |
| 1630 | - $inputs_disabled = $credentials_from_constants ? ' disabled' : ''; | |
| 1631 | 755 | print '<div class="wpstream_option_wrapper">'; |
| 1632 | 756 | foreach ($wpstream_options_array as $key=>$option){ |
| 1633 | 757 | print '<div class="wpstream_option">'; |
| 1634 | 758 | |
| 759 | + $options_value = esc_html( get_option('wpstream_'.$option['name'],'') ); | |
| 1635 | 760 | print '<label for="'.$option['name'].'">'.$option['label'].'</label>'; |
| 1636 | - if( $option['type']==='password' ){ | |
| 1637 | - $placeholder = get_option('wpstream_'.$option['name'],'') !== '' ? '*****' : ''; | |
| 1638 | - print '<input id="'.$option['name'].'" type="password" size="36" name="'.$option['name'].'" value="" autocomplete="new-password" placeholder="'.$placeholder.'"'.$inputs_disabled.' />'; | |
| 1639 | - }else{ | |
| 1640 | - $options_value = esc_html( get_option('wpstream_'.$option['name'],'') ); | |
| 1641 | - print '<input id="'.$option['name'].'" type="'.$option['type'].'" size="36" name="'.$option['name'].'" value="'.esc_html($options_value).'"'.$inputs_disabled.' />'; | |
| 1642 | - } | |
| 761 | + print '<input id="'.$option['name'].'" type="'.$option['type'].'" size="36" name="'.$option['name'].'" value="'.esc_html($options_value).'" />'; | |
| 1643 | 762 | |
| 1644 | 763 | print '</div>'; |
| 1645 | 764 | } |
| 1646 | 765 | print '</div>'; |
| @@ -1645,32 +764,24 @@ | ||
| 1645 | 764 | } |
| 1646 | 765 | print '</div>'; |
| 1647 | 766 | |
| 1648 | 767 | |
| 1649 | - print '<input type="submit"'.$inputs_disabled.' name="submit" class="wpstream_button wpstream_button_action" value="'.__('Save Changes','wpstream').'" />'; | |
| 768 | + print '<input type="submit" name="submit" class="wpstream_button" value="'.__('Save Changes','wpstream').'" />'; | |
| 1650 | 769 | |
| 1651 | - print '<h3>Video Tutorials</h3>'; | |
| 1652 | - | |
| 1653 | - print '<a class="how_to_videos" target="_blank" href="https://youtu.be/9DQrxsKcpmQ">How to Live Stream to WordPress with OBS</a>'; | |
| 1654 | - print '<a class="how_to_videos" target="_blank" href="https://youtu.be/qMSjJCskAfM">How to Live Stream to WordPress in less than 3 Minutes</a>'; | |
| 1655 | - print '<a class="how_to_videos" target="_blank" href="https://youtu.be/h6myD_vhKcg">How to Live-Stream to WordPress using your iPhone</a>'; | |
| 1656 | - | |
| 1657 | - print '<a style="margin-top:10px;" href="https://www.youtube.com/channel/UCIjItiJc4Z7aJApj3W6ArJA" target="_blank" class="how_to_videos">More Tutorials On Our YouTube Channel</a>'; | |
| 1658 | - | |
| 1659 | 770 | |
| 771 | + | |
| 1660 | 772 | print '</div>'; |
| 1661 | 773 | print '</form>'; |
| 1662 | 774 | |
| 1663 | - // Quick-action links: create free / paid channel, or jump to the channels list. | |
| 1664 | 775 | print '<div class="theme_options_tab_wpstream" style="display:block;" >'; |
| 1665 | - $link_new = admin_url('admin.php?page=wpstream_live_channels'); | |
| 776 | + $link_new = admin_url('admin.php?page=wpstream_new_general_set'); | |
| 1666 | 777 | $link_new_paid = admin_url('post-new.php?post_type=product').'&new_stream='. rawurlencode('new'); |
| 1667 | 778 | $link_new_free = admin_url('post-new.php?post_type=wpstream_product'); |
| 779 | + | |
| 1668 | 780 | |
| 1669 | - | |
| 1670 | - print '<a href="'.esc_url($link_new_free).'" class="wpstream_no_chanel_add_channel">'.esc_html__('Create new Free-To-View channel','wpstream').'</a>'; | |
| 1671 | - print '<a href="'.esc_url($link_new_paid).'" class="wpstream_no_chanel_add_channel">'.esc_html__('Create Pay-Per-View channel','wpstream').'</a>'; | |
| 1672 | - print '<a href="'.esc_url($link_new).'" class="wpstream_no_chanel_add_channel">'.esc_html__('My Channels','wpstream').'</a>'; | |
| 781 | + print '<a href="'.esc_url($link_new_free).'" class="wpstream_no_chanel_add_channel">'.esc_html__('Create new free channel','wpstream').'</a>'; | |
| 782 | + print '<a href="'.esc_url($link_new_paid).'" class="wpstream_no_chanel_add_channel">'.esc_html__('Create pay-per-view channel','wpstream').'</a>'; | |
| 783 | + print '<a href="'.esc_url($link_new).'" class="wpstream_no_chanel_add_channel">'.esc_html('My Channels','wpstream').'</a>'; | |
| 1673 | 784 | print '</div>'; |
| 1674 | 785 | |
| 1675 | 786 | |
| 1676 | 787 | } |
| @@ -1677,559 +788,177 @@ | ||
| 1677 | 788 | |
| 1678 | 789 | |
| 1679 | 790 | |
| 1680 | 791 | /** |
| 1681 | - * Media Management | |
| 1682 | - * | |
| 1683 | - * Render the Recordings admin screen: the quota summary, the upload widget, | |
| 1684 | - * and the list of existing recordings. Echoes HTML. | |
| 1685 | - * | |
| 1686 | - * @since 3.0.1 | |
| 1687 | - * @return void | |
| 1688 | - */ | |
| 792 | + * Media Management | |
| 793 | + * | |
| 794 | + * @since 3.0.1 | |
| 795 | + */ | |
| 1689 | 796 | public function wpstream_media_management(){ |
| 1690 | - // Storage/streaming quota data for the summary header. | |
| 1691 | - $pack_details = $this->main->quota_manager->get_live_quota_data( 'wpstream_media_management' ); | |
| 797 | + $pack_details = $this->main->wpstream_live_connection->wpstream_request_pack_data_per_user(); | |
| 1692 | 798 | |
| 1693 | 799 | $this->main->show_user_data($pack_details); |
| 1694 | 800 | |
| 1695 | 801 | |
| 1696 | - // Upload widget section. | |
| 1697 | - print '<div id="wpstream_media_upload"><h3>'.__('Upload New Recording','wpstream').'</h3>'.$this->wpstream_present_media_upload().'</div>'; | |
| 802 | + print '<div id="wpstream_media_upload"><h3>'.__('Media Upload','wpstream').'</h3>'.$this->wpstream_present_media_upload().'</div>'; | |
| 1698 | 803 | |
| 1699 | - // Existing recordings list section. | |
| 1700 | - print '<div id="wpstream_file_management"><h3 id="video_management_title">'.__('Your Recordings','wpstream').'</h3>'.$this->wpstream_present_file_management().'</div>'; | |
| 804 | + print '<div id="wpstream_file_management"><h3 id="video_management_title">'.__('Video Management','wpstream').'</h3>'.$this->wpstream_present_file_management().'</div>'; | |
| 1701 | 805 | |
| 1702 | - | |
| 1703 | 806 | } |
| 1704 | 807 | |
| 1705 | 808 | |
| 1706 | - | |
| 1707 | - | |
| 1708 | - /** | |
| 1709 | - * | |
| 1710 | - * | |
| 1711 | - * WpStream Pagination | |
| 1712 | - * | |
| 1713 | - * @since 3.0.1 | |
| 1714 | - * | |
| 1715 | - * | |
| 1716 | - */ | |
| 1717 | - | |
| 1718 | - /** | |
| 1719 | - * Build a numeric pager (first/prev/window/next/last) for list screens. | |
| 1720 | - * | |
| 1721 | - * @param int $pages Total number of pages. | |
| 1722 | - * @param int $range How many page links to show on each side of the current page. | |
| 1723 | - * @return string Pager HTML, or '' when there is a single page / no pages. | |
| 1724 | - */ | |
| 1725 | - public function wpstream_pagination($pages , $range = 2) { | |
| 1726 | - $return=''; | |
| 1727 | - // Total visible window width around the current page. | |
| 1728 | - $showitems = ($range * 2) + 1; | |
| 1729 | - // Current page from the query string (defaults to 1). | |
| 1730 | - $paged = ( isset( $_GET['paged'] ) ) ? intval($_GET['paged']) : 1; | |
| 1731 | - | |
| 1732 | - | |
| 1733 | - // Only render a pager when there is more than one page. | |
| 1734 | - if (1 != $pages && $pages != 0) { | |
| 1735 | - $return.= '<ul class="pagination wpstream_pagination">'; | |
| 1736 | - // "Previous" arrow. | |
| 1737 | - $return.= "<li class=\"roundleft\"><a href='" . get_pagenum_link($paged - 1) . "'><</a></li>"; | |
| 1738 | - | |
| 1739 | - $last_page = get_pagenum_link($pages); | |
| 1740 | - // Emit page-number links, but only those within the visible window (or all if they fit). | |
| 1741 | - for ($i = 1; $i <= $pages; $i++) { | |
| 1742 | - if (1 != $pages && (!($i >= $paged + $range + 1 || $i <= $paged - $range - 1) || $pages <= $showitems )) { | |
| 1743 | - if ($paged == $i) { | |
| 1744 | - // Current page marker. | |
| 1745 | - $return.= '<li class="active"><a href="' . esc_url(get_pagenum_link($i)) . '" >' . $i . '</a><li>'; | |
| 1746 | - } else { | |
| 1747 | - $return.= '<li><a href="' . esc_url(get_pagenum_link($i)) . '" >' . $i . '</a><li>'; | |
| 1748 | - } | |
| 1749 | - } | |
| 1750 | - } | |
| 1751 | - | |
| 1752 | - // "Next" target, clamped to the last page. | |
| 1753 | - $prev_page = get_pagenum_link($paged + 1); | |
| 1754 | - if (($paged + 1) > $pages) { | |
| 1755 | - $prev_page = get_pagenum_link($paged); | |
| 1756 | - } else { | |
| 1757 | - $prev_page = get_pagenum_link($paged + 1); | |
| 1758 | - } | |
| 1759 | - | |
| 1760 | - | |
| 1761 | - // "Next" and "Last" arrows, then close the list. | |
| 1762 | - $return.= "<li class=\"roundright\"><a href='" . $prev_page . "'>></a><li>"; | |
| 1763 | - $return.= "<li class=\"roundright\"><a href='" . $last_page . "'>>><li>"; | |
| 1764 | - $return.= "</ul>"; | |
| 1765 | - } | |
| 1766 | - return $return; | |
| 1767 | - } | |
| 1768 | - | |
| 1769 | - | |
| 1770 | - | |
| 1771 | - | |
| 1772 | - | |
| 1773 | 809 | |
| 1774 | 810 | /** |
| 1775 | - * Media upload | |
| 1776 | - * | |
| 1777 | - * Build the S3 direct-upload widget for new recordings: checks storage | |
| 1778 | - * quota and API connectivity, then renders a multipart form pre-populated | |
| 1779 | - * with the signed S3 upload fields. | |
| 1780 | - * | |
| 1781 | - * @since 3.0.1 | |
| 1782 | - * @return string Upload widget HTML, or an alert/notice when unavailable. | |
| 1783 | - */ | |
| 811 | + * Media upload | |
| 812 | + * | |
| 813 | + * @since 3.0.1 | |
| 814 | + */ | |
| 1784 | 815 | public function wpstream_present_media_upload(){ |
| 1785 | 816 | $to_return=''; |
| 1786 | - | |
| 1787 | - // Refuse when the account is out of storage/data quota. | |
| 1788 | - if ( ! $this->main->quota_manager->has_storage_quota( null, 'recordings_screen' ) ) { | |
| 1789 | - return '<div class="wpstream_upload_alert">'.esc_html__('You don\'t have enough cloud storage or data to upload a new item. Please delete some videos or upgrade your plan.','wpstream').'</div>'; | |
| 1790 | - } | |
| 1791 | - | |
| 1792 | - // Request the signed S3 POST fields from the cloud API. | |
| 1793 | 817 | $formInputs=$this->main->wpstream_live_connection->wpstream_get_signed_form_upload_data(); |
| 1794 | 818 | |
| 1795 | - // On failure, show either a "not connected" or an "out of quota" message. | |
| 1796 | - if( !$formInputs['success'] ){ | |
| 1797 | - if ($formInputs['error'] == 'not_connected'){ | |
| 1798 | - $to_return.='<div class="wpstream_upload_container">'.esc_html__('Not connected. Please connect to WpStream to upload videos.','wpstream').'</div>'; | |
| 1799 | - } | |
| 1800 | - else { | |
| 1801 | - $to_return.='<div class="wpstream_upload_alert">'.esc_html__('You don\'t have enough cloud storage and data to upload a new item. Please delete some videos or upgrade your plan.','wpstream').'</div>'; | |
| 1802 | - } | |
| 819 | + if($formInputs === 'notenough'){ | |
| 820 | + $to_return.='<div class="wpstream_upload_alert">'.esc_html__('You do not have enough bandwidth or storage to upload a video!','wpstream').'</div>'; | |
| 1803 | 821 | return $to_return; |
| 1804 | 822 | } |
| 1805 | 823 | |
| 1806 | - // Signed data obtained: render the direct-to-S3 upload form. | |
| 1807 | - if($formInputs['success'] ===true){ | |
| 1808 | 824 | |
| 1809 | - | |
| 825 | + $to_return.='<div class="wpstream_upload_container">'; | |
| 826 | + $to_return.='<div id="wpstream_uploaded_mes">'.esc_html__('Please select or drop a video file. Do not close this window during the upload!','wpstream').'</div>'; | |
| 827 | + $to_return.='<form action="https://wpstream-videos.s3.amazonaws.com/" | |
| 828 | + method="POST" | |
| 829 | + enctype="multipart/form-data" | |
| 830 | + class="direct-upload">'; | |
| 1810 | 831 | |
| 1811 | - $to_return.='<div class="wpstream_upload_container">'; | |
| 1812 | - $to_return.='<div id="wpstream_uploaded_mes">'.esc_html__('Please select or drop a video file. Do not close this window during the upload!','wpstream').'</div>'; | |
| 1813 | - $to_return.='<form action="https://wpstream-video.s3.amazonaws.com/" | |
| 1814 | - method="POST" | |
| 1815 | - enctype="multipart/form-data" | |
| 1816 | - data-singleFileUploads="true" | |
| 1817 | - data-limitMultiFileUploads="1" | |
| 1818 | - data-limitConcurrentUploads="1" | |
| 1819 | - class="direct-upload">'; | |
| 832 | + $to_return.='<input id="wpstream_upload" type="file" class="inputfile inputfile-1" value="Pick a video file" name="file" multiple>'; | |
| 833 | + $to_return.='<label for="wpstream_upload"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="17" viewBox="0 0 20 17"><path d="M10 0l-5.2 4.9h3.3v5.1h3.8v-5.1h3.3l-5.2-4.9zm9.3 11.5l-3.2-2.1h-2l3.4 2.6h-3.5c-.1 0-.2.1-.2.1l-.8 2.3h-6l-.8-2.2c-.1-.1-.1-.2-.2-.2h-3.6l3.4-2.6h-2l-3.2 2.1c-.4.3-.7 1-.6 1.5l.6 3.1c.1.5.7.9 1.2.9h16.3c.6 0 1.1-.4 1.3-.9l.6-3.1c.1-.5-.2-1.2-.7-1.5z"/></svg> <span id="wpstream_label_action">Choose a file…</span></label>'; | |
| 1820 | 834 | |
| 1821 | - $to_return.='<input id="wpstream_upload" type="file" class="inputfile inputfile-1" value="Pick a video file" name="file" multiple>'; | |
| 1822 | - $to_return.='<label for="wpstream_upload"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="17" viewBox="0 0 20 17"><path d="M10 0l-5.2 4.9h3.3v5.1h3.8v-5.1h3.3l-5.2-4.9zm9.3 11.5l-3.2-2.1h-2l3.4 2.6h-3.5c-.1 0-.2.1-.2.1l-.8 2.3h-6l-.8-2.2c-.1-.1-.1-.2-.2-.2h-3.6l3.4-2.6h-2l-3.2 2.1c-.4.3-.7 1-.6 1.5l.6 3.1c.1.5.7.9 1.2.9h16.3c.6 0 1.1-.4 1.3-.9l.6-3.1c.1-.5-.2-1.2-.7-1.5z"/></svg> <span id="wpstream_label_action">' . esc_html__('Choose a file…','wpstream') . '</span></label>'; | |
| 1823 | 835 | |
| 836 | + $to_return.='<div class="wpstream_file_drop_color">'; | |
| 837 | + $to_return.='<div class="wpstream_form_ex">'.esc_html__('Drop a video file here!','wpstream').'</div>'; | |
| 838 | + $to_return.='<div class="wpstream_form_ex_details">'.esc_html__('The Video File must be encoded with the following settings: | |
| 1824 | 839 | |
| 1825 | - $to_return.='<div class="wpstream_file_drop_color">'; | |
| 1826 | - $to_return.='<div class="wpstream_form_ex">'.esc_html__('Drop a video file here!','wpstream').'</div>'; | |
| 1827 | - $to_return.='<div class="wpstream_form_ex_details">'.__('The Video File must be encoded with the following settings:<br> | |
| 840 | + Container: MP4, | |
| 841 | + Video codec: H264, | |
| 842 | + Audio codec: AAC. Media will fail to play back if it does not follow the above settings. | |
| 843 | + You may use a tool like MediaInfo to verify your file. Also you may convert it with specialized software like HandBrake.','wpstream').'<strong>'.esc_html__('Accepted file extensions: .mp4, .mov .','wpstream').'</strong></div>'; | |
| 844 | + if(is_array($formInputs)){ | |
| 845 | + foreach ($formInputs as $name => $value) { | |
| 846 | + $to_return.='<input type="hidden" name="'. $name.'" value="'.$value.'">'; | |
| 847 | + } | |
| 848 | + } | |
| 1828 | 849 | |
| 1829 | - Container: <strong>MP4</strong>,<br> | |
| 1830 | - Video codec: <strong>H264</strong>,<br> | |
| 1831 | - Audio codec: <strong>AAC</strong>.<br> | |
| 1832 | - Media will fail to play if it does not follow the above settings. | |
| 1833 | - You may use a tool like MediaInfo to verify your file. Also you may convert it with specialized software like HandBrake.','wpstream').'<strong> '.esc_html__('Accepted file extensions: .mp4, .mov','wpstream').'</strong></div>'; | |
| 1834 | - // Inject each signed S3 field as a hidden input so the browser POST is authorized. | |
| 1835 | - if(is_array($formInputs)){ | |
| 1836 | - foreach ($formInputs['ref'] as $name => $value) { | |
| 1837 | - $to_return.='<input type="hidden" name="'. $name.'" value="'.$value.'">'; | |
| 1838 | - } | |
| 1839 | - } | |
| 850 | + $to_return.=' | |
| 851 | + <div class="progress-bar-area"></div></div> | |
| 852 | + </form>'; | |
| 1840 | 853 | |
| 1841 | - $to_return.=' | |
| 1842 | - <div class="progress-bar-area"></div></div> | |
| 1843 | - </form>'; | |
| 1844 | - | |
| 1845 | - $to_return.='</div>'; | |
| 1846 | - } | |
| 1847 | - | |
| 854 | + $to_return.='</div>'; | |
| 1848 | 855 | return $to_return; |
| 1849 | 856 | |
| 1850 | 857 | } |
| 1851 | 858 | |
| 1852 | - | |
| 1853 | 859 | |
| 1854 | 860 | |
| 1855 | - | |
| 1856 | 861 | /** |
| 1857 | - * Display movie list | |
| 1858 | - * | |
| 1859 | - * Fetch the account's recordings from the cloud API and render them: | |
| 1860 | - * still-processing ("pending") items first, then completed items with | |
| 1861 | - * delete/download links and "create VOD from this recording" actions. | |
| 1862 | - * | |
| 1863 | - * @since 3.0.1 | |
| 1864 | - * @return string Recordings list HTML, or a notice when not connected / empty. | |
| 1865 | - */ | |
| 862 | + * Display movie list | |
| 863 | + * | |
| 864 | + * @since 3.0.1 | |
| 865 | + */ | |
| 1866 | 866 | public function wpstream_present_file_management(){ |
| 1867 | - // Pull the raw recordings payload from the API. | |
| 1868 | - $video_list_raw = $this->main->wpstream_live_connection->wpstream_get_videos_from_api(); | |
| 867 | + $video_list_raw = $this->main->wpstream_live_connection->wpstream_get_videos_from_storage_raw_data(); | |
| 1869 | 868 | |
| 1870 | - // false means the API call failed / not connected. | |
| 1871 | - if ( $video_list_raw === false ) { | |
| 1872 | - return '<div class="wpstream_upload_container">'.esc_html__('Not connected. Please connect to WpStream to upload videos.','wpstream').'</div>'; | |
| 1873 | - } | |
| 1874 | - | |
| 1875 | - // Normalise the completed-items list. | |
| 1876 | - $video_list_raw_array = []; | |
| 1877 | - if( isset( $video_list_raw['items'] ) ){ | |
| 1878 | - $video_list_raw_array = $video_list_raw['items']; | |
| 1879 | - } | |
| 1880 | - | |
| 1881 | - // Sort completed items newest-first by their 'time' field. | |
| 1882 | - $keys = array_column( $video_list_raw_array, 'time' ); | |
| 1883 | - array_multisort($keys, SORT_DESC , $video_list_raw_array); | |
| 1884 | - | |
| 1885 | 869 | $to_return=''; |
| 870 | + if(is_array($video_list_raw)){ | |
| 871 | + foreach ($video_list_raw as $key =>$video){ | |
| 872 | + $to_return.='<div class="wpstream_video_wrapper">'; | |
| 1886 | 873 | |
| 1887 | - // show pending items | |
| 1888 | - // Render still-processing uploads with a "processing" badge. | |
| 1889 | - if ( key_exists( 'pending', $video_list_raw ) && is_array( $video_list_raw['pending'] ) ) { | |
| 1890 | - foreach ( $video_list_raw['pending'] as $key => $video ) { | |
| 1891 | - $video_size = intval($video['size']/1048576); | |
| 1892 | - $video_name = esc_html($video['name']); | |
| 1893 | - if($video_name!=''): | |
| 1894 | - $to_return.='<div class="wpstream_video_wrapper">'; | |
| 1895 | - $to_return.='<div class="wpstream_video_title">'; | |
| 1896 | - $to_return.='<div class="wpstream_video_notice"></div></div>'; | |
| 1897 | - $to_return.='<div class="wpstream_video_title"><strong class="storage_file_name">'.esc_html__('File Name :','wpstream').'</strong>'.'<span class="storage_file_name_real">'.$video_name.'</span><span class="storage_file_size">'.$video_size.' MB </span></div>'; | |
| 1898 | - $to_return.='<div class="wpstream_video_pending">' . esc_html__( 'The video is still processing', 'wpstream') . '</div>'; | |
| 1899 | - $to_return.='</div>'; | |
| 1900 | - endif; | |
| 874 | + $to_return.='<div class="wpstream_video_title">'; | |
| 875 | + $to_return.='<div class="wpstream_video_notice"></div></div>'; | |
| 876 | + $to_return.='<div class="wpstream_video_title"><strong class="storage_file_name">'.esc_html__('File Name :','wpstream').'</strong>'.'<span class="storage_file_name_real">'.$video['video_name_storage'].'</span></div>'; | |
| 877 | + $to_return.=' <div class="wpstream_delete_media" '; | |
| 878 | + $to_return.=' onclick="return confirm(\' Are you sure you wish to delete '.$video['video_name_storage'].'?\')" data-filename="'.$video['video_name_storage'].'">'.esc_html__('delete file','wpstream').'</div>'; | |
| 879 | + $to_return.='<div class="wpstream_get_download_link" data-filename="'.$video['video_name_storage'].'">'.esc_html__('get download link','wpstream').'</div>'; | |
| 880 | + $to_return.='<a href="" class="wpstream_download_link">'.esc_html__('Click to download! The url will work for the next 20 minutes!','wpstream').'</a>'; | |
| 1901 | 881 | |
| 1902 | - } | |
| 1903 | - } | |
| 882 | + $add_free_video_url=admin_url('post-new.php?post_type=wpstream_product').'&new_video_name='. rawurlencode($video['video_name_storage']); | |
| 883 | + $add_paid_video_url=admin_url('post-new.php?post_type=product').'&new_video_name='. rawurlencode($video['video_name_storage']); | |
| 1904 | 884 | |
| 1905 | - // show uploaded items | |
| 1906 | - // Render each completed recording with its size, delete/download controls and VOD-creation links. | |
| 1907 | - if( is_array($video_list_raw['items'] ) ) { | |
| 1908 | - foreach ($video_list_raw_array as $key =>$video){ | |
| 1909 | - // Keep the service-provided Source Recording identity | |
| 1910 | - // separate from its context-specific HTML rendering. | |
| 1911 | - $video_size = intval($video['size']/1048576); | |
| 1912 | - $video_source_name = (string) $video['name']; | |
| 1913 | - $video_name = esc_html($video_source_name); | |
| 1914 | - if($video_name!=''): | |
| 1915 | - $to_return.='<div class="wpstream_video_wrapper">'; | |
| 1916 | 885 | |
| 1917 | - $to_return.='<div class="wpstream_video_title">'; | |
| 1918 | - $to_return.='<div class="wpstream_video_notice"></div></div>'; | |
| 1919 | - $to_return.='<div class="wpstream_video_title"><strong class="storage_file_name">'.esc_html__('File Name:','wpstream').'</strong>'.'<span class="storage_file_name_real">'.$video_name.'</span><span class="storage_file_size">'.$video_size.' MB </span></div>'; | |
| 1920 | - // Delete control. The shared JS utility owns the | |
| 1921 | - // confirmation; the renderer supplies inert data | |
| 1922 | - // only so any valid recording name remains safe. | |
| 1923 | - $to_return.='<div class="wpstream_delete_media" data-filename="'.esc_attr($video_source_name).'">'.esc_html__('delete file','wpstream').'</div>'; | |
| 1924 | - // Download trigger (JS fetches a time-limited signed URL) and the resulting link. | |
| 1925 | - $to_return.='<div class="wpstream_get_download_link" data-filename="'.$video_name.'">'.esc_html__('download','wpstream').'</div>'; | |
| 1926 | - $to_return.='<a href="" class="wpstream_download_link">'.esc_html__('Click to download! The url will work for the next 20 minutes!','wpstream').'</a>'; | |
| 1927 | 886 | |
| 1928 | - // Pre-fill new-VOD links (free and, if WooCommerce present, paid) with this recording's name. | |
| 1929 | - $add_free_video_url=admin_url('post-new.php?post_type=wpstream_product_vod').'&new_video_name='. rawurlencode($video_source_name); | |
| 1930 | - $add_paid_video_url=admin_url('post-new.php?post_type=product').'&new_video_name='. rawurlencode($video_source_name); | |
| 887 | + $to_return .='<a class="create_new_free_video" href="'.esc_url($add_free_video_url).'">'.esc_html__('Create new free VOD from this video').'</a>'; | |
| 888 | + $to_return .='<a class="create_new_ppv_video" href="'.esc_url($add_paid_video_url).'">'.esc_html__('Create pay-per-view VOD from this video').'</a>'; | |
| 1931 | 889 | |
| 890 | + $to_return.='</div>'; | |
| 1932 | 891 | |
| 1933 | - | |
| 1934 | - $to_return .='<a class="create_new_free_video" href="'.esc_url($add_free_video_url).'">'.esc_html__('Create new Free-To-View VOD from this recording').'</a>'; | |
| 1935 | - if (class_exists('WooCommerce')) { | |
| 1936 | - $to_return .='<a class="create_new_ppv_video" href="'.esc_url($add_paid_video_url).'">'.esc_html__('Create new Pay-Per-View VOD from this recording').'</a>'; | |
| 1937 | - } | |
| 1938 | - | |
| 1939 | - $to_return.='</div>'; | |
| 1940 | - endif; | |
| 1941 | - | |
| 1942 | 892 | } |
| 1943 | - $current_page= get_current_screen(); | |
| 1944 | - } | |
| 1945 | - | |
| 1946 | - // no items to show | |
| 1947 | - // Empty-state message when there are neither completed nor pending items. | |
| 1948 | - if ( !is_array( $video_list_raw['items'] ) || ( key_exists( 'pending', $video_list_raw ) && !is_array( $video_list_raw['pending'] ) ) ) { | |
| 1949 | - $to_return.= '<div class="wpstream_video_wrapper">'.esc_html__('You don\'t have any videos.','wpstream').'</div>'; | |
| 893 | + } else { | |
| 894 | + $to_return.= '<div class="wpstream_video_wrapper">'.esc_html__('You don\'t have any videos.','wpstream').'</div>'; | |
| 1950 | 895 | } |
| 1951 | 896 | return $to_return; |
| 1952 | 897 | } |
| 1953 | 898 | |
| 1954 | 899 | |
| 1955 | - /** | |
| 1956 | - * Preserve the legacy free-Channel publish marker. | |
| 1957 | - * | |
| 1958 | - * Channel Settings initialization is coordinated by the Streaming Content | |
| 1959 | - * Creation Module; this compatibility hook only maintains historical meta. | |
| 1960 | - * | |
| 1961 | - * @since 3.0.1 | |
| 1962 | - * @param int $post_id Post ID being published. | |
| 1963 | - * @param WP_Post $post Post object being published. | |
| 1964 | - * @return void | |
| 1965 | - */ | |
| 1966 | - public function wpstream_publish_wpstream_product($post_id,$post){ | |
| 1967 | - // Only applies to free channel posts. | |
| 1968 | - if( $post->post_type == 'wpstream_product' ){ | |
| 1969 | - // Preserve the legacy marker used by existing installations. | |
| 1970 | - update_post_meta ($post_id,'local_event_options_test','working_on_'.$post_id); | |
| 1971 | - } | |
| 1972 | - } | |
| 1973 | - | |
| 900 | + | |
| 901 | + | |
| 902 | + | |
| 1974 | 903 | /** |
| 1975 | - * Initialize existing Streaming Content when it is published or saved. | |
| 1976 | - * | |
| 1977 | - * The shared Module performs safe legacy repair and retries cloud provisioning | |
| 1978 | - * for Live Channels. VODs receive only their applicable local initialization. | |
| 1979 | - * | |
| 1980 | - * @param int $post_id Post ID being published. | |
| 1981 | - * @param WP_Post $post Post object being published. | |
| 1982 | - * @return void | |
| 1983 | - */ | |
| 1984 | - public function wpstream_create_remote_channel_on_publish( $post_id, $post ) { | |
| 1985 | - // Skip autosaves and revisions (they are not real publishes). | |
| 1986 | - if ( defined( 'DOING_AUTOSAVE') && DOING_AUTOSAVE ) { | |
| 1987 | - return; | |
| 1988 | - } | |
| 1989 | - if ( wp_is_post_revision( $post_id ) ) { | |
| 1990 | - return; | |
| 1991 | - } | |
| 1992 | - $this->main->streaming_content_creation->initialize_existing( $post_id ); | |
| 1993 | - } | |
| 904 | + * save meta options | |
| 905 | + * | |
| 906 | + * @since 3.0.1 | |
| 907 | + */ | |
| 908 | + public function wpstream_free_product_update_post($post_id,$post){ | |
| 1994 | 909 | |
| 1995 | - /** | |
| 1996 | - * Initialize a manually saved paid streaming product after WooCommerce | |
| 1997 | - * has persisted its product-type taxonomy. The earlier publish hook may | |
| 1998 | - * run while a new product still looks like `simple`; this later adapter | |
| 1999 | - * enters the same idempotent creation policy once `live_stream` or | |
| 2000 | - * `video_on_demand` is observable. | |
| 2001 | - * | |
| 2002 | - * @param int $post_id WooCommerce product ID. | |
| 2003 | - * @return void | |
| 2004 | - */ | |
| 2005 | - public function wpstream_initialize_paid_streaming_product( $post_id ) { | |
| 2006 | - if ( 'product' !== get_post_type( $post_id ) ) { | |
| 910 | + if(!is_object($post) || !isset($post->post_type)) { | |
| 2007 | 911 | return; |
| 2008 | 912 | } |
| 2009 | - if ( ! has_term( array( 'live_stream', 'video_on_demand' ), 'product_type', $post_id ) ) { | |
| 2010 | - return; | |
| 2011 | - } | |
| 2012 | - $this->main->streaming_content_creation->initialize_existing( $post_id ); | |
| 2013 | - } | |
| 2014 | 913 | |
| 2015 | - /** | |
| 2016 | - * Delete the remote channel when its Live Channel post is deleted for good. | |
| 2017 | - * | |
| 2018 | - * Hooked to before_delete_post: fires only on permanent deletion, never on | |
| 2019 | - * trash, so trashing stays reversible and a restored channel keeps its | |
| 2020 | - * cloud identity. Only a Live Channel that was actually Provisioned | |
| 2021 | - * (`channelId` meta present) has anything at the service to remove. | |
| 2022 | - * | |
| 2023 | - * The local deletion proceeds whatever the service answers — this hook | |
| 2024 | - * cannot cancel it, and a channel the customer removed must leave the | |
| 2025 | - * site either way. | |
| 2026 | - * | |
| 2027 | - * @param int $post_id Post ID being permanently deleted. | |
| 2028 | - * @param WP_Post $post Post object being permanently deleted. | |
| 2029 | - * @return void | |
| 2030 | - */ | |
| 2031 | - public function wpstream_delete_remote_channel_on_delete( $post_id, $post ) { | |
| 2032 | - // Only Live Channel posts: the free post type, or a WooCommerce | |
| 2033 | - // product of the live_stream type (paid channels). | |
| 2034 | - $is_live_channel = $post instanceof WP_Post | |
| 2035 | - && ( 'wpstream_product' === $post->post_type | |
| 2036 | - || ( 'product' === $post->post_type && has_term( 'live_stream', 'product_type', $post_id ) ) ); | |
| 2037 | - if ( ! $is_live_channel ) { | |
| 2038 | - return; | |
| 914 | + if($post->post_type!='wpstream_product'){ | |
| 915 | + return; | |
| 2039 | 916 | } |
| 2040 | 917 | |
| 2041 | - // A channel that never obtained a cloud identity has nothing to delete. | |
| 2042 | - if ( '' === (string) get_post_meta( $post_id, 'channelId', true ) ) { | |
| 2043 | - return; | |
| 2044 | - } | |
| 2045 | 918 | |
| 2046 | - $this->main->wpstream_live_connection->wpstream_delete_channel( $post_id ); | |
| 2047 | - } | |
| 919 | + $allowed_keys=array( | |
| 920 | + 'wpstream_product_type', | |
| 921 | + 'wpstream_free_video', | |
| 922 | + 'wpstream_free_video_external' | |
| 923 | + ); | |
| 2048 | 924 | |
| 2049 | - /** | |
| 2050 | - * Restore a paid Live Channel as a draft instead of immediately putting | |
| 2051 | - * it back on sale. WooCommerce restores ordinary products to their | |
| 2052 | - * previous status; a channel requires the seller to republish it. | |
| 2053 | - * | |
| 2054 | - * @param string $new_status Status selected by earlier filters. | |
| 2055 | - * @param int $post_id Restored post ID. | |
| 2056 | - * @param string $previous_status Status before trashing. | |
| 2057 | - * @return string | |
| 2058 | - */ | |
| 2059 | - public function wpstream_paid_live_untrash_status( $new_status, $post_id, $previous_status ) { | |
| 2060 | - if ( 'product' === get_post_type( $post_id ) && has_term( 'live_stream', 'product_type', $post_id ) ) { | |
| 2061 | - return 'draft'; | |
| 2062 | - } | |
| 2063 | - return $new_status; | |
| 2064 | - } | |
| 925 | + $allowed_html=array(); | |
| 2065 | 926 | |
| 2066 | - /** Invalidate VOD DRM lookup state whenever publication visibility changes. */ | |
| 2067 | - public function wpstream_invalidate_vod_drm_on_status_change( $new_status, $old_status, $post ) { | |
| 2068 | - if ( $post instanceof WP_Post && 'wpstream_product_vod' === $post->post_type && $new_status !== $old_status ) { | |
| 2069 | - $this->main->drm_key_delivery->invalidate_vod_lookup( $post->ID ); | |
| 2070 | - } | |
| 2071 | - } | |
| 2072 | - | |
| 2073 | - /** Invalidate VOD DRM lookup state before its key-index metadata is deleted. */ | |
| 2074 | - public function wpstream_invalidate_vod_drm_on_delete( $post_id, $post ) { | |
| 2075 | - if ( $post instanceof WP_Post && 'wpstream_product_vod' === $post->post_type ) { | |
| 2076 | - $this->main->drm_key_delivery->invalidate_vod_lookup( $post_id ); | |
| 2077 | - } | |
| 2078 | - } | |
| 2079 | - | |
| 2080 | - /** | |
| 2081 | - * save meta options | |
| 2082 | - * | |
| 2083 | - * Persist the allow-listed free channel / VOD meta fields on save for the | |
| 2084 | - * `wpstream_product` and `wpstream_product_vod` post types. Hooked to the | |
| 2085 | - * post save action. | |
| 2086 | - * | |
| 2087 | - * @since 3.0.1 | |
| 2088 | - * @param int $post_id Post ID being saved. | |
| 2089 | - * @param WP_Post $post Post object being saved. | |
| 2090 | - * @return void | |
| 2091 | - */ | |
| 2092 | - public function wpstream_free_product_update_post($post_id,$post){ | |
| 2093 | - | |
| 2094 | - // Guard against non-post callers. | |
| 2095 | - if(!is_object($post) || !isset($post->post_type)) { | |
| 2096 | - return; | |
| 927 | + foreach ($_POST as $key => $value) { | |
| 928 | + if( !is_array ($value) ){ | |
| 929 | + if (in_array ($key, $allowed_keys)) { | |
| 930 | + $postmeta = wp_kses ( $value,$allowed_html ); | |
| 931 | + update_post_meta($post_id, sanitize_key($key), $postmeta ); | |
| 932 | + } | |
| 933 | + } | |
| 2097 | 934 | } |
| 2098 | - | |
| 2099 | - | |
| 2100 | - | |
| 2101 | - | |
| 2102 | - | |
| 2103 | - // Only handle the free channel and VOD post types. | |
| 2104 | - if( $post->post_type == 'wpstream_product' || | |
| 2105 | - $post->post_type == 'wpstream_product_vod' ): | |
| 2106 | - $previous_vod_type = 'wpstream_product_vod' === $post->post_type | |
| 2107 | - ? intval( get_post_meta( $post_id, 'wpstream_product_type', true ) ) | |
| 2108 | - : 0; | |
| 2109 | - $previous_recording = 'wpstream_product_vod' === $post->post_type | |
| 2110 | - ? (string) get_post_meta( $post_id, 'wpstream_free_video', true ) | |
| 2111 | - : ''; | |
| 2112 | - | |
| 2113 | - // Meta keys this handler is allowed to write. | |
| 2114 | - $allowed_keys=array( | |
| 2115 | - 'wpstream_product_type', | |
| 2116 | - 'wpstream_free_video', | |
| 2117 | - 'wpstream_free_video_external', | |
| 2118 | - 'wpstream_closed_captions_file' | |
| 2119 | - ); | |
| 2120 | - | |
| 2121 | - | |
| 2122 | - // Save each allow-listed, scalar POST field as sanitized post meta. | |
| 2123 | - foreach ($_POST as $key => $value) { | |
| 2124 | - if( !is_array ($value) ){ | |
| 2125 | - if (in_array ($key, $allowed_keys)) { | |
| 2126 | - $postmeta = sanitize_text_field ( $value ); | |
| 2127 | - update_post_meta($post_id, sanitize_key($key), $postmeta ); | |
| 2128 | - } | |
| 2129 | - } | |
| 2130 | - } | |
| 2131 | - | |
| 2132 | - if ( 'wpstream_product_vod' === $post->post_type && isset( $_POST['wpstream_product_type'] ) ) { | |
| 2133 | - $new_vod_type = intval( $_POST['wpstream_product_type'] ); | |
| 2134 | - if ( 3 === $new_vod_type ) { | |
| 2135 | - $this->wpstream_retire_vod_recording_identity( $post_id ); | |
| 2136 | - delete_post_meta( $post_id, 'wpstream_free_video' ); | |
| 2137 | - } elseif ( 2 === $new_vod_type ) { | |
| 2138 | - $new_recording = isset( $_POST['wpstream_free_video'] ) && is_scalar( $_POST['wpstream_free_video'] ) | |
| 2139 | - ? sanitize_text_field( wp_unslash( $_POST['wpstream_free_video'] ) ) | |
| 2140 | - : $previous_recording; | |
| 2141 | - if ( 2 !== $previous_vod_type || $new_recording !== $previous_recording ) { | |
| 2142 | - $this->wpstream_retire_vod_recording_identity( $post_id ); | |
| 2143 | - } | |
| 2144 | - delete_post_meta( $post_id, 'wpstream_free_video_external' ); | |
| 2145 | - } | |
| 2146 | - } | |
| 2147 | - | |
| 2148 | - endif; | |
| 2149 | - | |
| 2150 | 935 | } |
| 2151 | - | |
| 2152 | - /** Retire key and hosted-player metadata owned by a VOD's old recording. */ | |
| 2153 | - private function wpstream_retire_vod_recording_identity( $post_id ) { | |
| 2154 | - $this->main->drm_key_delivery->invalidate_vod_lookup( $post_id ); | |
| 2155 | - foreach ( array( 'hlsDecryptionKey', 'hlsDecryptionKeyIndex', 'wpstream_vod_video_data', 'wpstream_vod_embed_key', 'wpstream_vod_embed_url' ) as $meta_key ) { | |
| 2156 | - delete_post_meta( $post_id, $meta_key ); | |
| 2157 | - } | |
| 2158 | - } | |
| 2159 | 936 | |
| 2160 | 937 | |
| 2161 | 938 | /** |
| 2162 | - * save meta options | |
| 2163 | - * | |
| 2164 | - * Register the plugin's post metaboxes: VOD settings on `wpstream_product_vod`, | |
| 2165 | - * the video collection box on `wpstream_bundles`, and (for WooCommerce bundle | |
| 2166 | - * products) the video-collection options box on `product`. Hooked to add_meta_boxes. | |
| 2167 | - * | |
| 2168 | - * @since 3.0.1 | |
| 2169 | - * @return void | |
| 2170 | - */ | |
| 2171 | - public function add_wpstream_product_metaboxes() { | |
| 2172 | - global $post; | |
| 2173 | - $post_id = $post->ID; | |
| 2174 | - | |
| 2175 | - | |
| 2176 | - // VOD settings metabox and the bundle video-collection metabox. | |
| 2177 | - add_meta_box( 'add_wpstream_product_metaboxes-sectionid', esc_html__( 'Video On Demand Settings', 'wpstream' ),array($this,'display_meta_options'),'wpstream_product_vod' ,'normal','default'); | |
| 2178 | - add_meta_box( 'custom_metabox_video_collection', esc_html__( 'Video Collection', 'wpstream' ), 'wpstream_bundle_custom_metabox_callback', 'wpstream_bundles', 'normal', 'high' ); | |
| 2179 | - | |
| 2180 | - // For WooCommerce bundle products, add the video-collection options box on the product screen. | |
| 2181 | - if(function_exists('wc_get_product')): | |
| 2182 | - $product = wc_get_product( $post_id ); | |
| 2183 | - if ( $product ) { | |
| 2184 | - | |
| 2185 | - if ( $product->get_type() === 'wpstream_bundle' ) { | |
| 2186 | - add_meta_box( | |
| 2187 | - 'wpstream_woo_custom_metabox', | |
| 2188 | - esc_html__( 'Video Collection Options', 'wpstream' ), | |
| 2189 | - 'wpstream_bundle_custom_metabox_callback', | |
| 2190 | - 'product', | |
| 2191 | - 'normal', | |
| 2192 | - 'default' | |
| 2193 | - ); | |
| 2194 | - } | |
| 2195 | - } | |
| 2196 | - endif; | |
| 2197 | - | |
| 2198 | - /** | |
| 2199 | - * Fires after the plugin registered its metaboxes for the edit screen. | |
| 2200 | - * | |
| 2201 | - * @since 4.14.0 | |
| 2202 | - * | |
| 2203 | - * @param int $post_id Post being edited. | |
| 2204 | - * @param WP_Post $post The post. | |
| 2205 | - */ | |
| 2206 | - do_action( 'wpstream_registered_metaboxes', intval( $post_id ), $post ); | |
| 939 | + * save meta options | |
| 940 | + * | |
| 941 | + * @since 3.0.1 | |
| 942 | + */ | |
| 943 | + public function add_wpstream_product_metaboxes() { | |
| 944 | + add_meta_box( 'add_wpstream_product_metaboxes-sectionid', __( 'Live Channel/Video Settings', 'wpestate' ),array($this,'display_meta_options'),'wpstream_product' ,'normal','default'); | |
| 2207 | 945 | } |
| 2208 | 946 | |
| 2209 | 947 | |
| 2210 | 948 | /** |
| 2211 | - * make woocomerce virtual products | |
| 2212 | - * | |
| 2213 | - * Force WpStream WooCommerce product types (live_stream, video_on_demand, | |
| 2214 | - * wpstream_bundle) to be virtual so they need no shipping. Hooked to save. | |
| 2215 | - * | |
| 2216 | - * @since 3.0.1 | |
| 2217 | - * @param int $post_id Post ID being saved (unused; uses global $post). | |
| 2218 | - * @param WP_Post $post Post object (overwritten by global $post). | |
| 2219 | - * @return void | |
| 2220 | - */ | |
| 949 | + * make woocomerce virtual products | |
| 950 | + * | |
| 951 | + * @since 3.0.1 | |
| 952 | + */ | |
| 953 | + | |
| 954 | + | |
| 2221 | 955 | public function wpstream_make_product_virtual($post_id,$post){ |
| 2222 | 956 | global $post; |
| 2223 | 957 | if(isset($post->ID)){ |
| 2224 | - // Only WooCommerce products are relevant. | |
| 2225 | 958 | if ( $post->post_type !== 'product' ) return; |
| 2226 | - // Mark WpStream product types as virtual. | |
| 2227 | 959 | $term_list = wp_get_post_terms($post->ID, 'product_type'); |
| 2228 | - if( !empty($term_list) && | |
| 2229 | - isset($term_list[0]->slug) && | |
| 2230 | - in_array($term_list[0]->slug, ['live_stream', 'video_on_demand', 'wpstream_bundle']) | |
| 2231 | - ){ | |
| 960 | + if( $term_list[0]->name=='video_on_demand' || $term_list[0]->name=='live_stream'){ | |
| 2232 | 961 | update_post_meta( $post->ID, '_virtual', 'yes' ); |
| 2233 | 962 | } |
| 2234 | 963 | } |
| 2235 | 964 | } |
| @@ -2235,41 +964,31 @@ | ||
| 2235 | 964 | } |
| 2236 | 965 | |
| 2237 | 966 | |
| 2238 | 967 | |
| 2239 | - /** | |
| 2240 | - * render meta options | |
| 2241 | - * | |
| 2242 | - * Render the "Video On Demand Settings" metabox: media-type selector, | |
| 2243 | - * recording chooser, optional captions (.vtt) picker, and the self-hosted/ | |
| 2244 | - * external video URL field. Echoes HTML. | |
| 2245 | - * | |
| 2246 | - * @since 3.0.1 | |
| 2247 | - * @param WP_Post $post Post being edited (overwritten by global $post). | |
| 2248 | - * @return void | |
| 2249 | - */ | |
| 968 | + /** | |
| 969 | + * render meta options | |
| 970 | + * | |
| 971 | + * @since 3.0.1 | |
| 972 | + */ | |
| 2250 | 973 | public function display_meta_options( $post ) { |
| 2251 | - // Nonce for the metabox save + use the global post object. | |
| 2252 | 974 | wp_nonce_field( plugin_basename( __FILE__ ), 'estate_agent_noncename' ); |
| 2253 | 975 | global $post; |
| 2254 | 976 | |
| 2255 | - // Determine the pre-selected media type / video. | |
| 2256 | 977 | $is_live = ''; |
| 2257 | 978 | $is_video = ''; |
| 2258 | 979 | $is_video_external = ''; |
| 2259 | - // When arriving from "create VOD from recording", preselect the recording. | |
| 2260 | 980 | if( isset( $_GET['new_video_name']) && $_GET['new_video_name']!='' ){ |
| 2261 | 981 | $is_video = ' selected '; |
| 2262 | 982 | $wpstream_free_video = esc_html( $_GET['new_video_name']); |
| 2263 | 983 | }else{ |
| 2264 | - // Otherwise read the saved type/video from post meta and select accordingly. | |
| 2265 | 984 | $wpstream_product_type = esc_html(get_post_meta($post->ID, 'wpstream_product_type', true)); |
| 2266 | 985 | $wpstream_free_video = esc_html(get_post_meta($post->ID, 'wpstream_free_video', true)); |
| 2267 | - | |
| 986 | + | |
| 2268 | 987 | if($wpstream_product_type==1){ |
| 2269 | 988 | $is_live = ' selected '; |
| 2270 | 989 | } |
| 2271 | - | |
| 990 | + | |
| 2272 | 991 | if($wpstream_product_type==2){ |
| 2273 | 992 | $is_video = ' selected '; |
| 2274 | 993 | } |
| 2275 | 994 | |
| @@ -2277,90 +996,51 @@ | ||
| 2277 | 996 | $is_video_external = ' selected '; |
| 2278 | 997 | } |
| 2279 | 998 | } |
| 2280 | 999 | |
| 2281 | - // Media-type dropdown (recording vs self-hosted/external). | |
| 2282 | 1000 | print' |
| 2283 | 1001 | <p class="meta-options"> |
| 2284 | 1002 | <label for="wpstream_product_type">'.__('Media Type:','wpstream').' </label><br /> |
| 2285 | 1003 | <select id="wpstream_product_type" name="wpstream_product_type"> |
| 2286 | - <option value="2" '.$is_video.'>'.__('Recording','wpstream').'</option> | |
| 2287 | - <option value="3" '.$is_video_external.'>'.__('Self Hosted or External Video','wpstream').'</option> | |
| 1004 | + <option value="1" '.$is_live.'>'.__('Free Live Channel - encrypted streaming & copy protection','wpstream').'</option> | |
| 1005 | + <option value="2" '.$is_video.'>'.__('Free Video - encrypted streaming & copy protection','wpstream').'</option> | |
| 1006 | + <option value="3" '.$is_video_external.'>'.__('Free Video - unprotected','wpstream').'</option> | |
| 2288 | 1007 | </select> |
| 2289 | 1008 | </p> |
| 2290 | 1009 | '; |
| 2291 | 1010 | |
| 2292 | 1011 | |
| 2293 | - // Fetch the account's recordings to populate the chooser. | |
| 2294 | - $video_list = $this->main->wpstream_live_connection->wpstream_get_videos(); | |
| 2295 | 1012 | |
| 2296 | - | |
| 2297 | - // Recording chooser dropdown, pre-selecting the saved recording. | |
| 2298 | - print '<div class="meta-options video_free">'; | |
| 2299 | - print '<p class="meta-option wpstream_free_video">'; | |
| 2300 | - print '<label for="wpstream_free_video">'.__('Choose video:','wpstream').' </label><br /> | |
| 1013 | + print ' | |
| 1014 | + <p class="meta-options video_free"> | |
| 1015 | + <label for="wpstream_free_video">'.__('Choose video:','wpstream').' </label><br /> | |
| 2301 | 1016 | <select id="wpstream_free_video" name="wpstream_free_video">'; |
| 1017 | + $video_list = $this->main->wpstream_live_connection->wpstream_get_videos(); | |
| 2302 | 1018 | |
| 2303 | - if( is_array( $video_list ) ) { | |
| 2304 | - foreach ($video_list as $key=>$value){ | |
| 2305 | - print '<option value="'.$key.'"'; | |
| 2306 | - if($wpstream_free_video === $key){ | |
| 2307 | - print ' selected '; | |
| 1019 | + if(is_array($video_list)){ | |
| 1020 | + foreach ($video_list as $key=>$value){ | |
| 1021 | + print '<option value="'.$key.'"'; | |
| 1022 | + if($wpstream_free_video === $key){ | |
| 1023 | + print ' selected '; | |
| 1024 | + } | |
| 1025 | + print '>'.$value.'</option>'; | |
| 1026 | + } | |
| 2308 | 1027 | } |
| 2309 | - print '>'.$value.'</option>'; | |
| 2310 | - } | |
| 2311 | - } | |
| 2312 | - print'</select>'; | |
| 2313 | - print '</p> '; | |
| 2314 | - print '</div>'; | |
| 1028 | + print' | |
| 1029 | + </select> | |
| 1030 | + </p> | |
| 1031 | + '; | |
| 2315 | 1032 | |
| 2316 | - // Optional captions (.vtt) picker; hide the select button when a file is already set. | |
| 2317 | - $wpstream_closed_captions_file = get_post_meta($post->ID, 'wpstream_closed_captions_file', true); | |
| 2318 | - | |
| 2319 | - $button_style = $wpstream_closed_captions_file ? 'style="display:none;"' : ''; | |
| 2320 | - | |
| 2321 | - print '<p class="meta-option wpstream_vod_captions_url">'; | |
| 2322 | - print '<label for="wpstream_vod_captions_url_button">'.__('Captions file (optional):','wpstream').' </label><br /> | |
| 2323 | - <input type="hidden" id="wpstream_closed_captions_file" name="wpstream_closed_captions_file" value="'.esc_attr($wpstream_closed_captions_file).'" /> | |
| 2324 | - <input id="wpstream_vod_captions_url_button" type="button" class="upload_button button" value="'.esc_html__('Select .vtt Captions File','wpstream').'" '.$button_style.' /> | |
| 2325 | - <span class="wpstream_caption_file_display">'.( $wpstream_closed_captions_file ? esc_html( basename( $wpstream_closed_captions_file ) ) : '' ).'</span>'; | |
| 2326 | - if ( $wpstream_closed_captions_file ) { | |
| 2327 | - print '<input type="button" class="button wpstream_remove_caption" value="'.esc_html__('Remove','wpstream').'" style="margin-left: 5px;" />'; | |
| 2328 | - } | |
| 2329 | - print '</p> '; | |
| 2330 | - | |
| 2331 | - // Self-hosted / external video URL field with a media-library select button. | |
| 2332 | 1033 | $wpstream_free_video_external= esc_html(get_post_meta($post->ID, 'wpstream_free_video_external', true)); |
| 2333 | - print '<div class="meta-options1 video_free_external"> | |
| 2334 | - <label for="wpstream_free_video_external">'.__('Video:','wpstream').' </label><br /> | |
| 1034 | + print '<p class="meta-options1 video_free_external"> | |
| 1035 | + <label for="wpstream_free_video_external">'.__('Choose video:','wpstream').' </label><br /> | |
| 2335 | 1036 | |
| 2336 | 1037 | <input id="wpstream_free_video_external" type="text" size="36" name="wpstream_free_video_external" value="'.$wpstream_free_video_external.'" /> |
| 2337 | - <input id="wpstream_free_video_external_button" type="button" size="40" class="upload_button button" value="'.esc_html__('Select Video','wpstream').'" />'; | |
| 2338 | - // Show the recording hint vs the external hint depending on the saved media type. | |
| 2339 | - if($wpstream_product_type==2){ | |
| 2340 | - $show_recording=''; | |
| 2341 | - $show_external='style="display:none"'; | |
| 2342 | - }else{ | |
| 2343 | - $show_recording='style="display:none"'; | |
| 2344 | - $show_external=''; | |
| 2345 | - } | |
| 2346 | - print '<p '.$show_recording.' class="wpstream_option_vod_source wpstream_show_recording">'.esc_html__('Choose one of your existing recordings.','wpstream').'</p>'; | |
| 2347 | - print '<p '. $show_external.' class="wpstream_option_vod_source wpstream_show_external">'.esc_html__('Upload a video from your computer or paste the URL of a YouTube/external video.','wpstream').'</p>'; | |
| 2348 | - | |
| 2349 | - print '</div> '; | |
| 1038 | + <input id="wpstream_free_video_external_button" type="button" size="40" class="upload_button button" value="'.esc_html__('Select Video','wpstream').'" /> | |
| 2350 | 1039 | |
| 2351 | - /** | |
| 2352 | - * Fires at the end of the Video On Demand Settings metabox. | |
| 2353 | - * | |
| 2354 | - * Callbacks echo their own fields and own their escaping; saving | |
| 2355 | - * them is the callback's job (hook `save_post`). | |
| 2356 | - * | |
| 2357 | - * @since 4.14.0 | |
| 2358 | - * | |
| 2359 | - * @param int $post_id VOD post ID. | |
| 2360 | - * @param WP_Post $post The post. | |
| 2361 | - */ | |
| 2362 | - do_action( 'wpstream_vod_meta_options_after', intval( $post->ID ), $post ); | |
| 1040 | + <p>'.esc_html__('You can choose a video from your computer or use the url from external source or use the url of a YouTube Video or use the url from a Vimeo video.','wpstream').'</p> | |
| 1041 | + | |
| 1042 | + </p> '; | |
| 2363 | 1043 | } |
| 2364 | 1044 | |
| 2365 | 1045 | |
| 2366 | 1046 | |
| @@ -2370,179 +1050,44 @@ | ||
| 2370 | 1050 | |
| 2371 | 1051 | /** |
| 2372 | 1052 | * Add new product types to Woocommerce select product type |
| 2373 | 1053 | * |
| 2374 | - * Register the "Live Channel" and "Video On Demand" WooCommerce product | |
| 2375 | - * types in the product-type dropdown. Filter callback. | |
| 2376 | - * | |
| 2377 | - * @since 3.0.1 | |
| 2378 | - * @param array $types Existing product-type => label map. | |
| 2379 | - * @return array The map with the WpStream types added. | |
| 2380 | - */ | |
| 1054 | + * @since 3.0.1 | |
| 1055 | + */ | |
| 2381 | 1056 | public function wpstream_add_products( $types ){ |
| 2382 | - $types[ 'live_stream' ] = __( 'Live Channel','wpstream' ); | |
| 2383 | - $types[ 'video_on_demand' ] = __( 'Video On Demand','wpstream' ); | |
| 2384 | - | |
| 1057 | + $types[ 'live_stream' ] = __( 'Live Channel','wpestream' ); | |
| 1058 | + $types[ 'video_on_demand' ] = __( 'Video On Demand','wpestream' ); | |
| 1059 | + | |
| 2385 | 1060 | return $types; |
| 2386 | 1061 | } |
| 2387 | - | |
| 2388 | - /** | |
| 2389 | - * Map the WpStream product-type slugs to their WC_Product subclasses. | |
| 2390 | - * Filter callback for woocommerce_product_class. | |
| 2391 | - * | |
| 2392 | - * @param string $classname Default product class name. | |
| 2393 | - * @param string $product_type The product type slug being instantiated. | |
| 2394 | - * @return string The resolved product class name. | |
| 2395 | - */ | |
| 2396 | - public function wpstream_add_products_class( $classname, $product_type ) { | |
| 2397 | - /** | |
| 2398 | - * Filter the product-type slug => WC_Product subclass map. | |
| 2399 | - * | |
| 2400 | - * A mapped class must exist; unknown classes leave WooCommerce's own | |
| 2401 | - * resolution in place. | |
| 2402 | - * | |
| 2403 | - * @since 4.14.0 | |
| 2404 | - * | |
| 2405 | - * @param array $map Slug => class name. | |
| 2406 | - */ | |
| 2407 | - $map = (array) apply_filters( | |
| 2408 | - 'wpstream_product_class_map', | |
| 2409 | - array( | |
| 2410 | - 'live_stream' => 'WC_Product_Live_Stream', | |
| 2411 | - 'video_on_demand' => 'WC_Product_Video_On_Demand', | |
| 2412 | - ) | |
| 2413 | - ); | |
| 2414 | - if ( isset( $map[ $product_type ] ) && class_exists( $map[ $product_type ] ) ) { | |
| 2415 | - $classname = $map[ $product_type ]; | |
| 2416 | - } | |
| 2417 | - return $classname; | |
| 2418 | - } | |
| 2419 | - | |
| 2420 | - /** | |
| 2421 | - * Load the custom WC_Product subclass files when WooCommerce is active. | |
| 2422 | - * | |
| 2423 | - * @return void | |
| 2424 | - */ | |
| 2425 | - public function wpstream_add_custom_wc_products() { | |
| 2426 | - // Require the live-stream and VOD product classes (WooCommerce only). | |
| 2427 | - if( class_exists( 'WooCommerce' ) ){ | |
| 2428 | - require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/class-wc-product-live-stream.php'; | |
| 2429 | - require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/class-wc-product-video-on-demand.php'; | |
| 2430 | - } | |
| 2431 | - } | |
| 2432 | - | |
| 1062 | + | |
| 1063 | + | |
| 1064 | + | |
| 2433 | 1065 | /** |
| 2434 | 1066 | * Js action to do when user pick live stream or video on demand |
| 2435 | 1067 | * |
| 2436 | 1068 | * @since 3.0.1 |
| 2437 | - */ | |
| 2438 | - | |
| 2439 | - /** | |
| 2440 | - * Whether WpStream WooCommerce product UI should load for this product. | |
| 2441 | - * | |
| 2442 | - * Skips simple, course, and other non-WpStream types so LearnDash and | |
| 2443 | - * other integrations can use the General product data tab without conflict. | |
| 2444 | - * | |
| 2445 | - * @param int $post_id Product post ID. Uses global $post when 0. | |
| 2446 | - * @return bool | |
| 2447 | - */ | |
| 2448 | - public function wpstream_is_wpstream_wc_product_context( $post_id = 0 ) { | |
| 2449 | - // Creating a new stream/VOD from a query-string action always counts. | |
| 2450 | - if ( isset( $_GET['new_stream'] ) || isset( $_GET['new_video_name'] ) ) { | |
| 2451 | - return true; | |
| 2452 | - } | |
| 2453 | - | |
| 2454 | - // On the first product save WooCommerce has not necessarily made | |
| 2455 | - // the selected taxonomy term observable through wc_get_product() | |
| 2456 | - // yet. Trust only its allow-listed product-type form field here; | |
| 2457 | - // the save handler remains scoped to WooCommerce product metadata. | |
| 2458 | - if ( isset( $_POST['product-type'] ) && is_scalar( $_POST['product-type'] ) ) { | |
| 2459 | - $submitted_type = sanitize_key( wp_unslash( $_POST['product-type'] ) ); | |
| 2460 | - if ( in_array( $submitted_type, array( 'live_stream', 'video_on_demand', 'wpstream_bundle', 'subscription' ), true ) ) { | |
| 2461 | - return true; | |
| 2462 | - } | |
| 2463 | - } | |
| 2464 | - | |
| 2465 | - // Fall back to the current global post when no ID was passed. | |
| 2466 | - if ( ! $post_id ) { | |
| 2467 | - global $post; | |
| 2468 | - $post_id = ( $post && isset( $post->ID ) ) ? (int) $post->ID : 0; | |
| 2469 | - } | |
| 2470 | - | |
| 2471 | - // Need a product ID and WooCommerce to resolve the type. | |
| 2472 | - if ( ! $post_id || ! function_exists( 'wc_get_product' ) ) { | |
| 2473 | - return false; | |
| 2474 | - } | |
| 2475 | - | |
| 2476 | - $product = wc_get_product( $post_id ); | |
| 2477 | - if ( ! $product ) { | |
| 2478 | - return false; | |
| 2479 | - } | |
| 2480 | - | |
| 2481 | - // True only for WpStream (and subscription) product types. | |
| 2482 | - return in_array( | |
| 2483 | - $product->get_type(), | |
| 2484 | - array( 'live_stream', 'video_on_demand', 'wpstream_bundle', 'subscription' ), | |
| 2485 | - true | |
| 2486 | - ); | |
| 2487 | - } | |
| 2488 | - | |
| 2489 | - /** | |
| 2490 | - * WooCommerce product types that use the core Regular price field. | |
| 2491 | - * | |
| 2492 | - * @return string[] | |
| 2493 | - */ | |
| 2494 | - public function wpstream_get_wc_product_types_with_pricing() { | |
| 2495 | - return array( 'live_stream', 'video_on_demand', 'wpstream_bundle' ); | |
| 2496 | - } | |
| 2497 | - | |
| 2498 | - /** | |
| 2499 | - * Add show_if_* classes to the pricing panel for WpStream product types. | |
| 2500 | - * | |
| 2501 | - * WooCommerce renders .options_group.pricing with show_if_simple only. Custom | |
| 2502 | - * types rely on show_if_{type} classes so meta-boxes-product.js can toggle them | |
| 2503 | - * when the product type dropdown changes, including on unsaved new products. | |
| 2504 | - * | |
| 2505 | - * @param string $hook Admin screen hook suffix. | |
| 2506 | - */ | |
| 2507 | - public function wpstream_enqueue_wc_product_pricing_visibility( $hook ) { | |
| 2508 | - // Only on the add/edit-post admin screens. | |
| 2509 | - if ( ! in_array( $hook, array( 'post.php', 'post-new.php' ), true ) ) { | |
| 1069 | + */ | |
| 1070 | + | |
| 1071 | + public function wpstream_products_custom_js() { | |
| 1072 | + if ( 'product' != get_post_type() ) : | |
| 2510 | 1073 | return; |
| 2511 | - } | |
| 1074 | + endif; | |
| 2512 | 1075 | |
| 2513 | - // Only on the WooCommerce product post type. | |
| 2514 | - $screen = function_exists( 'get_current_screen' ) ? get_current_screen() : null; | |
| 2515 | - if ( ! $screen || 'product' !== $screen->post_type ) { | |
| 2516 | - return; | |
| 2517 | - } | |
| 1076 | + ?> | |
| 1077 | + <script type='text/javascript'> | |
| 1078 | + jQuery( document ).ready( function() { | |
| 1079 | + jQuery('.options_group.pricing' ).addClass ( 'show_if_live_stream' ).show(); | |
| 1080 | + jQuery('.options_group.pricing' ).addClass ( 'show_if_video_on_demand' ).show(); | |
| 1081 | + jQuery('._sold_individually_field').parent().addClass('show_if_live_stream').show(); | |
| 1082 | + jQuery('._sold_individually_field').parent().addClass('show_if_video_on_demand').show(); | |
| 1083 | + jQuery('._sold_individually_field').show(); | |
| 1084 | + | |
| 1085 | + var selected = jQuery('#product-type').val(); | |
| 1086 | + }); | |
| 1087 | + </script> | |
| 1088 | + <?php | |
| 2518 | 1089 | |
| 2519 | - // Need WooCommerce's product meta-boxes script to attach to. | |
| 2520 | - if ( ! wp_script_is( 'wc-admin-product-meta-boxes', 'registered' ) ) { | |
| 2521 | - return; | |
| 2522 | - } | |
| 2523 | - | |
| 2524 | - // Pass the WpStream pricing types to JS and add show_if_{type} classes so the pricing panel toggles correctly. | |
| 2525 | - $types_json = wp_json_encode( array_values( $this->wpstream_get_wc_product_types_with_pricing() ) ); | |
| 2526 | - | |
| 2527 | - wp_add_inline_script( | |
| 2528 | - 'wc-admin-product-meta-boxes', | |
| 2529 | - "jQuery( function( $ ) { | |
| 2530 | - var wpstreamPricingProductTypes = {$types_json}; | |
| 2531 | - var \$pricing = $( '.options_group.pricing' ); | |
| 2532 | - var \$soldIndividually = $( '._sold_individually_field' ).parent(); | |
| 2533 | - | |
| 2534 | - wpstreamPricingProductTypes.forEach( function( type ) { | |
| 2535 | - \$pricing.addClass( 'show_if_' + type ); | |
| 2536 | - \$soldIndividually.addClass( 'show_if_' + type ); | |
| 2537 | - } ); | |
| 2538 | - | |
| 2539 | - if ( wpstreamPricingProductTypes.indexOf( $( '#product-type' ).val() ) !== -1 ) { | |
| 2540 | - \$pricing.show(); | |
| 2541 | - \$soldIndividually.show(); | |
| 2542 | - } | |
| 2543 | - } );" | |
| 2544 | - ); | |
| 2545 | 1090 | } |
| 2546 | 1091 | |
| 2547 | 1092 | |
| 2548 | 1093 | /** |
| @@ -2547,103 +1092,44 @@ | ||
| 2547 | 1092 | |
| 2548 | 1093 | /** |
| 2549 | 1094 | * Add custom classes to the product types |
| 2550 | 1095 | * |
| 2551 | - * Adjust the WooCommerce product-data tab visibility classes so WpStream | |
| 2552 | - * types hide the Shipping tab and show the Inventory tab. Filter callback. | |
| 2553 | - * | |
| 2554 | - * @since 3.0.1 | |
| 2555 | - * @param array $tabs WooCommerce product data tabs config. | |
| 2556 | - * @return array The modified tabs config. | |
| 2557 | - */ | |
| 1096 | + * @since 3.0.1 | |
| 1097 | + */ | |
| 1098 | + | |
| 2558 | 1099 | public function wpstream_hide_attributes_data_panel( $tabs) { |
| 1100 | + | |
| 1101 | + $tabs['shipping']['class'][] = 'hide_if_live_stream hide_if_video_on_demand'; | |
| 1102 | + $tabs['inventory']['class'][] = 'show_if_live_stream show_if_video_on_demand'; | |
| 1103 | + // $tabs['general']['class'][] = 'show_if_live_stream show_if_video_on_demand'; | |
| 2559 | 1104 | |
| 2560 | - // Hide Shipping and show Inventory for WpStream product types. | |
| 2561 | - $tabs['shipping']['class'][] = 'hide_if_live_stream hide_if_video_on_demand hide_if_wpstream_bundle'; | |
| 2562 | - $tabs['inventory']['class'][] = 'show_if_live_stream show_if_video_on_demand show_if_wpstream_bundle'; | |
| 2563 | - | |
| 2564 | 1105 | return $tabs; |
| 2565 | 1106 | } |
| 2566 | 1107 | |
| 2567 | 1108 | |
| 2568 | - | |
| 2569 | - /** | |
| 2570 | - * Hide buy now on products if Netflix mode | |
| 2571 | - * | |
| 2572 | - * When global subscription ("Netflix") mode is on, mark WpStream media | |
| 2573 | - * products as not individually purchasable (access comes via the | |
| 2574 | - * subscription instead). Filter callback for is_purchasable. | |
| 2575 | - * | |
| 2576 | - * @since 3.12 | |
| 2577 | - * @param bool $purchaseable_product_wpblog Current purchasable flag. | |
| 2578 | - * @param WC_Product $product The product being checked. | |
| 2579 | - * @return bool False for WpStream media in global-sub mode, else the original flag. | |
| 2580 | - */ | |
| 2581 | - public function wpstream_hide_buy_now_subscription_mode( $purchaseable_product_wpblog,$product){ | |
| 2582 | - $product_id=$product->get_id(); | |
| 2583 | - | |
| 2584 | - // Stable type slug is '' when the product has no term (never a crash). | |
| 2585 | - $product_type_slug = wpstream_get_product_type_slug($product_id); | |
| 2586 | - | |
| 2587 | - // Global subscription ("Netflix") mode flag. | |
| 2588 | - $subscription_model = intval( get_option('wpstream_global_sub','')) ; | |
| 2589 | - | |
| 2590 | - if($subscription_model==1){ // if we have Neflix mode | |
| 2591 | - // WpStream media types are not directly purchasable in this mode. | |
| 2592 | - if( $product_type_slug=='live_stream' || $product_type_slug=='video_on_demand' || $product_type_slug=='wpstream_bundle' ){ | |
| 2593 | - return false; | |
| 2594 | - } | |
| 2595 | - } | |
| 2596 | - | |
| 2597 | - return $purchaseable_product_wpblog; | |
| 2598 | - } | |
| 2599 | - | |
| 2600 | - | |
| 2601 | - | |
| 2602 | - | |
| 2603 | - | |
| 2604 | - | |
| 2605 | 1109 | /** |
| 2606 | 1110 | * Add custom fields to custom product types |
| 2607 | 1111 | * |
| 2608 | - * Render the extra WooCommerce "General" product fields for WpStream types: | |
| 2609 | - * the subscription-live flag, the recording/video chooser, and the | |
| 2610 | - * "attach to subscription" multi-select. Echoes HTML. | |
| 2611 | - * | |
| 2612 | - * @since 3.0.1 | |
| 2613 | - * @return void | |
| 2614 | - */ | |
| 1112 | + * @since 3.0.1 | |
| 1113 | + */ | |
| 1114 | + | |
| 2615 | 1115 | public function wpstream_add_custom_general_fields() { |
| 1116 | + | |
| 2616 | 1117 | global $woocommerce, $post; |
| 2617 | - | |
| 2618 | - // A new WooCommerce product is still an auto-draft `simple` product | |
| 2619 | - // when this hook renders. Emit the type-scoped controls there so | |
| 2620 | - // WooCommerce can reveal them after the administrator selects a | |
| 2621 | - // WpStream type; the show_if_* classes keep them hidden otherwise. | |
| 2622 | - $post_id = isset( $post->ID ) ? (int) $post->ID : 0; | |
| 2623 | - $is_new_product = $post_id && 'auto-draft' === get_post_status( $post_id ); | |
| 2624 | - if ( ! $is_new_product && ! $this->wpstream_is_wpstream_wc_product_context( $post_id ) ) { | |
| 2625 | - return; | |
| 2626 | - } | |
| 2627 | - // Subscription-based live channel toggle (only when WC Subscriptions is active). | |
| 2628 | 1118 | if(function_exists('wcs_user_has_subscription')){ |
| 2629 | - echo '<div class="options_group show_if_subscription">'; | |
| 1119 | + echo '<div class="options_group show_if_subscription">'; | |
| 2630 | 1120 | woocommerce_wp_select( |
| 2631 | 1121 | array( |
| 2632 | 1122 | 'id' => '_subscript_live_event', |
| 2633 | 1123 | 'label' => __( 'Is a subscription based live channel ?', 'woocommerce' ), |
| 2634 | - 'options' => array("yes"=>"yes","no"=>"no", "none" => "none") | |
| 1124 | + 'options' => array("yes"=>"yes","no"=>"no") | |
| 2635 | 1125 | ) |
| 2636 | 1126 | ); |
| 2637 | 1127 | echo '</div>'; |
| 2638 | 1128 | } |
| 2639 | 1129 | |
| 2640 | - echo '<div class="options_group show_if_live_stream" style="border:none;"></div>'; | |
| 2641 | - // VOD video chooser section. | |
| 2642 | - echo '<div class="options_group show_if_video_on_demand">'; | |
| 2643 | - | |
| 2644 | - | |
| 2645 | - // Pre-selected video: from the new-video query arg, else the saved _movie_url meta. | |
| 1130 | + echo '<div class="options_group show_if_live_stream" style="border:none;"></div>'; | |
| 1131 | + echo '<div class="options_group show_if_video_on_demand">'; | |
| 2646 | 1132 | $selected=''; |
| 2647 | 1133 | if( isset( $_GET['new_video_name']) && $_GET['new_video_name']!='' ){ |
| 2648 | 1134 | $selected=esc_html($_GET['new_video_name']); |
| 2649 | 1135 | } |
| @@ -2649,161 +1135,43 @@ | ||
| 2649 | 1135 | } |
| 2650 | 1136 | if($selected==''){ |
| 2651 | 1137 | $selected= get_post_meta($post->ID,'_movie_url',true); |
| 2652 | 1138 | } |
| 2653 | - // Only administrators may assign videos. | |
| 2654 | - if( !current_user_can('administrator') ){ | |
| 2655 | - print '<div style="margin:10px;">'.esc_html__('You need to be an administrator in order to assign videos','wpstream').'</div>'; | |
| 2656 | - }else{ | |
| 2657 | - woocommerce_wp_select( | |
| 2658 | - array( | |
| 2659 | - 'id' => '_movie_url', | |
| 2660 | - 'label' => __( 'Choose video', 'woocommerce' ), | |
| 2661 | - 'options' => $this->main->wpstream_live_connection->wpstream_get_videos(), | |
| 2662 | - 'selected'=> true, | |
| 2663 | - 'value' => $selected | |
| 2664 | - ) | |
| 2665 | - ); | |
| 2666 | - } | |
| 2667 | - | |
| 2668 | - | |
| 2669 | 1139 | |
| 2670 | - echo '</div>'; | |
| 2671 | - | |
| 2672 | - // "Attach to subscription" multi-select (only when WC Subscriptions is active). | |
| 2673 | - if(function_exists('wcs_user_has_subscription')){ | |
| 2674 | - $selected_sub=''; | |
| 2675 | - echo '<div class="options_group show_if_video_on_demand show_if_live_stream">'; | |
| 2676 | - if( isset( $_GET['wpstream_parent_sub']) && $_GET['wpstream_parent_sub']!='' ){ | |
| 2677 | - $selected_sub=esc_html($_GET['wpstream_parent_sub']); | |
| 2678 | - } | |
| 2679 | - if($selected_sub==''){ | |
| 2680 | - $selected_sub= get_post_meta($post->ID,'_wpstream_parent_sub',true); | |
| 2681 | - } | |
| 2682 | - woocommerce_wp_select( | |
| 1140 | + woocommerce_wp_select( | |
| 2683 | 1141 | array( |
| 2684 | - 'id' => '_wpstream_parent_sub', | |
| 2685 | - 'name' => '_wpstream_parent_sub[]', | |
| 2686 | - 'label' => __( 'Attach to subscription', 'woocommerce' ), | |
| 2687 | - 'options' => $this->wpstream_return_subscriptions_created(), | |
| 1142 | + 'id' => '_movie_url', | |
| 1143 | + 'label' => __( 'Select the video file.', 'woocommerce' ), | |
| 1144 | + 'options' => $this->main->wpstream_live_connection->wpstream_get_videos(), | |
| 2688 | 1145 | 'selected'=> true, |
| 2689 | - 'value' => $selected_sub, | |
| 2690 | - 'custom_attributes' => array('multiple' => 'multiple') | |
| 1146 | + 'value' => $selected | |
| 2691 | 1147 | ) |
| 2692 | 1148 | ); |
| 2693 | - | |
| 2694 | - echo '</div>'; | |
| 2695 | - | |
| 2696 | - } | |
| 2697 | - } | |
| 2698 | - | |
| 2699 | - | |
| 2700 | - /** | |
| 2701 | - * Build an id => title map of all WooCommerce subscription products, | |
| 2702 | - * for the "attach to subscription" selector. Includes a "none" option. | |
| 2703 | - * | |
| 2704 | - * @return array Map of subscription product ID => title (0 => 'none'). | |
| 2705 | - */ | |
| 2706 | - public function wpstream_return_subscriptions_created(){ | |
| 2707 | - // Seed with the "none" choice. | |
| 2708 | - $return=array('0'=>'none'); | |
| 2709 | 1149 | |
| 2710 | - // Query all subscription-type products, title-ordered. | |
| 2711 | - $args = array( | |
| 2712 | - 'post_type' => 'product', | |
| 2713 | - 'posts_per_page' => -1, | |
| 2714 | - 'orderby' => 'title', | |
| 2715 | - 'order' => 'ASC', | |
| 2716 | - 'tax_query' => array( | |
| 2717 | - 'relation' => 'AND', | |
| 2718 | - array( | |
| 2719 | - 'taxonomy' => 'product_type', | |
| 2720 | - 'field' => 'slug', | |
| 2721 | - 'terms' => array( 'subscription'), | |
| 2722 | - ) | |
| 2723 | - ) | |
| 2724 | - ); | |
| 2725 | - | |
| 2726 | - // Collect each subscription's id => title. | |
| 2727 | - $subscriptions = new WP_Query($args); | |
| 2728 | - if($subscriptions->have_posts()): | |
| 2729 | - while ($subscriptions->have_posts()): $subscriptions->the_post(); | |
| 2730 | - $return[ get_the_ID() ] = get_the_title(); | |
| 2731 | - endwhile; | |
| 2732 | - endif; | |
| 2733 | - | |
| 2734 | - // Restore the main query and return the map. | |
| 2735 | - wp_reset_postdata(); | |
| 2736 | - return $return; | |
| 2737 | - | |
| 1150 | + echo '</div>'; | |
| 2738 | 1151 | } |
| 2739 | - | |
| 2740 | - | |
| 2741 | - | |
| 2742 | - | |
| 2743 | - | |
| 2744 | 1152 | |
| 2745 | 1153 | /** |
| 2746 | 1154 | * Save custom fields |
| 2747 | 1155 | * |
| 2748 | - * Persist the WpStream WooCommerce product fields (_movie_url, | |
| 2749 | - * _subscript_live_event, _wpstream_parent_sub) on save and reset the | |
| 2750 | - * event_passed flag. Hooked to the product save action. | |
| 2751 | - * | |
| 2752 | - * @since 3.0.1 | |
| 2753 | - * @param int $post_id Product ID being saved. | |
| 2754 | - * @return void | |
| 2755 | - */ | |
| 1156 | + * @since 3.0.1 | |
| 1157 | + */ | |
| 1158 | + | |
| 2756 | 1159 | public function wpstream_add_custom_general_fields_save( $post_id ){ |
| 2757 | - // Only handle WpStream product contexts. | |
| 2758 | - if ( ! $this->wpstream_is_wpstream_wc_product_context( (int) $post_id ) ) { | |
| 2759 | - return; | |
| 2760 | - } | |
| 2761 | 1160 | |
| 2762 | - // A Source Recording owns the cached DRM and hosted-player identity. | |
| 2763 | - // Retire that identity before replacing the source so its old key index | |
| 2764 | - // is still available to invalidate the lookup caches. | |
| 2765 | - if ( | |
| 2766 | - has_term( 'video_on_demand', 'product_type', $post_id ) | |
| 2767 | - && ! empty( $_POST['_movie_url'] ) | |
| 2768 | - && is_scalar( $_POST['_movie_url'] ) | |
| 2769 | - ) { | |
| 2770 | - $previous_recording = (string) get_post_meta( $post_id, '_movie_url', true ); | |
| 2771 | - $new_recording = sanitize_text_field( wp_unslash( $_POST['_movie_url'] ) ); | |
| 2772 | - if ( $new_recording !== $previous_recording ) { | |
| 2773 | - $this->wpstream_retire_vod_recording_identity( $post_id ); | |
| 2774 | - } | |
| 2775 | - } | |
| 2776 | - | |
| 2777 | - // Meta keys this handler may write. | |
| 2778 | 1161 | $permited_values = array( |
| 2779 | 1162 | '_movie_url', |
| 2780 | - '_subscript_live_event', | |
| 2781 | - '_wpstream_parent_sub', | |
| 2782 | - | |
| 1163 | + '_subscript_live_event' | |
| 2783 | 1164 | ); |
| 2784 | - | |
| 2785 | - | |
| 2786 | - | |
| 2787 | - // Reset event_passed and save each allow-listed field. | |
| 1165 | + $allowed_html=array(); | |
| 2788 | 1166 | foreach($_POST as $key=>$value){ |
| 2789 | 1167 | update_post_meta( $post_id, 'event_passed', 0 ); |
| 2790 | 1168 | if( in_array($key, $permited_values) ){ |
| 2791 | 1169 | if( !empty( $_POST[$key] ) ){ |
| 2792 | - $key = sanitize_key($key); | |
| 2793 | - $value = sanitize_text_field($_POST[$key]); | |
| 2794 | - | |
| 2795 | - // The parent-subscription field is an array; sanitize each element. | |
| 2796 | - if($key=='_wpstream_parent_sub'){ | |
| 2797 | - $value= $_POST[$key]; | |
| 2798 | - $value = array_map("sanitize_text_field", $value); | |
| 2799 | - | |
| 2800 | - } | |
| 2801 | - update_post_meta( $post_id, $key, $value ); | |
| 1170 | + update_post_meta( $post_id, wp_kses ($key,$allowed_html), wp_kses ( $_POST[$key],$allowed_html) ); | |
| 2802 | 1171 | } |
| 2803 | 1172 | } |
| 2804 | 1173 | } |
| 2805 | - //die(); | |
| 2806 | 1174 | |
| 2807 | 1175 | } |
| 2808 | 1176 | |
| 2809 | 1177 | /** |
| @@ -2808,34 +1176,25 @@ | ||
| 2808 | 1176 | |
| 2809 | 1177 | /** |
| 2810 | 1178 | * Add to cart redirect |
| 2811 | 1179 | * |
| 2812 | - * Render the simple add-to-cart template for WpStream product types. | |
| 2813 | - * | |
| 2814 | - * @since 3.0.1 | |
| 2815 | - * @return void | |
| 2816 | - */ | |
| 1180 | + * @since 3.0.1 | |
| 1181 | + */ | |
| 1182 | + | |
| 2817 | 1183 | public function wpstream_add_to_cart() { |
| 2818 | 1184 | wc_get_template( 'single-product/add-to-cart/simple.php' ); |
| 2819 | 1185 | } |
| 2820 | 1186 | |
| 2821 | - | |
| 1187 | + | |
| 2822 | 1188 | /** |
| 2823 | 1189 | * Replace add to cart button |
| 2824 | 1190 | * |
| 2825 | - * For live_stream / video_on_demand products, swap the loop add-to-cart | |
| 2826 | - * button for a direct shop add-to-cart link. Filter callback. | |
| 2827 | - * | |
| 2828 | - * @since 3.0.1 | |
| 2829 | - * @param string $button Original button HTML. | |
| 2830 | - * @param WC_Product $product The product (overwritten by global $product). | |
| 2831 | - * @return string The (possibly replaced) button HTML. | |
| 2832 | - */ | |
| 1191 | + * @since 3.0.1 | |
| 1192 | + */ | |
| 2833 | 1193 | public function replacing_add_to_cart_button( $button, $product ) { |
| 2834 | 1194 | global $product; |
| 2835 | 1195 | $product_type = $product->get_type(); |
| 2836 | 1196 | |
| 2837 | - // Only WpStream media types get the custom link; others keep the default button. | |
| 2838 | 1197 | if($product_type==='live_stream' || $product_type=='video_on_demand'){ |
| 2839 | 1198 | return $button = '<a class="button" href="'.get_site_url().'/shop/?add-to-cart=' .$product->get_id(). '&quantity=1">' . __( 'Add to Cart', 'woocommerce' ) . '</a>'; |
| 2840 | 1199 | }else{ |
| 2841 | 1200 | return $button; |
| @@ -2845,711 +1204,108 @@ | ||
| 2845 | 1204 | |
| 2846 | 1205 | /** |
| 2847 | 1206 | * Admin notices |
| 2848 | 1207 | * |
| 2849 | - * Print global admin notices: (commented-out) WooCommerce-missing notice | |
| 2850 | - * and an error if the PHP cURL extension is unavailable, plus the dismiss | |
| 2851 | - * nonce. Echoes HTML. | |
| 2852 | - * | |
| 2853 | - * @since 3.0.1 | |
| 2854 | - * @return void | |
| 2855 | - */ | |
| 1208 | + * @since 3.0.1 | |
| 1209 | + */ | |
| 2856 | 1210 | public function wpstream_admin_notice() { |
| 2857 | 1211 | global $pagenow; |
| 2858 | 1212 | global $typenow; |
| 2859 | 1213 | |
| 2860 | - // Stored dismissed-notice flags. | |
| 2861 | - $wpstream_notices = get_option('wpstream_notices'); | |
| 2862 | - | |
| 2863 | - /* | |
| 1214 | + | |
| 2864 | 1215 | if ( !in_array( 'woocommerce/woocommerce.php', apply_filters( 'active_plugins', get_option( 'active_plugins' ) ) ) ) { |
| 2865 | - if( !is_array($wpstream_notices) || | |
| 2866 | - !isset($wpstream_notices['wpstream_woo_notice']) || | |
| 2867 | - ( isset($wpstream_notices['wpstream_woo_notice']) && $wpstream_notices['wpstream_woo_notice']!='yes') ){ | |
| 2868 | - | |
| 2869 | - | |
| 2870 | - print '<div class="notice wpstream_notices notice-error is-dismissible" data-notice-type="wpstream_woo_notice" > | |
| 2871 | - <p>'.__( 'WpStream Pay-Per-View Live Streaming and VOD only works with WooCommerce - Please enable and activate the WooCommerce plugin if you want to monetize your Live Events or Recorded Videos', 'wpstream' ).'</p> | |
| 1216 | + print '<div class="notice notice-error is-dismissible"> | |
| 1217 | + <p>'.__( 'WpStream Pay Per View / Subscription mode works only with WooCommerce - If you want to charge money for your live events or videos you need to activate WooCommerce plugin', 'wpestate' ).'</p> | |
| 2872 | 1218 | </div>'; |
| 2873 | - } | |
| 2874 | 1219 | } |
| 2875 | - */ | |
| 2876 | - | |
| 2877 | - // Hard requirement: warn when the PHP cURL extension is missing. | |
| 2878 | 1220 | if( !in_array ('curl', get_loaded_extensions())) { |
| 2879 | 1221 | print '<div class="notice notice-error is-dismissible"> |
| 2880 | - <p>'.__( 'The php CURL library is not enabled on your server. WpStream plugin needs this library in order to work. Please address this issue with your hosting provider.', 'wpstream' ).'</p> | |
| 1222 | + <p>'.__( 'The php CURL library is not enabled on your server. WpStream plugin needs this library in order to work. Please address this issue with your hosting provider.', 'wpestate' ).'</p> | |
| 2881 | 1223 | </div>'; |
| 2882 | 1224 | } |
| 2883 | 1225 | |
| 2884 | 1226 | |
| 2885 | - // Nonce used by the JS that records notice dismissals. | |
| 2886 | - $ajax_nonce = wp_create_nonce( "wpstream_notice_nonce" ); | |
| 2887 | - print '<input type="hidden" id="wpstream_notice_nonce" value="'.esc_html($ajax_nonce).'"/>'; | |
| 1227 | + $wpestate_notices = get_option('wp_stream_notices'); | |
| 2888 | 1228 | |
| 2889 | - } | |
| 1229 | + if( !is_array($wpestate_notices) || | |
| 1230 | + !isset($wpestate_notices['wpstream_update_1021']) || | |
| 1231 | + ( isset($wpestate_notices['wpstream_update_1021']) && $wpestate_notices['wpstream_update_1021']!='yes') ){ | |
| 2890 | 1232 | |
| 2891 | - /** | |
| 2892 | - * Get plugin latest update release date from WordPress.org | |
| 2893 | - * @param $plugin_slug | |
| 2894 | - * @param $version | |
| 2895 | - * | |
| 2896 | - * @return bool | |
| 2897 | - */ | |
| 2898 | - public function get_plugin_release_date( $plugin_slug, $version = null ) { | |
| 2899 | - // This runs on every admin page while an update is pending, so the | |
| 2900 | - // answer is cached for 12h — including a negative one, otherwise a | |
| 2901 | - // failed lookup would retry per page load. Keyed by version so a | |
| 2902 | - // newer release triggers a fresh lookup. | |
| 2903 | - $cache_key = 'wpstream_release_date_' . md5( $plugin_slug . '|' . (string) $version ); | |
| 2904 | - $cached = get_transient( $cache_key ); | |
| 2905 | - if ( false !== $cached ) { | |
| 2906 | - // 'none' is the stored form of a negative result. | |
| 2907 | - return 'none' === $cached ? false : $cached; | |
| 1233 | + print '<div id ="setting-error-wprentals-cache" data-notice-type="wpstream_update_1021" data-dismissible="disable-done-notice-forever" class="wpestate_notices updated settings-error notice is-dismissible"> | |
| 1234 | + <p>'.esc_html__( 'New! We just released WpStream WordPress Theme - a turn key solution for video delivery & live streaming. This theme is built around WpStream plugin and is the perfect solution for video streaming or rentals platform. ','wpstream').'<a href="https://wpstream.net/wpstream-theme-a-live-streaming-wordpress-theme" target="_blank">'.esc_html__('Download Theme','wpstream').'</a></p> | |
| 1235 | + </div>'; | |
| 2908 | 1236 | } |
| 2909 | 1237 | |
| 2910 | - // Query the WordPress.org plugins info API (short timeout: this is | |
| 2911 | - // cosmetic notice logic and must never stall the admin). | |
| 2912 | - $api_url = 'https://api.wordpress.org/plugins/info/1.0/' . $plugin_slug . '.json'; | |
| 2913 | - $response = wp_remote_get( $api_url, array( 'timeout' => 3 ) ); | |
| 2914 | 1238 | |
| 2915 | - // Resolve the answer (false = no usable date), then cache it once. | |
| 2916 | - $release_date = false; | |
| 2917 | 1239 | |
| 2918 | - if ( ! is_wp_error( $response ) ) { | |
| 2919 | - // Decode the JSON body; a date needs a versions list to validate against. | |
| 2920 | - $data = json_decode( wp_remote_retrieve_body( $response ), true ); | |
| 2921 | 1240 | |
| 2922 | - if ( $data && isset( $data['versions'] ) ) { | |
| 2923 | - // no version provided, get the latest version | |
| 2924 | - if ( ! $version ) { | |
| 2925 | - $version = $data['version']; | |
| 2926 | - } | |
| 2927 | 1241 | |
| 2928 | - // The version must exist in the versions array. | |
| 2929 | - // (note: last_updated is the plugin's overall date, not per-version) | |
| 2930 | - if ( isset( $data['versions'][ $version ] ) && isset( $data['last_updated'] ) ) { | |
| 2931 | - $release_date = date( 'Y-m-d', strtotime( $data['last_updated'] ) ); | |
| 2932 | - } | |
| 2933 | - } | |
| 2934 | - } | |
| 1242 | + $ajax_nonce = wp_create_nonce( "wpstream_notice_nonce" ); | |
| 1243 | + print '<input type="hidden" id="wpstream_notice_nonce" value="'.esc_html($ajax_nonce).'"/>'; | |
| 2935 | 1244 | |
| 2936 | - set_transient( $cache_key, false === $release_date ? 'none' : $release_date, 12 * HOUR_IN_SECONDS ); | |
| 2937 | - return $release_date; | |
| 2938 | 1245 | } |
| 2939 | - | |
| 2940 | - /** | |
| 2941 | - * Adds notice for the WpStream update availability | |
| 2942 | - * when the update is not older than 30 days | |
| 2943 | - */ | |
| 2944 | - public function wpstream_plugin_update_available_notice() { | |
| 2945 | - // Only show to users who can update plugins. | |
| 2946 | - if (!current_user_can('update_plugins')) { | |
| 2947 | - return; | |
| 2948 | - } | |
| 2949 | - | |
| 2950 | - // Look up a pending update for this plugin in WP's transient. | |
| 2951 | - $plugin_slug = 'wpstream/wpstream.php'; | |
| 2952 | - $update_data = get_site_transient('update_plugins'); | |
| 2953 | - | |
| 2954 | - if ( is_object( $update_data ) && | |
| 2955 | - property_exists( $update_data, 'response' ) && | |
| 2956 | - is_array($update_data->response) && | |
| 2957 | - key_exists($plugin_slug, $update_data->response) | |
| 2958 | - ) { | |
| 2959 | - $new_version = $update_data->response[$plugin_slug]->new_version; | |
| 2960 | - | |
| 2961 | - // Suppress the notice for very fresh releases (grace period). | |
| 2962 | - $release_date = $this->get_plugin_release_date( 'wpstream', $new_version ); | |
| 2963 | - | |
| 2964 | - if ( $release_date ) { | |
| 2965 | - $days_since_release = ( time() - strtotime( $release_date ) ) / DAY_IN_SECONDS; | |
| 2966 | - | |
| 2967 | - // if there's an update newer than 7 days, do not show the notice | |
| 2968 | - if ( $days_since_release < 7 ) { | |
| 2969 | - return; | |
| 2970 | - } | |
| 2971 | - } | |
| 2972 | - // Build the one-click update URL (nonce-protected) and print the notice. | |
| 2973 | - $update_url = wp_nonce_url( | |
| 2974 | - self_admin_url('update.php?action=upgrade-plugin&plugin=' . urlencode($plugin_slug)), | |
| 2975 | - 'upgrade-plugin_' . $plugin_slug | |
| 2976 | - ); | |
| 2977 | - | |
| 2978 | - echo '<div class="notice notice-warning is-dismissible">'; | |
| 2979 | - echo '<p><strong>' . __('WpStream Plugin Update Available', 'wpstream') . '</strong></p>'; | |
| 2980 | - echo '<p>' . sprintf( | |
| 2981 | - __('Version %s is available. Please update to the latest version for new features and security improvements.', 'wpstream'), | |
| 2982 | - '<strong>' . esc_html($new_version) . '</strong>' | |
| 2983 | - ) . '</p>'; | |
| 2984 | - echo '<p><a href="' . esc_url($update_url) . '" class="button button-primary">' . | |
| 2985 | - __('Update Now', 'wpstream') . '</a></p>'; | |
| 2986 | - echo '</div>'; | |
| 2987 | - } | |
| 2988 | - } | |
| 2989 | - | |
| 1246 | + | |
| 2990 | 1247 | /** |
| 2991 | 1248 | * Admin notices |
| 2992 | 1249 | * |
| 2993 | - * AJAX handler that records a dismissed notice: marks the posted notice | |
| 2994 | - * type as 'yes' in the wpstream_notices option so it stops showing. | |
| 2995 | - * | |
| 2996 | - * @since 3.0.1 | |
| 2997 | - * @return void Ends the request with die(). | |
| 2998 | - */ | |
| 1250 | + * @since 3.0.1 | |
| 1251 | + */ | |
| 2999 | 1252 | public function wpstream_update_cache_notice(){ |
| 3000 | 1253 | |
| 3001 | - // CSRF gate: the dismiss JS sends the nonce printed next to the notice. | |
| 3002 | - check_ajax_referer( 'wpstream_notice_nonce', 'security' ); | |
| 3003 | - // Dismissals are stored in a site-wide option, so require admin rights. | |
| 3004 | - if ( ! current_user_can( 'manage_options' ) ) { | |
| 3005 | - die(); | |
| 3006 | - } | |
| 1254 | + //check_ajax_referer( 'wpstream_notice_nonce', 'security' ); | |
| 3007 | 1255 | |
| 3008 | - // Which notice was dismissed. | |
| 3009 | 1256 | $notice_type = esc_html($_POST['notice_type']); |
| 3010 | 1257 | $notices = get_option('wp_stream_notices'); |
| 3011 | 1258 | |
| 3012 | - // Normalise to an array. | |
| 3013 | 1259 | if(! is_array($notices) ){ |
| 3014 | 1260 | $notices=array(); |
| 3015 | 1261 | } |
| 3016 | 1262 | |
| 3017 | - // Flag this notice as dismissed and persist. | |
| 3018 | 1263 | $notices[$notice_type]='yes'; |
| 3019 | 1264 | |
| 3020 | - update_option('wpstream_notices',$notices); | |
| 1265 | + update_option('wp_stream_notices',$notices); | |
| 3021 | 1266 | die(); |
| 3022 | 1267 | } |
| 3023 | 1268 | |
| 3024 | - | |
| 3025 | 1269 | |
| 3026 | 1270 | |
| 3027 | 1271 | /** |
| 3028 | 1272 | * Activate metaboxes for Streaming controls on sidebar |
| 3029 | 1273 | * |
| 3030 | - * Register the "Live Streaming" sidebar metabox on free channel posts, and | |
| 3031 | - * also on WooCommerce products that are live_stream (or a subscription | |
| 3032 | - * flagged as a live event). Hooked to add_meta_boxes. | |
| 3033 | - * | |
| 3034 | - * @since 3.0.1 | |
| 3035 | - * @return void | |
| 3036 | - */ | |
| 1274 | + * @since 3.0.1 | |
| 1275 | + */ | |
| 3037 | 1276 | public function wpstream_startstreaming_sidebar_meta() { |
| 3038 | - return $this->main->get_live_channel_presentation()->register_metaboxes(); | |
| 3039 | - } | |
| 3040 | - public function wpstream_start_stream_meta(){ | |
| 3041 | - return $this->main->get_live_channel_presentation()->render_sidebar(); | |
| 3042 | - } | |
| 3043 | - public function wpstream_is_basic_streaming_mode(){ | |
| 3044 | - return $this->main->quota_manager->is_basic_streaming_mode( null, 'wpstream_is_basic_streaming_mode' ); | |
| 3045 | - } | |
| 1277 | + global $post; | |
| 1278 | + $term_list = wp_get_post_terms($post->ID, 'product_type'); | |
| 1279 | + if( get_post_meta($post->ID, 'wpstream_product_type', true)==1 ){ | |
| 1280 | + add_meta_box('wpstream-sidebar-meta', esc_html__('Live Streaming', 'wpstream'), array($this,'wpstream_start_stream_meta'), 'wpstream_product', 'side', 'high'); | |
| 1281 | + } | |
| 1282 | + | |
| 1283 | + $is_subscription_live_event = esc_html(get_post_meta($post->ID,'_subscript_live_event',true)); | |
| 1284 | + | |
| 3046 | 1285 | |
| 3047 | - /** | |
| 3048 | - * Whether the account's plan meters streaming by hours (vs. data). | |
| 3049 | - * | |
| 3050 | - * @return bool | |
| 3051 | - */ | |
| 3052 | - public function wpstream_is_use_streaming_hours() { | |
| 3053 | - $pack_details = $this->main->quota_manager->get_live_quota_data( 'wpstream_start_channel' ); | |
| 3054 | - return $this->main->quota_manager->uses_streaming_hours( $pack_details ); | |
| 3055 | - } | |
| 1286 | + if(!is_wp_error( $term_list )){ | |
| 1287 | + if( isset($term_list[0]->name) ){ | |
| 1288 | + if( $term_list[0]->name=='live_stream' || ($term_list[0]->name=='subscription' && $is_subscription_live_event=='yes' ) ){ | |
| 1289 | + add_meta_box('wpstream-sidebar-meta', esc_html__('Live Streaming', 'wpstream'), array($this,'wpstream_start_stream_meta'), 'product', 'side', 'high'); | |
| 1290 | + } | |
| 1291 | + } | |
| 1292 | + } | |
| 3056 | 1293 | |
| 3057 | - /** | |
| 3058 | - * Cached-only flags for start_streaming.js localization (no API on cold cache). | |
| 3059 | - * | |
| 3060 | - * @return array{is_basic_streaming: bool, use_streaming_hours: bool} | |
| 3061 | - */ | |
| 3062 | - public function wpstream_get_start_streaming_localization_flags() { | |
| 3063 | - return $this->main->get_live_channel_presentation()->get_localization_flags(); | |
| 3064 | - } | |
| 3065 | - | |
| 3066 | - | |
| 3067 | - | |
| 3068 | - /** | |
| 3069 | - * Register a hidden dashboard page used as the onboarding wizard endpoint. | |
| 3070 | - * | |
| 3071 | - * @return void | |
| 3072 | - */ | |
| 3073 | - public function add_dashboard_page() { | |
| 3074 | - $this->main->get_onboarding()->render_part( 'dashboard_page' ); | |
| 3075 | 1294 | } |
| 3076 | - | |
| 3077 | - | |
| 3078 | - | |
| 3079 | - | |
| 3080 | - /** | |
| 3081 | - * Bootstrap the full-screen onboarding wizard screen (non-AJAX requests). | |
| 3082 | - * | |
| 3083 | - * @return void | |
| 3084 | - */ | |
| 3085 | - public function wpstream_load_onboarding_wizard() { | |
| 3086 | - $this->main->get_onboarding()->render_part( 'standalone' ); | |
| 3087 | - } | |
| 3088 | - | |
| 3089 | - | |
| 3090 | - /* | |
| 3091 | - * Add on boarding to footer | |
| 3092 | - */ | |
| 3093 | - /** | |
| 3094 | - * On the onboarding admin page, print the onboarding modal into the footer. | |
| 3095 | - * | |
| 3096 | - * @return void | |
| 3097 | - */ | |
| 3098 | - public function wpstream_admin_footer_onboarding(){ | |
| 3099 | - $this->main->get_onboarding()->render_part( 'page_footer' ); | |
| 3100 | - } | |
| 3101 | 1295 | |
| 3102 | - | |
| 3103 | - /* | |
| 3104 | - * On Board Display | |
| 1296 | + /** | |
| 1297 | + * Show Streaming controls on sidebar | |
| 3105 | 1298 | * |
| 3106 | - */ | |
| 3107 | - /** | |
| 3108 | - * Render the Quick Start landing screen (logo, intro, "Start the Guide" | |
| 3109 | - * button and the script that opens the onboarding wizard). Echoes HTML. | |
| 3110 | - * | |
| 3111 | - * @return void | |
| 3112 | - */ | |
| 3113 | - public function wpstream_pre_onboard_display(){ | |
| 3114 | - echo $this->main->get_onboarding()->render(); | |
| 3115 | - } | |
| 1299 | + * @since 3.0.1 | |
| 1300 | + */ | |
| 1301 | + public function wpstream_start_stream_meta(){ | |
| 1302 | + global $live_event_for_user; | |
| 1303 | + global $post; | |
| 1304 | + | |
| 1305 | + $ajax_nonce = wp_create_nonce( "wpstream_start_event_nonce" ); | |
| 1306 | + print '<input type="hidden" id="wpstream_start_event_nonce" value="'.$ajax_nonce.'">'; | |
| 1307 | + $live_event_for_user = $this->main->wpstream_live_connection->api20_wpstream_request_live_stream_for_user(); | |
| 1308 | + $this->wpstream_live_stream_unit($post->ID); | |
| 3116 | 1309 | |
| 3117 | - | |
| 3118 | - | |
| 3119 | - | |
| 3120 | - | |
| 3121 | - | |
| 3122 | - | |
| 3123 | - | |
| 3124 | - /* | |
| 3125 | - * | |
| 3126 | - * On Boarding Content | |
| 3127 | - * | |
| 3128 | - */ | |
| 3129 | - /** | |
| 3130 | - * Emit the full onboarding wizard markup by rendering each step in order | |
| 3131 | - * (header, account, path choice, live/VOD branches, footer). Echoes HTML. | |
| 3132 | - * | |
| 3133 | - * @return void | |
| 3134 | - */ | |
| 3135 | - public function wpstream_onboard_display() { | |
| 3136 | - $this->main->get_onboarding()->render_part( 'wizard' ); | |
| 3137 | 1310 | } |
| 3138 | - | |
| 3139 | - | |
| 3140 | - /* | |
| 3141 | - * | |
| 3142 | - * On Boarding Step 1 - the login/register | |
| 3143 | - * | |
| 3144 | - */ | |
| 3145 | - /** | |
| 3146 | - * Onboarding step 1: WpStream account login/registration UI, including the | |
| 3147 | - * ALTCHA captcha widget (on HTTPS) and a hidden generated registration | |
| 3148 | - * password. Emits a marker div when a token already exists. Echoes HTML. | |
| 3149 | - * | |
| 3150 | - * @return void | |
| 3151 | - */ | |
| 3152 | - public function wpstream_onboarding_step1(){ | |
| 3153 | - $this->main->get_onboarding()->render_part( 'account' ); | |
| 3154 | - } | |
| 3155 | - | |
| 3156 | - public function randomPassword() { | |
| 3157 | - return $this->main->get_onboarding()->render_part( 'password' ); | |
| 3158 | - } | |
| 3159 | - | |
| 3160 | - public function wpstream_onboarding_step2(){ | |
| 3161 | - $this->main->get_onboarding()->render_part( 'path' ); | |
| 3162 | - } | |
| 3163 | - | |
| 3164 | - public function wpstream_onboarding_step3_live_streaming(){ | |
| 3165 | - $this->main->get_onboarding()->render_part( 'live' ); | |
| 3166 | - } | |
| 3167 | - | |
| 3168 | - public function wpstream_onboarding_step_3_A_live_streaming_free_view(){ | |
| 3169 | - $this->main->get_onboarding()->render_part( 'live_free' ); | |
| 3170 | - } | |
| 3171 | - | |
| 3172 | - public function wpstream_onboarding_step_3_B_live_streaming_pay_per_view(){ | |
| 3173 | - $this->main->get_onboarding()->render_part( 'live_ppv' ); | |
| 3174 | - } | |
| 3175 | - | |
| 3176 | - public function wpstream_onboarding_woo_warning(){ | |
| 3177 | - $this->main->get_onboarding()->render_part( 'woo_warning' ); | |
| 3178 | - } | |
| 3179 | - | |
| 3180 | - public function wpstream_onboarding_step4_vod(){ | |
| 3181 | - $this->main->get_onboarding()->render_part( 'vod' ); | |
| 3182 | - } | |
| 3183 | - | |
| 3184 | - public function wpstream_onboarding_step_4_free_vod(){ | |
| 3185 | - $this->main->get_onboarding()->render_part( 'vod_free' ); | |
| 3186 | - } | |
| 3187 | - | |
| 3188 | - public function wpstream_obboarding_file_warning(){ | |
| 3189 | - $this->main->get_onboarding()->render_part( 'file_warning' ); | |
| 3190 | - } | |
| 3191 | - | |
| 3192 | - public function wpstream_onboarding_step_4_ppv_vod(){ | |
| 3193 | - $this->main->get_onboarding()->render_part( 'vod_ppv' ); | |
| 3194 | - } | |
| 3195 | - | |
| 3196 | - public function onboarding_wizard_header() { | |
| 3197 | - $this->main->get_onboarding()->render_part( 'wizard_header' ); | |
| 3198 | - } | |
| 3199 | - | |
| 3200 | - | |
| 3201 | - | |
| 3202 | - | |
| 3203 | - | |
| 3204 | - /* | |
| 3205 | - * | |
| 3206 | - * On Boarding Footer | |
| 3207 | - * | |
| 3208 | - */ | |
| 3209 | - /** | |
| 3210 | - * Close the onboarding wizard wrapper and print its modal background. Echoes HTML. | |
| 3211 | - * | |
| 3212 | - * @return void | |
| 3213 | - */ | |
| 3214 | - public function onboarding_wizard_footer() { | |
| 3215 | - $this->main->get_onboarding()->render_part( 'wizard_footer' ); | |
| 3216 | - } | |
| 3217 | - | |
| 3218 | - | |
| 3219 | - | |
| 3220 | - /* | |
| 3221 | - * | |
| 3222 | - * On Boarding create PPV channel | |
| 3223 | - * | |
| 3224 | - */ | |
| 3225 | - | |
| 3226 | - | |
| 3227 | - /** | |
| 3228 | - * AJAX: create a Pay-Per-View live channel during onboarding. | |
| 3229 | - * | |
| 3230 | - * Inserts a WooCommerce `product`, sets its price, marks it live_stream, | |
| 3231 | - * and returns the edit link (with onboarding query args) as JSON. | |
| 3232 | - * Nonce- and administrator-gated. | |
| 3233 | - * | |
| 3234 | - * @return void Ends with die(). | |
| 3235 | - */ | |
| 3236 | - public function wpstream_on_board_create_channel_ppv(){ | |
| 3237 | - return $this->main->get_onboarding()->handle_ajax( 'wpstream_on_board_create_channel_ppv' ); | |
| 3238 | - } | |
| 3239 | - | |
| 3240 | - /* | |
| 3241 | - * | |
| 3242 | - * On Boarding create channel | |
| 3243 | - * | |
| 3244 | - */ | |
| 3245 | - | |
| 3246 | - | |
| 3247 | - /** | |
| 3248 | - * AJAX: create a Free-To-View live channel during onboarding. | |
| 3249 | - * | |
| 3250 | - * Inserts a `wpstream_product` post and returns its edit link (with | |
| 3251 | - * onboarding query args) as JSON. Nonce- and administrator-gated. | |
| 3252 | - * | |
| 3253 | - * @return void Ends with die(). | |
| 3254 | - */ | |
| 3255 | - public function wpstream_on_board_create_channel(){ | |
| 3256 | - return $this->main->get_onboarding()->handle_ajax( 'wpstream_on_board_create_channel' ); | |
| 3257 | - } | |
| 3258 | - | |
| 3259 | - /* | |
| 3260 | - * | |
| 3261 | - * On Boarding create free vod | |
| 3262 | - * | |
| 3263 | - */ | |
| 3264 | - /** | |
| 3265 | - * AJAX: create a Free-To-View VOD during onboarding. | |
| 3266 | - * | |
| 3267 | - * Inserts a `wpstream_product_vod` post, links the chosen recording, and | |
| 3268 | - * returns the edit link (with onboarding query args). Nonce/admin gated. | |
| 3269 | - * | |
| 3270 | - * @return void Ends with die(). | |
| 3271 | - */ | |
| 3272 | - public function wpstream_on_board_create_free_vod(){ | |
| 3273 | - return $this->main->get_onboarding()->handle_ajax( 'wpstream_on_board_create_free_vod' ); | |
| 3274 | - } | |
| 3275 | - | |
| 3276 | - | |
| 3277 | - /* | |
| 3278 | - * | |
| 3279 | - * On Boarding create ppv vod | |
| 3280 | - * | |
| 3281 | - */ | |
| 3282 | - | |
| 3283 | - | |
| 3284 | - /** | |
| 3285 | - * AJAX: create a Pay-Per-View VOD during onboarding. | |
| 3286 | - * | |
| 3287 | - * Inserts a WooCommerce `product`, sets its price, links the recording, | |
| 3288 | - * marks it video_on_demand, and returns the edit link (with onboarding | |
| 3289 | - * query args). Nonce- and administrator-gated. | |
| 3290 | - * | |
| 3291 | - * @return void Ends with die(). | |
| 3292 | - */ | |
| 3293 | - public function wpstream_on_board_create_ppv_vod(){ | |
| 3294 | - return $this->main->get_onboarding()->handle_ajax( 'wpstream_on_board_create_ppv_vod' ); | |
| 3295 | - } | |
| 3296 | - | |
| 3297 | - | |
| 3298 | - /* | |
| 3299 | - * | |
| 3300 | - * On Boarding login | |
| 3301 | - * | |
| 3302 | - */ | |
| 3303 | - /** | |
| 3304 | - * AJAX: log in to WpStream during onboarding. | |
| 3305 | - * | |
| 3306 | - * Stores the submitted credentials, clears the token cache, then attempts | |
| 3307 | - * to fetch a token; returns success/failure JSON without ever exposing the | |
| 3308 | - * token to the client. Nonce- and administrator-gated. | |
| 3309 | - * | |
| 3310 | - * @return void Ends with die(). | |
| 3311 | - */ | |
| 3312 | - public function wpstream_on_board_login(){ | |
| 3313 | - return $this->main->get_onboarding()->handle_ajax( 'wpstream_on_board_login' ); | |
| 3314 | - } | |
| 3315 | - | |
| 3316 | - /** | |
| 3317 | - * AJAX proxy: fetch a captcha challenge from the baker API and return it. | |
| 3318 | - * Used on HTTP sites where the Altcha widget cannot run (requires Web Crypto / HTTPS). | |
| 3319 | - * The JS side solves the PoW locally and sends back the full base64 Altcha payload. | |
| 3320 | - * Logged-in administrators only: every call proxies an outbound request, so the | |
| 3321 | - * endpoint is gated like the rest of the onboarding wizard. | |
| 3322 | - */ | |
| 3323 | - public function wpstream_get_captcha_challenge() { | |
| 3324 | - return $this->main->get_onboarding()->handle_ajax( 'wpstream_get_captcha_challenge' ); | |
| 3325 | - } | |
| 3326 | - | |
| 3327 | - /* | |
| 3328 | - * | |
| 3329 | - * On Boarding login | |
| 3330 | - * | |
| 3331 | - */ | |
| 3332 | - /** | |
| 3333 | - * AJAX: register a new WpStream account during onboarding. | |
| 3334 | - * | |
| 3335 | - * Validates the email/password, requires an ALTCHA solution, calls the | |
| 3336 | - * account-create API, and on success stores the credentials and fetches a | |
| 3337 | - * token. Returns JSON. Nonce- and administrator-gated. | |
| 3338 | - * | |
| 3339 | - * @return void Ends with die(). | |
| 3340 | - */ | |
| 3341 | - public function wpstream_on_board_register(){ | |
| 3342 | - return $this->main->get_onboarding()->handle_ajax( 'wpstream_on_board_register' ); | |
| 3343 | - } | |
| 3344 | - | |
| 3345 | - | |
| 3346 | - /* | |
| 3347 | - * | |
| 3348 | - * Validate for register | |
| 3349 | - * | |
| 3350 | - */ | |
| 3351 | - /** | |
| 3352 | - * Validate the onboarding registration email + password. | |
| 3353 | - * | |
| 3354 | - * Checks for a non-empty, well-formed email whose domain has DNS records, | |
| 3355 | - * and a password of at least 5 characters. | |
| 3356 | - * | |
| 3357 | - * @param string $wpstream_register_email Submitted email. | |
| 3358 | - * @param string $wpstream_register_password Submitted password. | |
| 3359 | - * @return array{success: bool, message?: string} Validation result. | |
| 3360 | - */ | |
| 3361 | - public function wpstream_validate_onboard_register($wpstream_register_email,$wpstream_register_password){ | |
| 3362 | - return $this->main->get_onboarding()->validate_registration( $wpstream_register_email, $wpstream_register_password ); | |
| 3363 | - } | |
| 3364 | - | |
| 3365 | - /** | |
| 3366 | - * Handle the AJAX request to initiate a multipart upload | |
| 3367 | - * | |
| 3368 | - * Validates the request, builds a clean filename, and asks the cloud API to | |
| 3369 | - * open a multipart S3 upload; returns the upload id and per-part pre-signed | |
| 3370 | - * URLs as JSON. Nonce- and administrator-gated. | |
| 3371 | - * | |
| 3372 | - * @since 3.0.1 | |
| 3373 | - * @return void Responds via wp_send_json_*. | |
| 3374 | - */ | |
| 3375 | - public function handle_initiate_multipart_upload() { | |
| 3376 | - check_ajax_referer( 'wpstream_multipart_upload_nonce', 'security' ); | |
| 3377 | - | |
| 3378 | - // Security check - only admins can do this | |
| 3379 | - if (!current_user_can('administrator')) { | |
| 3380 | - wp_send_json_error('Unauthorized access'); | |
| 3381 | - return; | |
| 3382 | - } | |
| 3383 | - | |
| 3384 | - // Get file details from request | |
| 3385 | - $file_name = sanitize_text_field($_POST['file_name']); | |
| 3386 | - $file_size = intval($_POST['file_size']); | |
| 3387 | - $content_type = sanitize_text_field($_POST['content_type']); | |
| 3388 | - $num_parts = intval($_POST['parts']); | |
| 3389 | - | |
| 3390 | - // Reject incomplete/invalid file metadata. | |
| 3391 | - if (empty($file_name) || $file_size <= 0 || $num_parts <= 0) { | |
| 3392 | - wp_send_json_error('Invalid file information'); | |
| 3393 | - return; | |
| 3394 | - } | |
| 3395 | - | |
| 3396 | - // The part count is caller-supplied: refuse a split the backend can | |
| 3397 | - // never assemble before spending a cloud call on it. | |
| 3398 | - if ($num_parts > self::MULTIPART_MAX_PARTS) { | |
| 3399 | - wp_send_json_error( | |
| 3400 | - sprintf( | |
| 3401 | - /* translators: 1: requested part count, 2: maximum part count */ | |
| 3402 | - __('The file would be split into %1$d parts but at most %2$d are allowed. Reload the page to get the current uploader and try again.', 'wpstream'), | |
| 3403 | - $num_parts, | |
| 3404 | - self::MULTIPART_MAX_PARTS | |
| 3405 | - ) | |
| 3406 | - ); | |
| 3407 | - return; | |
| 3408 | - } | |
| 3409 | - | |
| 3410 | - // Prepare a clean filename (similar to the standard upload process) | |
| 3411 | - // Keep the extension, slugify the base name (spaces -> _, strip non-word chars). | |
| 3412 | - $file_name_array = explode(".", $file_name); | |
| 3413 | - $file_extension = $file_name_array[count($file_name_array) - 1]; | |
| 3414 | - $temp_file_name = $file_name_array[0]; | |
| 3415 | - $temp_file_name = str_replace(' ', '_', $temp_file_name); | |
| 3416 | - $temp_file_name = preg_replace('/\W/', '', $temp_file_name); | |
| 3417 | - $clean_file_name = $temp_file_name . '.' . $file_extension; | |
| 3418 | - | |
| 3419 | - // Make API call to initiate multipart upload; the auth token is | |
| 3420 | - // injected by the transport (not-connected surfaces as a WP_Error | |
| 3421 | - // whose message is the legacy "Not connected to WPStream service"). | |
| 3422 | - $api_params = array( | |
| 3423 | - 'size' => $file_size, | |
| 3424 | - 'name' => $clean_file_name, | |
| 3425 | - 'content_type' => $content_type, | |
| 3426 | - 'parts' => $num_parts | |
| 3427 | - ); | |
| 3428 | - | |
| 3429 | - $response_data = $this->main->wpstream_live_connection->authorized_request('video/upload', $api_params); | |
| 3430 | - | |
| 3431 | - // Bubble up any API error. | |
| 3432 | - if (is_wp_error($response_data)) { | |
| 3433 | - wp_send_json_error($response_data->get_error_message()); | |
| 3434 | - return; | |
| 3435 | - } | |
| 3436 | - if (!isset($response_data['success']) || $response_data['success'] !== true) { | |
| 3437 | - $error_message = isset($response_data['error']) ? $response_data['error'] : 'Failed to initiate multipart upload'; | |
| 3438 | - wp_send_json_error($error_message); | |
| 3439 | - return; | |
| 3440 | - } | |
| 3441 | - | |
| 3442 | - // Return the upload ID and pre-signed URLs for each part | |
| 3443 | - wp_send_json_success($response_data); | |
| 3444 | - } | |
| 3445 | - | |
| 3446 | - /** | |
| 3447 | - * Handle the AJAX request to complete a multipart upload | |
| 3448 | - * | |
| 3449 | - * Validates the request and tells the cloud API to finalize the multipart S3 | |
| 3450 | - * upload for the given parts/handle. Nonce- and administrator-gated. | |
| 3451 | - * | |
| 3452 | - * @since 3.0.1 | |
| 3453 | - * @return void Responds via wp_send_json_*. | |
| 3454 | - */ | |
| 3455 | - public function handle_complete_multipart_upload() { | |
| 3456 | - check_ajax_referer( 'wpstream_multipart_upload_nonce', 'security' ); | |
| 3457 | - | |
| 3458 | - // Security check - only admins can do this | |
| 3459 | - if (!current_user_can('administrator')) { | |
| 3460 | - wp_send_json_error('Unauthorized access'); | |
| 3461 | - return; | |
| 3462 | - } | |
| 3463 | - | |
| 3464 | - // Get completion details. The client sends 'parts' as the plain part | |
| 3465 | - // COUNT (not a part list), so parse it as a positive integer. | |
| 3466 | - $parts = isset($_POST['parts']) ? absint(wp_unslash($_POST['parts'])) : 0; | |
| 3467 | - $file_name = sanitize_text_field($_POST['file_name']); | |
| 3468 | - $handle = sanitize_text_field($_POST['handle']); | |
| 3469 | - | |
| 3470 | - // Reject incomplete completion metadata: no parts uploaded or no file name. | |
| 3471 | - if ($parts < 1 || empty($file_name)) { | |
| 3472 | - wp_send_json_error('Invalid completion information'); | |
| 3473 | - return; | |
| 3474 | - } | |
| 3475 | - | |
| 3476 | - // Send the finalize ("complete") request with the uploaded part list; | |
| 3477 | - // the auth token is injected by the transport (not-connected surfaces | |
| 3478 | - // as a WP_Error whose message is the legacy "Not connected to WPStream | |
| 3479 | - // service"). | |
| 3480 | - $api_params = array( | |
| 3481 | - 'parts' => $parts, | |
| 3482 | - 'name' => $file_name, | |
| 3483 | - 'handle' => $handle, | |
| 3484 | - 'action' => 'complete' | |
| 3485 | - ); | |
| 3486 | - | |
| 3487 | - $response_data = $this->main->wpstream_live_connection->authorized_request('video/upload', $api_params); | |
| 3488 | - | |
| 3489 | - // Bubble up any API error. | |
| 3490 | - if (is_wp_error($response_data)) { | |
| 3491 | - wp_send_json_error($response_data->get_error_message()); | |
| 3492 | - return; | |
| 3493 | - } | |
| 3494 | - if (!isset($response_data['success']) || $response_data['success'] !== true) { | |
| 3495 | - $error_message = isset($response_data['error']) ? $response_data['error'] : 'Failed to complete multipart upload'; | |
| 3496 | - wp_send_json_error($error_message); | |
| 3497 | - return; | |
| 3498 | - } | |
| 3499 | - | |
| 3500 | - /** | |
| 3501 | - * Fires after the cloud accepted a completed multipart VOD upload. | |
| 3502 | - * | |
| 3503 | - * @since 4.14.0 | |
| 3504 | - * | |
| 3505 | - * @param string $file_name Uploaded file name. | |
| 3506 | - * @param string $handle Upload handle issued at initiation. | |
| 3507 | - * @param int $parts Number of parts uploaded. | |
| 3508 | - */ | |
| 3509 | - do_action( 'wpstream_multipart_upload_completed', $file_name, $handle, $parts ); | |
| 3510 | - | |
| 3511 | - // Return success | |
| 3512 | - wp_send_json_success(); | |
| 3513 | - } | |
| 3514 | - | |
| 3515 | - /** | |
| 3516 | - * AJAX: update the WpStream plugin in place from the Settings/Support tab. | |
| 3517 | - * | |
| 3518 | - * Loads the upgrader APIs, initializes WP_Filesystem, runs the plugin | |
| 3519 | - * upgrade, re-activates the plugin, and returns success/error JSON. | |
| 3520 | - * Requires the update_plugins capability. | |
| 3521 | - * | |
| 3522 | - * @return void Responds via wp_send_json_*. | |
| 3523 | - */ | |
| 3524 | - public function wpstream_settings_tab_update_plugin() { | |
| 3525 | - // CSRF gate: the update button JS sends the settings-page nonce as 'security'. | |
| 3526 | - check_ajax_referer( 'wpstream-settings-nonce', 'security' ); | |
| 3527 | - // Capability gate. | |
| 3528 | - if ( !current_user_can( 'update_plugins' ) ) { | |
| 3529 | - wp_send_json_error( __( 'Not enough permissions to make this change', 'wpstream' ) ); | |
| 3530 | - } | |
| 3531 | - | |
| 3532 | - // Load the core upgrade/filesystem APIs. | |
| 3533 | - include_once ABSPATH . 'wp-admin/includes/plugin-install.php'; | |
| 3534 | - include_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php'; | |
| 3535 | - include_once ABSPATH . 'wp-admin/includes/file.php'; | |
| 3536 | - | |
| 3537 | - // Initialize the filesystem abstraction (needed to write plugin files). | |
| 3538 | - $credentials = request_filesystem_credentials(''); | |
| 3539 | - if ( !WP_Filesystem( $credentials ) ) { | |
| 3540 | - wp_send_json_error( __( 'Failed to connect to the filesystem', 'wpstream' ) ); | |
| 3541 | - } | |
| 3542 | - | |
| 3543 | - // Run the in-place upgrade for this plugin, then re-activate it. | |
| 3544 | - $upgrader = new Plugin_Upgrader(new Automatic_Upgrader_Skin()); | |
| 3545 | - $plugin_path = plugin_basename( WPSTREAM_PLUGIN_PATH . 'wpstream.php' ); | |
| 3546 | - $result = $upgrader->upgrade( $plugin_path ); | |
| 3547 | - activate_plugin( $plugin_path ); | |
| 3548 | - | |
| 3549 | - if ( is_wp_error( $result ) ) { | |
| 3550 | - wp_send_json_error( __( 'Update failed due to', 'wpstream' ) . $result->get_error_message() ); | |
| 3551 | - } | |
| 3552 | - | |
| 3553 | - wp_send_json_success(); | |
| 3554 | - } | |
| 3555 | -} | |
| 1311 | +} | |