PluginProbe
WpStream – Live Streaming, Video on Demand, Pay Per View / 4.8.2
WpStream – Live Streaming, Video on Demand, Pay Per View v4.8.2
4.14.1 4.14.0 4.13.2 4.13.1 4.13 4.12.5 4.12.4 4.12.3 4.12.2 4.12.1 4.12 4.4.4 4.4.5 4.4.6 4.4.7 4.4.8 4.4.9 4.5 4.5.1 4.5.11 4.5.11.1 4.5.11.2 4.5.11.4 4.5.11.5 4.5.11.6 All 181 releases
← All changes | admin/class-wpstream-admin.php +2346 -1656 4.14.14.8.2 View file →
@@ -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.
@@ -72,49 +50,31 @@
72 50 */
73 51 private $version;
74 52
75 53 /**
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 ;
82 -
83 -
84 -
85 -
86 -
87 - /**
88 54 * Initialize the class and set its properties.
89 55 *
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
56 + * @since 3.0.1
57 + * @param string $plugin_name The name of this plugin.
58 + * @param string $version The version of this plugin.
95 59 */
60 +
61 + public $global_event_options ;
62 +
63 +
64 +
65 +
66 +
96 67 public function __construct( $plugin_name, $version,$plugin_main ) {
97 68
98 - // Remember the plugin identity and the main class for later use.
99 69 $this->plugin_name = $plugin_name;
100 70 $this->version = $version;
101 71 $this->main = $plugin_main;
102 72
103 - // Build the translatable global event options once WP (and its i18n) is ready.
104 73 add_action('init', array($this, 'load_global_event_options'));
105 74 }
106 75
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 76 public function load_global_event_options() {
116 - // Each key maps to a label/details/default triple used when rendering the event option toggles.
117 77 $this->global_event_options = array(
118 78 'record' => array(
119 79 'name' => esc_html__('Record Live Stream','wpstream'),
120 80 'details' => esc_html__('If enabled, live streams will be recorded and saved to your library.','wpstream'),
@@ -159,31 +119,20 @@
159 119 'name' => esc_html__('Use Sessions with Encryption','wpstream'),
160 120 '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 121 'defaults' => 'no',
162 122 ),
123 + 'autostart' =>array(
124 + 'name' => esc_html__('Auto TURN ON','wpstream'),
125 + 'details' => esc_html__('If enabled, channel will TURN ON automatically when broadcasting with an External Streaming App (RTMP Encoder/Broadcaster)','wpstream'),
126 + 'defaults' => 'no',
127 + ),
163 128 );
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 129 }
178 130
179 131 /**
180 - * Register and enqueue the plugin's admin-area stylesheets.
132 + * Register the stylesheets for the admin area.
181 133 *
182 - * Hooked (via Wpstream_Loader) to admin_enqueue_scripts.
183 - *
184 - * @since 3.0.1
185 - * @return void
134 + * @since 3.0.1
186 135 */
187 136 public function enqueue_styles() {
188 137
189 138 /**
@@ -196,11 +145,9 @@
196 145 * The Wpstream_Loader will then create the relationship
197 146 * between the defined hooks and the functions defined in this
198 147 * class.
199 148 */
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.
149 + wp_enqueue_style( 'wpstream-roboto', "https://fonts.googleapis.com/css?family=Roboto:300,400,500,600,700,900&display=swap&subset=latin-ext" );
203 150 wp_enqueue_style(
204 151 $this->plugin_name,
205 152 plugin_dir_url( __FILE__ ) . 'css/wpstream-admin.css',
206 153 array(),
@@ -206,10 +153,16 @@
206 153 array(),
207 154 filemtime(plugin_dir_path(__FILE__) . 'css/wpstream-admin.css' ),
208 155 'all'
209 156 );
210 -
211 - // Ensure the WP media library scripts/styles are available (for logo/image pickers) if not already loaded.
157 +
158 + wp_enqueue_style(
159 + 'wpstream-on-boarding-css',
160 + plugin_dir_url( __FILE__ ) . 'css/wpstream-admin-onboarding.css',
161 + array(),
162 + filemtime(plugin_dir_path(__FILE__) . 'css/wpstream-admin-onboarding.css'),
163 + );
164 +
212 165 if (!did_action('wp_enqueue_media')) {
213 166 wp_enqueue_media();
214 167 }
215 168 }
@@ -214,36 +167,23 @@
214 167 }
215 168 }
216 169
217 170 /**
218 - * Register, enqueue and localize the plugin's admin-area JavaScript.
171 + * Register the JavaScript for the admin area.
219 172 *
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
173 + * @since 3.0.1
228 174 */
229 175 public function enqueue_scripts() {
230 176
231 - // jQuery UI widgets used by the settings/date pickers and sliders.
232 177 wp_enqueue_script("jquery-ui-slider");
233 - wp_enqueue_script("jquery-ui-datepicker");
234 - // Blueimp-style file upload library backing the recordings/VOD uploader.
178 + wp_enqueue_script("jquery-ui-datepicker");
235 179 wp_enqueue_script('jquery.fileupload', plugin_dir_url( __FILE__ ) .'js/jquery.fileupload.js?v='.time(),array(), WPSTREAM_PLUGIN_VERSION, true);
236 180
237 - // Shared admin utility helpers, then the main admin control script that drives uploads and channel actions.
238 181 wp_enqueue_script( 'wpstream-admin-utils', plugin_dir_url( __FILE__ ) .'js/utils/admin_utils.js?v='.time(),array(), WPSTREAM_PLUGIN_VERSION, true);
239 182 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',
183 + wp_localize_script('wpstream-admin-control', 'wpstream_admin_control_vars',
242 184 array(
243 185 '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 186 'loading_url' => WPSTREAM_PLUGIN_DIR_URL.'/img/loading.gif',
247 187 'download_mess' => esc_html__('Click to download!','wpstream'),
248 188 'uploading' => esc_html__('We are uploading your file. Do not close this window!','wpstream'),
249 189 'upload_complete2' => esc_html__('Upload Complete! You can upload another file!','wpstream'),
@@ -248,12 +188,11 @@
248 188 'uploading' => esc_html__('We are uploading your file. Do not close this window!','wpstream'),
249 189 'upload_complete2' => esc_html__('Upload Complete! You can upload another file!','wpstream'),
250 190 'not_accepted' => esc_html__('The file is not an accepted video format','wpstream'),
251 191 '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'),
192 + 'no_band' => esc_html__('Not enough streaming data.','wpsteam'),
193 + 'no_band_no_store' => esc_html__('Not enough streaming data or storage.','wpsteam'),
194 + 'exceeding_limit' => esc_html__('File size exceeds 5GB. Initiating multipart upload...','wpsteam'),
256 195 'upload_failed' => esc_html__('Upload Failed!','wpstream'),
257 196 'upload_failed2' => esc_html__('Upload Failed! Please Try again!','wpstream'),
258 197 'choose_a_file' => esc_html__('Choose a file&hellip;','wpstream'),
259 198 'preparing_multipart' => esc_html__('Preparing multipart upload...','wpstream'),
@@ -266,15 +205,10 @@
266 205 'invalid_response' => esc_html__('Invalid response from server. Missing required upload data.', 'wpstream'),
267 206 'video_processing' => esc_html__( 'The video is still processing', 'wpstream' ),
268 207 'file_name_text' => esc_html__('File Name:','wpstream'),
269 208 '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'],
274 209 ));
275 210
276 - // Recordings list script + its localized labels and the "create VOD from recording" links (free vs paid depending on WooCommerce).
277 211 wp_enqueue_script('wpstream-recordings-videos-list', plugin_dir_url( __FILE__ ) .'js/recordings_videos_list.js?v='.time(),array(), WPSTREAM_PLUGIN_VERSION, true);
278 212 wp_localize_script( 'wpstream-recordings-videos-list', 'wpstream_recordings_videos_list_vars',
279 213 array(
280 214 'delete_file' => esc_html__('Delete file', 'wpstream'),
@@ -287,10 +221,56 @@
287 221 'create_ptv_vod' => esc_html__( 'Create new Pay-Per-View VOD from this recording' , 'wpstream' ),
288 222 )
289 223 );
290 224
225 + $modified_start_streaming_file_time = gmdate( 'YmdHi', filemtime( WPSTREAM_PLUGIN_PATH . 'public/js/start_streaming.js' ) );
226 + wp_enqueue_script('wpstream-start-streaming_admin', plugin_dir_url( __DIR__ ) .'public/js/start_streaming.js', array(), $modified_start_streaming_file_time, true);
227 + wp_localize_script('wpstream-start-streaming_admin', 'wpstream_start_streaming_vars',
228 + array(
229 + 'admin_url' => get_admin_url(),
230 + 'loading_url' => WPSTREAM_PLUGIN_DIR_URL.'/img/loading.gif',
231 + 'download_mess' => esc_html__('Click to download!','wpstream'),
232 + 'uploading' => esc_html('We are uploading your file.Do not close this window!','wpstream'),
233 + 'upload_complete2' => esc_html('Upload Complete! You can upload another file!','wpstream'),
234 + 'not_accepted' => esc_html('The file is not an accepted video format','wpstream'),
235 + 'upload_complete' => esc_html('Upload Complete!','wpstream'),
236 + 'no_band' => esc_html('Not enough streaming data.','wpsteam'),
237 + 'no_band_no_store' => esc_html('Not enough streaming data or storage.','wpsteam'),
291 238
292 - // Settings-page script with its save/logo-picker strings and the broadcaster page URL.
239 + 'start_streaming_action'=> esc_html__('TURNING ON','wpstream'),
240 + 'stop_streaming_action' => esc_html__('TURNING OFF','wpstream'),
241 + 'start_streaming' => esc_html__('TURN ON','wpstream'),
242 + 'stop_streaming' => esc_html__('TURN OFF','wpstream'),
243 + 'failed_fetching' => esc_html__('Failed to get channel info. Please try again.','wpstream'),
244 + 'turned_on_tooltip' => esc_html__('Channel is now OFF. Click to turn ON.','wpstream'),
245 + 'turned_off_tooltip' => esc_html__('Click to turn channel off. This will interrupt any ongoing broadcast.','wpstream'),
246 + 'turning_on_tooltip' => esc_html__('Turning a channel on may take 1-2 minutes or more. Please be patient.','wpstream'),
247 + 'turning_off_tooltip' => esc_html__('This may take a few minutes.','wpstream'),
248 + 'error1' => esc_html__('You don\'t have enough data to start a new event!','wpstream'),
249 + 'failed_event_creation' => esc_html__('Failed to start the channel. Please try again in a few minutes.','wpstream'),
250 + 'channel_turning_on' => esc_html__('Channel is turning on','wpstream'),
251 + 'channel_turning_off' => esc_html__('Channel is turning off','wpstream'),
252 + 'channel_on' => esc_html__('Channel is ON','wpstream'),
253 + 'channel_off' => esc_html__('Channel is OFF','wpstream'),
254 + 'turn_off_confirm' => esc_html__(
255 + 'ARE YOU SURE you\'d like to TURN OFF the channel now? ' . PHP_EOL . PHP_EOL .
256 + '- Channels TURN OFF automatically after 1 hour of inactivity (no active broadcast).' . PHP_EOL .
257 + '- Manual TURN OFF is only useful if you require to change the channel settings immediately.' . PHP_EOL .
258 + '- If your channel is configured with Auto TURN ON, it will turn back on as soon as there is a broadcast.',
259 + 'wpstream'
260 + ),
261 + 'basic_streaming_warning' => esc_html__(
262 + 'Your account is now in BASIC STREAMING mode.' . PHP_EOL . PHP_EOL .
263 + 'Instead of offloading to the WpStream Cloud, this mode relies on WordPress and hosting resources to process and deliver video. In some WP environments, streaming may be unreliable.' . PHP_EOL .
264 + 'Certain features, such as recording, viewer count, browser broadcasting, and content protection are unavailable.' . PHP_EOL . PHP_EOL .
265 + '- To take advantage of all features, please choose Cancel and upgrade your plan.' . PHP_EOL .
266 + '- Otherwise, choose OK to start your channel with these limitations.' . PHP_EOL . PHP_EOL .
267 + 'ARE YOU SURE you want to continue with Basic Streaming?',
268 + 'wpstream'
269 + ),
270 + 'broadcaster_url' => esc_url( esc_url(home_url('/broadcaster-page/') ) ),
271 + ));
272 +
293 273 wp_enqueue_script('wpstream-settings', plugin_dir_url( __DIR__ ) .'/admin/js/wpstream_settings.js?v='.time(),array(), WPSTREAM_PLUGIN_VERSION, true);
294 274 wp_localize_script('wpstream-settings', 'wpstream_settings_vars', array(
295 275 'error_message' => esc_html__( 'Failed to save settings. Please try again.', 'wpstream'),
296 276 'choose_image_text' => esc_html__( 'Choose Logo Image', 'wpstream'),
@@ -300,29 +280,40 @@
300 280 'broadcaster_url' => esc_url( esc_url(home_url('/broadcaster-page/') ) ),
301 281 ));
302 282
303 283
304 - // Identify the current admin screen so screen-specific bundles load only where needed.
305 - $current_screen=get_current_screen();
284 + wp_enqueue_script('wpstream-on-boarding-js',plugin_dir_url( __DIR__ ) .'/admin/js/wpstream-onboarding2.js',array(), WPSTREAM_PLUGIN_VERSION, true);
285 + wp_localize_script('wpstream-on-boarding-js', 'wpstreamonboarding_js_vars',
286 + array(
287 + 'admin_url' => get_admin_url(),
288 + 'plugin_url' => get_dashboard_url().'/plugins.php',
289 + 'upload_url' => get_dashboard_url().'admin.php?page=wpstream_recordings'
290 +
291 + ));
306 292
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 - }
293 +// wp_enqueue_style(
294 +// 'wpstream-broadcaster-css',
295 +// plugin_dir_url(__FILE__) . 'public/css/broadcaster.css',
296 +// array(),
297 +// filemtime(plugin_dir_path(__FILE__) . 'public/css/broadcaster.css' ),
298 +// );
299 +//
300 +// wp_enqueue_script(
301 +// 'wpstream-broadcaster',
302 +// plugin_dir_url(__FILE__) . 'public/js/broadcaster.js',
303 +// array('jquery'),
304 +// WPSTREAM_PLUGIN_VERSION,
305 +// true
306 +// );
314 307
315 308 // Add localized variables for broadcaster
316 - // Provide the broadcaster script (registered elsewhere) with its AJAX URL and nonce.
317 309 wp_localize_script('wpstream-broadcaster', 'wpstream_broadcaster_vars', array(
318 310 'ajax_url' => admin_url('admin-ajax.php'),
319 311 'nonce' => wp_create_nonce('wpstream_broadcaster_nonce'),
320 312 'plugin_url' => plugin_dir_url(__FILE__),
321 - // Gates the broadcaster's diagnostic console logging (see broadcaster.js).
322 - 'debug' => defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG,
313 +
323 314 ));
324 -
315 +
325 316 }
326 317
327 318
328 319 /**
@@ -327,34 +318,24 @@
327 318
328 319 /**
329 320 * Add Plugin Administation menu
330 321 *
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
322 + * @since 3.0.1
337 323 */
324 +
338 325 public function wpstream_manage_admin_menu() {
339 326
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'));
327 + add_menu_page( __('WpStream','wpestream'), __('WpStream ','wpstream'), 'administrator', 'wpstream_credentials', array($this,'wpstream_set_wpstream_credentials'), WPSTREAM_PLUGIN_DIR_URL.'img/wpstream-icon-menu_2.png',20 );
328 + add_submenu_page( 'wpstream_credentials', __('WpStream Credentials','wpestream'), __('Credentials','wpestream'), 'administrator', 'wpstream_credentials', array($this,'wpstream_set_wpstream_credentials') );
329 + add_submenu_page( 'wpstream_credentials', __('WpStream Live Channels','wpestream'), __('All Channels','wpestream'), 'administrator', 'wpstream_live_channels', array( $this,'wpstream_new_general_set'));
330 + add_submenu_page( 'wpstream_credentials', __('WpStream Recordings','wpestream'), __('Recordings','wpestream'), 'administrator', 'wpstream_recordings', array($this,'wpstream_media_management'));
331 + add_submenu_page( 'wpstream_credentials', __('WpStream Settings','wpestream'), __('Settings','wpestream'), 'administrator', 'wpstream_settings', array($this,'wpstream_settings'));
332 +
333 + add_submenu_page( 'wpstream_credentials', __('WpStream Quick Start','wpestream'), __('WpStream Quick Start','wpestream'), 'administrator', 'wpstream_onboard', array($this,'wpstream_pre_onboard_display'));
334 +
350 335
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 -
336 +
337 +
357 338 }
358 339
359 340
360 341
@@ -361,62 +342,1038 @@
361 342
362 343 /**
363 344 * Shows events wpstream
364 345 *
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.
346 + * @since 3.0.1
347 + */
348 +
349 + public function wpstream_new_general_set() {
350 +
351 + $no_channel=1;
352 +
353 + if(class_exists ('WC_Subscription')){
354 +
355 + }
356 +
357 + //event_passed
358 + $args = array(
359 + 'posts_per_page' => -1,
360 + 'post_type' => 'product',
361 + 'post_status' => 'publish',
362 + 'meta_query' => array(
363 + array(
364 + 'key' => 'event_passed',
365 + 'value' => 1,
366 + 'compare' => '!=',
367 + )
368 + ),
369 +
370 + 'tax_query' => array(
371 + 'relation' => 'AND',
372 + array(
373 + 'taxonomy' => 'product_type',
374 + 'field' => 'slug',
375 + 'terms' => array('live_stream','subscription')
376 + )
377 + ),
378 + );
379 +
380 +
381 +
382 + $event_list = new WP_Query($args);
383 + global $live_event_for_user;
384 + $live_event_for_user = $this->main->wpstream_live_connection->wpstream_get_live_event_for_user();
385 + $pack_details = $this->main->wpstream_live_connection->wpstream_request_pack_data_per_user('wpstream_new_general_set');
386 +
387 + $this->main->show_user_data($pack_details);
388 + if( $event_list->have_posts()){
389 +
390 +
391 + print '<div class="pack_details_wrapper_transparent">
392 + <h3>'.__('Your Pay-Per-View Channel List','wpstream').'</h3>';
393 +
394 +
395 + $link_new = admin_url('post-new.php?post_type=product').'&new_stream='. rawurlencode('new');
396 +
397 + print '<a href="'.esc_url($link_new).'" class="wpstream_create_new_product_link">'.esc_html__('Create new Pay-Per-View channel.','wpstream').'</a>';
398 + print '</div>';
399 +
400 + print '<div style="clear: both;"></div><div class="event_list_wrapper">';
401 +
402 + while ($event_list->have_posts()): $event_list->the_post();
403 +
404 + $the_id = get_the_ID();
405 + $is_subscription_live_event = esc_html(get_post_meta($the_id,'_subscript_live_event',true));
406 + $term_list = wp_get_post_terms($the_id, 'product_type');
407 +
408 + if( $term_list[0]->name=='subscription' && $is_subscription_live_event=='no'){
409 + continue;
410 + }
411 +
412 + $this->wpstream_live_stream_unit($the_id);
413 +
414 + endwhile;
415 +
416 + print'</div>';
417 + $no_channel=1;
418 + }else{
419 + $no_channel=0;
420 + }
421 +
422 +
423 + $ajax_nonce = wp_create_nonce( "wpstream_start_event_nonce" );
424 + print '<input type="hidden" id="wpstream_start_event_nonce" value="'.$ajax_nonce.'">';
425 + $pack_details = $this->main->wpstream_live_connection->wpstream_request_pack_data_per_user('wpstream_new_general_set');
426 + if( isset($pack_details['available_data_mb'])){
427 + if ($pack_details['available_data_mb'] <= 0){
428 + print '<input type="hidden" id="wpstream_basic_streaming" value="true">';
429 + }
430 + }
431 + $current_user = wp_get_current_user();
432 + $allowded_html = array();
433 + $userID = $current_user->ID;
434 + $user_live_streams = get_user_meta($userID,'live_shows');
435 +
436 +
437 + wp_reset_postdata();
438 +
439 +
440 +
441 +
442 + // free
443 +
444 + $args_free = array(
445 + 'posts_per_page' => -1,
446 + 'post_type' => 'wpstream_product',
447 + 'post_status' => 'publish',
448 +
449 +
450 + );
451 + $event_list_free = new WP_Query($args_free);
452 +
453 +
454 + if( $event_list_free->have_posts()){
455 + print '<div class="pack_details_wrapper_transparent">
456 + <h3>'.__('Free-To-View Channels','wpstream').'</h3>';
457 +
458 + $link_new = admin_url('post-new.php?post_type=wpstream_product');
459 + print '<a href="'.esc_url($link_new).'" class="wpstream_create_new_product_link">'.esc_html__('Create new Free-To-View channel.','wpstream').'</a>';
460 + print '</div>';
461 + print '<div style="clear: both;"></div><div class="event_list_wrapper">';
462 +
463 + while ($event_list_free->have_posts()): $event_list_free->the_post();
464 +
465 +
466 + $the_id = get_the_ID();
467 +
468 + if( get_post_meta ($the_id,'event_passed',true)!=1){
469 + $this->wpstream_live_stream_unit($the_id);
470 + }
471 +
472 + endwhile;
473 +
474 + print'</div><div class="wpstream_modal_background"></div>';
475 + print '<div class="wpstream_error_modal_notification"><div class="wpstream_error_content">er2</div>
476 + <div class="wpstream_error_ok wpstream_button" type="button">'.esc_html__('Close','wpstream').'</div>
477 + </div>';
478 + $no_channel=1;
479 + }else{
480 + $no_channel=0;
481 + }
482 +
483 +
484 +
485 +
486 + $link_new_paid = admin_url('post-new.php?post_type=product').'&new_stream='. rawurlencode('new');
487 + $link_new_free = admin_url('post-new.php?post_type=wpstream_product');
488 + print '<div class="no_events_warning"> ';
489 + if($event_list->found_posts==0){
490 + print '<div class="no_events_warning_mes">'.__('* You do not have any Pay-Per-View channels!','wpstream').'</div>';
491 + }
492 + if($event_list_free->found_posts==0){
493 + print '<div class="no_events_warning_mes">'. __('* You do not have any free channels!','wpstream').'</div>';
494 + }
495 +
496 + print '<a href="'.esc_url($link_new_free).'" class="wpstream_no_chanel_add_channel">'.esc_html__('Add new Free-To-View channel ','wpstream').'</a>';
497 + print '<a href="'.esc_url($link_new_paid).'" class="wpstream_no_chanel_add_channel">'.esc_html__('Add new Pay-Per-View channel ','wpstream').'</a>';
498 +
499 + print '</div>';
500 +
501 +
502 +
503 +
504 + }
505 + // end wpstream_new_general_set
506 +
507 +
508 + /**
509 + * Social share
369 510 *
370 - * @since 3.0.1
371 - * @return void
511 + * @since 3.0.1
372 512 */
373 - public function wpstream_new_general_set() {
374 - return $this->main->get_live_channel_presentation()->render_channels_page();
375 - }
513 +
376 514 public function wpstream_social_share($the_id){
377 - return $this->main->get_live_channel_presentation()->render_part( 'social_share', array( $the_id ) );
515 + $protocol = is_ssl() ? 'https' : 'http';
516 + $pinterest = wp_get_attachment_image_src(get_post_thumbnail_id($the_id), 'full');
517 + $link = esc_url ( get_permalink($the_id) );
518 + $title = get_the_title($the_id);
519 + $twiter_status = urlencode( $title.' '.$link);
520 + $email_link = 'subject='.urlencode ( $title ) .'&body='. urlencode( esc_url($link));
521 +
522 + $facebook_link = esc_html($protocol).'://www.facebook.com/sharer.php?u='. esc_url($link) .'&amp;t='. urlencode(get_the_title());
523 +
524 + ?>
525 + <div class="wpstream_social_share_wrapper">
526 +
527 + <a href="<?php print esc_url( $facebook_link); ?>" target="_blank" class="social_facebook wpstream_sharing_social">
528 + <span class="dashicons dashicons-facebook-alt"></span>
529 + </a>
530 +
531 + <a href="<?php print esc_html($protocol);?>://twitter.com/intent/tweet?text=<?php echo esc_html($twiter_status); ?>" class="social_tweet wpstream_sharing_social" target="_blank">
532 + <span class="dashicons dashicons-twitter"></span>
533 + </a>
534 +
535 + <a href="<?php print esc_html($protocol);?>://pinterest.com/pin/create/button/?url=<?php echo esc_url($link); ?>&amp;media=<?php if (isset( $pinterest[0])){ echo esc_url($pinterest[0]); }?>&amp;description=<?php echo urlencode(get_the_title()); ?>" target="_blank" class="social_pinterest wpstream_sharing_social">
536 + <span class="dashicons dashicons-pinterest"></span>
537 + </a>
538 +
539 + <a href="<?php print esc_html($protocol);?>://api.whatsapp.com/send?text=<?php echo urlencode( get_the_title().' '. esc_url( $link )); ?>" class="social_whatsup wpstream_sharing_social" target="_blank">
540 + <span class="dashicons dashicons-whatsapp"></span>
541 + </a>
542 +
543 + <a href="<?php print esc_html($protocol);?>://www.linkedin.com/sharing/share-offsite/?url=<?php echo urlencode(esc_url($link)); ?>" class="social_linkedin wpstream_sharing_social" target="_blank">
544 + <span class="dashicons dashicons-linkedin"></span>
545 + </a>
546 +
547 + <a href="<?php print esc_html($protocol);?>:///www.reddit.com/submit?url==<?php echo urlencode(esc_url($link)); ?>" class="social_linkedin wpstream_sharing_social" target="_blank">
548 + <span class="dashicons dashicons-reddit"></span>
549 + </a>
550 +
551 + <a href="mailto:email@email.com?<?php echo trim(esc_html($email_link));?>" data-action="share email" class="social_email wpstream_sharing_social">
552 + <span class="dashicons dashicons-email-alt"></span>
553 + </a>
554 +
555 + <div class="wpstream_modal_explanations"> <?php print esc_html__('Spread the word! To let people know about your channel, click on the corresponding icon and share on the social platforms of your choice. The more the merrier!','wpstream'); ?> </div>
556 + <?php
557 + print '</div>';
378 558 }
559 +
560 +
561 +
562 +
563 + /**
564 + * Shows event unit card in admin
565 + *
566 + * @since 3.0.1
567 + */
568 +
379 569 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 );
570 + global $live_event_for_user;
571 + global $wpstream_plugin;
572 + $current_user = wp_get_current_user();
573 +
574 + if( !current_user_can('administrator')){
575 + if($is_front=='' ){
576 + print '<div class="event_list_unit">';
577 + esc_html_e('You are not allowed to broadcast.','wpstream');
578 + print '</div>';
579 + return;
580 + }
581 +
582 + }
583 +
584 + if( !$this->main->wpstream_check_user_can_stream() ){
585 + print '<div class="event_list_unit">';
586 + esc_html_e('You are not allowed to broadcast','wpstream');
587 + print '</div>';
588 + return;
589 + }
590 +
591 +
592 + $live_class='';
593 + if(isset($live_event_for_user[$the_id])) {
594 + $live_class=" wpstream_show_started";
595 + }
596 +
597 +
598 + if(has_post_thumbnail($the_id)){
599 + $thumb = get_the_post_thumbnail_url($the_id,'thumbnail');
600 + }else{
601 + $thumb= plugin_dir_url( dirname( __FILE__ ) ). 'img/plugin-logo.png';
602 + }
603 +
604 + $pending_streaming_class = 'hide_stream_data';
605 + $external_software_streaming_class = '';
606 + $obs_uri = '';
607 + $obs_stream = '';
608 + $live_data_url = '';
609 +
610 + if( $live_event_for_user=='' && $is_front=='front' ){
611 + $live_event_for_user = $this->main->wpstream_live_connection->wpstream_get_live_event_for_user();
612 + }
613 + $channel_status = '<div class="spinner" style="visibility: visible"></div>';
614 + $button_status = '<div class="spinner" style="visibility: visible"></div>';
615 + if(is_array($live_event_for_user) && isset($live_event_for_user[$the_id])) {
616 + $pending_streaming_class = 'pending_trigger';
617 + $live_data_url = get_post_meta($the_id,'qos_url',true);
618 + // $channel_status = esc_html__('Channel is on','wpstream');
619 + } else {
620 + $channel_status = esc_html__('Channel is OFF','wpstream');
621 + $button_status = esc_html__('TURN ON','wpstream');
622 + }
623 +
624 + $server_id = get_post_meta($the_id,'server_id',true);
625 + $obs_uri = get_post_meta($the_id,'obs_uri',true);
626 + $obs_stream = get_post_meta($the_id,'obs_stream',true);
627 + $webcaster_url = get_post_meta($the_id,'webcaster_url',true);
628 + $rtmp_ip_uri = '';
629 +
630 + print '<div class="event_list_unit '.$live_class.' '.$pending_streaming_class.' event_unit_style_'.esc_attr($is_front).'" data-show-id="'.intval($the_id).'" data-server-id="'.$server_id.'" data-server-url="'.$rtmp_ip_uri.'"">';
631 +
632 + print '<div class="wpstream_channel_status">'.$channel_status.'</div>';
633 +
634 + print '<div class="server_notification"></div>';
635 +
636 + print '<div class="event_thumb_wrapper" style="background-image:url('.$thumb.')"></div>';
637 +
638 + print '<div class="event_title" data-prodid="'.$the_id.'">'.wp_trim_words(get_the_title($the_id),10);
639 +
640 +
641 + /* print '***</br>'.get_post_meta($the_id,'obs_uri',true) .'***</br>'.
642 + get_post_meta($the_id,'obs_stream',true).'***</br>'.
643 + get_post_meta($the_id,'broadcast_url',true);
644 + */
645 + print '<div class="wpstream_channel_item_id">'.esc_html( '#ID' ).' '.$the_id.'</div>';
646 + print '</div>';
647 +
648 +
649 + print '<div class="start_event wpstream_button wpstream_tooltip_wrapper" data-show-id="'.$the_id.'" > ' . $button_status;
650 + print '<div class="wpstream_tooltip">'.esc_html__('Channel is now OFF. Click to turn ON.','wpestream').'</div>';
651 + print '</div>';
652 +
653 + print '<div class="wpstream_options_col1 wpstream_stream_browser_wrapper">';
654 +
655 + print '<div class="wpstream_inactive_icon start_webcaster wpstream_stream_browser wpstream-button-icon wpstream_tooltip_wrapper" data-webcaster-url="'.$webcaster_url.'" data-show-id="'.$the_id.'"">';
656 +
657 + print '<div class="wpstream_tooltip_disabled">'.esc_html__('Turn ON the channel to go live.','wpestream').'</div>';
658 + print '<div class="wpstream_tooltip">'.esc_html__('Go live with your webcam','wpestream').'</div>';
659 +
660 + print '<svg width="41" height="51" viewBox="0 0 41 51" fill="none" xmlns="http://www.w3.org/2000/svg">
661 + <path d="M40.7646 44.2989C39.8782 41.4216 38.3361 38.7814 36.181 36.4522C35.7274 35.9619 35.1629 35.3518 34.4858 34.8356C34.0448 34.4996 33.4262 34.5281 33.0182 34.9035C29.358 38.2714 25.2628 39.9088 20.4979 39.9088H20.4853C15.7103 39.9059 11.6117 38.264 7.95648 34.889C7.52404 34.4896 6.85874 34.484 6.41953 34.8764C3.30565 37.6569 1.20501 40.9206 0.175434 44.5778C-0.276291 46.1833 0.15652 47.8497 1.33328 49.0353C2.22709 49.9362 3.39869 50.4173 4.61958 50.4173C5.0357 50.4173 5.45813 50.3613 5.87645 50.247C10.147 49.081 14.0772 48.4108 17.8916 48.1983C21.1954 48.014 24.4465 48.1323 27.5541 48.5495C29.9559 48.8718 32.4237 49.3888 35.0996 50.1299C36.823 50.6076 38.459 50.1562 39.7059 48.86C40.9268 47.5901 41.2933 46.0132 40.7651 44.2994L40.7646 44.2989ZM38.0572 47.274C37.3825 47.9754 36.6367 48.1823 35.7092 47.9257C32.9321 47.1565 30.3638 46.6187 27.8578 46.2827C24.6079 45.8465 21.2117 45.723 17.7643 45.9151C13.7874 46.1365 9.70183 46.8319 5.27439 48.041C4.43435 48.2706 3.5673 48.0403 2.9568 47.425C2.35932 46.8227 2.14793 46.0108 2.37712 45.1975C3.21567 42.2171 4.7982 39.6162 7.2018 37.2734C11.0641 40.5378 15.5276 42.193 20.4845 42.196H20.4978C25.4557 42.196 29.9251 40.5386 33.7967 37.2667C34.024 37.4904 34.254 37.7359 34.5032 38.0059C36.4236 40.0816 37.7951 42.4256 38.5799 44.9728C38.8603 45.8811 38.6941 46.6125 38.0581 47.274L38.0572 47.274ZM20.4954 30.7538C13.8088 30.7523 8.54664 25.4128 8.54379 18.6256C8.5412 12.2624 13.9961 6.83353 20.3776 6.84872C27.1094 6.86467 32.4526 12.1652 32.4488 18.8231C32.4447 25.4243 27.1038 30.7547 20.4954 30.7538V30.7538ZM29.4401 18.8383C29.5559 13.9512 25.4358 9.8445 20.5347 9.83671C15.5301 9.82892 11.6488 13.9279 11.5328 18.5667C11.4086 23.5202 15.344 27.7103 20.3381 27.7926C25.5542 27.8783 29.554 23.5758 29.4401 18.8383V18.8383ZM20.4917 25.1342C17.2131 25.2436 14.1541 22.4349 14.1567 18.8924C14.1593 15.2627 16.9642 12.4191 20.5858 12.4662C24.0109 12.5111 26.8269 15.2466 26.8362 18.8471C26.8451 22.4293 23.782 25.2436 20.4917 25.1342V25.1342ZM18.5119 13.9982C17.3006 13.9908 15.6202 15.656 15.6295 16.8543C15.6328 17.3209 15.961 17.661 16.3983 17.6513C17.5973 17.6246 19.2281 16.0169 19.2696 14.8205C19.2881 14.2742 19.0371 14.0016 18.5119 13.9982L18.5119 13.9982ZM20.4964 0.568359C10.4428 0.568359 2.26333 8.74761 2.26333 18.8014C2.26333 28.8551 10.4426 37.0345 20.4964 37.0345C30.5502 37.0345 38.7295 28.8553 38.7295 18.8014C38.7291 8.7478 30.5502 0.568359 20.4964 0.568359V0.568359ZM20.4964 33.3886C12.4528 33.3886 5.90919 26.8449 5.90919 18.8014C5.90919 11.3105 11.585 5.12093 18.8624 4.30631C18.8561 4.36009 18.8528 4.41423 18.8528 4.46912C18.8468 5.37368 19.6112 6.16064 20.4927 6.15846C21.3636 6.15586 22.1283 5.39706 22.142 4.52143C22.1431 4.44874 22.1372 4.3768 22.1279 4.30596C29.4067 5.11929 35.0849 11.3092 35.0849 18.802C35.0842 26.8456 28.5404 33.3892 20.4968 33.3892L20.4964 33.3886Z" fill="black"/>
662 + </svg>';
663 + print '</div>';
664 +
665 +
666 + print '<div class="wpstream_inactive_icon wpstream_stream_pro wpstream-button-icon wpstream-trigger-modal wpstream_tooltip_wrapper" data-modal="wpestate_broadcast_modal" data-show-id="'.$the_id.'"">';
667 +
668 + print '<div class="wpstream_tooltip_disabled">'.esc_html__('Turn ON the channel to go live.','wpestream').'</div>';
669 + print '<div class="wpstream_tooltip">'.esc_html__('Go Live with external streaming app','wpestream').'</div>';
670 +
671 + print '<svg width="51" height="38" viewBox="0 0 51 38" fill="none" xmlns="http://www.w3.org/2000/svg">
672 + <path d="M48.1266 13.9634L41.891 17.5343V13.6438C41.891 10.8723 39.6525 8.63384 36.8811 8.63384H33.1504L30.1124 3.62393C28.7268 1.3324 26.2751 0 23.6103 0H10.2863C8.84722 0 7.67471 1.17251 7.67471 2.6116C7.67471 4.05068 8.84722 5.22319 10.2863 5.22319H23.6103C24.4631 5.22319 25.2093 5.64961 25.6888 6.3957L27.0744 8.63413L5.00991 8.63376C2.23843 8.63376 0 10.8722 0 13.6437V32.9901C0 35.7616 2.23843 38 5.00991 38H36.9342C39.7057 38 41.9441 35.7616 41.9441 32.9901V29.0461L48.1797 32.6169C49.2991 33.2564 50.6846 32.4571 50.6846 31.1778L50.6842 15.4022C50.6311 14.123 49.2455 13.3237 48.1261 13.9632L48.1266 13.9634ZM38.1603 32.9368C38.1603 33.6297 37.574 34.1625 36.9345 34.1625L5.01029 34.1629C4.31733 34.1629 3.78458 33.5766 3.78458 32.9372V13.5907C3.78458 12.8978 4.37086 12.365 5.01029 12.365H36.9345C37.6275 12.365 38.1603 12.9513 38.1603 13.5907V32.9368Z" fill="black"/>
673 + <path d="M22.4917 21.585H9.70066C8.84784 21.585 8.15527 22.2779 8.15527 23.1304V28.247C8.15527 29.0998 8.84823 29.7923 9.70066 29.7923H22.4917C23.3445 29.7923 24.0371 29.0994 24.0371 28.247V23.1304C24.0371 22.2775 23.3445 21.585 22.4917 21.585Z" fill="black"/>
674 + </svg>';
675 + print '</div>';
676 +
677 +
678 +
679 +
680 + print '<a href="'.esc_url($live_data_url).'" target="_blank" class="wpstream_inactive_icon wpstream_live_data wpstream_statistics_channel wpstream-button-icon wpstream_tooltip_wrapper" data-show-id="'.$the_id.'" >';
681 +
682 + print '<div class="wpstream_tooltip_disabled">'.esc_html__('Turn ON the channel to see live stats.','wpestream').'</div>';
683 + print '<div class="wpstream_tooltip">'.esc_html__('Live Statistics','wpestream').'</div>';
684 +
685 + print'<svg width="50" height="42" viewBox="0 0 50 42" fill="none" xmlns="http://www.w3.org/2000/svg">
686 + <path fill-rule="evenodd" clip-rule="evenodd" d="M48.9001 9.02344H40.3342C39.7288 9.02344 39.2344 9.51791 39.2344 10.1233V40.4275C39.2344 41.033 39.7288 41.5274 40.3342 41.5274H48.9001C49.5055 41.5274 50 41.0329 50 40.4275V10.1233C50 9.51791 49.5055 9.02344 48.9001 9.02344V9.02344Z" fill="black"/>
687 + <path fill-rule="evenodd" clip-rule="evenodd" d="M35.821 22.4067H27.2551C26.6497 22.4067 26.1553 22.9012 26.1553 23.5066V40.4277C26.1553 41.0332 26.6497 41.5276 27.2551 41.5276H35.821C36.4264 41.5276 36.9209 41.0332 36.9209 40.4277V23.5066C36.9209 22.9012 36.4264 22.4067 35.821 22.4067V22.4067Z" fill="black"/>
688 + <path fill-rule="evenodd" clip-rule="evenodd" d="M22.7439 0H14.178C13.5726 0 13.0781 0.494478 13.0781 1.09989V40.4275C13.0781 41.0329 13.5726 41.5274 14.178 41.5274H22.7439C23.3493 41.5274 23.8438 41.0329 23.8438 40.4275V1.09989C23.8438 0.49447 23.3493 0 22.7439 0V0Z" fill="black"/>
689 + <path fill-rule="evenodd" clip-rule="evenodd" d="M9.66573 15.2559H1.09987C0.49445 15.2559 -2.24584e-05 15.7512 -2.24584e-05 16.3558V40.4285C-2.24584e-05 41.0331 0.495325 41.5284 1.09987 41.5284H9.66573C10.2703 41.5284 10.7656 41.034 10.7656 40.4285V16.3558C10.7656 15.7503 10.2711 15.2559 9.66573 15.2559V15.2559Z" fill="black"/>
690 + </svg>';
691 + print '</a>';
692 + print '</div>';
693 +
694 + print '<div class="wpstream_options_col2 wpstream_show_settings_wrapper">';
695 + if($is_front==''){
696 + print '<div class="wpstream_show_settings wpstream-button-icon wpstream-trigger-modal wpstream_tooltip_wrapper" data-modal="wpestate_settings_modal" data-show-id="'.$the_id.'" value="'.esc_html__('Settings','wpstream').'">';
697 +
698 + print '<div class="wpstream_tooltip_disabled">'.esc_html__('
699 + Turn OFF the channel to change its settings.','wpestream').'</div>';
700 + print '<div class="wpstream_tooltip">'.esc_html__('Channel Settings','wpestream').'</div>';
701 +
702 + print '<svg width="50" height="50" viewBox="0 0 50 50" fill="none" xmlns="http://www.w3.org/2000/svg">
703 + <path d="M49.22 21.8648C48.82 21.6099 45.665 19.7247 44.415 19.15L42.8651 15.4C43.3251 14.1601 44.2099 10.6849 44.3652 10.0798H44.3649C44.4911 9.52035 44.3213 8.93514 43.9149 8.52987L41.47 6.09995C41.0658 5.69189 40.4795 5.52168 39.9201 5.65003C39.4601 5.75501 35.92 6.64994 34.5999 7.15012L30.8499 5.60021C30.3048 4.40012 28.4699 1.32529 28.1351 0.795199V0.79485C27.8337 0.301688 27.298 0.00069643 26.7201 0H23.2798C22.7057 0.000348769 22.1718 0.294715 21.8648 0.779859C21.6098 1.1799 19.7247 4.33487 19.15 5.58487L15.4 7.13478C14.1601 6.67476 10.6849 5.78996 10.0798 5.63469V5.63504C9.52035 5.50878 8.93513 5.67864 8.52987 6.08496L6.09995 8.52988C5.69189 8.9341 5.52168 9.52042 5.65003 10.0798C5.75501 10.5398 6.64994 14.0799 7.15012 15.4L5.60021 19.15C4.40012 19.6951 1.32529 21.53 0.795198 21.8648H0.79485C0.301688 22.1662 0.00069643 22.7019 0 23.2798V26.7149C0.000348751 27.2893 0.294715 27.8233 0.779858 28.1299C1.1799 28.3849 4.33486 30.27 5.58487 30.8448L7.13478 34.5948C6.67475 35.8347 5.78996 39.3099 5.63469 39.915H5.63504C5.50878 40.4747 5.67863 41.06 6.08496 41.4649L8.51487 43.8948V43.8951C8.9191 44.3032 9.50541 44.4731 10.0648 44.3451C10.5248 44.2401 14.0649 43.3451 15.385 42.845L19.135 44.3949C19.6801 45.595 21.515 48.6698 21.8498 49.1999C22.1525 49.6997 22.6956 50.0035 23.2798 50H26.7149C27.2893 49.9996 27.8233 49.7053 28.1299 49.2201C28.3849 48.8201 30.27 45.6651 30.8447 44.4151L34.5947 42.8652C35.8347 43.3252 39.3098 44.21 39.9149 44.3653V44.3649C40.4747 44.4912 41.0599 44.3213 41.4649 43.915L43.8948 41.4851H43.8951C44.3032 41.0809 44.473 40.4945 44.345 39.9352C44.2401 39.4751 43.3451 35.9351 42.8449 34.615L44.3949 30.865C45.5949 30.3198 48.6698 28.485 49.1999 28.1501C49.6997 27.8474 50.0034 27.3044 49.9999 26.7201V23.2799C50.0045 22.7047 49.7087 22.1683 49.2201 21.8649L49.22 21.8648ZM24.9995 35.8845C22.1099 35.882 19.3399 34.7314 17.2985 32.6866C15.2572 30.6414 14.1118 27.8694 14.1146 24.9798C14.1171 22.0903 15.2676 19.3199 17.3125 17.2785C19.3577 15.2372 22.1297 14.0921 25.0193 14.0946C27.9088 14.0974 30.6792 15.2477 32.7205 17.2928C34.7619 19.338 35.907 22.1101 35.9045 24.9996C35.8978 27.8879 34.7462 30.6557 32.7021 32.6964C30.6576 34.7367 27.8876 35.8834 24.9994 35.8845H24.9995Z" fill="black"/>
704 + </svg>
705 + </div>';
706 +
707 +
708 + print '<a href="'.get_edit_post_link($the_id).'" class="wpstream_edit_channel wpstream-button-icon wpstream_tooltip_wrapper" target="_blank" data-show-id="'.$the_id.'"">';
709 + print '<div class="wpstream_tooltip">'.esc_html__('Edit Channel','wpestream').'</div>';
710 + print '<svg width="50" height="50" viewBox="0 0 50 50" fill="none" xmlns="http://www.w3.org/2000/svg">
711 + <path d="M44.8203 1.79549C42.4263 -0.598498 38.5591 -0.598498 36.1651 1.79549L4.67494 33.2246C4.55203 33.3475 4.49079 33.4088 4.42954 33.5317C4.42954 33.5317 4.42954 33.5929 4.36829 33.5929C4.30705 33.7159 4.24539 33.7771 4.24539 33.9V33.9613L0.0711091 47.5886C-0.113044 48.264 0.0711092 48.9389 0.500659 49.4301C0.868966 49.7984 1.29852 49.9826 1.78973 49.9826C1.97388 49.9826 2.15804 49.9826 2.34219 49.9213L15.9085 45.747H15.9697C16.0926 45.6858 16.2151 45.6858 16.2768 45.6241C16.2768 45.6241 16.338 45.6241 16.338 45.5629C16.4609 45.5016 16.5834 45.44 16.6451 45.3175L48.0742 13.8884C50.4682 11.4944 50.4682 7.62715 48.0742 5.23316L44.8203 1.79549Z" fill="black"/>
712 + </svg>';
713 + print '</a>';
714 + }
715 +
716 + print '<a href="'.get_permalink($the_id).'" target="_blank" class="wpstream_view_channel wpstream-button-icon wpstream_tooltip_wrapper" data-show-id="'.$the_id.'"">';
717 + print '<div class="wpstream_tooltip">'.esc_html__('View Channel','wpestream').'</div>';
718 + print '<svg width="50" height="32" viewBox="0 0 50 32" fill="none" xmlns="http://www.w3.org/2000/svg">
719 + <path d="M18.6201 15.2828H21.8752C21.8752 14.069 22.8681 13.0207 24.1373 13.0207V9.76562C21.1032 9.76562 18.6201 12.2487 18.6201 15.2828Z" fill="black"/>
720 + <path d="M24.855 0C12.9378 0 3.28272 10.9792 0.579292 14.3447C-0.193097 15.2826 -0.193097 16.662 0.579292 17.6553C3.28282 21.0208 12.9378 32 24.855 32C36.7722 32 46.4273 21.0208 49.1307 17.6553C49.9031 16.7174 49.9031 15.338 49.1307 14.3447C46.4275 10.9792 36.7722 0 24.855 0V0ZM24.855 25.8205C19.4482 25.8205 15.0344 21.4067 15.0344 15.9999C15.0344 10.5931 19.4482 6.17927 24.855 6.17927C30.2618 6.17927 34.6756 10.5931 34.6756 15.9999C34.6756 21.4067 30.2618 25.8205 24.855 25.8205Z" fill="black"/>
721 + </svg>';
722 + print '</a>';
723 +
724 +
725 + print '<div class="wpstream_share_channel wpstream-button-icon wpstream-trigger-modal wpstream_tooltip_wrapper" data-modal="wpestate_share_modal" data-show-id="'.$the_id.'"">';
726 + print '<div class="wpstream_tooltip">'.esc_html__('Share Channel','wpestream').'</div>';
727 + print '<svg width="44" height="50" viewBox="0 0 44 50" fill="none" xmlns="http://www.w3.org/2000/svg">
728 + <path d="M20.0777 20.5087L24.3481 17.9427C26.6432 16.5645 29.4554 16.2443 31.96 17.198C33.443 17.7642 35.1166 17.9363 36.852 17.6105C40.3163 16.9521 43.1162 14.1831 43.8115 10.7248C45.0606 4.51597 39.7751 -0.910703 33.5907 0.12835C30.2924 0.682061 27.5604 3.16211 26.5942 6.36168C26.4405 6.86646 26.3418 7.35835 26.2804 7.84466C25.9482 10.5028 24.2498 12.8044 21.9547 14.1827L19.3458 15.7456C17.1061 17.0869 14.3986 17.1792 11.9494 16.2748C10.9956 15.9241 9.96159 15.7271 8.88507 15.7271C3.39004 15.7271 -0.960663 20.7607 0.184097 26.4527C0.879447 29.911 3.67936 32.68 7.14364 33.3384C8.87902 33.6706 10.5525 33.492 12.0356 32.9259C14.5402 31.9721 17.3461 32.2919 19.6475 33.6706L23.906 36.2241C25.346 37.0855 26.2195 38.6424 26.2195 40.3159V40.3403C26.2195 45.8229 31.2287 50.1611 36.9018 49.0472C40.3602 48.3703 43.1415 45.583 43.8244 42.1246C44.9383 36.451 40.6 31.4423 35.1175 31.4423C34.0406 31.4423 33.007 31.6394 32.0532 31.9901C29.604 32.8944 26.9029 32.8022 24.6627 31.4608L20.0721 28.7038C18.6445 27.8484 17.7706 26.304 17.7706 24.6364V24.5875C17.7642 22.9208 18.6441 21.37 20.0777 20.5085L20.0777 20.5087Z" fill="black"/>
729 + </svg>';
730 + print '</div>';
731 + print '</div>';
732 +
733 + $this->wpstream_display_modal_seetings($the_id);
734 + $this->wpstream_display_modal_share($the_id);
735 + $this->wpstream_display_modal_broadcast($the_id,$external_software_streaming_class,$obs_uri,$obs_stream);
736 +
737 + print '</div>';
738 +
382 739 }
740 +
741 +
742 +
743 +
744 + /**
745 + * Shows event unit card in admin - theme version
746 + *
747 + * @since 3.0.1
748 + */
383 749 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 ) );
750 + global $live_event_for_user;
751 + global $wpstream_plugin;
752 + $current_user = wp_get_current_user();
753 +
754 + if( !current_user_can('administrator')){
755 + if($is_front=='' ){
756 + print '<div class="event_list_unit">';
757 + esc_html_e('You are not allowed to broadcast.','wpstream');
758 + print '</div>';
759 + return;
760 + }
761 +
762 + }
763 +
764 + if( !$this->main->wpstream_check_user_can_stream() ){
765 + print '<div class="event_list_unit">';
766 + esc_html_e('You are not allowed to broadcast','wpstream');
767 + print '</div>';
768 + return;
769 + }
770 +
771 +
772 + $live_class='';
773 + if(isset($live_event_for_user[$the_id])) {
774 + $live_class=" wpstream_show_started";
775 + }
776 +
777 +
778 + if(has_post_thumbnail($the_id)){
779 + $thumb = get_the_post_thumbnail_url($the_id,'thumbnail');
780 + }else{
781 + $thumb= plugin_dir_url( dirname( __FILE__ ) ). 'img/plugin-logo.png';
782 + }
783 +
784 + $pending_streaming_class = 'hide_stream_data';
785 + $external_software_streaming_class = '';
786 + $obs_uri = '';
787 + $obs_stream = '';
788 + $live_data_url = '';
789 +
790 + if( $live_event_for_user=='' && $is_front=='front' ){
791 + $live_event_for_user = $this->main->wpstream_live_connection->wpstream_get_live_event_for_user();
792 + }
793 +
794 + $spinner_url = admin_url('images/spinner-2x.gif');
795 + $button_status = '<div class="spinner" style="background-image: url(' . $spinner_url . ')"></div>';
796 + $channel_status = '';
797 + if(is_array($live_event_for_user) && isset($live_event_for_user[$the_id])) {
798 + $pending_streaming_class = 'pending_trigger';
799 + $live_data_url = get_post_meta($the_id,'qos_url',true);
800 + // $channel_status = esc_html__('Channel is on','wpstream');
801 + } else {
802 + $channel_status = esc_html__('Channel is OFF','wpstream');
803 + $button_status = esc_html__('TURN ON', 'wpstream');
804 + }
805 +
806 + $server_id = get_post_meta($the_id,'server_id',true);
807 + $obs_uri = get_post_meta($the_id,'obs_uri',true);
808 + $obs_stream = get_post_meta($the_id,'obs_stream',true);
809 + $webcaster_url = get_post_meta($the_id,'webcaster_url',true);
810 + $rtmp_ip_uri = '';
811 +
812 + print '<div class="wpstream_theme_event_list_unit event_list_unit '.$live_class.' '.$pending_streaming_class.' event_unit_style_'.esc_attr($is_front).'" data-show-id="'.intval($the_id).'" data-server-id="'.$server_id.'" data-server-url="'.$rtmp_ip_uri.'"">';
813 +
814 + print '<div class="wpstream_channel_status" style="' . ($channel_status ? '' : 'display: none') . '">'.$channel_status.'</div>';
815 +
816 + print '<div class="server_notification"></div>';
817 +
818 + print '<div class="wpstream_theme_event_thumb_wrapper">';
819 + print '<div class="event_thumb_wrapper" style="background-image:url('.$thumb.')"></div>';
820 + print '<div class="event_title" data-prodid="'.$the_id.'">'.wp_trim_words(get_the_title($the_id),10);
821 + print '<div class="wpstream_channel_item_id">'.esc_html('#ID','wpstream').' '.$the_id.'</div>';
822 + print '</div>';
823 + print '</div>';
824 +
825 + print '<div class="wpstream_theme_control_bar_wrapper">';
826 +
827 +
828 + print '<div class="wpstream_options_col1 wpstream_stream_browser_wrapper">';
829 +
830 + print '<div class="wpstream_inactive_icon start_webcaster wpstream_stream_browser wpstream-button-icon wpstream_tooltip_wrapper" data-webcaster-url="'.$webcaster_url.'" data-show-id="'.$the_id.'"">';
831 +
832 + print '<div class="wpstream_tooltip_disabled">'.esc_html__('Turn ON the channel to go live.','wpestream').'</div>';
833 + print '<div class="wpstream_tooltip">'.esc_html__('Go live with your webcam','wpestream').'</div>';
834 +
835 + print '<svg width="41" height="51" viewBox="0 0 41 51" fill="none" xmlns="http://www.w3.org/2000/svg">
836 + <path d="M40.7646 44.2989C39.8782 41.4216 38.3361 38.7814 36.181 36.4522C35.7274 35.9619 35.1629 35.3518 34.4858 34.8356C34.0448 34.4996 33.4262 34.5281 33.0182 34.9035C29.358 38.2714 25.2628 39.9088 20.4979 39.9088H20.4853C15.7103 39.9059 11.6117 38.264 7.95648 34.889C7.52404 34.4896 6.85874 34.484 6.41953 34.8764C3.30565 37.6569 1.20501 40.9206 0.175434 44.5778C-0.276291 46.1833 0.15652 47.8497 1.33328 49.0353C2.22709 49.9362 3.39869 50.4173 4.61958 50.4173C5.0357 50.4173 5.45813 50.3613 5.87645 50.247C10.147 49.081 14.0772 48.4108 17.8916 48.1983C21.1954 48.014 24.4465 48.1323 27.5541 48.5495C29.9559 48.8718 32.4237 49.3888 35.0996 50.1299C36.823 50.6076 38.459 50.1562 39.7059 48.86C40.9268 47.5901 41.2933 46.0132 40.7651 44.2994L40.7646 44.2989ZM38.0572 47.274C37.3825 47.9754 36.6367 48.1823 35.7092 47.9257C32.9321 47.1565 30.3638 46.6187 27.8578 46.2827C24.6079 45.8465 21.2117 45.723 17.7643 45.9151C13.7874 46.1365 9.70183 46.8319 5.27439 48.041C4.43435 48.2706 3.5673 48.0403 2.9568 47.425C2.35932 46.8227 2.14793 46.0108 2.37712 45.1975C3.21567 42.2171 4.7982 39.6162 7.2018 37.2734C11.0641 40.5378 15.5276 42.193 20.4845 42.196H20.4978C25.4557 42.196 29.9251 40.5386 33.7967 37.2667C34.024 37.4904 34.254 37.7359 34.5032 38.0059C36.4236 40.0816 37.7951 42.4256 38.5799 44.9728C38.8603 45.8811 38.6941 46.6125 38.0581 47.274L38.0572 47.274ZM20.4954 30.7538C13.8088 30.7523 8.54664 25.4128 8.54379 18.6256C8.5412 12.2624 13.9961 6.83353 20.3776 6.84872C27.1094 6.86467 32.4526 12.1652 32.4488 18.8231C32.4447 25.4243 27.1038 30.7547 20.4954 30.7538V30.7538ZM29.4401 18.8383C29.5559 13.9512 25.4358 9.8445 20.5347 9.83671C15.5301 9.82892 11.6488 13.9279 11.5328 18.5667C11.4086 23.5202 15.344 27.7103 20.3381 27.7926C25.5542 27.8783 29.554 23.5758 29.4401 18.8383V18.8383ZM20.4917 25.1342C17.2131 25.2436 14.1541 22.4349 14.1567 18.8924C14.1593 15.2627 16.9642 12.4191 20.5858 12.4662C24.0109 12.5111 26.8269 15.2466 26.8362 18.8471C26.8451 22.4293 23.782 25.2436 20.4917 25.1342V25.1342ZM18.5119 13.9982C17.3006 13.9908 15.6202 15.656 15.6295 16.8543C15.6328 17.3209 15.961 17.661 16.3983 17.6513C17.5973 17.6246 19.2281 16.0169 19.2696 14.8205C19.2881 14.2742 19.0371 14.0016 18.5119 13.9982L18.5119 13.9982ZM20.4964 0.568359C10.4428 0.568359 2.26333 8.74761 2.26333 18.8014C2.26333 28.8551 10.4426 37.0345 20.4964 37.0345C30.5502 37.0345 38.7295 28.8553 38.7295 18.8014C38.7291 8.7478 30.5502 0.568359 20.4964 0.568359V0.568359ZM20.4964 33.3886C12.4528 33.3886 5.90919 26.8449 5.90919 18.8014C5.90919 11.3105 11.585 5.12093 18.8624 4.30631C18.8561 4.36009 18.8528 4.41423 18.8528 4.46912C18.8468 5.37368 19.6112 6.16064 20.4927 6.15846C21.3636 6.15586 22.1283 5.39706 22.142 4.52143C22.1431 4.44874 22.1372 4.3768 22.1279 4.30596C29.4067 5.11929 35.0849 11.3092 35.0849 18.802C35.0842 26.8456 28.5404 33.3892 20.4968 33.3892L20.4964 33.3886Z" fill="black"/>
837 + </svg>';
838 + esc_html_e('Webcam','wpstream');
839 + print '</div>';
840 +
841 +
842 + print '<div class="wpstream_inactive_icon wpstream_stream_pro wpstream-button-icon wpstream-trigger-modal wpstream_tooltip_wrapper" data-modal="wpestate_broadcast_modal" data-show-id="'.$the_id.'"">';
843 +
844 + print '<div class="wpstream_tooltip_disabled">'.esc_html__('Turn ON the channel to go live.','wpestream').'</div>';
845 + print '<div class="wpstream_tooltip">'.esc_html__('Go Live with external streaming app','wpestream').'</div>';
846 +
847 + print '<svg width="51" height="38" viewBox="0 0 51 38" fill="none" xmlns="http://www.w3.org/2000/svg">
848 + <path d="M48.1266 13.9634L41.891 17.5343V13.6438C41.891 10.8723 39.6525 8.63384 36.8811 8.63384H33.1504L30.1124 3.62393C28.7268 1.3324 26.2751 0 23.6103 0H10.2863C8.84722 0 7.67471 1.17251 7.67471 2.6116C7.67471 4.05068 8.84722 5.22319 10.2863 5.22319H23.6103C24.4631 5.22319 25.2093 5.64961 25.6888 6.3957L27.0744 8.63413L5.00991 8.63376C2.23843 8.63376 0 10.8722 0 13.6437V32.9901C0 35.7616 2.23843 38 5.00991 38H36.9342C39.7057 38 41.9441 35.7616 41.9441 32.9901V29.0461L48.1797 32.6169C49.2991 33.2564 50.6846 32.4571 50.6846 31.1778L50.6842 15.4022C50.6311 14.123 49.2455 13.3237 48.1261 13.9632L48.1266 13.9634ZM38.1603 32.9368C38.1603 33.6297 37.574 34.1625 36.9345 34.1625L5.01029 34.1629C4.31733 34.1629 3.78458 33.5766 3.78458 32.9372V13.5907C3.78458 12.8978 4.37086 12.365 5.01029 12.365H36.9345C37.6275 12.365 38.1603 12.9513 38.1603 13.5907V32.9368Z" fill="black"/>
849 + <path d="M22.4917 21.585H9.70066C8.84784 21.585 8.15527 22.2779 8.15527 23.1304V28.247C8.15527 29.0998 8.84823 29.7923 9.70066 29.7923H22.4917C23.3445 29.7923 24.0371 29.0994 24.0371 28.247V23.1304C24.0371 22.2775 23.3445 21.585 22.4917 21.585Z" fill="black"/>
850 + </svg>';
851 + esc_html_e('External App','wpstream');
852 + print '</div>';
853 +
854 +
855 +
856 +
857 + print '<a href="'.esc_url($live_data_url).'" target="_blank" class="wpstream_inactive_icon wpstream_live_data wpstream_statistics_channel wpstream-button-icon wpstream_tooltip_wrapper" data-show-id="'.$the_id.'" >';
858 +
859 + print '<div class="wpstream_tooltip_disabled">'.esc_html__('Turn ON the channel to see live stats.','wpestream').'</div>';
860 + print '<div class="wpstream_tooltip">'.esc_html__('Live Statistics','wpestream').'</div>';
861 +
862 + print'<svg width="50" height="42" viewBox="0 0 50 42" fill="none" xmlns="http://www.w3.org/2000/svg">
863 + <path fill-rule="evenodd" clip-rule="evenodd" d="M48.9001 9.02344H40.3342C39.7288 9.02344 39.2344 9.51791 39.2344 10.1233V40.4275C39.2344 41.033 39.7288 41.5274 40.3342 41.5274H48.9001C49.5055 41.5274 50 41.0329 50 40.4275V10.1233C50 9.51791 49.5055 9.02344 48.9001 9.02344V9.02344Z" fill="black"/>
864 + <path fill-rule="evenodd" clip-rule="evenodd" d="M35.821 22.4067H27.2551C26.6497 22.4067 26.1553 22.9012 26.1553 23.5066V40.4277C26.1553 41.0332 26.6497 41.5276 27.2551 41.5276H35.821C36.4264 41.5276 36.9209 41.0332 36.9209 40.4277V23.5066C36.9209 22.9012 36.4264 22.4067 35.821 22.4067V22.4067Z" fill="black"/>
865 + <path fill-rule="evenodd" clip-rule="evenodd" d="M22.7439 0H14.178C13.5726 0 13.0781 0.494478 13.0781 1.09989V40.4275C13.0781 41.0329 13.5726 41.5274 14.178 41.5274H22.7439C23.3493 41.5274 23.8438 41.0329 23.8438 40.4275V1.09989C23.8438 0.49447 23.3493 0 22.7439 0V0Z" fill="black"/>
866 + <path fill-rule="evenodd" clip-rule="evenodd" d="M9.66573 15.2559H1.09987C0.49445 15.2559 -2.24584e-05 15.7512 -2.24584e-05 16.3558V40.4285C-2.24584e-05 41.0331 0.495325 41.5284 1.09987 41.5284H9.66573C10.2703 41.5284 10.7656 41.034 10.7656 40.4285V16.3558C10.7656 15.7503 10.2711 15.2559 9.66573 15.2559V15.2559Z" fill="black"/>
867 + </svg>';
868 + esc_html_e('Statistics','wpstream');
869 + print '</a>';
870 + print '</div>';
871 +
872 + print '<div class="wpstream_options_col2 wpstream_show_settings_wrapper">';
873 + if($is_front==''){
874 + print '<div class="wpstream_show_settings wpstream-button-icon wpstream-trigger-modal wpstream_tooltip_wrapper" data-modal="wpestate_settings_modal" data-show-id="'.$the_id.'" value="'.esc_html__('Settings','wpstream').'">';
875 +
876 + print '<div class="wpstream_tooltip_disabled">'.esc_html__('Turn OFF the channel to change its settings.','wpestream').'</div>';
877 + print '<div class="wpstream_tooltip">'.esc_html__('Channel Settings','wpestream').'</div>';
878 +
879 + print '<svg width="50" height="50" viewBox="0 0 50 50" fill="none" xmlns="http://www.w3.org/2000/svg">
880 + <path d="M49.22 21.8648C48.82 21.6099 45.665 19.7247 44.415 19.15L42.8651 15.4C43.3251 14.1601 44.2099 10.6849 44.3652 10.0798H44.3649C44.4911 9.52035 44.3213 8.93514 43.9149 8.52987L41.47 6.09995C41.0658 5.69189 40.4795 5.52168 39.9201 5.65003C39.4601 5.75501 35.92 6.64994 34.5999 7.15012L30.8499 5.60021C30.3048 4.40012 28.4699 1.32529 28.1351 0.795199V0.79485C27.8337 0.301688 27.298 0.00069643 26.7201 0H23.2798C22.7057 0.000348769 22.1718 0.294715 21.8648 0.779859C21.6098 1.1799 19.7247 4.33487 19.15 5.58487L15.4 7.13478C14.1601 6.67476 10.6849 5.78996 10.0798 5.63469V5.63504C9.52035 5.50878 8.93513 5.67864 8.52987 6.08496L6.09995 8.52988C5.69189 8.9341 5.52168 9.52042 5.65003 10.0798C5.75501 10.5398 6.64994 14.0799 7.15012 15.4L5.60021 19.15C4.40012 19.6951 1.32529 21.53 0.795198 21.8648H0.79485C0.301688 22.1662 0.00069643 22.7019 0 23.2798V26.7149C0.000348751 27.2893 0.294715 27.8233 0.779858 28.1299C1.1799 28.3849 4.33486 30.27 5.58487 30.8448L7.13478 34.5948C6.67475 35.8347 5.78996 39.3099 5.63469 39.915H5.63504C5.50878 40.4747 5.67863 41.06 6.08496 41.4649L8.51487 43.8948V43.8951C8.9191 44.3032 9.50541 44.4731 10.0648 44.3451C10.5248 44.2401 14.0649 43.3451 15.385 42.845L19.135 44.3949C19.6801 45.595 21.515 48.6698 21.8498 49.1999C22.1525 49.6997 22.6956 50.0035 23.2798 50H26.7149C27.2893 49.9996 27.8233 49.7053 28.1299 49.2201C28.3849 48.8201 30.27 45.6651 30.8447 44.4151L34.5947 42.8652C35.8347 43.3252 39.3098 44.21 39.9149 44.3653V44.3649C40.4747 44.4912 41.0599 44.3213 41.4649 43.915L43.8948 41.4851H43.8951C44.3032 41.0809 44.473 40.4945 44.345 39.9352C44.2401 39.4751 43.3451 35.9351 42.8449 34.615L44.3949 30.865C45.5949 30.3198 48.6698 28.485 49.1999 28.1501C49.6997 27.8474 50.0034 27.3044 49.9999 26.7201V23.2799C50.0045 22.7047 49.7087 22.1683 49.2201 21.8649L49.22 21.8648ZM24.9995 35.8845C22.1099 35.882 19.3399 34.7314 17.2985 32.6866C15.2572 30.6414 14.1118 27.8694 14.1146 24.9798C14.1171 22.0903 15.2676 19.3199 17.3125 17.2785C19.3577 15.2372 22.1297 14.0921 25.0193 14.0946C27.9088 14.0974 30.6792 15.2477 32.7205 17.2928C34.7619 19.338 35.907 22.1101 35.9045 24.9996C35.8978 27.8879 34.7462 30.6557 32.7021 32.6964C30.6576 34.7367 27.8876 35.8834 24.9994 35.8845H24.9995Z" fill="black"/>
881 + </svg>
882 + </div>';
883 +
884 +
885 + print '<a href="'.get_edit_post_link($the_id).'" class="wpstream_edit_channel wpstream-button-icon wpstream_tooltip_wrapper" target="_blank" data-show-id="'.$the_id.'"">';
886 + print '<div class="wpstream_tooltip">'.esc_html__('Edit Channel','wpestream').'</div>';
887 + print '<svg width="50" height="50" viewBox="0 0 50 50" fill="none" xmlns="http://www.w3.org/2000/svg">
888 + <path d="M44.8203 1.79549C42.4263 -0.598498 38.5591 -0.598498 36.1651 1.79549L4.67494 33.2246C4.55203 33.3475 4.49079 33.4088 4.42954 33.5317C4.42954 33.5317 4.42954 33.5929 4.36829 33.5929C4.30705 33.7159 4.24539 33.7771 4.24539 33.9V33.9613L0.0711091 47.5886C-0.113044 48.264 0.0711092 48.9389 0.500659 49.4301C0.868966 49.7984 1.29852 49.9826 1.78973 49.9826C1.97388 49.9826 2.15804 49.9826 2.34219 49.9213L15.9085 45.747H15.9697C16.0926 45.6858 16.2151 45.6858 16.2768 45.6241C16.2768 45.6241 16.338 45.6241 16.338 45.5629C16.4609 45.5016 16.5834 45.44 16.6451 45.3175L48.0742 13.8884C50.4682 11.4944 50.4682 7.62715 48.0742 5.23316L44.8203 1.79549Z" fill="black"/>
889 + </svg>';
890 + print '</a>';
891 + }
892 +
893 + print '<a href="'.get_permalink($the_id).'" target="_blank" class="wpstream_view_channel wpstream-button-icon wpstream_tooltip_wrapper" data-show-id="'.$the_id.'"">';
894 + print '<div class="wpstream_tooltip">'.esc_html__('View Channel','wpestream').'</div>';
895 + print '<svg width="50" height="32" viewBox="0 0 50 32" fill="none" xmlns="http://www.w3.org/2000/svg">
896 + <path d="M18.6201 15.2828H21.8752C21.8752 14.069 22.8681 13.0207 24.1373 13.0207V9.76562C21.1032 9.76562 18.6201 12.2487 18.6201 15.2828Z" fill="black"/>
897 + <path d="M24.855 0C12.9378 0 3.28272 10.9792 0.579292 14.3447C-0.193097 15.2826 -0.193097 16.662 0.579292 17.6553C3.28282 21.0208 12.9378 32 24.855 32C36.7722 32 46.4273 21.0208 49.1307 17.6553C49.9031 16.7174 49.9031 15.338 49.1307 14.3447C46.4275 10.9792 36.7722 0 24.855 0V0ZM24.855 25.8205C19.4482 25.8205 15.0344 21.4067 15.0344 15.9999C15.0344 10.5931 19.4482 6.17927 24.855 6.17927C30.2618 6.17927 34.6756 10.5931 34.6756 15.9999C34.6756 21.4067 30.2618 25.8205 24.855 25.8205Z" fill="black"/>
898 + </svg>';
899 + esc_html_e('View','wpstream');
900 + print '</a>';
901 +
902 +
903 + print '<div class="wpstream_share_channel wpstream-button-icon wpstream-trigger-modal wpstream_tooltip_wrapper" data-modal="wpestate_share_modal" data-show-id="'.$the_id.'"">';
904 + print '<div class="wpstream_tooltip">'.esc_html__('Share Channel','wpestream').'</div>';
905 + print '<svg width="44" height="50" viewBox="0 0 44 50" fill="none" xmlns="http://www.w3.org/2000/svg">
906 + <path d="M20.0777 20.5087L24.3481 17.9427C26.6432 16.5645 29.4554 16.2443 31.96 17.198C33.443 17.7642 35.1166 17.9363 36.852 17.6105C40.3163 16.9521 43.1162 14.1831 43.8115 10.7248C45.0606 4.51597 39.7751 -0.910703 33.5907 0.12835C30.2924 0.682061 27.5604 3.16211 26.5942 6.36168C26.4405 6.86646 26.3418 7.35835 26.2804 7.84466C25.9482 10.5028 24.2498 12.8044 21.9547 14.1827L19.3458 15.7456C17.1061 17.0869 14.3986 17.1792 11.9494 16.2748C10.9956 15.9241 9.96159 15.7271 8.88507 15.7271C3.39004 15.7271 -0.960663 20.7607 0.184097 26.4527C0.879447 29.911 3.67936 32.68 7.14364 33.3384C8.87902 33.6706 10.5525 33.492 12.0356 32.9259C14.5402 31.9721 17.3461 32.2919 19.6475 33.6706L23.906 36.2241C25.346 37.0855 26.2195 38.6424 26.2195 40.3159V40.3403C26.2195 45.8229 31.2287 50.1611 36.9018 49.0472C40.3602 48.3703 43.1415 45.583 43.8244 42.1246C44.9383 36.451 40.6 31.4423 35.1175 31.4423C34.0406 31.4423 33.007 31.6394 32.0532 31.9901C29.604 32.8944 26.9029 32.8022 24.6627 31.4608L20.0721 28.7038C18.6445 27.8484 17.7706 26.304 17.7706 24.6364V24.5875C17.7642 22.9208 18.6441 21.37 20.0777 20.5085L20.0777 20.5087Z" fill="black"/>
907 + </svg>';
908 + esc_html_e('Share','wpstream');
909 + print '</div>';
910 + print '</div>';
911 +
912 +
913 + print '<div class="start_event wpstream_button wpstream_tooltip_wrapper" data-show-id="'.$the_id.'" > '. $button_status;
914 + print '<div class="wpstream_tooltip">'.esc_html__('Channel is now OFF. Click to turn ON.','wpestream').'</div>';
915 + print '</div>';
916 +
917 + print '</div>';
918 +
919 +
920 +
921 +
922 + $this->wpstream_display_modal_seetings($the_id);
923 + $this->wpstream_display_modal_share($the_id);
924 + $this->wpstream_display_modal_broadcast($the_id,$external_software_streaming_class,$obs_uri,$obs_stream);
925 +
926 + print '</div>';
927 +
385 928 }
929 +
930 +
931 + /*
932 + *
933 + * Close modal button
934 + *
935 + */
936 +
386 937 public function wpstream_close_modal_button(){
387 - return $this->main->get_live_channel_presentation()->render_part( 'close_modal_button' );
938 + print '<div class="wpstream_close_modal"></div>';
388 939 }
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 ) );
940 +
941 + public function wpstream_local_event_options_toggle() {
942 + $use_global_event_options = get_post_meta(get_the_ID(), 'use_global_event_options', true );
943 + $local_event_options = get_post_meta( get_the_ID(), 'local_event_options', true );
944 + $use_local_event_options_enabled = ( is_array( $local_event_options ) && empty( $use_global_event_options ) ) ||
945 + ( !empty($use_global_event_options) && intval( $use_global_event_options ) === 0 );
946 +
947 + print '<div class="wpstream_local_event_options_toggle_wrapper">';
948 + print '<div class="wpstream_local_event_options_toggle_info">';
949 + print '<label for="local_event_options_enabled" class="wpstream_local_event_options_label">'.esc_html__('Edit settings for this channel','wpstream').'</label>';
950 + print '<span>'.sprintf(esc_html__('When is OFF, the settings from %s will be applied','wpstream'), '<a href="' . admin_url('admin.php?page=wpstream_settings&tab=default_options') . '" target="_blank">'.esc_html__('Default Channel Settings','wpstream').'</a>').'</span>';
951 + print '</div>';
952 + print '<label class="wpstream_switch">';
953 + print '<input id="local_event_options_enabled" type="checkbox" class="wpstream_local_event_options_toggle" ' . ($use_local_event_options_enabled === true ? 'checked' : '') . '>';
954 + print '<span class="wpstream_slider round"></span>';
955 + print '</label>';
956 + print '</div>';
391 957 }
392 - public function wpstream_basic_stream_mode_message() {
393 - return $this->main->get_live_channel_presentation()->render_part( 'basic_stream_mode_message' );
394 - }
958 +
959 + /*
960 + *
961 + * Display modal settings
962 + *
963 + */
964 +
395 965 public function wpstream_display_modal_seetings($the_id){
396 - return $this->main->get_live_channel_presentation()->render_part( 'settings_modal', array( $the_id ) );
966 + print '<div class="wpstream_modal_form wpestate_settings_modal">';
967 + $this->wpstream_close_modal_button();
968 + print '<h3>';
969 + printf( esc_html__('Channel Settings (#ID %s)','wpstream'),$the_id);
970 + print '</h3>';
971 +
972 + $this->wpstream_local_event_options_toggle();
973 +
974 + $local_event_options = get_post_meta($the_id,'local_event_options',true);
975 + $use_global_event_options = get_post_meta($the_id, 'use_global_event_options',true);
976 + $is_local_event_options_enabled = ( is_array( $local_event_options ) && empty( $use_global_event_options ) ) ||
977 + ( !empty($use_global_event_options) && intval( $use_global_event_options ) === 0 );
978 +
979 + if( !$is_local_event_options_enabled ) {
980 + $local_event_options = get_option('wpstream_user_streaming_global_channel_options') ;
981 + }
982 +
983 + $local_array_exclude=array('ses_encrypt','vod_domain_lock','vod_encrypt');
984 +
985 + print '<div class="wpstream_event_streaming_local">';
986 + $this->user_streaming_global_channel_options(
987 + '',
988 + $local_event_options,
989 + $local_array_exclude,
990 + !$is_local_event_options_enabled,
991 + );
992 + print '</div>';
993 + print '</div>';
397 994 }
995 +
996 +
997 + /*
998 + *
999 + * Display share settings
1000 + *
1001 + */
398 1002 public function wpstream_display_modal_share($the_id){
399 - return $this->main->get_live_channel_presentation()->render_part( 'share_modal', array( $the_id ) );
1003 + print '<div class="wpstream_modal_form wpestate_share_modal">';
1004 + $this->wpstream_close_modal_button();
1005 + print '<h3>'.esc_html__('Share your Channel','wpstream').'</h3>';
1006 + $this->wpstream_social_share($the_id);
1007 + print '</div>';
400 1008 }
1009 +
1010 +
1011 + /*
1012 + *
1013 + * Display broadcast modal
1014 + *
1015 + */
1016 +
401 1017 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 )
405 - );
1018 + print '<div class="wpstream_modal_form wpestate_broadcast_modal">';
1019 + $this->wpstream_close_modal_button();
1020 + print '<h3>'.esc_html__('Go Live with External Streaming App','wpstream').'</h3>';
1021 +
1022 + print '<div class="wpstream_modal_explanations">'.esc_html__('Please choose your RTMP encoder/broadcaster','wpstream').'</div>';
1023 +
1024 + print '<select class="wpstream_external_broadcast_options">';
1025 + print '<option value="wpstream_obs_settings">'.esc_html('OBS','wpstream').'</option>';
1026 + print '<option value="wpstream_streamyard_settings">'.esc_html('StreamYard','wpstream').'</option>';
1027 + print '<option value="wpstream_restream_settings">'.esc_html('Restream','wpstream').'</option>';
1028 + print '<option value="wpstream_wimx_settings">'.esc_html('vMix','wpstream').'</option>';
1029 + print '<option value="wpstream_wirecast_settings">'.esc_html('Wirecast','wpstream').'</option>';
1030 + print '<option value="wpstream_xplit_settings">'.esc_html('XSplit','wpstream').'</option>';
1031 + print '<option value="wpstream_larix_settings">'.esc_html('Larix Broadcaster','wpstream').'</option>';
1032 +
1033 + print '</select>';
1034 +
1035 + $this->wpstream_obs_settings($obs_uri,$obs_stream);
1036 + $this->wpstream_streamyard_settings($obs_uri,$obs_stream);
1037 + $this->wpstream_restream_settings($obs_uri,$obs_stream);
1038 + $this->wpstream_wmix_settings($obs_uri,$obs_stream);
1039 + $this->wpstream_wirecast_settings($obs_uri,$obs_stream);
1040 + $this->wpstream_xplit_settings($obs_uri,$obs_stream);
1041 + $this->wpstream_larix_settings($obs_uri,$obs_stream);
1042 +
1043 + print '</div>';
406 1044 }
407 - public function wpstream_encoder_table(){
408 - return $this->main->get_live_channel_presentation()->render_part( 'encoder_table' );
1045 +
1046 +
1047 +
1048 +
1049 + /*
1050 + *
1051 + * Display OBS settings
1052 + *
1053 + */
1054 +
1055 + public function wpstream_obs_settings($obs_uri,$obs_stream){
1056 +
1057 + print '<div class="external_software_streaming wpstream_obs_settings" style="display:block;">';
1058 +
1059 + print '<div class="external_software_streaming_details">';
1060 + print '<div class="event_list_unit_notificationx"><strong>'.esc_html__('Server:').' </strong>';
1061 + print '<div class="wpstream_live_uri_text">' . $obs_uri.'</div>
1062 + <div class="copy_live_uri">'.__('copy','wpstream').'</div>';
1063 +
1064 + print '<div class="event_list_stream_key_wrap"><strong>'.__('Stream Key:').' </strong>
1065 + <div class="wpstream_live_key_text">'. $obs_stream.'</div><div class="copy_live_key">'.__('copy','wpstream').'</div></div>';
1066 + print '</div>';
1067 +
1068 + print'</div>';
1069 +
1070 + print ' <div class="wpstream_modal_explanations">';
1071 + print '<ul>
1072 + <li>1. Click Settings in the OBS Window and then Select Stream.</li>
1073 + <li>2. Choose Custom Streaming Server in the Stream Type dropdown menu.</li>
1074 + <li>3. In the URL box, type/paste your Server.</li>
1075 + <li>4. In the Stream key, type/paste your Stream key.</li>
1076 + <li>5. Save changes.Close the Settings window and click on the "Start Streaming" button in the main window of OBS.</li></ul>';
1077 +
1078 + print '</div>';
1079 +
1080 +
1081 + print'</div>';
409 1082 }
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 - );
1083 +
1084 + /*
1085 + *
1086 + * Display StreamYard settings
1087 + *
1088 + */
1089 +
1090 + public function wpstream_streamyard_settings($obs_uri,$obs_stream){
1091 +
1092 + print '<div class="external_software_streaming wpstream_streamyard_settings">';
1093 +
1094 + print '<div class="external_software_streaming_details">';
1095 + print '<div class="event_list_unit_notificationx"><strong>'.esc_html__('RTMP server URL:').' </strong>';
1096 + print '<div class="wpstream_live_uri_text">' . $obs_uri.'</div>
1097 + <div class="copy_live_uri">'.__('copy','wpstream').'</div>';
1098 +
1099 + print '<div class="event_list_stream_key_wrap"><strong>'.__('Stream key:').' </strong>
1100 + <div class="wpstream_live_key_text">'. $obs_stream.'</div><div class="copy_live_key">'.__('copy','wpstream').'</div></div>';
1101 + print '</div>';
1102 +
1103 + print'</div>';
1104 +
1105 + print ' <div class="wpstream_modal_explanations">';
1106 + print '<ul>
1107 + <li>1. Set up your destination by going to your StreamYard account.</li>
1108 + <li>2. Choose "Custom RTMP" and add the RTMP server URL and Stream key from WpStream.</li>
1109 + <li>3. Go to "Broadcasts" then "create a broadcast".</li>
1110 + <li>4. Enter Live Studio.</li>
1111 + <li>5. Adjust all your preferred settings and Click on "Go Live".</li></ul>';
1112 +
1113 + print '</div>';
1114 +
1115 +
1116 + print'</div>';
415 1117 }
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(
1118 +
1119 +
1120 +
1121 + /*
1122 + *
1123 + * Display StreamYard settings
1124 + *
1125 + */
1126 +
1127 + public function wpstream_restream_settings($obs_uri,$obs_stream){
1128 +
1129 + print '<div class="external_software_streaming wpstream_restream_settings">';
1130 +
1131 + print '<div class="external_software_streaming_details">';
1132 + print '<div class="event_list_unit_notificationx"><strong>'.esc_html__('RTMP URL:').' </strong>';
1133 + print '<div class="wpstream_live_uri_text">' . $obs_uri.'</div>
1134 + <div class="copy_live_uri">'.__('copy','wpstream').'</div>';
1135 +
1136 + print '<div class="event_list_stream_key_wrap"><strong>'.__('Stream key:').' </strong>
1137 + <div class="wpstream_live_key_text">'. $obs_stream.'</div><div class="copy_live_key">'.__('copy','wpstream').'</div></div>';
1138 + print '</div>';
1139 +
1140 + print'</div>';
1141 +
1142 + print ' <div class="wpstream_modal_explanations">';
1143 + print '<ul>
1144 + <li>1. Go to your Restream account and set up a destination or channel.</li>
1145 + <li>2. Choose "Custom RTMP" and add the RTMP URL and Stream Key from WpStream.</li>
1146 + <li>3. Click on "Add Channel".</li>
1147 + <li>4. Enter Live Studio.</li>
1148 + <li>5. Adjust your preferred settings and Go Live.</li></ul>';
1149 +
1150 + print '</div>';
1151 +
1152 +
1153 + print'</div>';
1154 + }
1155 +
1156 +
1157 +
1158 + /*
1159 + *
1160 + * Display Xplit settings
1161 + *
1162 + */
1163 +
1164 +
1165 + public function wpstream_xplit_settings($obs_uri,$obs_stream){
1166 + print '<div class="external_software_streaming wpstream_xplit_settings" style="display:none;">';
1167 + print '<div class="external_software_streaming_details">';
1168 + print '<div class="event_list_unit_notificationx"><strong>'.esc_html__('RTMP Url:').' </strong>';
1169 + print '<div class="wpstream_live_uri_text">' . $obs_uri.'</div>
1170 + <div class="copy_live_uri">'.__('copy','wpstream').'</div>';
1171 +
1172 + print '<div class="event_list_stream_key_wrap"><strong>'.__('Stream Key:').' </strong>
1173 + <div class="wpstream_live_key_text">'. $obs_stream.'</div><div class="copy_live_key">'.__('copy','wpstream').'</div></div>';
1174 + print '</div>';
1175 +
1176 + print'</div>';
1177 +
1178 + print ' <div class="wpstream_modal_explanations">';
1179 + print '<ul>
1180 + <li>1. Click Broadcast in the XSplit Window and then click "Set up a new output".</li>
1181 + <li>2. Choose Custom RTMP in the Set up a new output dropdown menu.</li>
1182 + <li>3. In the URL box, type/paste your RTMP Url.</li>
1183 + <li>4. In the Stream key, type/paste your Stream key.</li>
1184 + <li>5. Save changes and click on the "Stream" button in the main window.</li></ul>';
1185 + print '</div>';
1186 +
1187 + print '</div>';
1188 + }
1189 +
1190 +
1191 +
1192 + /*
1193 + *
1194 + * Display WireCast settings
1195 + *
1196 + */
1197 +
1198 +
1199 + public function wpstream_wirecast_settings($obs_uri,$obs_stream){
1200 + print '<div class="external_software_streaming wpstream_wirecast_settings" style="display:none;">';
1201 +
1202 + print '<div class="external_software_streaming_details">';
1203 + print '<div class="event_list_unit_notificationx"><strong>'.esc_html__('Address:').' </strong>';
1204 + print '<div class="wpstream_live_uri_text">' . $obs_uri.'</div>
1205 + <div class="copy_live_uri">'.__('copy','wpstream').'</div>';
1206 +
1207 + print '<div class="event_list_stream_key_wrap"><strong>'.__('Stream:').' </strong>
1208 + <div class="wpstream_live_key_text">'. $obs_stream.'</div><div class="copy_live_key">'.__('copy','wpstream').'</div></div>';
1209 + print '</div>';
1210 +
1211 + print'</div>';
1212 +
1213 + print ' <div class="wpstream_modal_explanations">';
1214 + print '<ul>
1215 + <li>1. Click Output on the top of the screen and then Select Output Settings.</li>
1216 + <li>2. In the destination, choose RTMP Server and click OK.</li>
1217 + <li>3. In the Address box, type/paste your Address.</li>
1218 + <li>4. In the Stream box, type/paste your Stream key.</li>
1219 + <li>5. Click on OK to save changes just click the Output on the top of the screen and then Start/Stop Broadcasting.</li></ul>';
1220 + print '</div>';
1221 +
1222 + print '</div>';
1223 + }
1224 +
1225 +
1226 +
1227 + /*
1228 + *
1229 + * Display Larix settings
1230 + *
1231 + */
1232 +
1233 +
1234 + public function wpstream_larix_settings($obs_uri,$obs_stream){
1235 + print '<div class="external_software_streaming wpstream_larix_settings" style="display:none;">';
1236 + $larix_rtmp=$obs_uri.$obs_stream;
1237 + print '<div class="external_software_streaming_details">';
1238 + print '<div class="event_list_unit_notificationx"><strong>'.esc_html__('RTMP:').'</strong>';
1239 + print '<div class="wpstream_live_uri_text wpstream_larix_rtmp"></div>
1240 + <div class="copy_live_uri">'.__('copy','wpstream').'</div>';
1241 +
1242 + print '</div>';
1243 +
1244 + print'</div>';
1245 +
1246 + print ' <div class="wpstream_modal_explanations">';
1247 + print '<ul>
1248 + <li>A. Scan the QR code.</li>
1249 + <li>or</li>
1250 + <li>B. Manually configure Larix with the above RTMP</li>';
1251 + if(wp_is_mobile() ){
1252 + print '
1253 + <li>or</li>
1254 + <li>C. Click on the button below </li></ul>';
1255 + }
1256 +
1257 +
1258 + print '</div>';
1259 +
1260 +
1261 + print '<img class="print_qrcode" src="" />';
1262 + if(wp_is_mobile() ){
1263 + print '<a href="" class="wpstream_start_with_larix_mobile" >Start Streaming with Larix</a>';
1264 + }
1265 +
1266 +
1267 +
1268 + print '</div>';
1269 + }
1270 +
1271 +
1272 +
1273 +
1274 + /*
1275 + *
1276 + * Display Wmix settings
1277 + *
1278 + */
1279 +
1280 +
1281 + public function wpstream_wmix_settings($obs_uri,$obs_stream){
1282 + print '<div class="external_software_streaming wpstream_wimx_settings" style="display:none;">';
1283 +
1284 + print '<div class="external_software_streaming_details">';
1285 + print '<div class="event_list_unit_notificationx"><strong>'.esc_html__('URL:').' </strong>';
1286 + print '<div class="wpstream_live_uri_text">' . $obs_uri.'</div>
1287 + <div class="copy_live_uri">'.__('copy','wpstream').'</div>';
1288 +
1289 + print '<div class="event_list_stream_key_wrap"><strong>'.__('Stream Key:').' </strong>
1290 + <div class="wpstream_live_key_text">'. $obs_stream.'</div><div class="copy_live_key">'.__('copy','wpstream').'</div></div>';
1291 + print '</div>';
1292 +
1293 + print'</div>';
1294 +
1295 + print ' <div class="wpstream_modal_explanations">';
1296 + print '<ul>
1297 + <li>1. Click on the gear icon near the stream button on the bottom.</li>
1298 + <li>2. Choose a custom RTMP Server in destination.</li>
1299 + <li>3. In the URL box, type/paste your URL.</li>
1300 + <li>4. In the Stream key, type/paste your Stream key.</li>
1301 + <li>5. Save changes. You can start streaming by clicking on the stream button at the bottom of the dashboard.</li></ul>';
1302 + print '</div>';
1303 +
1304 + print '</div>';
1305 + }
1306 +
1307 +
1308 +
1309 + /*
1310 + * Set Settings
1311 + *
1312 + *
1313 + */
1314 +
1315 + public function wpstream_settings(){
1316 +
1317 + if( !current_user_can('administrator') ){
1318 + die('Only for administrators');
1319 + }
1320 +
1321 +
1322 + if($_SERVER['REQUEST_METHOD'] === 'POST'){
1323 + if( !wp_verify_nonce($_POST['wpstream-settings-nonce'],'wpstream-settings-nonce') ){
1324 + die('Security check');
1325 + }
1326 +
1327 + $allowed_html = array();
1328 + $exclude_array = array();
1329 + $allowed_html = array();
1330 +
1331 +
1332 +
1333 + if( isset($_POST['user_streaming_channel_type_hidden']) && intval($_POST['user_streaming_channel_type_hidden'])==1 && !isset($_POST['stream_role']) ){
1334 + update_option( sanitize_key('wpstream_stream_role'), '' );
1335 + }
1336 +
1337 + foreach($_POST as $variable=>$value){
1338 + if ($variable!='submit'){
1339 + if (!in_array($variable, $exclude_array) ){
1340 + update_option( sanitize_key('wpstream_'.$variable), sanitize_text_field ($value) );
1341 + }
1342 +
1343 + if($variable=='stream_role'){
1344 + update_option( sanitize_key('wpstream_stream_role'), $value );
1345 + }
1346 +
1347 + }
1348 + }
1349 +
1350 +
1351 + if( isset($_GET['tab']) && $_GET['tab']=='default_options' ){
1352 + $event_settings=array();
1353 + foreach($this->global_event_options as $key=>$option){
1354 + $event_settings[$key]='';
1355 + if(isset($_POST['wpstream_event_set_'.$key]) && $_POST['wpstream_event_set_'.$key]=='on'){
1356 + $event_settings[$key]=1;
1357 + }else{
1358 + $event_settings[$key]=0;
1359 + }
1360 + }
1361 + update_option('wpstream_user_streaming_global_channel_options',$event_settings);
1362 + }
1363 +
1364 +
1365 +
1366 +
1367 + // reset permalinkgs
1368 + global $wp_rewrite;
1369 +
1370 + update_option( "rewrite_rules", FALSE );
1371 + $wp_rewrite->flush_rules( true );
1372 +
1373 + }
1374 +
1375 + $wpstream_settings_array =array(
419 1376 1 => array(
420 1377 'tab' => 'general_options',
421 1378 'label' => esc_html__('Slug for free video/channel pages ','wpstream'),
422 1379 'name' => 'free_media_slug',
@@ -422,16 +1379,8 @@
422 1379 'name' => 'free_media_slug',
423 1380 'type' => 'text',
424 1381 '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 1382 ),
426 -
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 1383
435 1384 2 => array(
436 1385 'tab' => 'general_options',
437 1386 'label' => esc_html__('Non-Admin User Roles Allowed to Broadcast','wpstream'),
@@ -637,199 +1586,30 @@
637 1586 'details' => esc_html__('This is the error log of the plugin.','wpstream'),
638 1587 )
639 1588
640 1589 );
641 - }
642 -
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 - }
656 -
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(){
669 -
670 - // Admin-only screen.
671 - $this->wpstream_require_settings_capability();
672 -
673 -
674 - $active_tab = isset( $_GET['tab'] ) ? sanitize_key( $_GET['tab'] ) : 'general_options';
675 -
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 );
690 -
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 -
715 - // Handle a settings submission.
716 - if($_SERVER['REQUEST_METHOD'] === 'POST'){
717 - // CSRF protection.
718 - check_admin_referer( 'wpstream-settings-nonce', 'wpstream-settings-nonce' );
719 -
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 -
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();
732 -
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 -
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 -
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 -
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 - }
763 -
764 -
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 - }
783 -
784 -
785 -
786 -
787 - // reset permalinkgs
788 - // Slug settings can change permalinks, so drop and rebuild the rewrite rules.
789 - global $wp_rewrite;
790 -
791 - update_option( "rewrite_rules", FALSE );
792 - $wp_rewrite->flush_rules( true );
793 -
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 );
807 -
808 - }
809 -
810 -
811 -
812 -
813 - // Open the settings panel and the form.
1590 +
1591 + $active_tab = 'general_options';
1592 + if( isset( $_GET[ 'tab' ] ) ) {
1593 + $active_tab = $_GET[ 'tab' ];
1594 + }
1595 +
1596 +
814 1597 print '<div class="theme_options_tab_wpstream" style="display:block;" >
815 1598 <h1>'.__('WpStream Settings','wpstream').'</h1>
816 1599 <form method="post" action="" >';
817 1600
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>';
1601 + print '<h2 class="nav-tab-wrapper">
1602 + <a href="?page=wpstream_settings&tab=general_options" class="nav-tab '; echo $active_tab == 'general_options' ? 'nav-tab-active' : ''; echo '">'.esc_html__('General Options','wpstream').'</a>
1603 + <a href="?page=wpstream_settings&tab=default_options" class="nav-tab '; echo $active_tab == 'default_options' ? 'nav-tab-active' : ''; echo '">'.esc_html__('Default Channel Settings','wpstream').'</a>
1604 + <a href="?page=wpstream_settings&tab=default_options_vod" class="nav-tab '; echo $active_tab == 'default_options_vod' ? 'nav-tab-active' : ''; echo '">'.esc_html__('VOD Settings','wpstream').'</a>
1605 + <a href="?page=wpstream_settings&tab=subscription_options" class="nav-tab '; echo $active_tab == 'subscription_options' ? 'nav-tab-active' : '';echo '">'.esc_html__('Subscription Options','wpstream').'</a>
1606 + <a href="?page=wpstream_settings&tab=messages_options" class="nav-tab '; echo $active_tab == 'messages_options' ? 'nav-tab-active' : ''; echo '">'.esc_html__('Customize Messages','wpstream').'</a>
1607 + <a href="?page=wpstream_settings&tab=support_tab" class="nav-tab '; echo $active_tab == 'support_tab' ? 'nav-tab-active' : ''; echo '">'.esc_html__('Support','wpstream').'</a>
1608 + </h2>';
825 1609 $help_link='';
826 -
827 - // Basic-stream mode disables/annotates some default-channel controls.
828 - $is_basic_stream_mode = $this->wpstream_is_basic_streaming_mode();
829 1610 print '<div class="wpstream_option_wrapper">';
830 1611
831 - // Pick the contextual "Video Help" docs link for the active tab.
832 1612 switch ($active_tab) {
833 1613 case 'general_options':
834 1614 $help_link='https://docs.wpstream.net/docs/general-settings/';
835 1615 break;
@@ -847,49 +1627,33 @@
847 1627 break;
848 1628 }
849 1629
850 1630 print '<div class="options_wrapper">';
851 - // Render each field that belongs to the active tab.
852 1631 foreach ($wpstream_settings_array as $key=>$option){
853 - // Skip fields from other tabs.
854 1632 if($option['tab']!=$active_tab){
855 1633 continue;
856 1634 }
857 1635
858 - // Intro blurb (and basic-mode notice) shown above the global channel options control.
859 1636 if ( $option['type']=='user_streaming_global_channel_options' ) {
860 1637 print '<div class="default-channel-settings-info">';
861 1638 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 1639 print '</div>';
866 1640
867 1641 }
868 1642 print '<div class="wpstream_option">';
869 - // Load this option's stored value.
870 1643 $options_value = get_option('wpstream_'.$option['name']) ;
871 -
872 -
873 - // Render the appropriate control for this field's type.
1644 +
1645 +
874 1646 switch( $option['type'] ) {
875 - // Multi-select of WordPress user roles allowed to broadcast.
876 1647 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>';
1648 + print '<label for="'.$option['name'].'">'.$option['label'].'</label>';
1649 + print $this->wpstream_select_user_roles($option['name'],$options_value);
1650 + print '<div class="settings_details">'.$option['details'].'</div>';
880 1651 break;
881 - // The grid of default per-event streaming options.
882 1652 case 'user_streaming_global_channel_options':
883 1653 $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 - );
1654 + $this->user_streaming_global_channel_options($option['name'],$options_value,$exclude_array);
890 1655 break;
891 - // Plain text input; falls back to the field's default when unset.
892 1656 case 'text':
893 1657 if($options_value==''){
894 1658 $options_value='';
895 1659 if(isset($option['default'])){
@@ -896,19 +1660,17 @@
896 1660 $options_value=$option['default'];
897 1661 }
898 1662 }
899 1663
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>';
1664 + print '<label for="'.$option['name'].'">'.$option['label'].'</label>';
1665 + print '<input class="wpstream-text-input-setting" id="'.$option['name'].'" type="'.$option['type'].'" size="36" name="'.$option['name'].'" value="'.esc_attr($options_value).'" />';
1666 + print '<div class="settings_details">'.$option['details'].'</div>';
903 1667 break;
904 - // Dropdown built from the field's select_values map; a hidden mirror marks the field as present.
905 1668 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'] ).'" >';
1669 + print '<label for="'.$option['name'].'">'.$option['label'].'</label>';
1670 + print '<select id="'.$option['name'].'" name="'.$option['name'].'" >';
908 1671 foreach($option['select_values'] as $key=>$value){
909 1672 print '<option value="'.$key.'" ';
910 - // Pre-select the currently stored value.
911 1673 if( $key == esc_html($options_value) ){
912 1674 print ' selected ';
913 1675 }
914 1676 print '>'.$value.'</option>';
@@ -913,19 +1675,18 @@
913 1675 }
914 1676 print '>'.$value.'</option>';
915 1677 }
916 1678 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>';
1679 + print '<input type="hidden" name="'.$option['name'].'_hidden" value="1" >';
1680 + print '<div class="settings_details">'.$option['details'].'</div>';
919 1681 break;
920 - // On/off switch; a hidden 0-valued twin ensures "off" posts a value.
921 1682 case 'slidertoogle':
922 - print '<label for="'.esc_attr( $option['name'] ).'">'.wp_kses_post( $option['label'] ).'</label>';
1683 + print '<label for="'.$option['name'].'">'.$option['label'].'</label>';
923 1684 print '<div style="display: flex; gap: 25px; justify-content: space-between;">';
924 - print '<div class="settings_details">'.wp_kses_post( $option['details'] ).'</div>';
1685 + print '<div class="settings_details">'.$option['details'].'</div>';
925 1686 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'] ).'" ';
1687 + <input type="hidden" class="wpstream_event_option_itemc" value="0" name="'.$option['name'].'" >
1688 + <input type="checkbox" class="wpstream_event_option_itemc" value="1" name="'.$option['name'].'" ';
928 1689 if( intval($options_value) !==0 ){
929 1690 print ' checked ';
930 1691 }
931 1692 print '> <span class="wpstream_slider round"></span>';
@@ -931,16 +1692,15 @@
931 1692 print '> <span class="wpstream_slider round"></span>';
932 1693 print '</label>';
933 1694 print '</div>';
934 1695 break;
935 - // Media-library image picker with preview + upload/remove buttons.
936 1696 case 'image':
937 1697 $image_url = $options_value ? esc_url($options_value) : '';
938 1698 $has_image = !empty($image_url);
939 1699
940 - print '<label for="' . esc_attr( $option['name'] ) . '">' . wp_kses_post( $option['label'] ) . '</label>';
1700 + print '<label for="' . $option['name'] . '">' . $option['label'] . '</label>';
941 1701 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 . '" />';
1702 + print '<input type="hidden" id="' . $option['name'] . '" name="' . $option['name'] . '" value="' . $image_url . '" />';
943 1703
944 1704 // Preview area
945 1705 print '<div class="wpstream-image-preview" style="' . (!$has_image ? 'display:none;' : '') . '">';
946 1706 print '<img src="' . $image_url . '" alt="Preview" />';
@@ -952,17 +1712,15 @@
952 1712 print '<button type="button" class="wpstream-remove-image button" style="' . (!$has_image ? 'display:none;' : '') . '">' . esc_html__('Remove Image', 'wpstream') . '</button>';
953 1713 print '</div>';
954 1714
955 1715 print '</div>';
956 - print '<div class="settings_details">' . wp_kses_post( $option['details'] ) . '</div>';
1716 + print '<div class="settings_details">' . $option['details'] . '</div>';
957 1717 break;
958 - // 0-100 range slider.
959 1718 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>';
1719 + print '<label for="'.$option['name'].'">'.$option['label'].'</label>';
1720 + print '<input class="wpstream-range-input" type="range" id="'.$option['name'].'" name="'.$option['name'].'" min="0" max="100" step="10" value="'.esc_attr($options_value).'" />';
1721 + print '<div class="settings_details">'.$option['details'].'</div>';
963 1722 break;
964 - // Delegates to the Support tab renderer (plugin error log table).
965 1723 case 'logs_table':
966 1724 $this->wpstream_support_tab();
967 1725 break;
968 1726 }
@@ -967,23 +1725,9 @@
967 1725 break;
968 1726 }
969 1727 print '</div>';
970 1728 }
971 -
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 1729 print '</div>'; // options wrapper
985 - // Contextual help link for tabs that have one.
986 1730 if($help_link!==''){
987 1731 print '<div class="wpstream_options_help"><a href="'.esc_url($help_link).'" target="_blank" >'.esc_html__('Video Help','wpstream').'</a></div>';
988 1732 }
989 1733 print '</div>';
@@ -988,9 +1732,8 @@
988 1732 }
989 1733 print '</div>';
990 1734
991 1735
992 - // Save button (hidden on the read-only Support tab).
993 1736 if ( $active_tab != 'support_tab') {
994 1737 print '<div class="wpstream-save-settings">';
995 1738 print '<input type="submit" name="submit" class="wpstream_button wpstream_button_action" value="'.__('Save Changes','wpstream').'" />';
996 1739 print '<div class="spinner"></div>';
@@ -996,13 +1739,12 @@
996 1739 print '<div class="spinner"></div>';
997 1740 print '</div>';
998 1741 }
999 1742
1000 - // CSRF nonce for the submission handled at the top of this method.
1001 1743 print '<input id="wpstream-settings-nonce" name="wpstream-settings-nonce" type="hidden" value="'.wp_create_nonce('wpstream-settings-nonce').'" /> ';
1002 1744 print '</form>';
1003 1745 print '</div>';
1004 -
1746 +
1005 1747 }
1006 1748
1007 1749 /**
1008 1750 * Get system information for support tab
@@ -1011,9 +1753,8 @@
1011 1753 */
1012 1754 private function get_system_info() {
1013 1755 global $wp_version;
1014 1756
1015 - // Environment facts: PHP/WP version, debug flag, memory limit and the plugin version.
1016 1757 $php_version = phpversion();
1017 1758 $wp_version_info = $wp_version;
1018 1759 $site_debug_mode = (defined('WP_DEBUG') && WP_DEBUG);
1019 1760 $wp_memory_limit = WP_MEMORY_LIMIT;
@@ -1021,9 +1762,8 @@
1021 1762 $wpstream_version = WPSTREAM_PLUGIN_VERSION;
1022 1763 $wpstream_plugin_outdated = false;
1023 1764
1024 1765 // Check if plugin is outdated
1025 - // Mark the plugin outdated if WP's update transient lists an available update for it.
1026 1766 $update_plugins = get_site_transient('update_plugins');
1027 1767 if (isset($update_plugins->response['plugin/wpstream.php'])) {
1028 1768 $wpstream_plugin_outdated = true;
1029 1769 }
@@ -1028,15 +1768,14 @@
1028 1768 $wpstream_plugin_outdated = true;
1029 1769 }
1030 1770
1031 1771 // Check API status
1032 - // API is "connected" when a WpStream cloud token can be obtained.
1033 1772 $api_status = false;
1034 - if (method_exists($this->main->wpstream_live_connection, 'is_connected')) {
1035 - $api_status = $this->main->wpstream_live_connection->is_connected();
1773 + if (method_exists($this->main->wpstream_live_connection, 'wpstream_get_token')) {
1774 + $token = $this->main->wpstream_live_connection->wpstream_get_token();
1775 + $api_status = !empty($token);
1036 1776 }
1037 1777
1038 - // Return the collected diagnostics for the Support tab to render.
1039 1778 return array(
1040 1779 'php_version' => $php_version,
1041 1780 'wp_version' => $wp_version_info,
1042 1781 'site_debug_mode' => $site_debug_mode,
@@ -1048,19 +1787,11 @@
1048 1787 }
1049 1788
1050 1789 /**
1051 1790 * 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 1791 */
1059 1792 private function render_system_info() {
1060 - // Pull the current environment diagnostics.
1061 1793 $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 1794 ?>
1064 1795
1065 1796 <div class="wpstream-system-info">
1066 1797 <h3><?php esc_html_e('System Information', 'wpstream'); ?></h3>
@@ -1153,17 +1884,10 @@
1153 1884 }
1154 1885
1155 1886 /**
1156 1887 * 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 1888 */
1164 1889 public function wpstream_support_tab() {
1165 - // Below: Support tab markup (system info, active plugins table, recent logs table).
1166 1890 ?>
1167 1891 <div class="wrap">
1168 1892 <div class="wpstream-support-tab-root">
1169 1893 <?php $this->render_system_info(); ?>
@@ -1178,14 +1902,12 @@
1178 1902 </tr>
1179 1903 </thead>
1180 1904 <tbody>
1181 1905 <?php
1182 - // Build the relevant-plugins list; show a placeholder row when none are found.
1183 1906 $plugins_data = $this->wpstream_get_plugins_data();
1184 1907 if (empty($plugins_data)) {
1185 1908 echo '<tr><td colspan="3">' . esc_html__('No WPStream plugins found.', 'wpstream') . '</td></tr>';
1186 1909 } else {
1187 - // One row per plugin; append an "update available" tooltip when a newer version exists.
1188 1910 foreach ($plugins_data as $plugin) {
1189 1911 echo '<tr>';
1190 1912 echo '<td>' . esc_html($plugin['name']) . '</td>';
1191 1913 echo '<td>';
@@ -1220,14 +1942,12 @@
1220 1942 </tr>
1221 1943 </thead>
1222 1944 <tbody>
1223 1945 <?php
1224 - // Load the stored plugin logs; show a placeholder row when empty.
1225 1946 $logs = get_option('wpstream_logs');
1226 1947 if ( !is_array($logs) || empty($logs) ) {
1227 1948 echo '<tr><td colspan="3">' . esc_html__('No logs found.', 'wpstream') . '</td></tr>';
1228 1949 } else {
1229 - // One row per log entry (time, type, description).
1230 1950 foreach ($logs as $log) {
1231 1951 echo '<tr>';
1232 1952 echo '<td>' . esc_html(date('Y-m-d H:i:s', $log['timestamp'] ) ) . '</td>';
1233 1953 echo '<td>' . esc_html($log['type']) . '</td>';
@@ -1246,16 +1966,11 @@
1246 1966
1247 1967 /**
1248 1968 * Get plugins data.
1249 1969 *
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]).
1970 + * @return array
1255 1971 */
1256 1972 public function wpstream_get_plugins_data() {
1257 - // Ensure get_plugins() is available in non-admin contexts.
1258 1973 if (!function_exists('get_plugins')) {
1259 1974 require_once ABSPATH . 'wp-admin/includes/plugin.php';
1260 1975 }
1261 1976
@@ -1283,9 +1998,8 @@
1283 1998 ),
1284 1999
1285 2000 );
1286 2001
1287 - // Build an info array for every installed plugin (filtered down afterwards).
1288 2002 foreach ($all_plugins as $plugin_path => $plugin_data) {
1289 2003 $is_active = is_plugin_active( $plugin_path );
1290 2004 $has_update = isset( $update_data->response[$plugin_path] );
1291 2005
@@ -1296,9 +2010,8 @@
1296 2010 'active' => $is_active ? 'Yes' : 'No',
1297 2011 'needs_update' => $has_update ? 'Yes' : 'No'
1298 2012 ];
1299 2013
1300 - // Record the offered version when an update is pending.
1301 2014 if ($has_update) {
1302 2015 $plugin_info['new_version'] = $update_data->response[$plugin_path]->new_version;
1303 2016 }
1304 2017
@@ -1315,62 +2028,20 @@
1315 2028 }
1316 2029
1317 2030 return $all_plugins_info;
1318 2031 }
1319 -
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
1343 - }
1344 - }
1345 -
1346 -
2032 +
2033 +
1347 2034 /**
1348 2035 * Set user roles
1349 2036 *
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 - ) {
2037 + * @since 3.0.1
2038 + */
1368 2039
1369 - // Render one switch per defined global event option.
2040 + public function user_streaming_global_channel_options( $name, $value, $local_array='', $disabled = false ){
2041 +
1370 2042 foreach($this->global_event_options as $key=>$option){
1371 -
1372 - // Skip options listed in the exclude array (used by the per-channel modal).
2043 +
1373 2044 if( is_array($local_array) && !in_array($key,$local_array)){
1374 2045 print '<div class="wpstream_setting_event_unit_wrapper wpstream-setting-'.esc_attr($key).' ">';
1375 2046
1376 2047 print '<label for="'.$option['name'].'">'.$option['name'].'</label>';
@@ -1379,16 +2050,18 @@
1379 2050 print '<div class="settings_details">'.$option['details'].'</div>';
1380 2051 print '
1381 2052 <label class="wpstream_switch">
1382 2053 <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 ';
2054 + if( isset($value[$key]) ){
2055 + if( intval($value[$key]) !==0 ){
2056 + print ' checked ';
2057 + }
2058 + }else{
2059 + if($option['defaults']=='yes') {
2060 + print ' checked ';
2061 + }
1388 2062 }
1389 - // Disable the switch when requested or in basic-streaming mode.
1390 - if ( $disabled || $is_basic_stream_mode ) {
2063 + if ($disabled) {
1391 2064 print ' disabled ';
1392 2065 }
1393 2066
1394 2067
@@ -1399,10 +2072,10 @@
1399 2072
1400 2073 print '</div>';
1401 2074 }
1402 2075 }
1403 -
1404 -
2076 +
2077 +
1405 2078 }
1406 2079
1407 2080
1408 2081
@@ -1415,29 +2088,19 @@
1415 2088 /*
1416 2089 * Set user roles
1417 2090 *
1418 2091 * @since 3.0.1
1419 - */
1420 - /**
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 - */
2092 + */
2093 +
1428 2094 public function wpstream_select_user_roles($name,$value){
1429 - // Normalize an empty stored value to an array for in_array() below.
1430 2095 if($value==''){
1431 2096 $value=array();
1432 2097 }
1433 -
1434 - // All editable roles minus administrator (admins always can broadcast).
2098 +
1435 2099 $roles = get_editable_roles();
1436 2100 $return = '<select id="wpstream_user_roles" name="'.esc_html($name).'[]" multiple>';
1437 2101 unset( $roles['administrator'] );
1438 -
1439 - // One option per role, pre-selecting those already chosen.
2102 +
1440 2103 foreach ($roles as $key=>$role){
1441 2104 $return .= '<option value="'.$key.'" ';
1442 2105 if( in_array($key, $value) ){
1443 2106 $return .= ' selected ';
@@ -1444,10 +2107,10 @@
1444 2107 }
1445 2108 $return .= '>'.$role['name'].'</option>';
1446 2109 }
1447 2110 $return .= '</select>';
1448 -
1449 -
2111 +
2112 +
1450 2113 return $return;
1451 2114 }
1452 2115
1453 2116
@@ -1454,119 +2117,46 @@
1454 2117 /*
1455 2118 * Set credential admin function
1456 2119 *
1457 2120 * @since 3.0.1
1458 - */
1459 - /**
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 - */
2121 + */
1468 2122 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 -
2123 +
2124 + if($_SERVER['REQUEST_METHOD'] === 'POST'){
1482 2125 $allowed_html = array();
1483 2126 $exclude_array = array();
1484 2127 $allowed_html = array();
1485 2128
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 2129 foreach($_POST as $variable=>$value){
1491 2130 if ($variable!='submit'){
1492 2131 if (!in_array($variable, $exclude_array) ){
1493 2132 switch ( $variable ) {
1494 2133 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 ) ) );
2134 + update_option( sanitize_key('wpstream_api_username'), sanitize_text_field($value) );
1500 2135 break;
1501 2136 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 - }
2137 + update_option( sanitize_key('wpstream_api_password'), $value );
1522 2138 break;
1523 2139 }
1524 2140 }
1525 - }
2141 + }
1526 2142 }
2143 +
2144 +
1527 2145
1528 2146
1529 -
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',' ');
2147 + update_option('wp_estate_token_expire',0);
2148 + update_option('wp_estate_curent_token',' ');
1533 2149 delete_transient( 'wpstream_token_api');
1534 2150 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 - }
2151 + delete_transient('wpstream_request_pack_data_per_user_transient');
1562 2152 }
1563 2153
1564 2154
1565 2155 $allowed_html = array();
2156 +
1566 2157
1567 2158
1568 - // Field definitions for the credentials form (username + password).
1569 2159 $wpstream_options_array =array(
1570 2160 2 => array(
1571 2161 'label' => 'WpStream.net Username or Email',
1572 2162 'name' => 'api_username',
@@ -1580,67 +2170,41 @@
1580 2170
1581 2171 );
1582 2172
1583 2173
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 -
2174 + $token = $this->main->wpstream_live_connection->wpstream_get_token();
2175 + $pack_details = $this->main->wpstream_live_connection->wpstream_request_pack_data_per_user('wpstream_set_wpstream_credentials');
2176 +
1594 2177 $this->main->show_user_data($pack_details);
1595 2178
1596 2179 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 2180 print '<div class="theme_options_tab_wpstream" style="display:block;" >
1600 2181 <h1>'.__('WpStream Credentials','wpstream').'</h1>';
1601 2182
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()== '' ){
2183 +
2184 + if( get_option('wpstream_api_username')=='' || get_option('wpstream_api_password')== '' ){
1610 2185 echo '<div class="api_not_conected wpstream_orange">';
1611 2186 $admin_url_onboard=get_admin_url().'admin.php?page=wpstream_onboard';
1612 2187 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 2188 echo '</div>';
1614 2189
1615 - }else if(!$connected){
1616 - // Translate the literals at definition — gettext cannot extract variable strings.
2190 + }else if($token==''){
1617 2191 $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>';
2192 + ' 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.' :
2193 + 'Not connected to WpStream. Please note the errors above and contact support.';
2194 + echo '<div class="api_not_conected">'.__($text,'wpstream').'</div>';
2195 + }else if( $this->main->wpstream_live_connection->wpstream_client_check_api_status() ){
2196 + echo '<div class="api_conected">'.__('Connected to WpStream.net!','wpstream').'</div>';
1621 2197 }else{
1622 - // Credentials present and a token was obtained: connected.
1623 - echo '<div class="api_conected">'.__('Connected to WpStream.net!','wpstream').'</div>';
2198 + 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 2199 }
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 2200 print '<div class="wpstream_option_wrapper">';
1632 2201 foreach ($wpstream_options_array as $key=>$option){
1633 2202 print '<div class="wpstream_option">';
1634 2203
2204 + $options_value = esc_html( get_option('wpstream_'.$option['name'],'') );
1635 2205 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 - }
2206 + print '<input id="'.$option['name'].'" type="'.$option['type'].'" size="36" name="'.$option['name'].'" value="'.esc_html($options_value).'" />';
1643 2207
1644 2208 print '</div>';
1645 2209 }
1646 2210 print '</div>';
@@ -1645,9 +2209,9 @@
1645 2209 }
1646 2210 print '</div>';
1647 2211
1648 2212
1649 - print '<input type="submit"'.$inputs_disabled.' name="submit" class="wpstream_button wpstream_button_action" value="'.__('Save Changes','wpstream').'" />';
2213 + print '<input type="submit" name="submit" class="wpstream_button wpstream_button_action" value="'.__('Save Changes','wpstream').'" />';
1650 2214
1651 2215 print '<h3>Video Tutorials</h3>';
1652 2216
1653 2217 print '<a class="how_to_videos" target="_blank" href="https://youtu.be/9DQrxsKcpmQ">How to Live Stream to WordPress with OBS</a>';
@@ -1659,18 +2223,17 @@
1659 2223
1660 2224 print '</div>';
1661 2225 print '</form>';
1662 2226
1663 - // Quick-action links: create free / paid channel, or jump to the channels list.
1664 2227 print '<div class="theme_options_tab_wpstream" style="display:block;" >';
1665 2228 $link_new = admin_url('admin.php?page=wpstream_live_channels');
1666 2229 $link_new_paid = admin_url('post-new.php?post_type=product').'&new_stream='. rawurlencode('new');
1667 2230 $link_new_free = admin_url('post-new.php?post_type=wpstream_product');
2231 +
1668 2232
1669 -
1670 2233 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 2234 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>';
2235 + print '<a href="'.esc_url($link_new).'" class="wpstream_no_chanel_add_channel">'.esc_html('My Channels','wpstream').'</a>';
1673 2236 print '</div>';
1674 2237
1675 2238
1676 2239 }
@@ -1679,33 +2242,27 @@
1679 2242
1680 2243 /**
1681 2244 * Media Management
1682 2245 *
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 - */
2246 + * @since 3.0.1
2247 + */
2248 +
1689 2249 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' );
2250 + $pack_details = $this->main->wpstream_live_connection->wpstream_request_pack_data_per_user('wpstream_media_management');
1692 2251
1693 2252 $this->main->show_user_data($pack_details);
1694 2253
1695 2254
1696 - // Upload widget section.
1697 2255 print '<div id="wpstream_media_upload"><h3>'.__('Upload New Recording','wpstream').'</h3>'.$this->wpstream_present_media_upload().'</div>';
1698 2256
1699 - // Existing recordings list section.
1700 2257 print '<div id="wpstream_file_management"><h3 id="video_management_title">'.__('Your Recordings','wpstream').'</h3>'.$this->wpstream_present_file_management().'</div>';
1701 2258
1702 -
2259 +
1703 2260 }
1704 2261
1705 2262
1706 -
1707 2263
2264 +
1708 2265 /**
1709 2266 *
1710 2267 *
1711 2268 * WpStream Pagination
@@ -1714,35 +2271,22 @@
1714 2271 *
1715 2272 *
1716 2273 */
1717 2274
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 2275 public function wpstream_pagination($pages , $range = 2) {
1726 2276 $return='';
1727 - // Total visible window width around the current page.
1728 2277 $showitems = ($range * 2) + 1;
1729 - // Current page from the query string (defaults to 1).
1730 2278 $paged = ( isset( $_GET['paged'] ) ) ? intval($_GET['paged']) : 1;
1731 2279
1732 2280
1733 - // Only render a pager when there is more than one page.
1734 2281 if (1 != $pages && $pages != 0) {
1735 2282 $return.= '<ul class="pagination wpstream_pagination">';
1736 - // "Previous" arrow.
1737 2283 $return.= "<li class=\"roundleft\"><a href='" . get_pagenum_link($paged - 1) . "'><</a></li>";
1738 2284
1739 2285 $last_page = get_pagenum_link($pages);
1740 - // Emit page-number links, but only those within the visible window (or all if they fit).
1741 2286 for ($i = 1; $i <= $pages; $i++) {
1742 2287 if (1 != $pages && (!($i >= $paged + $range + 1 || $i <= $paged - $range - 1) || $pages <= $showitems )) {
1743 2288 if ($paged == $i) {
1744 - // Current page marker.
1745 2289 $return.= '<li class="active"><a href="' . esc_url(get_pagenum_link($i)) . '" >' . $i . '</a><li>';
1746 2290 } else {
1747 2291 $return.= '<li><a href="' . esc_url(get_pagenum_link($i)) . '" >' . $i . '</a><li>';
1748 2292 }
@@ -1748,9 +2292,8 @@
1748 2292 }
1749 2293 }
1750 2294 }
1751 2295
1752 - // "Next" target, clamped to the last page.
1753 2296 $prev_page = get_pagenum_link($paged + 1);
1754 2297 if (($paged + 1) > $pages) {
1755 2298 $prev_page = get_pagenum_link($paged);
1756 2299 } else {
@@ -1757,9 +2300,8 @@
1757 2300 $prev_page = get_pagenum_link($paged + 1);
1758 2301 }
1759 2302
1760 2303
1761 - // "Next" and "Last" arrows, then close the list.
1762 2304 $return.= "<li class=\"roundright\"><a href='" . $prev_page . "'>></a><li>";
1763 2305 $return.= "<li class=\"roundright\"><a href='" . $last_page . "'>>><li>";
1764 2306 $return.= "</ul>";
1765 2307 }
@@ -1773,27 +2315,14 @@
1773 2315
1774 2316 /**
1775 2317 * Media upload
1776 2318 *
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 - */
2319 + * @since 3.0.1
2320 + */
1784 2321 public function wpstream_present_media_upload(){
1785 2322 $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 2323 $formInputs=$this->main->wpstream_live_connection->wpstream_get_signed_form_upload_data();
1794 -
1795 - // On failure, show either a "not connected" or an "out of quota" message.
2324 +
1796 2325 if( !$formInputs['success'] ){
1797 2326 if ($formInputs['error'] == 'not_connected'){
1798 2327 $to_return.='<div class="wpstream_upload_container">'.esc_html__('Not connected. Please connect to WpStream to upload videos.','wpstream').'</div>';
1799 2328 }
@@ -1802,9 +2331,8 @@
1802 2331 }
1803 2332 return $to_return;
1804 2333 }
1805 2334
1806 - // Signed data obtained: render the direct-to-S3 upload form.
1807 2335 if($formInputs['success'] ===true){
1808 2336
1809 2337
1810 2338
@@ -1830,14 +2358,13 @@
1830 2358 Video codec: <strong>H264</strong>,<br>
1831 2359 Audio codec: <strong>AAC</strong>.<br>
1832 2360 Media will fail to play if it does not follow the above settings.
1833 2361 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) {
2362 + if(is_array($formInputs)){
2363 + foreach ($formInputs['ref'] as $name => $value) {
1837 2364 $to_return.='<input type="hidden" name="'. $name.'" value="'.$value.'">';
1838 - }
1839 - }
2365 + }
2366 + }
1840 2367
1841 2368 $to_return.='
1842 2369 <div class="progress-bar-area"></div></div>
1843 2370 </form>';
@@ -1855,38 +2382,28 @@
1855 2382
1856 2383 /**
1857 2384 * Display movie list
1858 2385 *
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 - */
2386 + * @since 3.0.1
2387 + */
1866 2388 public function wpstream_present_file_management(){
1867 - // Pull the raw recordings payload from the API.
1868 2389 $video_list_raw = $this->main->wpstream_live_connection->wpstream_get_videos_from_api();
1869 2390
1870 - // false means the API call failed / not connected.
1871 2391 if ( $video_list_raw === false ) {
1872 2392 return '<div class="wpstream_upload_container">'.esc_html__('Not connected. Please connect to WpStream to upload videos.','wpstream').'</div>';
1873 2393 }
1874 2394
1875 - // Normalise the completed-items list.
1876 2395 $video_list_raw_array = [];
1877 2396 if( isset( $video_list_raw['items'] ) ){
1878 2397 $video_list_raw_array = $video_list_raw['items'];
1879 2398 }
1880 2399
1881 - // Sort completed items newest-first by their 'time' field.
1882 2400 $keys = array_column( $video_list_raw_array, 'time' );
1883 2401 array_multisort($keys, SORT_DESC , $video_list_raw_array);
1884 -
2402 +
1885 2403 $to_return='';
1886 2404
1887 2405 // show pending items
1888 - // Render still-processing uploads with a "processing" badge.
1889 2406 if ( key_exists( 'pending', $video_list_raw ) && is_array( $video_list_raw['pending'] ) ) {
1890 2407 foreach ( $video_list_raw['pending'] as $key => $video ) {
1891 2408 $video_size = intval($video['size']/1048576);
1892 2409 $video_name = esc_html($video['name']);
@@ -1902,16 +2419,12 @@
1902 2419 }
1903 2420 }
1904 2421
1905 2422 // show uploaded items
1906 - // Render each completed recording with its size, delete/download controls and VOD-creation links.
1907 2423 if( is_array($video_list_raw['items'] ) ) {
1908 2424 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);
2425 + $video_size = intval($video['size']/1048576);
2426 + $video_name = esc_html($video['name']);
1914 2427 if($video_name!=''):
1915 2428 $to_return.='<div class="wpstream_video_wrapper">';
1916 2429
1917 2430 $to_return.='<div class="wpstream_video_title">';
@@ -1916,36 +2429,31 @@
1916 2429
1917 2430 $to_return.='<div class="wpstream_video_title">';
1918 2431 $to_return.='<div class="wpstream_video_notice"></div></div>';
1919 2432 $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.
2433 + $to_return.=' <div class="wpstream_delete_media" ';
2434 + $to_return.=' onclick="return confirm(\' Are you sure you wish to delete '.$video_name.'?\')" data-filename="'.$video_name.'">'.esc_html__('delete file','wpstream').'</div>';
1925 2435 $to_return.='<div class="wpstream_get_download_link" data-filename="'.$video_name.'">'.esc_html__('download','wpstream').'</div>';
1926 2436 $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 2437
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);
2438 + $add_free_video_url=admin_url('post-new.php?post_type=wpstream_product_vod').'&new_video_name='. rawurlencode($video_name);
2439 + $add_paid_video_url=admin_url('post-new.php?post_type=product').'&new_video_name='. rawurlencode($video_name);
1931 2440
1932 2441
1933 2442
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>';
2443 + $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 2444 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>';
2445 + $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 2446 }
1938 -
2447 +
1939 2448 $to_return.='</div>';
1940 2449 endif;
1941 -
2450 +
1942 2451 }
1943 2452 $current_page= get_current_screen();
1944 2453 }
1945 2454
1946 2455 // no items to show
1947 - // Empty-state message when there are neither completed nor pending items.
1948 2456 if ( !is_array( $video_list_raw['items'] ) || ( key_exists( 'pending', $video_list_raw ) && !is_array( $video_list_raw['pending'] ) ) ) {
1949 2457 $to_return.= '<div class="wpstream_video_wrapper">'.esc_html__('You don\'t have any videos.','wpstream').'</div>';
1950 2458 }
1951 2459 return $to_return;
@@ -1952,233 +2460,97 @@
1952 2460 }
1953 2461
1954 2462
1955 2463 /**
1956 - * Preserve the legacy free-Channel publish marker.
2464 + * Set defualt channels values
1957 2465 *
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 - */
2466 + * @since 3.0.1
2467 + */
2468 +
2469 +
2470 +
2471 +
1966 2472 public function wpstream_publish_wpstream_product($post_id,$post){
1967 - // Only applies to free channel posts.
1968 2473 if( $post->post_type == 'wpstream_product' ){
1969 - // Preserve the legacy marker used by existing installations.
1970 2474 update_post_meta ($post_id,'local_event_options_test','working_on_'.$post_id);
1971 - }
1972 - }
2475 + $to_save_option=array();
1973 2476
1974 - /**
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 - }
2477 + $global_options= get_option('wpstream_user_streaming_global_channel_options');
2478 +
2479 + $local_events = get_post_meta ($post_id ,'local_event_options',true) ;
2480 +
2481 + if( $local_events =='' ){
2482 + if( is_array($global_options) ){
2483 + foreach($global_options as $key=>$value){
2484 + $to_save_option[sanitize_key($key)]=sanitize_text_field($value);
2485 + }
2486 +
2487 + update_post_meta ($post_id,'local_event_options',$to_save_option);
2488 +
2489 + }
2490 + }
1994 2491
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 ) ) {
2007 - return;
2008 - }
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 2492
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;
2039 2493 }
2040 -
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 -
2046 - $this->main->wpstream_live_connection->wpstream_delete_channel( $post_id );
2047 2494 }
2048 2495
2049 2496 /**
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 - }
2065 -
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 2497 * save meta options
2082 2498 *
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.
2499 + * @since 3.0.1
2500 + */
2501 + public function wpstream_free_product_update_post($post_id,$post){
2502 +
2095 2503 if(!is_object($post) || !isset($post->post_type)) {
2096 2504 return;
2097 2505 }
2098 2506
2099 2507
2508 +
2100 2509
2101 2510
2102 2511
2103 - // Only handle the free channel and VOD post types.
2512 +
2104 2513 if( $post->post_type == 'wpstream_product' ||
2105 2514 $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.
2515 +
2114 2516 $allowed_keys=array(
2115 2517 'wpstream_product_type',
2116 2518 'wpstream_free_video',
2117 - 'wpstream_free_video_external',
2118 - 'wpstream_closed_captions_file'
2519 + 'wpstream_free_video_external'
2119 2520 );
2120 2521
2121 2522
2122 - // Save each allow-listed, scalar POST field as sanitized post meta.
2123 2523 foreach ($_POST as $key => $value) {
2124 2524 if( !is_array ($value) ){
2125 2525 if (in_array ($key, $allowed_keys)) {
2126 - $postmeta = sanitize_text_field ( $value );
2526 + $postmeta = sanitize_text_field ( $value );
2127 2527 update_post_meta($post_id, sanitize_key($key), $postmeta );
2128 2528 }
2129 - }
2529 + }
2130 2530 }
2131 2531
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 2532 endif;
2149 2533
2150 2534 }
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 2535
2160 2536
2161 2537 /**
2162 2538 * save meta options
2163 2539 *
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 - */
2540 + * @since 3.0.1
2541 + */
2171 2542 public function add_wpstream_product_metaboxes() {
2172 2543 global $post;
2173 2544 $post_id = $post->ID;
2174 -
2175 -
2176 - // VOD settings metabox and the bundle video-collection metabox.
2545 +
2546 +
2547 +
2548 +
2177 2549 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 2550 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.
2551 + add_meta_box( 'woocommerce-product-data', esc_html__( 'Product Data', 'wpstream' ), 'woocommerce_product_data_box', 'product', 'normal', 'default' );
2552 +
2181 2553 if(function_exists('wc_get_product')):
2182 2554 $product = wc_get_product( $post_id );
2183 2555 if ( $product ) {
2184 2556
@@ -2186,9 +2558,9 @@
2186 2558 add_meta_box(
2187 2559 'wpstream_woo_custom_metabox',
2188 2560 esc_html__( 'Video Collection Options', 'wpstream' ),
2189 2561 'wpstream_bundle_custom_metabox_callback',
2190 - 'product',
2562 + 'product',
2191 2563 'normal',
2192 2564 'default'
2193 2565 );
2194 2566 }
@@ -2194,17 +2566,8 @@
2194 2566 }
2195 2567 }
2196 2568 endif;
2197 2569
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 );
2207 2570 }
2208 2571
2209 2572
2210 2573 /**
@@ -2209,28 +2572,21 @@
2209 2572
2210 2573 /**
2211 2574 * make woocomerce virtual products
2212 2575 *
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
2576 + * @since 3.0.1
2220 2577 */
2578 +
2579 +
2221 2580 public function wpstream_make_product_virtual($post_id,$post){
2222 2581 global $post;
2223 2582 if(isset($post->ID)){
2224 - // Only WooCommerce products are relevant.
2225 2583 if ( $post->post_type !== 'product' ) return;
2226 - // Mark WpStream product types as virtual.
2227 2584 $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 - ){
2232 - update_post_meta( $post->ID, '_virtual', 'yes' );
2585 + if( $term_list[0]->name=='video_on_demand' ||
2586 + $term_list[0]->name=='live_stream' ||
2587 + $term_list[0]->name=='wpstream_bundle'){
2588 + update_post_meta( $post->ID, '_virtual', 'yes' );
2233 2589 }
2234 2590 }
2235 2591 }
2236 2592
@@ -2238,38 +2594,28 @@
2238 2594
2239 2595 /**
2240 2596 * render meta options
2241 2597 *
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 - */
2598 + * @since 3.0.1
2599 + */
2250 2600 public function display_meta_options( $post ) {
2251 - // Nonce for the metabox save + use the global post object.
2252 2601 wp_nonce_field( plugin_basename( __FILE__ ), 'estate_agent_noncename' );
2253 2602 global $post;
2254 2603
2255 - // Determine the pre-selected media type / video.
2256 2604 $is_live = '';
2257 2605 $is_video = '';
2258 2606 $is_video_external = '';
2259 - // When arriving from "create VOD from recording", preselect the recording.
2260 2607 if( isset( $_GET['new_video_name']) && $_GET['new_video_name']!='' ){
2261 2608 $is_video = ' selected ';
2262 2609 $wpstream_free_video = esc_html( $_GET['new_video_name']);
2263 2610 }else{
2264 - // Otherwise read the saved type/video from post meta and select accordingly.
2265 2611 $wpstream_product_type = esc_html(get_post_meta($post->ID, 'wpstream_product_type', true));
2266 2612 $wpstream_free_video = esc_html(get_post_meta($post->ID, 'wpstream_free_video', true));
2267 -
2613 +
2268 2614 if($wpstream_product_type==1){
2269 2615 $is_live = ' selected ';
2270 2616 }
2271 -
2617 +
2272 2618 if($wpstream_product_type==2){
2273 2619 $is_video = ' selected ';
2274 2620 }
2275 2621
@@ -2277,9 +2623,8 @@
2277 2623 $is_video_external = ' selected ';
2278 2624 }
2279 2625 }
2280 2626
2281 - // Media-type dropdown (recording vs self-hosted/external).
2282 2627 print'
2283 2628 <p class="meta-options">
2284 2629 <label for="wpstream_product_type">'.__('Media Type:','wpstream').' </label><br />
2285 2630 <select id="wpstream_product_type" name="wpstream_product_type">
@@ -2289,54 +2634,37 @@
2289 2634 </p>
2290 2635 ';
2291 2636
2292 2637
2293 - // Fetch the account's recordings to populate the chooser.
2294 2638 $video_list = $this->main->wpstream_live_connection->wpstream_get_videos();
2639 +
2295 2640
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 />
2641 + print '
2642 + <p class="meta-options video_free">
2643 + <label for="wpstream_free_video">'.__('Choose video:','wpstream').' </label><br />
2301 2644 <select id="wpstream_free_video" name="wpstream_free_video">';
2302 -
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 ';
2645 +
2646 + if(is_array($video_list)){
2647 + foreach ($video_list as $key=>$value){
2648 + print '<option value="'.$key.'"';
2649 + if($wpstream_free_video === $key){
2650 + print ' selected ';
2651 + }
2652 + print '>'.$value.'</option>';
2653 + }
2308 2654 }
2309 - print '>'.$value.'</option>';
2310 - }
2311 - }
2312 - print'</select>';
2313 - print '</p> ';
2314 - print '</div>';
2655 +
2656 + print'
2657 + </select>
2658 + </p>
2659 + ';
2315 2660
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 2661 $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">
2662 + print '<p class="meta-options1 video_free_external">
2334 2663 <label for="wpstream_free_video_external">'.__('Video:','wpstream').' </label><br />
2335 2664
2336 2665 <input id="wpstream_free_video_external" type="text" size="36" name="wpstream_free_video_external" value="'.$wpstream_free_video_external.'" />
2337 2666 <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 2667 if($wpstream_product_type==2){
2340 2668 $show_recording='';
2341 2669 $show_external='style="display:none"';
2342 2670 }else{
@@ -2345,22 +2673,9 @@
2345 2673 }
2346 2674 print '<p '.$show_recording.' class="wpstream_option_vod_source wpstream_show_recording">'.esc_html__('Choose one of your existing recordings.','wpstream').'</p>';
2347 2675 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 2676
2349 - print '</div> ';
2350 -
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 );
2677 + print '</p> ';
2363 2678 }
2364 2679
2365 2680
2366 2681
@@ -2370,64 +2685,31 @@
2370 2685
2371 2686 /**
2372 2687 * Add new product types to Woocommerce select product type
2373 2688 *
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 - */
2689 + * @since 3.0.1
2690 + */
2381 2691 public function wpstream_add_products( $types ){
2382 - $types[ 'live_stream' ] = __( 'Live Channel','wpstream' );
2383 - $types[ 'video_on_demand' ] = __( 'Video On Demand','wpstream' );
2384 -
2692 + $types[ 'live_stream' ] = __( 'Live Channel','wpestream' );
2693 + $types[ 'video_on_demand' ] = __( 'Video On Demand','wpestream' );
2694 +
2385 2695 return $types;
2386 2696 }
2387 2697
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 2698 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 ];
2699 + if ( 'live_stream' === $product_type ) {
2700 + $classname = 'WC_Product_Live_Stream';
2416 2701 }
2702 + if ( 'video_on_demand' === $product_type ) {
2703 + $classname = 'WC_Product_Video_On_Demand';
2704 + }
2417 2705 return $classname;
2418 2706 }
2419 2707
2420 - /**
2421 - * Load the custom WC_Product subclass files when WooCommerce is active.
2422 - *
2423 - * @return void
2424 - */
2425 2708 public function wpstream_add_custom_wc_products() {
2426 - // Require the live-stream and VOD product classes (WooCommerce only).
2427 2709 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';
2710 + require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/class-wc_product_live_stream.php';
2711 + require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/class-wc_product_video_on_demand.php';
2430 2712 }
2431 2713 }
2432 2714
2433 2715 /**
@@ -2433,116 +2715,33 @@
2433 2715 /**
2434 2716 * Js action to do when user pick live stream or video on demand
2435 2717 *
2436 2718 * @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 ) ) {
2719 + */
2720 +
2721 + public function wpstream_products_custom_js() {
2722 + if ( 'product' != get_post_type() ) :
2510 2723 return;
2511 - }
2724 + endif;
2512 2725
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 - }
2726 + ?>
2727 + <script type='text/javascript'>
2728 + jQuery( document ).ready( function() {
2729 + jQuery('.options_group.pricing' ).addClass ( 'show_if_live_stream' ).show();
2730 + jQuery('.options_group.pricing' ).addClass ( 'show_if_video_on_demand' ).show();
2731 + jQuery('.options_group.pricing' ).addClass ( 'show_if_wpstream_bundle' ).show();
2732 +
2733 + jQuery('._sold_individually_field').parent().addClass('show_if_live_stream').show();
2734 + jQuery('._sold_individually_field').parent().addClass('show_if_video_on_demand').show();
2735 + jQuery('._sold_individually_field').parent().addClass('show_if_wpstream_bundle').show();
2736 +
2737 + jQuery('._sold_individually_field').show();
2738 +
2739 + var selected = jQuery('#product-type').val();
2740 + });
2741 + </script>
2742 + <?php
2518 2743
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 2744 }
2546 2745
2547 2746
2548 2747 /**
@@ -2547,21 +2746,16 @@
2547 2746
2548 2747 /**
2549 2748 * Add custom classes to the product types
2550 2749 *
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 - */
2750 + * @since 3.0.1
2751 + */
2752 +
2558 2753 public function wpstream_hide_attributes_data_panel( $tabs) {
2559 -
2560 - // Hide Shipping and show Inventory for WpStream product types.
2754 +
2561 2755 $tabs['shipping']['class'][] = 'hide_if_live_stream hide_if_video_on_demand hide_if_wpstream_bundle';
2562 2756 $tabs['inventory']['class'][] = 'show_if_live_stream show_if_video_on_demand show_if_wpstream_bundle';
2563 -
2757 +
2564 2758 return $tabs;
2565 2759 }
2566 2760
2567 2761
@@ -2568,33 +2762,25 @@
2568 2762
2569 2763 /**
2570 2764 * Hide buy now on products if Netflix mode
2571 2765 *
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 - */
2766 + * @since 3.12
2767 + */
2768 +
2769 +
2581 2770 public function wpstream_hide_buy_now_subscription_mode( $purchaseable_product_wpblog,$product){
2582 2771 $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.
2772 +
2773 + $term_list = wp_get_post_terms($product_id, 'product_type');
2774 +
2588 2775 $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' ){
2776 +
2777 + if($subscription_model==1){ // if we have Neflix mode
2778 + if( $term_list[0]->name=='live_stream' || $term_list[0]->name=='video_on_demand' || $term_list[0]->name=='wpstream_bundle' ){
2593 2779 return false;
2594 2780 }
2595 2781 }
2596 -
2782 +
2597 2783 return $purchaseable_product_wpblog;
2598 2784 }
2599 2785
2600 2786
@@ -2604,46 +2790,31 @@
2604 2790
2605 2791 /**
2606 2792 * Add custom fields to custom product types
2607 2793 *
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 - */
2794 + * @since 3.0.1
2795 + */
2796 +
2615 2797 public function wpstream_add_custom_general_fields() {
2798 +
2799 +
2616 2800 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 2801 if(function_exists('wcs_user_has_subscription')){
2629 - echo '<div class="options_group show_if_subscription">';
2802 + echo '<div class="options_group show_if_subscription">';
2630 2803 woocommerce_wp_select(
2631 2804 array(
2632 2805 'id' => '_subscript_live_event',
2633 2806 'label' => __( 'Is a subscription based live channel ?', 'woocommerce' ),
2634 - 'options' => array("yes"=>"yes","no"=>"no", "none" => "none")
2807 + 'options' => array("yes"=>"yes","no"=>"no")
2635 2808 )
2636 2809 );
2637 2810 echo '</div>';
2638 2811 }
2639 2812
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">';
2813 + echo '<div class="options_group show_if_live_stream" style="border:none;"></div>';
2814 + echo '<div class="options_group show_if_video_on_demand">';
2643 2815
2644 -
2645 - // Pre-selected video: from the new-video query arg, else the saved _movie_url meta.
2816 +
2646 2817 $selected='';
2647 2818 if( isset( $_GET['new_video_name']) && $_GET['new_video_name']!='' ){
2648 2819 $selected=esc_html($_GET['new_video_name']);
2649 2820 }
@@ -2649,11 +2820,10 @@
2649 2820 }
2650 2821 if($selected==''){
2651 2822 $selected= get_post_meta($post->ID,'_movie_url',true);
2652 2823 }
2653 - // Only administrators may assign videos.
2654 2824 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>';
2825 + print '<div style="margin:10px;">'.esc_html('You need to be an administrator in order to assign videos','wpstream').'</div>';
2656 2826 }else{
2657 2827 woocommerce_wp_select(
2658 2828 array(
2659 2829 'id' => '_movie_url',
@@ -2668,12 +2838,11 @@
2668 2838
2669 2839
2670 2840 echo '</div>';
2671 2841
2672 - // "Attach to subscription" multi-select (only when WC Subscriptions is active).
2673 2842 if(function_exists('wcs_user_has_subscription')){
2674 2843 $selected_sub='';
2675 - echo '<div class="options_group show_if_video_on_demand show_if_live_stream">';
2844 + echo '<div class="options_group show_if_video_on_demand show_if_live_stream">';
2676 2845 if( isset( $_GET['wpstream_parent_sub']) && $_GET['wpstream_parent_sub']!='' ){
2677 2846 $selected_sub=esc_html($_GET['wpstream_parent_sub']);
2678 2847 }
2679 2848 if($selected_sub==''){
@@ -2696,19 +2865,11 @@
2696 2865 }
2697 2866 }
2698 2867
2699 2868
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 2869 public function wpstream_return_subscriptions_created(){
2707 - // Seed with the "none" choice.
2708 2870 $return=array('0'=>'none');
2709 -
2710 - // Query all subscription-type products, title-ordered.
2871 +
2711 2872 $args = array(
2712 2873 'post_type' => 'product',
2713 2874 'posts_per_page' => -1,
2714 2875 'orderby' => 'title',
@@ -2721,10 +2882,9 @@
2721 2882 'terms' => array( 'subscription'),
2722 2883 )
2723 2884 )
2724 2885 );
2725 -
2726 - // Collect each subscription's id => title.
2886 +
2727 2887 $subscriptions = new WP_Query($args);
2728 2888 if($subscriptions->have_posts()):
2729 2889 while ($subscriptions->have_posts()): $subscriptions->the_post();
2730 2890 $return[ get_the_ID() ] = get_the_title();
@@ -2729,13 +2889,12 @@
2729 2889 while ($subscriptions->have_posts()): $subscriptions->the_post();
2730 2890 $return[ get_the_ID() ] = get_the_title();
2731 2891 endwhile;
2732 2892 endif;
2733 -
2734 - // Restore the main query and return the map.
2893 +
2735 2894 wp_reset_postdata();
2736 2895 return $return;
2737 -
2896 +
2738 2897 }
2739 2898
2740 2899
2741 2900
@@ -2744,48 +2903,22 @@
2744 2903
2745 2904 /**
2746 2905 * Save custom fields
2747 2906 *
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 - */
2907 + * @since 3.0.1
2908 + */
2909 +
2756 2910 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 2911
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 2912 $permited_values = array(
2779 2913 '_movie_url',
2780 2914 '_subscript_live_event',
2781 2915 '_wpstream_parent_sub',
2782 -
2916 +
2783 2917 );
2784 -
2785 -
2786 -
2787 - // Reset event_passed and save each allow-listed field.
2918 +
2919 +
2920 +
2788 2921 foreach($_POST as $key=>$value){
2789 2922 update_post_meta( $post_id, 'event_passed', 0 );
2790 2923 if( in_array($key, $permited_values) ){
2791 2924 if( !empty( $_POST[$key] ) ){
@@ -2790,14 +2923,13 @@
2790 2923 if( in_array($key, $permited_values) ){
2791 2924 if( !empty( $_POST[$key] ) ){
2792 2925 $key = sanitize_key($key);
2793 2926 $value = sanitize_text_field($_POST[$key]);
2794 -
2795 - // The parent-subscription field is an array; sanitize each element.
2927 +
2796 2928 if($key=='_wpstream_parent_sub'){
2797 2929 $value= $_POST[$key];
2798 2930 $value = array_map("sanitize_text_field", $value);
2799 -
2931 +
2800 2932 }
2801 2933 update_post_meta( $post_id, $key, $value );
2802 2934 }
2803 2935 }
@@ -2808,34 +2940,25 @@
2808 2940
2809 2941 /**
2810 2942 * Add to cart redirect
2811 2943 *
2812 - * Render the simple add-to-cart template for WpStream product types.
2813 - *
2814 - * @since 3.0.1
2815 - * @return void
2816 - */
2944 + * @since 3.0.1
2945 + */
2946 +
2817 2947 public function wpstream_add_to_cart() {
2818 2948 wc_get_template( 'single-product/add-to-cart/simple.php' );
2819 2949 }
2820 2950
2821 -
2951 +
2822 2952 /**
2823 2953 * Replace add to cart button
2824 2954 *
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 - */
2955 + * @since 3.0.1
2956 + */
2833 2957 public function replacing_add_to_cart_button( $button, $product ) {
2834 2958 global $product;
2835 2959 $product_type = $product->get_type();
2836 2960
2837 - // Only WpStream media types get the custom link; others keep the default button.
2838 2961 if($product_type==='live_stream' || $product_type=='video_on_demand'){
2839 2962 return $button = '<a class="button" href="'.get_site_url().'/shop/?add-to-cart=' .$product->get_id(). '&quantity=1">' . __( 'Add to Cart', 'woocommerce' ) . '</a>';
2840 2963 }else{
2841 2964 return $button;
@@ -2845,27 +2968,21 @@
2845 2968
2846 2969 /**
2847 2970 * Admin notices
2848 2971 *
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 - */
2972 + * @since 3.0.1
2973 + */
2856 2974 public function wpstream_admin_notice() {
2857 2975 global $pagenow;
2858 2976 global $typenow;
2859 2977
2860 - // Stored dismissed-notice flags.
2861 2978 $wpstream_notices = get_option('wpstream_notices');
2862 -
2979 +
2863 2980 /*
2864 2981 if ( !in_array( 'woocommerce/woocommerce.php', apply_filters( 'active_plugins', get_option( 'active_plugins' ) ) ) ) {
2865 2982 if( !is_array($wpstream_notices) ||
2866 2983 !isset($wpstream_notices['wpstream_woo_notice']) ||
2867 - ( isset($wpstream_notices['wpstream_woo_notice']) && $wpstream_notices['wpstream_woo_notice']!='yes') ){
2984 + ( isset($wpestate_notices['wpstream_woo_notice']) && $wpestate_notices['wpstream_woo_notice']!='yes') ){
2868 2985
2869 2986
2870 2987 print '<div class="notice wpstream_notices notice-error is-dismissible" data-notice-type="wpstream_woo_notice" >
2871 2988 <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>
@@ -2873,9 +2990,8 @@
2873 2990 }
2874 2991 }
2875 2992 */
2876 2993
2877 - // Hard requirement: warn when the PHP cURL extension is missing.
2878 2994 if( !in_array ('curl', get_loaded_extensions())) {
2879 2995 print '<div class="notice notice-error is-dismissible">
2880 2996 <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>
2881 2997 </div>';
@@ -2881,141 +2997,29 @@
2881 2997 </div>';
2882 2998 }
2883 2999
2884 3000
2885 - // Nonce used by the JS that records notice dismissals.
2886 3001 $ajax_nonce = wp_create_nonce( "wpstream_notice_nonce" );
2887 3002 print '<input type="hidden" id="wpstream_notice_nonce" value="'.esc_html($ajax_nonce).'"/>';
2888 3003
2889 3004 }
2890 -
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;
2908 - }
2909 -
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 -
2915 - // Resolve the answer (false = no usable date), then cache it once.
2916 - $release_date = false;
2917 -
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 -
2922 - if ( $data && isset( $data['versions'] ) ) {
2923 - // no version provided, get the latest version
2924 - if ( ! $version ) {
2925 - $version = $data['version'];
2926 - }
2927 -
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 - }
2935 -
2936 - set_transient( $cache_key, false === $release_date ? 'none' : $release_date, 12 * HOUR_IN_SECONDS );
2937 - return $release_date;
2938 - }
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 -
3005 +
2990 3006 /**
2991 3007 * Admin notices
2992 3008 *
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 - */
3009 + * @since 3.0.1
3010 + */
2999 3011 public function wpstream_update_cache_notice(){
3000 3012
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 - }
3013 + //check_ajax_referer( 'wpstream_notice_nonce', 'security' );
3007 3014
3008 - // Which notice was dismissed.
3009 3015 $notice_type = esc_html($_POST['notice_type']);
3010 3016 $notices = get_option('wp_stream_notices');
3011 3017
3012 - // Normalise to an array.
3013 3018 if(! is_array($notices) ){
3014 3019 $notices=array();
3015 3020 }
3016 3021
3017 - // Flag this notice as dismissed and persist.
3018 3022 $notices[$notice_type]='yes';
3019 3023
3020 3024 update_option('wpstream_notices',$notices);
3021 3025 die();
@@ -3026,65 +3030,107 @@
3026 3030
3027 3031 /**
3028 3032 * Activate metaboxes for Streaming controls on sidebar
3029 3033 *
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 - */
3034 + * @since 3.0.1
3035 + */
3037 3036 public function wpstream_startstreaming_sidebar_meta() {
3038 - return $this->main->get_live_channel_presentation()->register_metaboxes();
3037 + global $post;
3038 + $term_list = wp_get_post_terms($post->ID, 'product_type');
3039 +
3040 + add_meta_box(
3041 + 'wpstream-sidebar-meta',
3042 + esc_html__('Live Streaming', 'wpstream'),
3043 + array($this,'wpstream_start_stream_meta'),
3044 + 'wpstream_product',
3045 + 'side',
3046 + 'high'
3047 + );
3048 +
3049 + $is_subscription_live_event = esc_html(get_post_meta($post->ID,'_subscript_live_event',true));
3050 + if(!is_wp_error( $term_list )){
3051 + if( isset($term_list[0]->name) ){
3052 + if( $term_list[0]->name=='live_stream' || ($term_list[0]->name=='subscription' && $is_subscription_live_event=='yes' ) ){
3053 + add_meta_box('wpstream-sidebar-meta', esc_html__('Live Streaming', 'wpstream'), array($this,'wpstream_start_stream_meta'), 'product', 'side', 'high');
3054 + }
3055 + }
3056 + }
3057 +
3039 3058 }
3059 +
3060 + /**
3061 + * edited 4.0
3062 + *
3063 + * Show Streaming controls on sidebar
3064 + *
3065 + * @since 3.0.1
3066 + */
3040 3067 public function wpstream_start_stream_meta(){
3041 - return $this->main->get_live_channel_presentation()->render_sidebar();
3068 + global $live_event_for_user;
3069 + $live_event_for_user = $this->main->wpstream_live_connection->wpstream_get_live_event_for_user();
3070 +
3071 + global $post;
3072 + $local_event_options = get_post_meta ($post->ID,'local_event_options','');
3073 +
3074 +
3075 +
3076 + if( get_post_status( $post->ID ) === 'publish' ) {
3077 + $ajax_nonce = wp_create_nonce( "wpstream_start_event_nonce" );
3078 + print '<input type="hidden" id="wpstream_start_event_nonce" value="'.$ajax_nonce.'">';
3079 + $pack_details = $this->main->wpstream_live_connection->wpstream_request_pack_data_per_user('wpstream_start_stream_meta');
3080 + if( isset($pack_details['available_data_mb'])){
3081 + if ($pack_details['available_data_mb'] <= 0){
3082 + print '<input type="hidden" id="wpstream_basic_streaming" value="true">';
3083 + }
3084 + }
3085 +
3086 + $this->wpstream_live_stream_unit($post->ID);
3087 + print '<div class="wpstream_modal_background"></div>';
3088 + print '<div class="wpstream_error_modal_notification"><div class="wpstream_error_content">er1</div>
3089 + <div class="wpstream_error_ok wpstream_button" type="button">'.esc_html__('Close','wpstream').'</div>
3090 + </div>';
3091 + } else {
3092 + esc_html_e('To Go Live, please publish your channel first !','wpstream');
3093 + }
3042 3094 }
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 - }
3046 3095
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 - }
3056 3096
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 3097
3066 3098
3067 3099
3100 +
3068 3101 /**
3069 - * Register a hidden dashboard page used as the onboarding wizard endpoint.
3102 + *
3070 3103 *
3071 - * @return void
3104 + *
3072 3105 */
3073 3106 public function add_dashboard_page() {
3074 - $this->main->get_onboarding()->render_part( 'dashboard_page' );
3107 + add_dashboard_page( '', '', 'administrator', 'wpstream-onboarding', '' );
3075 3108 }
3109 +
3076 3110
3077 3111
3078 3112
3079 3113
3080 - /**
3081 - * Bootstrap the full-screen onboarding wizard screen (non-AJAX requests).
3082 - *
3083 - * @return void
3084 - */
3085 3114 public function wpstream_load_onboarding_wizard() {
3086 - $this->main->get_onboarding()->render_part( 'standalone' );
3115 +
3116 + // Check for wizard-specific parameter
3117 + // Allow plugins to disable the onboarding wizard
3118 + // Check if current user is allowed to save settings.
3119 +
3120 +
3121 + // Don't load the interface if doing an ajax call.
3122 + if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
3123 + return;
3124 + }
3125 +
3126 + set_current_screen();
3127 +
3128 + // Remove an action in the Gutenberg plugin ( not core Gutenberg ) which throws an error.
3129 + remove_action( 'admin_print_styles', 'gutenberg_block_editor_admin_print_styles' );
3130 +
3131 + $this->actual_load_onboarding_wizard();
3132 +
3087 3133 }
3088 3134
3089 3135
3090 3136 /*
@@ -3089,30 +3135,62 @@
3089 3135
3090 3136 /*
3091 3137 * Add on boarding to footer
3092 3138 */
3093 - /**
3094 - * On the onboarding admin page, print the onboarding modal into the footer.
3095 - *
3096 - * @return void
3097 - */
3139 +
3140 +
3141 +
3098 3142 public function wpstream_admin_footer_onboarding(){
3099 - $this->main->get_onboarding()->render_part( 'page_footer' );
3143 + if( isset($_GET['page']) && $_GET['page']==='wpstream_onboard') {
3144 + $this->wpstream_onboard_display();
3145 + }
3100 3146 }
3101 3147
3102 3148
3103 3149 /*
3104 3150 * On Board Display
3105 - *
3151 + *
3106 3152 */
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 - */
3153 +
3113 3154 public function wpstream_pre_onboard_display(){
3114 - echo $this->main->get_onboarding()->render();
3155 + $pack_details = $this->main->wpstream_live_connection->wpstream_request_pack_data_per_user('wpstream_pre_onboard_display');
3156 +
3157 + $this->main->show_user_data($pack_details);
3158 +
3159 +
3160 + $thumb= plugin_dir_url( dirname( __FILE__ ) ). 'img/logo_onboarding.svg';
3161 + ?>
3162 +
3163 + <div class="wpstream_quick_start_wrapper">
3164 + <img class="wpstream_onboarding_logo" src="<?php echo esc_url($thumb); ?>" />
3165 +
3166 + <h1><?php print esc_html__('WpStream','wpstream').' <span class="header_special">'.esc_html__('Quick Start','wpstream').'</span>';?></h1>
3167 +
3168 +
3169 + <p>
3170 + <?php esc_html_e('The quick start guide will help you set up Live Streaming, Video On Demand, and Monetization in a fun and interactive way. Give it a shot! ','wpstream');?>
3171 + </p>
3172 +
3173 + <div id="wpstream_trigger_quick_start" class="wpstream_button wpstream_button_action"><?php esc_html_e('Start the Guide','wpstream');?></div>
3174 +
3175 +
3176 +
3177 + </div>
3178 +
3179 +
3180 +
3181 + <script type="text/javascript">
3182 + //<![CDATA[
3183 + jQuery(document).ready(function(){
3184 + jQuery(".wpstream_on_boarding_wrapper").show();
3185 + jQuery(".wpstream_modal_background_onboard").show();
3186 + });
3187 +
3188 + //]]>
3189 + </script>
3190 +
3191 + <?php
3192 +
3115 3193 }
3116 3194
3117 3195
3118 3196
@@ -3125,16 +3203,21 @@
3125 3203 *
3126 3204 * On Boarding Content
3127 3205 *
3128 3206 */
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 - */
3207 +
3208 +
3135 3209 public function wpstream_onboard_display() {
3136 - $this->main->get_onboarding()->render_part( 'wizard' );
3210 + $this->onboarding_wizard_header();
3211 + $this->wpstream_onboarding_step1();
3212 + $this->wpstream_onboarding_step2();
3213 + $this->wpstream_onboarding_step3_live_streaming();
3214 + $this->wpstream_onboarding_step_3_A_live_streaming_free_view();
3215 + $this->wpstream_onboarding_step_3_B_live_streaming_pay_per_view();
3216 + $this->wpstream_onboarding_step4_vod();
3217 + $this->wpstream_onboarding_step_4_free_vod();
3218 + $this->wpstream_onboarding_step_4_ppv_vod();
3219 + $this->onboarding_wizard_footer();
3137 3220 }
3138 3221
3139 3222
3140 3223 /*
@@ -3141,61 +3224,428 @@
3141 3224 *
3142 3225 * On Boarding Step 1 - the login/register
3143 3226 *
3144 3227 */
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 - */
3228 +
3229 +
3152 3230 public function wpstream_onboarding_step1(){
3153 - $this->main->get_onboarding()->render_part( 'account' );
3231 +
3232 + $wpstream_options_array =array(
3233 + 2 => array(
3234 + 'label' => 'WpStream.net Username or Email',
3235 + 'name' => 'api_username',
3236 + 'type' => 'text',
3237 + ),
3238 + 3 => array(
3239 + 'label' => 'WpStream.net Password',
3240 + 'name' => 'api_password',
3241 + 'type' => 'password',
3242 + ),
3243 +
3244 + );
3245 + $token = $this->main->wpstream_live_connection->wpstream_get_token();
3246 +
3247 + ?>
3248 + <div class="wpstream_step_wrapper wpstream_step_1" id="wpstream_step_1">
3249 + <div class="wpstream_has_credential">
3250 + <h1><?php esc_html_e('WpStream Account','wpstream');?></h1>
3251 +
3252 + <div class="wpstream_on_board_login_wrapper_explanations">
3253 + <?php esc_html_e('A WpStream account is required to make use of the plugin.','wpstream');?>
3254 + </div>
3255 +
3256 +
3257 + <div class="wpstream_check_account_status">
3258 + <?php esc_html_e( 'Checking if you are already logged.....', 'wpstream' ); ?>
3259 + </div>
3260 +
3261 + <div class="wpstream_onboarding_notification"></div>
3262 +
3263 + <div class="wpstream_option_wrapper wpstream_on_board_login_wrapper">
3264 + <h2><?php esc_html_e('Login with your WpStream Account','wpstream');?></h2>
3265 + <?php
3266 +
3267 + foreach ($wpstream_options_array as $key=>$option){
3268 + print '<div class="wpstream_option">';
3269 +
3270 + $options_value = esc_html( get_option('wpstream_'.$option['name'],'') );
3271 + print '<label for="'.$option['name'].'">'.$option['label'].'</label>';
3272 + print '<input id="'.$option['name'].'" type="'.$option['type'].'" size="36" name="'.$option['name'].'" value="'.esc_html($options_value).'" />';
3273 +
3274 + print '</div>';
3275 + }
3276 + ?>
3277 + <input type="submit" name="submit" class="wpstream_button wpstream_button_action wpstream_onboard_login" value="<?php esc_html_e('Login','wpstream');?>" />
3278 + </div>
3279 +
3280 +
3281 +
3282 +
3283 + <div class="wpstream_on_board_register_wrapper">
3284 + <h2><?php esc_html_e('Register for a WpStream Account','wpstream');?></h2>
3285 + <div class="wpstream_option">
3286 + <label for="wpstream_register_email"><?php esc_html_e('Your Email','wpstream');?></label>
3287 + <input id="wpstream_register_email" type="text" size="36" name="wpstream_register_email" value="<?php echo get_option('admin_email'); ?>" />
3288 +
3289 + </div>
3290 +
3291 + <div class="wpstream_option">
3292 + <label for="wpstream_register_password"><?php esc_html_e('Your Password','wpstream');?></label>
3293 + <input id="wpstream_register_password" type="text" size="36" name="wpstream_register_password" value="<?php echo $this->randomPassword();?>" />
3294 + </div>
3295 +
3296 +
3297 + <?php
3298 +
3299 + $curl_response_decoded['capthca']='';
3300 + $curl_response_decoded['capthca_id']='';
3301 +
3302 +
3303 + if( isset($_GET['page']) && $_GET['page']==='wpstream_onboard') {
3304 + $url = 'user/getcapthca';
3305 + $curl_post_fields = array();
3306 + $curl_response = $this->main->wpstream_live_connection->wpstream_baker_do_curl_base($url,$curl_post_fields,true);
3307 + $curl_response_decoded = json_decode($curl_response,JSON_OBJECT_AS_ARRAY);
3308 +
3309 + }
3310 +
3311 + ?>
3312 + <div class="wpstream_option">
3313 + <?php print '<div id="wpstream_capthca">'.$curl_response_decoded['capthca'].'</div>';?>
3314 + <label for="wpstream_register_captcha"><?php esc_html_e('Type the characters above','wpstream');?></label>
3315 +
3316 + <input id="wpstream_register_captcha" type="text" size="36" name="wpstream_register_captcha" />
3317 + <input id="wpstream_register_captcha_id" type="hidden" size="36" name="wpstream_register_captcha_id" value="<?php echo esc_html($curl_response_decoded['capthca_id']); ?>" />
3318 + </div>
3319 +
3320 +
3321 +
3322 + <input type="submit" name="submit" class="wpstream_button wpstream_button_action wpstream_onboard_register" value="<?php esc_html_e('register','wpstream');?>" />
3323 + </div>
3324 +
3325 +
3326 + <div id="wpstream_onboarding_action_login"><?php esc_html_e('I already have a WpStream Account','wpstream');?></div>
3327 +
3328 + <div id="wpstream_onboarding_action_register"><?php esc_html_e('Back to Registration','wpstream');?></div>
3329 +
3330 + </div>
3331 +
3332 +
3333 + <?php
3334 + $ajax_nonce = wp_create_nonce( "wpstream_onboarding_nonce");
3335 + print'<input type="hidden" id="wpstream_onboarding_nonce" value="'.esc_html($ajax_nonce).'" /> ';
3336 +
3337 + ?>
3338 +
3339 +
3340 + <div id="wpstream_on_board" class="wpstream_action_next_step" data-nextthing="wpstream_step_2" style="display:none;" >Move to step 2</div>
3341 + </div>
3342 + <?php
3343 +
3344 + if( !is_null( $token ) && trim( $token ) !== '' ) {
3345 + print '<div id="wpstream_have_token"></div>';
3346 + }
3154 3347 }
3348 +
3155 3349
3350 +
3351 +
3352 +
3353 +
3354 +
3355 +
3356 +
3357 +
3358 + /*
3359 + *
3360 + * Generate random pass
3361 + *
3362 + */
3363 +
3156 3364 public function randomPassword() {
3157 - return $this->main->get_onboarding()->render_part( 'password' );
3365 + $alphabet = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890';
3366 + $pass = array(); //remember to declare $pass as an array
3367 + $alphaLength = strlen($alphabet) - 1; //put the length -1 in cache
3368 + for ($i = 0; $i < 8; $i++) {
3369 + $n = rand(0, $alphaLength);
3370 + $pass[] = $alphabet[$n];
3371 + }
3372 + return implode($pass); //turn the array into a string
3158 3373 }
3159 3374
3375 +
3376 + /*
3377 + *
3378 + *
3379 + *
3380 + */
3381 +
3160 3382 public function wpstream_onboarding_step2(){
3161 - $this->main->get_onboarding()->render_part( 'path' );
3383 + ?>
3384 +
3385 + <div class="wpstream_step_wrapper wpstream_step_2" id="wpstream_step_2">
3386 + <h1>Welcome to <span class="header_special">WpStream</span>! How would you like to start?</h1>
3387 +
3388 + <div class="wpstream_accordion_header wpstream_action_next_step" data-nextthing="wpstream_step_3" ><?php esc_html_e('Go LIVE!','wpstream');?></div>
3389 + <div class="wpstram_or">or</div>
3390 + <div class="wpstream_accordion_header wpstream_action_next_step" data-nextthing="wpstream_step_4" ><?php esc_html_e('Create a Video-On-Demand (VOD)','wpstream');?></div>
3391 +
3392 + </div>
3393 +
3394 +
3395 + <?php
3162 3396 }
3163 3397
3398 + /*
3399 + *
3400 + *
3401 + *
3402 + */
3403 +
3164 3404 public function wpstream_onboarding_step3_live_streaming(){
3165 - $this->main->get_onboarding()->render_part( 'live' );
3405 + ?>
3406 +
3407 + <div class="wpstream_step_wrapper wpstream_step_3 wpstream_onboarding_live" id="wpstream_step_3">
3408 + <h1><?php esc_html_e('Do you want to charge a fee for watching?','wpstream'); ?></h1>
3409 +
3410 + <div class="wpstream_accordion_header wpstream_action_next_step wpstream_step_3a" data-nextthing="wpstream_step_3a"><?php esc_html_e('No - Free-To-View (FTV)','wpstream');?></div>
3411 + <div class="wpstram_or">or</div>
3412 + <div class="wpstream_accordion_header wpstream_action_next_step" data-nextthing="wpstream_step_3b" ><?php esc_html_e('Yes - Pay-Per-View (PPV)','wpstream');?></div>
3413 +
3414 + <div class="wpstream_initial_onboarding_controls_wrapper">
3415 + <span class="wpstream_onboard_initial_bubble_prev" data-step="wpstream_step_2"><?php esc_html_e('Prev','wpstream');?></span>
3416 + </div>
3417 +
3418 + </div>
3419 +
3420 +
3421 + <?php
3166 3422 }
3423 +
3424 +
3425 + /*
3426 + *
3427 + *
3428 + *
3429 + */
3430 + public function wpstream_onboarding_step_3_A_live_streaming_free_view(){
3431 + ?>
3432 +
3433 + <div class="wpstream_step_wrapper wpstream_step_3a wpstream_onboarding_live" id="wpstream_step_3a">
3434 + <h1><?php esc_html_e('Let’s create your first FTV live channel','wpstream');?></h1>
3167 3435
3168 - public function wpstream_onboarding_step_3_A_live_streaming_free_view(){
3169 - $this->main->get_onboarding()->render_part( 'live_free' );
3436 + <div id="wpstream_onboard_live_notice" class="wpstream_onboarding_notification"></div>
3437 + <div id="wpstream_onboard_live" class="wpstream_accordion_container">
3438 + <label>Name your first Free-To-View channel</label>
3439 + <input type="text" name="channel_name" id="wpstream_onboarding_channel_name" class="wpstream_onboarding_channel_name" value="<?php esc_html_e('My first FTV channel','wpstream');?>" >
3440 + <input type="submit" name="submit" id="wpstream_on_board_create_channel" class="wpstream_button wpstream_button_action wpstream_onboard_live_action" value="<?php esc_html_e('Create Channel','wpstream');?>" />
3441 +
3442 + </div>
3443 +
3444 + <div class="wpstream_initial_onboarding_controls_wrapper">
3445 + <span class="wpstream_onboard_initial_bubble_prev" data-step="wpstream_step_3"><?php esc_html_e('Prev','wpstream');?></span>
3446 + </div>
3447 +
3448 + </div>
3449 +
3450 +
3451 + <?php
3170 3452 }
3171 3453
3454 +
3455 + /*
3456 + *
3457 + *
3458 + *
3459 + */
3460 +
3172 3461 public function wpstream_onboarding_step_3_B_live_streaming_pay_per_view(){
3173 - $this->main->get_onboarding()->render_part( 'live_ppv' );
3462 + ?>
3463 +
3464 + <div class="wpstream_step_wrapper wpstream_step_3b wpstream_onboarding_live" id="wpstream_step_3b">
3465 + <h1><?php esc_html_e('Make your live stream Pay Per View','wpstream');?></h1>
3466 + <?php
3467 + if ( class_exists( 'WooCommerce' ) ) {
3468 + ?>
3469 + <div id="wpstream_onboard_live_ppv_notice" class="wpstream_onboarding_notification"></div>
3470 + <div id="wpstream_onboard_live_ppv" class="wpstream_accordion_container">
3471 + <label><?php esc_html_e('Choose a name for your channel','wpstream');?></label>
3472 + <input type="text" name="channel_name" id="wpstream_onboarding_channel_name_ppv" class="wpstream_onboarding_channel_name" value="<?php esc_html_e('My First PPV Channel','wpstream');?>">
3473 + <label><?php esc_html_e('Pay-Per-View Price ($)','wpstream');?></label>
3474 + <input type="text" name="channel_name" id="wpstream_onboarding_event_price_ppv" class="wpstream_onboarding_event_price" value="10">
3475 + <input type="submit" name="submit" id="wpstream_onboard_live_ppv_action" class="wpstream_button wpstream_button_action wpstream_onboard_live_ppv_action" value="<?php esc_html_e('Create Channel','wpstream');?>" />
3476 +
3477 + </div>
3478 + <?php
3479 + } else {
3480 + $this->wpstream_onboarding_woo_warning();
3481 + } ?>
3482 +
3483 +
3484 + <div class="wpstream_initial_onboarding_controls_wrapper">
3485 + <span class="wpstream_onboard_initial_bubble_prev" data-step="wpstream_step_3"><?php esc_html_e('Prev','wpstream');?></span>
3486 + </div>
3487 + </div>
3488 + <?php
3174 3489 }
3175 3490
3491 +
3492 +
3493 +
3494 +
3495 +
3496 + /*
3497 + * WooCommerce not installed Warning
3498 + *
3499 + *
3500 + */
3501 +
3176 3502 public function wpstream_onboarding_woo_warning(){
3177 - $this->main->get_onboarding()->render_part( 'woo_warning' );
3503 + print'<div class="wpstream_warning_onboarding">
3504 + '.esc_html__('Pay-Per-View streaming requires WooCommerce. Please install the WooCommerce plugin and try again.','wpstream').'
3505 + </br>
3506 + <div class="wpstream_install_plugin">'. esc_html__('Install WooCommerce','wpstream').'</div>
3507 +
3508 + <div class="wpstream_onboarding_tryagain">'.esc_html__('Try Again','wpstream').'</div>
3509 + </div>';
3178 3510 }
3179 3511
3512 +
3513 + /*
3514 + *
3515 + *
3516 + *
3517 + */
3518 +
3180 3519 public function wpstream_onboarding_step4_vod(){
3181 - $this->main->get_onboarding()->render_part( 'vod' );
3520 + ?>
3521 + <div class="wpstream_step_wrapper wpstream_step_4 wpstream_onboarding_vod" id="wpstream_step_4">
3522 + <h1><?php esc_html_e('Do you want to charge a fee for watching?','wpstream');?></h1>
3523 +
3524 + <div class="wpstream_accordion_header wpstream_action_next_step wpstream_step_4a" data-control="wpstream_onboard_vod_free" data-nextthing="wpstream_step_4a" ><?php esc_html_e('No - Free-To-View (FTV)','wpstream'); ?></div>
3525 + <div class="wpstram_or">or</div>
3526 + <input type="hidden" id="wpstream_onboarding_video_list_nonce" value="<?php echo wp_create_nonce( "wpstream_onboarding_video_list_nonce" ); ?>">
3527 + <div class="wpstream_accordion_header wpstream_action_next_step wpstream_step_4b" data-control="wpstream_onboard_vod_ppv" data-nextthing="wpstream_step_4b" ><?php esc_html_e('Yes - Pay-Per-View (PPV)','wpstream'); ?></div>
3528 + <div class="wpstream_initial_onboarding_controls_wrapper">
3529 + <span class="wpstream_onboard_initial_bubble_prev" data-step="wpstream_step_2"><?php esc_html_e('Prev','wpstream');?></span>
3530 + </div>
3531 +
3532 + </div>
3533 + <?php
3182 3534 }
3183 3535
3536 +
3537 + /*
3538 + *
3539 + *
3540 + *
3541 + */
3184 3542 public function wpstream_onboarding_step_4_free_vod(){
3185 - $this->main->get_onboarding()->render_part( 'vod_free' );
3543 +
3544 + $current_screen=get_current_screen();
3545 + if($current_screen->base !=='wpstream_page_wpstream_onboard'){
3546 + return;
3547 + }
3548 + ?>
3549 +
3550 + <div class="wpstream_step_wrapper wpstream_step_4a wpstream_onboarding_live" id="wpstream_step_4a">
3551 + <h1><?php esc_html_e('Let’s create your first Free-To-View VOD','wpstream');?></h1>
3552 + <div id="wpstream_onboard_vod_free_notice" class="wpstream_onboarding_notification"></div>
3553 + <div id="wpstream_onboard_vod_free" class="wpstream_accordion_container">
3554 + <div class="spinner"></div>
3555 + <div class="wpstream-step-container" style="display: none">
3556 + <label><?php esc_html_e('Name your FTV Video-On-Demand','wpstream')?></label>
3557 + <input type="text" name="channel_name" class="wpstream_onboarding_vod_name" id="wpstream_onboarding_vod_name" value="<?php esc_html_e('My First FTV VOD','wpstream');?>" >
3558 + <div id="wpstream_free_vod_dropdown_videos_list"></div>
3559 + <input type="submit" name="submit" class="wpstream_button wpstream_button_action wpstream_onboard_vod_free_action" id="wpstream_onboard_vod_free_action" value="Create FTV VOD">
3560 + </div>
3561 + </div>
3562 + <?php $this->wpstream_obboarding_file_warning(); ?>
3563 +
3564 + <div class="wpstream_initial_onboarding_controls_wrapper">
3565 + <span class="wpstream_onboard_initial_bubble_prev" data-step="wpstream_step_4"><?php esc_html_e('Prev','wpstream');?></span>
3566 + </div>
3567 +
3568 + </div>
3569 +
3570 +
3571 + <?php
3186 3572 }
3187 3573
3574 + /*
3575 + *
3576 + *
3577 + *
3578 + */
3188 3579 public function wpstream_obboarding_file_warning(){
3189 - $this->main->get_onboarding()->render_part( 'file_warning' );
3580 + print '<div class="wpstream_warning_onboarding" style="display: none">
3581 + '.esc_html__('A recording is needed to create a VOD from. There are no recordings under your account. You can create new recordings by recording a live channel or uploading video files directly.','wpstream').'
3582 + </br>
3583 + <div class="wpstream_upload_video">'.esc_html__('Upload Video','wpstream').'</div>
3584 +
3585 + <div class="wpstream_onboarding_tryagain">'.esc_html__('Try Again','wpstream').'</div>
3586 + </div>';
3190 3587 }
3191 3588
3589 + /*
3590 + *
3591 + *
3592 + *
3593 + */
3192 3594 public function wpstream_onboarding_step_4_ppv_vod(){
3193 - $this->main->get_onboarding()->render_part( 'vod_ppv' );
3595 + $current_screen=get_current_screen();
3596 +
3597 + if($current_screen->base !=='wpstream_page_wpstream_onboard'){
3598 + return;
3599 + }
3600 + ?>
3601 +
3602 + <div class="wpstream_step_wrapper wpstream_step_4b wpstream_onboarding_live" id="wpstream_step_4b">
3603 + <h1><?php esc_html_e('Let\'s create your first Pay-Per-View VOD','wpstream');?></h1>
3604 +
3605 + <div id="wpstream_onboard_vod_ppv_notice" class="wpstream_onboarding_notification"></div>
3606 + <?php
3607 + if ( class_exists( 'WooCommerce' ) ) { ?>
3608 + <div id="wpstream_onboard_vod_ppv" class="wpstream_accordion_container">
3609 + <div class="spinner"></div>
3610 + <div class="wpstream-step-container" style="display: none">
3611 + <label><?php esc_html_e('Name your PPV Video-On-Demand','wpstream'); ?></label>
3612 + <input type="text" name="channel_name" class="wpstream_onboarding_ppv_vod_name" id="wpstream_onboarding_ppv_vod_name" value="<?php esc_html_e('My First PPV VOD','wpstream');?>">
3613 + <div id="wpstream_ppv_vod_dropdown_videos_list"></div>
3614 + <label><?php esc_html_e('Pay-Per-View Price','wpstream');?></label>
3615 + <input type="text" name="channel_name" class="wpstream_onboarding_vod_price" id="wpstream_onboarding_vod_price" value="10">
3616 + <input type="submit" name="submit" class="wpstream_button wpstream_button_action wpstream_onboard_vod_ppv_action" id="wpstream_onboard_vod_ppv_action" value="<?php esc_html_e('Create PPV VOD','wpstream');?>" />
3617 + </div>
3618 + </div>
3619 + <?php $this->wpstream_obboarding_file_warning(); ?>
3620 + <?php } else {
3621 + $this->wpstream_onboarding_woo_warning();
3622 + } ?>
3623 + <div class="wpstream_initial_onboarding_controls_wrapper">
3624 + <span class="wpstream_onboard_initial_bubble_prev" data-step="wpstream_step_4"><?php esc_html_e('Prev','wpstream');?></span>
3625 + </div>
3626 + </div>
3627 + <?php
3194 3628 }
3195 3629
3630 +
3631 +
3632 +
3633 + /*
3634 + *
3635 + * On boarding Header
3636 + *
3637 + */
3196 3638 public function onboarding_wizard_header() {
3197 - $this->main->get_onboarding()->render_part( 'wizard_header' );
3639 + $thumb= plugin_dir_url( dirname( __FILE__ ) ). 'img/logo_onboarding.svg';
3640 + ?>
3641 +
3642 + <div class="wpstream_on_boarding_wrapper">
3643 + <div class="wpstream_close_onboarding wpstream_close_initial_onboarding"></div>
3644 + <img class="wpstream_onboarding_logo" src="<?php echo esc_url($thumb); ?>" />
3645 + <div class="wpstream_close_onboarding_warning"></div>
3646 +
3647 + <?php
3198 3648 }
3199 3649
3200 3650
3201 3651
@@ -3205,15 +3655,13 @@
3205 3655 *
3206 3656 * On Boarding Footer
3207 3657 *
3208 3658 */
3209 - /**
3210 - * Close the onboarding wizard wrapper and print its modal background. Echoes HTML.
3211 - *
3212 - * @return void
3213 - */
3214 3659 public function onboarding_wizard_footer() {
3215 - $this->main->get_onboarding()->render_part( 'wizard_footer' );
3660 + ?>
3661 + </div>
3662 + <div class="wpstream_modal_background_onboard"></div>
3663 + <?php
3216 3664 }
3217 3665
3218 3666
3219 3667
@@ -3223,19 +3671,63 @@
3223 3671 *
3224 3672 */
3225 3673
3226 3674
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 3675 public function wpstream_on_board_create_channel_ppv(){
3237 - return $this->main->get_onboarding()->handle_ajax( 'wpstream_on_board_create_channel_ppv' );
3676 + check_ajax_referer( 'wpstream_onboarding_nonce', 'security' );
3677 + $current_user = wp_get_current_user();
3678 +
3679 + if(current_user_can('administrator')){
3680 + $channel_name = sanitize_text_field($_POST['channel_name']);
3681 + $channel_price = floatval($_POST['channel_price']);
3682 + $my_post = array(
3683 + 'post_title' => $channel_name,
3684 + 'post_content' => '',
3685 + 'post_status' => 'publish',
3686 + 'post_type' => 'product',
3687 + 'post_author' => $current_user->ID
3688 + );
3689 +
3690 + // Insert the post into the database
3691 + $post_id = wp_insert_post( $my_post );
3692 +
3693 + if(is_wp_error($post_id)){
3694 + $logger = new WPStream_Logger();
3695 + $log_entry = new WpStream_Log_Entry([
3696 + 'type' => 'error',
3697 + 'description' => 'Couldn\'t create channel during onboarding because of error: ' . $post_id->get_error_message(),
3698 + ]);
3699 + $logger->add( $log_entry );
3700 + echo json_encode( array('succes'=>false) );
3701 + }else{
3702 +
3703 + $product = wc_get_product($post_id);
3704 + $price = wc_format_decimal($channel_price);
3705 +
3706 + $product = wc_get_product( $post_id );
3707 + $product->set_price( $price );
3708 + $product->set_regular_price( $price ); // To be sure
3709 + $product->save();
3710 + update_post_meta ($post_id,'event_passed',0);
3711 + wp_set_object_terms( $post_id, 'live_stream', 'product_type' );
3712 +
3713 +
3714 +
3715 +
3716 + $permalink = get_edit_post_link($post_id);
3717 +
3718 + $permalink= add_query_arg( 'onboard', 'yes', $permalink );
3719 + $permalink= add_query_arg( 'branch', '2', $permalink );
3720 +
3721 +
3722 + echo json_encode( array(
3723 + 'success'=> true,
3724 + 'link' => ($permalink)
3725 + ));
3726 + }
3727 +
3728 + }
3729 + die();
3238 3730 }
3239 3731
3240 3732 /*
3241 3733 *
@@ -3243,18 +3735,46 @@
3243 3735 *
3244 3736 */
3245 3737
3246 3738
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 3739 public function wpstream_on_board_create_channel(){
3256 - return $this->main->get_onboarding()->handle_ajax( 'wpstream_on_board_create_channel' );
3740 + check_ajax_referer( 'wpstream_onboarding_nonce', 'security' );
3741 + $current_user = wp_get_current_user();
3742 +
3743 + if(current_user_can('administrator')){
3744 + $channel_name=sanitize_text_field($_POST['channel_name']);
3745 + $my_post = array(
3746 + 'post_title' => $channel_name,
3747 + 'post_content' => '',
3748 + 'post_status' => 'publish',
3749 + 'post_type' => 'wpstream_product',
3750 + 'post_author' => $current_user->ID
3751 + );
3752 +
3753 + // Insert the post into the database
3754 + $post_id = wp_insert_post( $my_post );
3755 +
3756 + if( is_wp_error( $post_id ) ) {
3757 + $logger = new WPStream_Logger();
3758 + $log_entry = new WpStream_Log_Entry([
3759 + 'type' => 'error',
3760 + 'description' => 'Couldn\'t create channel during onboarding because of error: ' . $post_id->get_error_message(),
3761 + ]);
3762 + $logger->add( $log_entry );
3763 + echo json_encode( array('succes'=>false) );
3764 + } else {
3765 + $permalink = get_edit_post_link($post_id);
3766 +
3767 + $permalink= add_query_arg( 'onboard', 'yes', $permalink );
3768 + $permalink= add_query_arg( 'branch', '1', $permalink );
3769 +
3770 + echo json_encode( array(
3771 + 'success'=> true,
3772 + 'link' => ($permalink)
3773 + ));
3774 + }
3775 + }
3776 + die();
3257 3777 }
3258 3778
3259 3779 /*
3260 3780 *
@@ -3260,18 +3780,52 @@
3260 3780 *
3261 3781 * On Boarding create free vod
3262 3782 *
3263 3783 */
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 3784 public function wpstream_on_board_create_free_vod(){
3273 - return $this->main->get_onboarding()->handle_ajax( 'wpstream_on_board_create_free_vod' );
3785 + $current_user = wp_get_current_user();
3786 + check_ajax_referer( 'wpstream_onboarding_nonce', 'security' );
3787 + if(current_user_can('administrator')){
3788 + $channel_name =sanitize_text_field($_POST['channel_name']);
3789 + $file_name =sanitize_text_field($_POST['file_name']);
3790 + $my_post = array(
3791 + 'post_title' => $channel_name,
3792 + 'post_content' => '',
3793 + 'post_status' => 'publish',
3794 + 'post_type' => 'wpstream_product_vod',
3795 + 'post_author' => $current_user->ID
3796 + );
3797 +
3798 + // Insert the post into the database
3799 + $post_id = wp_insert_post( $my_post );
3800 +
3801 + if(is_wp_error($post_id)){
3802 + $logger = new WPStream_Logger();
3803 + $log_entry = new WpStream_Log_Entry([
3804 + 'type' => 'error',
3805 + 'description' => 'Couldn\'t create free VOD during onboarding because of error: ' . $post_id->get_error_message(),
3806 + ]);
3807 + $logger->add( $log_entry );
3808 + echo json_encode( array('succes'=>false) );
3809 + }else{
3810 + update_post_meta($post_id, 'wpstream_product_type', 2);
3811 + update_post_meta($post_id, 'wpstream_free_video', $file_name);
3812 +
3813 +
3814 + $permalink = get_edit_post_link($post_id);
3815 +
3816 + $permalink= add_query_arg( 'onboard', 'yes', $permalink );
3817 + $permalink= add_query_arg( 'branch', '3', $permalink );
3818 +
3819 +
3820 + echo json_encode( array(
3821 + 'success'=> true,
3822 + 'link' => ($permalink)
3823 + ));
3824 + }
3825 +
3826 + }
3827 + die();
3274 3828 }
3275 3829
3276 3830
3277 3831 /*
@@ -3280,19 +3834,67 @@
3280 3834 *
3281 3835 */
3282 3836
3283 3837
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 3838 public function wpstream_on_board_create_ppv_vod(){
3294 - return $this->main->get_onboarding()->handle_ajax( 'wpstream_on_board_create_ppv_vod' );
3839 + $current_user = wp_get_current_user();
3840 + check_ajax_referer( 'wpstream_onboarding_nonce', 'security' );
3841 +
3842 + if(current_user_can('administrator')){
3843 + $channel_name = sanitize_text_field($_POST['channel_name']);
3844 + $vod_price = floatval($_POST['vod_price']);
3845 + $file_name = sanitize_text_field($_POST['file_name']);
3846 +
3847 + $my_post = array(
3848 + 'post_title' => $channel_name,
3849 + 'post_content' => '',
3850 + 'post_status' => 'publish',
3851 + 'post_type' => 'product',
3852 + 'post_author' => $current_user->ID
3853 + );
3854 +
3855 + // Insert the post into the database
3856 + $post_id = wp_insert_post( $my_post );
3857 +
3858 + if( is_wp_error( $post_id ) ) {
3859 + $logger = new WPStream_Logger();
3860 + $log_entry = new WpStream_Log_Entry([
3861 + 'type' => 'error',
3862 + 'description' => 'Couldn\'t create PPV VOD during onboarding because of error: ' . $post_id->get_error_message(),
3863 + ]);
3864 + $logger->add( $log_entry );
3865 + echo json_encode( array('succes'=>false) );
3866 + } else {
3867 +
3868 + $product = wc_get_product($post_id);
3869 + $price = wc_format_decimal($vod_price);
3870 +
3871 + $product = wc_get_product( $post_id );
3872 + $product->set_price( $price );
3873 + $product->set_regular_price( $price ); // To be sure
3874 + $product->save();
3875 + update_post_meta ($post_id,'event_passed',0);
3876 + update_post_meta ($post_id,'_movie_url', $file_name);
3877 + wp_set_object_terms( $post_id, 'video_on_demand', 'product_type' );
3878 +
3879 +
3880 +
3881 +
3882 + $permalink = get_edit_post_link($post_id);
3883 +
3884 + $permalink= add_query_arg( 'onboard', 'yes', $permalink );
3885 + $permalink= add_query_arg( 'branch', '4', $permalink );
3886 +
3887 +
3888 + echo json_encode( array(
3889 + 'success'=> true,
3890 + 'link' => ($permalink) ,
3891 + ' $file_name'=> $file_name,
3892 + ));
3893 + }
3894 +
3895 + }
3896 + die();
3295 3897 }
3296 3898
3297 3899
3298 3900 /*
@@ -3299,48 +3901,155 @@
3299 3901 *
3300 3902 * On Boarding login
3301 3903 *
3302 3904 */
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 3905 public function wpstream_on_board_login(){
3313 - return $this->main->get_onboarding()->handle_ajax( 'wpstream_on_board_login' );
3906 + check_ajax_referer( 'wpstream_onboarding_nonce', 'security' );
3907 +
3908 + if(current_user_can('administrator')){
3909 + $username = sanitize_text_field($_POST['api_username']);
3910 + $password = $_POST['api_password'];
3911 + update_option('wpstream_api_username',$username);
3912 + update_option('wpstream_api_password',$password);
3913 +
3914 + $token = $this->main->wpstream_live_connection->wpstream_get_token();
3915 + $videos_list = $this->main->wpstream_live_connection->wpstream_get_videos();
3916 + // cleanup any previous echo before sending json
3917 + ob_end_clean();
3918 + // !DO NOT SEND TOKEN TO THE CLIENT!
3919 + if ($token){
3920 + echo json_encode( array(
3921 + 'success'=> true
3922 + ));
3923 + }
3924 + else {
3925 + $text = get_option('wpstream_curl_failed') ?
3926 + 'Login failed with critical error: ' . get_option('wpstream_curl_failed') :
3927 + 'Wrong username or password!';
3928 + echo json_encode( array(
3929 + 'success'=> false,
3930 + 'error' => $text,
3931 + ));
3932 + }
3933 +
3934 + }else{
3935 + echo json_encode( array(
3936 + 'success'=> false,
3937 + 'token' => esc_html('You are not an administrator','wpstream')
3938 + ));
3939 + }
3940 + die();
3314 3941 }
3315 3942
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 -
3943 +
3944 + public function wpstream_register_refresh_capthca(){
3945 +
3946 + if(current_user_can('administrator')){
3947 +
3948 + }
3949 + }
3950 +
3327 3951 /*
3328 3952 *
3329 3953 * On Boarding login
3330 3954 *
3331 3955 */
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 3956 public function wpstream_on_board_register(){
3342 - return $this->main->get_onboarding()->handle_ajax( 'wpstream_on_board_register' );
3957 + check_ajax_referer( 'wpstream_onboarding_nonce', 'security' );
3958 +
3959 + if(current_user_can('administrator')){
3960 + $wpstream_register_email = sanitize_text_field($_POST['wpstream_register_email']);
3961 + $wpstream_register_password = $_POST['wpstream_register_password'];
3962 + $wpstream_register_captcha = sanitize_text_field($_POST['wpstream_register_captcha']);
3963 + $wpstream_register_captcha_id = sanitize_text_field($_POST['wpstream_register_captcha_id']);
3964 +
3965 + $validate = $this->wpstream_validate_onboard_register($wpstream_register_email,$wpstream_register_password);
3966 + if(!$validate['success']){
3967 + // cleanup any previous echo before sending json
3968 + ob_end_clean();
3969 + echo json_encode($validate);
3970 + die();
3971 + }
3972 +
3973 + $url='user/create';
3974 + $curl_post_fields=array(
3975 + 'email' => $wpstream_register_email,
3976 + 'password' => $wpstream_register_password,
3977 + 'captcha' => $wpstream_register_captcha,
3978 + 'captcha_id' => $wpstream_register_captcha_id,
3979 + );
3980 +
3981 +
3982 +
3983 + $curl_response = $this->main->wpstream_live_connection->wpstream_baker_do_curl_base($url,$curl_post_fields,true);
3984 + $curl_response_decoded = json_decode($curl_response,JSON_OBJECT_AS_ARRAY);
3985 +
3986 +
3987 +
3988 + if($curl_response_decoded['success']){
3989 +
3990 + if($curl_response_decoded['request']['registred']){
3991 + // we are registerd
3992 +
3993 + update_option('wpstream_api_username',$wpstream_register_email);
3994 + update_option('wpstream_api_password',$wpstream_register_password);
3995 +
3996 + $token = $this->main->wpstream_live_connection->wpstream_get_token();
3997 +
3998 + // cleanup any previous echo before sending json
3999 + ob_end_clean();
4000 + echo json_encode( array(
4001 + 'success' => true,
4002 + 'token' => $token ,
4003 + 'message' => esc_html__('Your Account was created. Please stand by...','wpstream'),
4004 +
4005 + ));
4006 + die();
4007 + }else{
4008 +
4009 + // cleanup any previous echo before sending json
4010 + ob_end_clean();
4011 + echo json_encode( array(
4012 + 'success'=> false,
4013 + 'message'=> $curl_response_decoded['request']['message'],
4014 + 'curl'=>$curl_response_decoded,
4015 +
4016 + ));
4017 + die();
4018 + }
4019 +
4020 +
4021 +
4022 +
4023 + }else{
4024 + // cleanup any previous echo before sending json
4025 + ob_end_clean();
4026 + echo json_encode( array(
4027 + 'success'=> false,
4028 + 'message'=> esc_html__('Registration could not be completed. Please try again or register on wpstream.net','wpstream'),
4029 +
4030 + ));
4031 + die();
4032 + }
4033 +
4034 +
4035 +
4036 +
4037 +
4038 +
4039 +
4040 +
4041 + }else{
4042 + // cleanup any previous echo before sending json
4043 + ob_end_clean();
4044 + echo json_encode( array(
4045 + 'success'=> false,
4046 + 'message' => esc_html('You are not an administrator','wpstream')
4047 + ));
4048 + die();
4049 + }
4050 +
4051 + die();
3343 4052 }
3344 4053
3345 4054
3346 4055 /*
@@ -3347,35 +4056,61 @@
3347 4056 *
3348 4057 * Validate for register
3349 4058 *
3350 4059 */
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 - */
4060 +
4061 +
3361 4062 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 );
4063 +
4064 + $return= array(
4065 + 'success'=>true
4066 + );
4067 +
4068 + if ($wpstream_register_email=='' ){
4069 + $return= array(
4070 + 'success'=> false,
4071 + 'message' => esc_html('The email Field is Empty','wpstream')
4072 + );
4073 + return $return;die();
4074 + }
4075 +
4076 + if(filter_var($wpstream_register_email,FILTER_VALIDATE_EMAIL) === false) {
4077 + $return= array(
4078 + 'success'=> false,
4079 + 'message' => esc_html__("The email doesn't look right !",'wpstream')
4080 + );
4081 + return $return;die();
4082 + }
4083 +
4084 +
4085 + $domain = mb_substr(strrchr($wpstream_register_email, "@"), 1);
4086 + if( $domain!='' && !checkdnsrr ($domain) ){
4087 + $return= array(
4088 + 'success'=> false,
4089 + 'message' => esc_html__("The email doesn't look right !",'wpstream')
4090 + );
4091 + return $return;die();
4092 + }
4093 +
4094 +
4095 +
4096 + if(strlen($wpstream_register_password)<5){
4097 + $return= array(
4098 + 'success'=> false,
4099 + 'message' => esc_html('The password is too short. Please use at least 5 characters.','wpstream')
4100 + );
4101 + return $return;die();
4102 + }
4103 +
4104 + return $return;die();
3363 4105 }
3364 4106
3365 4107 /**
3366 4108 * Handle the AJAX request to initiate a multipart upload
3367 4109 *
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_*.
4110 + * @since 3.0.1
3374 4111 */
3375 4112 public function handle_initiate_multipart_upload() {
3376 - check_ajax_referer( 'wpstream_multipart_upload_nonce', 'security' );
3377 -
3378 4113 // Security check - only admins can do this
3379 4114 if (!current_user_can('administrator')) {
3380 4115 wp_send_json_error('Unauthorized access');
3381 4116 return;
@@ -3386,30 +4121,14 @@
3386 4121 $file_size = intval($_POST['file_size']);
3387 4122 $content_type = sanitize_text_field($_POST['content_type']);
3388 4123 $num_parts = intval($_POST['parts']);
3389 4124
3390 - // Reject incomplete/invalid file metadata.
3391 4125 if (empty($file_name) || $file_size <= 0 || $num_parts <= 0) {
3392 4126 wp_send_json_error('Invalid file information');
3393 4127 return;
3394 4128 }
3395 4129
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 4130 // Prepare a clean filename (similar to the standard upload process)
3411 - // Keep the extension, slugify the base name (spaces -> _, strip non-word chars).
3412 4131 $file_name_array = explode(".", $file_name);
3413 4132 $file_extension = $file_name_array[count($file_name_array) - 1];
3414 4133 $temp_file_name = $file_name_array[0];
3415 4134 $temp_file_name = str_replace(' ', '_', $temp_file_name);
@@ -3415,12 +4134,19 @@
3415 4134 $temp_file_name = str_replace(' ', '_', $temp_file_name);
3416 4135 $temp_file_name = preg_replace('/\W/', '', $temp_file_name);
3417 4136 $clean_file_name = $temp_file_name . '.' . $file_extension;
3418 4137
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").
4138 + // Make API call to initiate multipart upload
4139 + $url = 'video/upload';
4140 + $access_token = $this->main->wpstream_live_connection->wpstream_get_token();
4141 +
4142 + if (!$access_token) {
4143 + wp_send_json_error('Not connected to WPStream service');
4144 + return;
4145 + }
4146 +
3422 4147 $api_params = array(
4148 + 'access_token' => $access_token,
3423 4149 'size' => $file_size,
3424 4150 'name' => $clean_file_name,
3425 4151 'content_type' => $content_type,
3426 4152 'parts' => $num_parts
@@ -3425,15 +4151,11 @@
3425 4151 'content_type' => $content_type,
3426 4152 'parts' => $num_parts
3427 4153 );
3428 4154
3429 - $response_data = $this->main->wpstream_live_connection->authorized_request('video/upload', $api_params);
4155 + $response = $this->main->wpstream_live_connection->wpstream_baker_do_curl_base($url, $api_params, true);
4156 + $response_data = json_decode($response, true);
3430 4157
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 4158 if (!isset($response_data['success']) || $response_data['success'] !== true) {
3437 4159 $error_message = isset($response_data['error']) ? $response_data['error'] : 'Failed to initiate multipart upload';
3438 4160 wp_send_json_error($error_message);
3439 4161 return;
@@ -3445,17 +4167,11 @@
3445 4167
3446 4168 /**
3447 4169 * Handle the AJAX request to complete a multipart upload
3448 4170 *
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_*.
4171 + * @since 3.0.1
3454 4172 */
3455 4173 public function handle_complete_multipart_upload() {
3456 - check_ajax_referer( 'wpstream_multipart_upload_nonce', 'security' );
3457 -
3458 4174 // Security check - only admins can do this
3459 4175 if (!current_user_can('administrator')) {
3460 4176 wp_send_json_error('Unauthorized access');
3461 4177 return;
@@ -3460,25 +4176,29 @@
3460 4176 wp_send_json_error('Unauthorized access');
3461 4177 return;
3462 4178 }
3463 4179
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;
4180 + // Get completion details
4181 + $parts = json_decode(stripslashes($_POST['parts']), true);
3467 4182 $file_name = sanitize_text_field($_POST['file_name']);
3468 4183 $handle = sanitize_text_field($_POST['handle']);
3469 4184
3470 - // Reject incomplete completion metadata: no parts uploaded or no file name.
3471 - if ($parts < 1 || empty($file_name)) {
4185 + if (empty($parts) || !is_numeric($parts) || empty($file_name)) {
3472 4186 wp_send_json_error('Invalid completion information');
3473 4187 return;
3474 4188 }
3475 4189
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").
4190 + // Make API call to complete the multipart upload
4191 + $url = 'video/upload';
4192 + $access_token = $this->main->wpstream_live_connection->wpstream_get_token();
4193 +
4194 + if (!$access_token) {
4195 + wp_send_json_error('Not connected to WPStream service');
4196 + return;
4197 + }
4198 +
3480 4199 $api_params = array(
4200 + 'access_token' => $access_token,
3481 4201 'parts' => $parts,
3482 4202 'name' => $file_name,
3483 4203 'handle' => $handle,
3484 4204 'action' => 'complete'
@@ -3483,15 +4203,11 @@
3483 4203 'handle' => $handle,
3484 4204 'action' => 'complete'
3485 4205 );
3486 4206
3487 - $response_data = $this->main->wpstream_live_connection->authorized_request('video/upload', $api_params);
4207 + $response = $this->main->wpstream_live_connection->wpstream_baker_do_curl_base($url, $api_params, true);
4208 + $response_data = json_decode($response, true);
3488 4209
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 4210 if (!isset($response_data['success']) || $response_data['success'] !== true) {
3495 4211 $error_message = isset($response_data['error']) ? $response_data['error'] : 'Failed to complete multipart upload';
3496 4212 wp_send_json_error($error_message);
3497 4213 return;
@@ -3496,52 +4212,26 @@
3496 4212 wp_send_json_error($error_message);
3497 4213 return;
3498 4214 }
3499 4215
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 4216 // Return success
3512 4217 wp_send_json_success();
3513 4218 }
3514 4219
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 4220 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 4221 if ( !current_user_can( 'update_plugins' ) ) {
3529 4222 wp_send_json_error( __( 'Not enough permissions to make this change', 'wpstream' ) );
3530 4223 }
3531 4224
3532 - // Load the core upgrade/filesystem APIs.
3533 4225 include_once ABSPATH . 'wp-admin/includes/plugin-install.php';
3534 4226 include_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
3535 4227 include_once ABSPATH . 'wp-admin/includes/file.php';
3536 4228
3537 - // Initialize the filesystem abstraction (needed to write plugin files).
3538 4229 $credentials = request_filesystem_credentials('');
3539 4230 if ( !WP_Filesystem( $credentials ) ) {
3540 4231 wp_send_json_error( __( 'Failed to connect to the filesystem', 'wpstream' ) );
3541 4232 }
3542 4233
3543 - // Run the in-place upgrade for this plugin, then re-activate it.
3544 4234 $upgrader = new Plugin_Upgrader(new Automatic_Upgrader_Skin());
3545 4235 $plugin_path = plugin_basename( WPSTREAM_PLUGIN_PATH . 'wpstream.php' );
3546 4236 $result = $upgrader->upgrade( $plugin_path );
3547 4237 activate_plugin( $plugin_path );