PluginProbe
WpStream – Live Streaming, Video on Demand, Pay Per View / 4.4.10
WpStream – Live Streaming, Video on Demand, Pay Per View v4.4.10
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 | includes/class-wpstream.php +212 -633 4.13.24.4.10 View file →
@@ -1,5 +1,6 @@
1 1 <?php
2 +
2 3 /**
3 4 * The file that defines the core plugin class
4 5 *
5 6 * A class definition that includes attributes and functions used across both the
@@ -34,10 +35,8 @@
34 35 * @since 3.0.1
35 36 * @var object The main class.
36 37 */
37 38 public $main;
38 - /** @var Wpstream_Admin The admin-area controller instance. */
39 - public $admin;
40 39
41 40 /**
42 41 * The loader that's responsible for maintaining and registering all hooks that power
43 42 * the plugin.
@@ -75,159 +74,61 @@
75 74 *
76 75 * @since 3.0.1
77 76 */
78 77
79 - /** @var Wpstream_Live_Api_Connection Cloud API client for channels/quota. */
80 78 public $wpstream_live_connection;
81 - /** @var Wpstream_Player Player/rendering service. */
82 79 public $wpstream_player;
83 - /** @var Wpstream_Quota_Manager Quota cache manager. */
84 - public $quota_manager;
85 - /** @var object User quota service resolved from the live connection. */
86 - public $user_quota_service;
87 - /** @var mixed Unused/reserved property. */
88 80 public $xtest;
89 - /** @var Wpstream_Admin Admin controller (also stored in $admin). */
90 81 public $plugin_admin;
91 -
92 - /**
93 - * Bootstrap the plugin: resolve version/name, load dependencies, then wire
94 - * all admin, public, AJAX, template, and service objects together.
95 - */
82 +
96 83 public function __construct() {
97 - // Expose this instance as the shared "main" service locator.
98 - $this->main = $this;
99 -
100 - // Resolve the plugin version from the defined constant, else fall back.
84 + $this->main = $this;
101 85 if ( defined( 'WPSTREAM_PLUGIN_VERSION' ) ) {
102 - $this->version = WPSTREAM_PLUGIN_VERSION;
86 + $this->version = WPSTREAM_PLUGIN_VERSION;
103 87 } else {
104 - $this->version = '3.0.1';
88 + $this->version = '3.0.1';
105 89 }
106 -
107 - // Text-domain / unique plugin identifier.
108 90 $this->plugin_name = 'wpstream';
109 91
110 - // Require class files and instantiate the hook loader.
111 92 $this->load_dependencies();
112 - // Register admin-area hooks (menus, metaboxes, WooCommerce, onboarding).
93 + $this->set_locale();
113 94 $this->define_admin_hooks();
114 - // Register public-facing hooks (scripts, endpoints, shortcodes).
115 95 $this->define_public_hooks();
116 - // Register AJAX handlers.
117 - $this->define_ajax_hooks();
118 - // Register the front-end page/single template loader.
119 - $this->wpstream_load_page_templates();
120 - // Register the "theme update available" admin notice.
121 - $this->wpstream_load_theme_notice();
96 +
97 +
98 + $this->wpstream_conection();
99 + $this->wpstream_player();
122 100
123 - // Instantiate the cloud API connection (and user quota service).
124 - $this->wpstream_conection();
125 - // Instantiate the player service.
126 - $this->wpstream_player();
127 - // Instantiate the quota cache manager.
128 - $this->wpstream_init_quota_manager();
129 -
130 101 }
131 102
132 -
133 -
134 -
135 -
136 - /**
137 - * Convert a bandwidth figure from megabits to gigabits.
138 - *
139 - * @param float|int $megabits Value in megabits.
140 - * @return float Value in gigabits, rounded to one decimal.
141 - */
103 +
104 +
105 +
106 +
142 107 public function wpstream_convert_band($megabits){
143 - // 1 gigabit = 1000 megabits.
144 - $gigabit = $megabits * 0.001;
145 - // Return with a single decimal place.
146 - return floatval( sprintf( '%.1f', $gigabit ) );
108 + $gigabit = $megabits * 0.001;
109 + $gigabit = number_format($gigabit,2);
110 + return $gigabit;
147 111 }
148 112
149 - /**
150 - * Floor a number to a given number of decimal places.
151 - *
152 - * @param float $value The number to floor.
153 - * @param int $decimals Number of decimal places.
154 - * @return float
155 - */
156 - public function wpstream_floor_decimals( $value, $decimals = 2 ) {
157 - // Clamp decimals to a non-negative integer.
158 - $decimals = max( 0, (int) $decimals );
159 - // Scale factor for the requested precision.
160 - $factor = pow( 10, $decimals );
161 -
162 - // Multiply, floor, divide back, then format to fixed precision.
163 - return floatval( sprintf( '%.' . $decimals . 'f', floor( (float) $value * $factor ) / $factor ) );
164 - }
165 -
166 -
167 - /** @var WpStream_Ajax The AJAX handler service. */
168 - public $wpstream_ajax;
169 -
170 - /**
171 - * Load and instantiate the AJAX handler service.
172 - */
173 - private function define_ajax_hooks() {
174 - // Pull in the AJAX class and construct it with the main instance.
175 - require_once plugin_dir_path(dirname(__FILE__)) . 'includes/class-wpstream-ajax.php';
176 - $this->wpstream_ajax = new WpStream_Ajax( $this->main );
177 - }
178 -
179 -
180 - /**
181 - * Load the cloud API connection and resolve the user quota service.
182 - */
113 +
114 +
115 +
116 +
183 117 private function wpstream_conection(){
184 - // Pull in and instantiate the live/cloud API client.
185 118 require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/class-wpstream-live-api-connection.php';
186 119 $this->wpstream_live_connection = new Wpstream_Live_Api_Connection();
187 - // Cache the user quota service exposed by the connection.
188 - $this->user_quota_service = $this->wpstream_live_connection->get_user_quota_service();
189 120 }
190 -
191 -
192 - /**
193 - * Load and instantiate the player service.
194 - */
121 +
122 +
195 123 private function wpstream_player(){
196 - // Pull in the player class and build it with the main instance.
197 124 require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/class-wpstream-player.php';
198 125 $this->wpstream_player = new Wpstream_Player($this->main);
199 126 }
200 -
201 - /**
202 - * Load and instantiate the quota cache manager.
203 - */
204 - private function wpstream_init_quota_manager() {
205 - // Pull in the quota manager and build it with this main instance.
206 - require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/class-wpstream-quota-manager.php';
207 - $this->quota_manager = new Wpstream_Quota_Manager( $this );
208 - }
209 -
210 -
211 - /**
212 - * Load and register the front-end template loader.
213 - */
214 - private function wpstream_load_page_templates() {
215 - // Pull in the loader and register its hooks by constructing it.
216 - require_once WPSTREAM_PLUGIN_PATH . 'includes/class-wpstream-templates.php';
217 - new WpStream_Template_Loader();
218 - }
219 -
220 - /**
221 - * Load and register the companion-theme update admin notice.
222 - */
223 - private function wpstream_load_theme_notice() {
224 - // Pull in the notice class and register it by constructing it.
225 - require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/class-wpstream-theme-notice.php';
226 - new WPStream_Theme_Notice();
227 - }
228 127
229 128
129 +
130 +
230 131 /**
231 132 * Load the required dependencies for this plugin.
232 133 *
233 134 * Include the following files that make up the plugin:
@@ -266,30 +167,19 @@
266 167 * The class responsible for defining all actions that occur in the public-facing
267 168 * side of the site.
268 169 */
269 170 require_once plugin_dir_path( dirname( __FILE__ ) ) . 'public/class-wpstream-public.php';
270 - /**
171 +
172 + /**
271 173 * The class responsible for custom post type
174 +
175 + */
176 + require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/class-wpstream_product.php';
177 + if( class_exists( 'WooCommerce' ) ){
178 + require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/class-wc_product_live_stream.php';
179 + require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/class-wc_product_video_on_demand.php';
180 + }
272 181
273 - */
274 - require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/class-wpstream_product.php';
275 - // WooCommerce product-type classes are only needed when WooCommerce is active.
276 - if( class_exists( 'WooCommerce' ) ){
277 - // Paid live-stream product type.
278 - require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/class-wc_product_live_stream.php';
279 - // Paid video-on-demand product type.
280 - require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/class-wc_product_video_on_demand.php';
281 - }
282 -
283 - // Channel-ownership authorization helper (wpstream_can_manage_channel),
284 - // used by every live/broadcast handler to enforce per-channel ownership.
285 - require_once plugin_dir_path(__FILE__) . 'Helpers/wpstream-authorization.php';
286 -
287 - // Logging helper classes used across the plugin.
288 - require_once plugin_dir_path(__FILE__) . 'Helpers/class-wpstream-log-entry.php';
289 - require_once plugin_dir_path(__FILE__) . 'Logger/class-wpstream-logger.php';
290 -
291 - // Create the hook loader that other define_*_hooks() methods populate.
292 182 $this->loader = new Wpstream_Loader();
293 183
294 184 }
295 185
@@ -303,13 +193,11 @@
303 193 * @access private
304 194 */
305 195 private function set_locale() {
306 196
307 - // Internationalization helper responsible for loading the text domain.
308 197 $plugin_i18n = new Wpstream_i18n();
309 198
310 - // Load the translations early on plugins_loaded.
311 - $this->loader->add_action( 'plugins_loaded', $plugin_i18n, 'load_plugin_textdomain', 1 );
199 + $this->loader->add_action( 'plugins_loaded', $plugin_i18n, 'load_plugin_textdomain' );
312 200
313 201 }
314 202
315 203 /**
@@ -320,126 +208,100 @@
320 208 * @access private
321 209 */
322 210 private function define_admin_hooks() {
323 211
324 - // Build the admin controller and keep a reference to it.
325 - $plugin_admin = new Wpstream_Admin( $this->get_plugin_name(), $this->get_version(), $this->main );
326 -
327 - $this->admin = $plugin_admin;
328 -
329 - // Admin CSS/JS and the plugin's admin menu (late priority).
330 - $this->loader->add_action( 'admin_enqueue_scripts', $plugin_admin, 'enqueue_styles' );
212 + $this->admin= $plugin_admin = new Wpstream_Admin( $this->get_plugin_name(), $this->get_version(), $this->main );
213 +
214 + $this->loader->add_action( 'admin_enqueue_scripts', $plugin_admin, 'enqueue_styles' );
331 215 $this->loader->add_action( 'admin_enqueue_scripts', $plugin_admin, 'enqueue_scripts' );
332 216 $this->loader->add_action( 'admin_menu', $plugin_admin, 'wpstream_manage_admin_menu',999);
333 -
334 - // Register the custom post types on init.
217 +
335 218 $plugin_post_types = new Wpstream_Product();
336 219 $this->loader->add_action( 'init', $plugin_post_types, 'create_custom_post_type', 999 );
337 -
220 +
338 221 // save and render metaboxed
339 - // Register product metaboxes; persist their values on save; and,
340 - // on publish, create the remote streaming channel.
341 - $this->loader->add_action( 'add_meta_boxes', $plugin_admin, 'add_wpstream_product_metaboxes' );
342 - $this->loader->add_action( 'save_post', $plugin_admin, 'wpstream_free_product_update_post',1,2 );
343 - $this->loader->add_action( 'publish_wpstream_product', $plugin_admin, 'wpstream_publish_wpstream_product',1,2 );
344 - $this->loader->add_action( 'publish_wpstream_product', $plugin_admin, 'wpstream_create_remote_channel_on_publish',20,2 );
345 - $this->loader->add_action( 'publish_product', $plugin_admin, 'wpstream_create_remote_channel_on_publish', 20, 2 );
346 -
347 -
348 -
222 + $this->loader->add_action( 'admin_init', $plugin_admin, 'add_wpstream_product_metaboxes' );
223 + $this->loader->add_action( 'save_post', $plugin_admin, 'wpstream_free_product_update_post',1,2 );
224 + $this->loader->add_action( 'publish_wpstream_product', $plugin_admin, 'wpstream_publish_wpstream_product',1,2 );
225 +
226 +
227 +
349 228 // make product virtual
350 229 $this->loader->add_action( 'save_post', $plugin_admin, 'wpstream_make_product_virtual', 99999, 2 );
351 -
352 -
353 -
230 +
231 +
232 +
354 233 // show streaming controls on sidebar
355 234 $this->loader->add_action('add_meta_boxes', $plugin_admin, 'wpstream_startstreaming_sidebar_meta');
356 235
357 236 // on boarding actions
358 - // Onboarding wizard markup plus its AJAX channel/VOD/login/register endpoints.
359 237 $this->loader->add_action('admin_footer',$plugin_admin, 'wpstream_admin_footer_onboarding');
360 238 $this->loader->add_action( 'wp_ajax_wpstream_on_board_create_channel', $plugin_admin,'wpstream_on_board_create_channel' );
361 - $this->loader->add_action( 'wp_ajax_wpstream_on_board_create_channel_ppv', $plugin_admin,'wpstream_on_board_create_channel_ppv' );
362 - $this->loader->add_action( 'wp_ajax_wpstream_on_board_create_free_vod', $plugin_admin,'wpstream_on_board_create_free_vod' );
363 - $this->loader->add_action( 'wp_ajax_wpstream_on_board_create_ppv_vod', $plugin_admin,'wpstream_on_board_create_ppv_vod' );
239 + $this->loader->add_action( 'wp_ajax_wpstream_on_board_create_channel_ppv', $plugin_admin,'wpstream_on_board_create_channel_ppv' );
240 + $this->loader->add_action( 'wp_ajax_wpstream_on_board_create_free_vod', $plugin_admin,'wpstream_on_board_create_free_vod' );
241 + $this->loader->add_action( 'wp_ajax_wpstream_on_board_create_ppv_vod', $plugin_admin,'wpstream_on_board_create_ppv_vod' );
242 +
364 243
365 -
366 - // Onboarding login/registration plus the captcha challenge (logged-in and guest).
367 244 $this->loader->add_action( 'wp_ajax_wpstream_on_board_login', $plugin_admin,'wpstream_on_board_login' );
368 245 $this->loader->add_action( 'wp_ajax_wpstream_on_board_register', $plugin_admin,'wpstream_on_board_register' );
369 - $this->loader->add_action( 'wp_ajax_wpstream_get_captcha_challenge', $plugin_admin, 'wpstream_get_captcha_challenge' );
370 - $this->loader->add_action( 'wp_ajax_nopriv_wpstream_get_captcha_challenge', $plugin_admin, 'wpstream_get_captcha_challenge' );
371 246
372 - // Register AJAX actions for multipart uploads
373 - $this->loader->add_action( 'wp_ajax_wpstream_initiate_multipart_upload', $plugin_admin, 'handle_initiate_multipart_upload' );
374 - $this->loader->add_action( 'wp_ajax_wpstream_complete_multipart_upload', $plugin_admin, 'handle_complete_multipart_upload' );
375 247
376 - // General and plugin-update admin notices.
377 248 $this->loader->add_action( 'admin_notices', $plugin_admin,'wpstream_admin_notice' );
378 - $this->loader->add_action( 'admin_notices', $plugin_admin,'wpstream_plugin_update_available_notice' );
379 -
380 - // Dismiss-cache-notice AJAX endpoint.
381 249 $this->loader->add_action( 'wp_ajax_wpstream_update_cache_notice', $plugin_admin,'wpstream_update_cache_notice' );
382 -// $this->loader->add_action( 'wp_ajax_wpstream_get_videos_list', $plugin_admin,'wpstream_get_videos_list' );
250 +
383 251
384 252
385 - // Settings-tab "update plugin" AJAX endpoint.
386 - $this->loader->add_action( 'wp_ajax_wpstream_settings_tab_update_plugin', $plugin_admin, 'wpstream_settings_tab_update_plugin' );
387 -
253 +
388 254 // add and save category extra fields
389 - // The same add/edit/create/save callbacks are shared across every taxonomy below.
390 255 $this->loader->add_action( 'category_edit_form_fields', $plugin_post_types, 'wpstream_category_callback_function', 10, 2);
391 - $this->loader->add_action( 'category_add_form_fields', $plugin_post_types, 'wpstream_category_callback_add_function' );
256 + $this->loader->add_action( 'category_add_form_fields', $plugin_post_types, 'wpstream_category_callback_add_function', 10, 2 );
392 257 $this->loader->add_action( 'created_category', $plugin_post_types, 'wpstream_category_save_extra_fields_callback', 10, 2);
393 258 $this->loader->add_action( 'edited_category', $plugin_post_types, 'wpstream_category_save_extra_fields_callback', 10, 2);
394 259
395 - // Same extra fields on the WooCommerce product category taxonomy.
396 260 $this->loader->add_action( 'product_cat_edit_form_fields', $plugin_post_types, 'wpstream_category_callback_function', 10, 2);
397 - $this->loader->add_action( 'product_cat_add_form_fields', $plugin_post_types, 'wpstream_category_callback_add_function' );
261 + $this->loader->add_action( 'product_cat_add_form_fields', $plugin_post_types, 'wpstream_category_callback_add_function', 10, 2 );
398 262 $this->loader->add_action( 'created_product_cat', $plugin_post_types, 'wpstream_category_save_extra_fields_callback', 10, 2);
399 263 $this->loader->add_action( 'edited_product_cat', $plugin_post_types, 'wpstream_category_save_extra_fields_callback', 10, 2);
400 264
401 265
402 - // Same extra fields on the plugin's own wpstream_category taxonomy.
403 266 $this->loader->add_action( 'wpstream_category_edit_form_fields', $plugin_post_types, 'wpstream_category_callback_function', 10, 2);
404 - $this->loader->add_action( 'wpstream_category_add_form_fields', $plugin_post_types, 'wpstream_category_callback_add_function' );
267 + $this->loader->add_action( 'wpstream_category_add_form_fields', $plugin_post_types, 'wpstream_category_callback_add_function', 10, 2 );
405 268 $this->loader->add_action( 'created_wpstream_category', $plugin_post_types, 'wpstream_category_save_extra_fields_callback', 10, 2);
406 269 $this->loader->add_action( 'edited_wpstream_category', $plugin_post_types, 'wpstream_category_save_extra_fields_callback', 10, 2);
407 270
408 271
409 - // Same extra fields on the wpstream_actors taxonomy.
410 272 $this->loader->add_action( 'wpstream_actors_edit_form_fields', $plugin_post_types, 'wpstream_category_callback_function', 10, 2);
411 - $this->loader->add_action( 'wpstream_actors_add_form_fields', $plugin_post_types, 'wpstream_category_callback_add_function' );
273 + $this->loader->add_action( 'wpstream_actors_add_form_fields', $plugin_post_types, 'wpstream_category_callback_add_function', 10, 2 );
412 274 $this->loader->add_action( 'created_wpstream_actors', $plugin_post_types, 'wpstream_category_save_extra_fields_callback', 10, 2);
413 275 $this->loader->add_action( 'edited_wpstream_actors', $plugin_post_types, 'wpstream_category_save_extra_fields_callback', 10, 2);
414 276
415 - // Same extra fields on the wpstream_movie_rating taxonomy.
416 277 $this->loader->add_action( 'wpstream_movie_rating_edit_form_fields', $plugin_post_types, 'wpstream_category_callback_function', 10, 2);
417 - $this->loader->add_action( 'wpstream_movie_rating_add_form_fields', $plugin_post_types, 'wpstream_category_callback_add_function' );
278 + $this->loader->add_action( 'wpstream_movie_rating_add_form_fields', $plugin_post_types, 'wpstream_category_callback_add_function', 10, 2 );
418 279 $this->loader->add_action( 'created_wpstream_movie_rating', $plugin_post_types, 'wpstream_category_save_extra_fields_callback', 10, 2);
419 280 $this->loader->add_action( 'edited_wpstream_movie_rating', $plugin_post_types, 'wpstream_category_save_extra_fields_callback', 10, 2);
281 +
282 +
420 283
421 284
422 - // WooCommerce-only admin hooks: register the custom product types,
423 - // their data tabs/fields, pricing visibility, and add-to-cart handling.
424 285 if ( in_array( 'woocommerce/woocommerce.php', apply_filters( 'active_plugins', get_option( 'active_plugins' ) ) ) ) {
425 -
426 - // Register product types and map them to their PHP classes.
427 - $this->loader->add_action( 'init', $plugin_admin, 'wpstream_add_custom_wc_products' );
286 +
428 287 $this->loader->add_filter( 'product_type_selector', $plugin_admin, 'wpstream_add_products' );
429 - $this->loader->add_filter( 'woocommerce_product_class', $plugin_admin, 'wpstream_add_products_class', 10, 2 );
430 - // Pricing-field visibility, tab hiding, and purchasability rules.
431 - $this->loader->add_action( 'admin_enqueue_scripts', $plugin_admin, 'wpstream_enqueue_wc_product_pricing_visibility', 20 );
288 + $this->loader->add_action( 'admin_footer', $plugin_admin, 'wpstream_products_custom_js' );
432 289 $this->loader->add_filter( 'woocommerce_product_data_tabs', $plugin_admin, 'wpstream_hide_attributes_data_panel',10,1 );
433 290 $this->loader->add_filter( 'woocommerce_is_purchasable', $plugin_admin, 'wpstream_hide_buy_now_subscription_mode',10,2);
434 -
435 - // Custom general-tab fields (render + save) and add-to-cart wiring.
436 - $this->loader->add_action( 'woocommerce_product_options_general_product_data', $plugin_admin, 'wpstream_add_custom_general_fields', 20 );
291 +
292 + $this->loader->add_filter( 'woocommerce_product_options_general_product_data',$plugin_admin, 'wpstream_add_custom_general_fields', 10,1);
437 293 $this->loader->add_filter( 'woocommerce_process_product_meta',$plugin_admin, 'wpstream_add_custom_general_fields_save',10,1 );
438 294 $this->loader->add_action( 'woocommerce_live_stream_add_to_cart', $plugin_admin, 'wpstream_add_to_cart',10,1);
439 295 $this->loader->add_action( 'woocommerce_video_on_demand_add_to_cart', $plugin_admin, 'wpstream_add_to_cart',10,1);
440 296 $this->loader->add_filter( 'woocommerce_loop_add_to_cart_link', $plugin_admin,'replacing_add_to_cart_button', 10, 2 );
441 297 }
298 +
299 +
300 +
301 +
302 +
303 +
442 304 }
443 305
444 306
445 307
@@ -453,66 +315,42 @@
453 315 * @access private
454 316 */
455 317 private function define_public_hooks() {
456 318
457 - // Build the public-facing controller.
458 319 $plugin_public = new Wpstream_Public( $this->get_plugin_name(), $this->get_version(), $this->main );
459 320
460 - // Front-end styles.
461 321 $this->loader->add_action( 'wp_enqueue_scripts', $plugin_public, 'enqueue_styles' );
462 - // Registered on `wp` (not `wp_enqueue_scripts`/`wp_head`) because block themes render
463 - // the Post Content block - and thus our `the_content` filter that enqueues/localizes
464 - // these scripts - before `wp_head` ever fires, leaving the handles unregistered.
465 - $this->loader->add_action( 'wp', $plugin_public, 'enqueue_scripts' );
322 + $this->loader->add_action( 'wp_enqueue_scripts', $plugin_public, 'enqueue_scripts' );
323 +
324 + $this->loader->add_action( 'init', $plugin_public,'wpstream_my_custom_endpoints' );
325 + $this->loader->add_filter( 'query_vars',$plugin_public, 'wpstream_my_custom_query_vars', 0 );
326 +
327 + //live stream action
328 + $this->loader->add_action('init',$plugin_public,'wpstream_set_cookies',0);
329 + $this->loader->add_action('init',$plugin_public,'wpstream_live_streaming_key');
330 + $this->loader->add_action('init',$plugin_public,'wpstream_live_streaming_key_for_3rdparty');
331 + $this->loader->add_action('init',$plugin_public,'wpstream_live_streaming_key_vod',10);
332 + // woo action
333 +
334 + $this->loader->add_action( 'woocommerce_before_single_product', $plugin_public,'wpstream_non_image_content_wrapper_start', 20 );
335 + $this->loader->add_action( 'woocommerce_after_single_product', $plugin_public,'wpstream_non_image_content_wrapper_end', 20 );
336 + $this->loader->add_action( 'woocommerce_thankyou_order_received_text', $plugin_public,'wpstream_thankyou_extra', 20,2 );
337 + $this->loader->add_action( 'woocommerce_email_order_details', $plugin_public,'wpstream_email_order_details', 20,4 );
338 +
339 + $this->loader->add_filter( 'woocommerce_account_menu_items', $plugin_public,'wpstream_custom_my_account_menu_items' );
340 + $this->loader->add_action( 'woocommerce_account_event-list_endpoint', $plugin_public,'wpstream_custom_endpoint_content_event_list' );
341 + $this->loader->add_action( 'woocommerce_account_video-list_endpoint', $plugin_public,'wpstream_custom_endpoint_video_list' );
342 +
466 343
467 - // Custom rewrite endpoints and their query vars.
468 - $this->loader->add_action( 'init', $plugin_public,'wpstream_my_custom_endpoints' );
469 - $this->loader->add_filter( 'query_vars',$plugin_public, 'wpstream_my_custom_query_vars', 0 );
470 -
471 - //live stream action
472 - // Streaming cookies plus the RTMP/3rd-party/VOD streaming-key handlers.
473 - $this->loader->add_action('init',$plugin_public,'wpstream_set_cookies',0);
474 - $this->loader->add_action('init',$plugin_public,'wpstream_live_streaming_key');
475 - $this->loader->add_action('init',$plugin_public,'wpstream_live_streaming_key_for_3rdparty');
476 - $this->loader->add_action('init',$plugin_public,'wpstream_live_streaming_key_vod',10);
477 -
478 - // woo action
479 - // Product-page content wrappers and order/email extras.
480 - $this->loader->add_action( 'woocommerce_before_single_product', $plugin_public,'wpstream_non_image_content_wrapper_start', 20 );
481 - $this->loader->add_action( 'woocommerce_after_single_product', $plugin_public,'wpstream_non_image_content_wrapper_end', 20 );
482 - $this->loader->add_action( 'woocommerce_thankyou_order_received_text', $plugin_public,'wpstream_thankyou_extra', 20,2 );
483 - $this->loader->add_action( 'woocommerce_email_order_details', $plugin_public,'wpstream_email_order_details', 20,4 );
484 -
485 - // My Account: add the Events/Videos menu items and their endpoint content.
486 - $this->loader->add_filter( 'woocommerce_account_menu_items', $plugin_public,'wpstream_custom_my_account_menu_items' );
487 - $this->loader->add_action( 'woocommerce_account_event-list_endpoint', $plugin_public,'wpstream_custom_endpoint_content_event_list' );
488 - $this->loader->add_action( 'woocommerce_account_video-list_endpoint', $plugin_public,'wpstream_custom_endpoint_video_list' );
489 -
490 - // Flush rewrite rules on theme switch; register plugin and WPBakery shortcodes.
491 - $this->loader->add_action( 'after_switch_theme', $plugin_public,'wpstream_custom_flush_rewrite_rules' );
492 - $this->loader->add_action('init', $plugin_public,'wpstream_shortcodes');
493 - $this->loader->add_action('vc_before_init', $plugin_public,'wpstream_bakery_shortcodes');
494 -
495 - // CORS preflight check for the API (uses a plain function callback).
496 - $this->loader->add_action('wo_before_api', 'wpstream_cors_check_and_response',10,1);
497 -
498 - // Theme-integration filters/actions: search, sidebars, archives, and
499 - // author/episode/past-broadcast content resolution by post type.
500 - $this->loader->add_filter( 'wpstream_search_template_item_post_type', $plugin_public, 'wpstream_search_template_add_item_post_type' );
501 - $this->loader->add_filter( 'wpstream_sidebar_id_by_post_type', $plugin_public, 'wpstream_sidebar_id_by_post_type' );
502 - $this->loader->add_filter( 'wpstream_header_search_values', $plugin_public, 'wpstream_header_search_values' );
503 - $this->loader->add_filter( 'wpstream_extend_category_archive_query_filter', $plugin_public, 'wpstream_extend_category_archive_query_filter_callback' );
504 - $this->loader->add_filter( 'wpstream_archives_lists_taxonomy_labels', $plugin_public, 'wpstream_archives_lists_taxonomy_labels_callback' );
505 - $this->loader->add_filter( 'wpstream_author_archive_list_taxonomy_labels', $plugin_public, 'wpstream_author_archive_list_taxonomy_labels_callback' );
506 - $this->loader->add_action( 'wpstream_vod_attached_to_channel', $plugin_public, 'wpstream_vod_attached_to_channel' );
507 - $this->loader->add_action( 'wpstream_additional_content_post_type', $plugin_public, 'wpstream_additional_content_post_type_callback' );
508 - $this->loader->add_action( 'wpstream_post_author_content_post_type_list', $plugin_public, 'wpstream_post_author_content_post_type_list_callback' );
509 - $this->loader->add_action( 'wpstream_author_content_simple_post_type_message', $plugin_public, 'wpstream_author_content_simple_post_type_message_callback', 10, 2 );
510 - $this->loader->add_action( 'wpstream_author_content_post_type_message', $plugin_public, 'wpstream_author_content_post_type_message_callback', 10, 2 );
511 - $this->loader->add_action( 'wpstream_show_sidebar_for_post_type', $plugin_public, 'wpstream_show_sidebar_for_post_type_callback', 10, 2 );
512 - $this->loader->add_action( 'wpstream_video_episodes_post_type', $plugin_public, 'wpstream_video_episodes_post_type_callback' );
513 - $this->loader->add_action( 'wpstream_video_past_broadcast_post_type', $plugin_public, 'wpstream_video_past_broadcast_post_type_callback' );
514 - $this->loader->add_action( 'wpstream_additional_content_post_type_label', $plugin_public, 'wpstream_additional_content_post_type_label_callback', 10, 2 );
344 + $this->loader->add_action( 'after_switch_theme', $plugin_public,'wpstream_custom_flush_rewrite_rules' );
345 + $this->loader->add_action('init', $plugin_public,'wpstream_shortcodes');
346 + $this->loader->add_action('vc_before_init', $plugin_public,'wpstream_bakery_shortcodes');
347 +
348 +
349 + $this->loader->add_action('wo_before_api', 'wpstream_cors_check_and_response',10,1);
350 +
351 +
352 +
515 353 }
516 354
517 355 /**
518 356 * Run the loader to execute all of the hooks with WordPress.
@@ -519,9 +357,8 @@
519 357 *
520 358 * @since 3.0.1
521 359 */
522 360 public function run() {
523 - // Hand off to the loader, which calls add_action/add_filter for every hook.
524 361 $this->loader->run();
525 362 }
526 363
527 364 /**
@@ -531,9 +368,8 @@
531 368 * @since 3.0.1
532 369 * @return string The name of the plugin.
533 370 */
534 371 public function get_plugin_name() {
535 - // Return the stored text-domain / identifier string.
536 372 return $this->plugin_name;
537 373 }
538 374
539 375 /**
@@ -542,9 +378,8 @@
542 378 * @since 3.0.1
543 379 * @return Wpstream_Loader Orchestrates the hooks of the plugin.
544 380 */
545 381 public function get_loader() {
546 - // Return the hook loader instance.
547 382 return $this->loader;
548 383 }
549 384
550 385 /**
@@ -553,141 +388,47 @@
553 388 * @since 3.0.1
554 389 * @return string The version number of the plugin.
555 390 */
556 391 public function get_version() {
557 - // Return the resolved plugin version string.
558 392 return $this->version;
559 393 }
560 -
561 - /**
562 - * Whether WordPress currently reports a pending update for this plugin.
563 - *
564 - * @return bool True when an update is available in the update_plugins transient.
565 - */
566 - public function is_plugin_outdated(){
567 - // WordPress caches pending plugin updates in this site transient.
568 - $update_data = get_site_transient('update_plugins');
569 - // The plugin's basename key within that transient.
570 - $plugin_path = 'wpstream/wpstream.php';
571 -
572 - // Presence of a response entry means an update is offered.
573 - if (isset($update_data->response[$plugin_path])) {
574 - return true;
575 - }
576 -
577 - // No entry -> up to date.
578 - return false;
579 - }
580 -
581 -
394 +
395 +
582 396
583 - /**
584 - * Print the account resource summary (data/storage or hours) shown in the UI.
585 - *
586 - * @param array $pack_details Quota payload for the current account.
587 - */
588 397 public function show_user_data($pack_details){
589 - // Branch A: data/storage (megabyte) plans - when NOT using streaming hours.
590 - if ( ! isset( $pack_details['use_streaming_hours'] ) || $pack_details['use_streaming_hours'] !== true ) {
591 - // Only render when both data and storage figures are present.
592 - if ( isset( $pack_details['available_data_mb'] ) && isset( $pack_details['available_storage_mb'] ) ) {
593 - // Convert available data MB to GB, clamping negatives to zero.
594 - $wpstream_convert_band = $this->wpstream_convert_band( $pack_details['available_data_mb'] );
595 - if ( $wpstream_convert_band < 0 ) {
596 - $wpstream_convert_band = 0;
597 - }
398 + if( isset($pack_details['available_data_mb']) && isset( $pack_details['available_storage_mb']) ){
399 + $wpstream_convert_band = $this->wpstream_convert_band($pack_details['available_data_mb']);
400 + if($wpstream_convert_band<0)$wpstream_convert_band=0;
401 +
402 + $wpstream_convert_storage = $this->wpstream_convert_band($pack_details['available_storage_mb']);
403 + if($wpstream_convert_storage<0)$wpstream_convert_storage=0;
404 +
405 + print '<div class="pack_details_wrapper"><strong>'.__('Your account information: ','wpstream').'</strong> '.__('You have','wpstream').'<strong> '.$wpstream_convert_band.' Gb</strong> '.__('available streaming data and','wpstream').' <strong>'.$wpstream_convert_storage.' Gb</strong> '.__('available recording storage','wpstream');
406 + print '<a href="https://wpstream.net/pricing/" class="wpstream_upgrade_topbar" target="_blank">'.esc_html__('Upgrade Subscription','wpstream').'</a>';
407 + print '</div>';
408 + print'<input type="hidden" id="wpstream_band" value="'.$pack_details['available_data_mb'].'">';
409 + print'<input type="hidden" id="wpstream_storage" value="'.$pack_details['available_storage_mb'].'">';
598 410
599 - // Convert available storage MB to GB, clamping negatives to zero.
600 - $wpstream_convert_storage = $this->wpstream_convert_band( $pack_details['available_storage_mb'] );
601 - if ( $wpstream_convert_storage < 0 ) {
602 - $wpstream_convert_storage = 0;
603 - }
411 + }
412 + }
604 413
605 - // Output the cloud data + storage summary line.
606 - print '<div class="pack_details_wrapper">'
607 - . '<strong>' . __( 'Your account information: ', 'wpstream' ) . '</strong> '
608 - . __( 'You have ', 'wpstream' ) . '<strong id="wpstream_available_data">' . abs( $wpstream_convert_band ) . ' GB</strong> '
609 - . __( 'available cloud data and ', 'wpstream' )
610 - . '<strong id="wpstream_available_storage">' . abs( $wpstream_convert_storage ) . ' GB</strong> '
611 - . __( 'available cloud storage', 'wpstream' ) . '.';
612 -
613 - // Upgrade link plus hidden inputs carrying the raw MB figures for JS.
614 - print '<a href="https://wpstream.net/pricing/" class="wpstream_upgrade_topbar" target="_blank">' . esc_html__( 'Upgrade Plan', 'wpstream' ) . '</a>';
615 - print '</div>';
616 - print '<input type="hidden" id="wpstream_band" value="' . esc_attr( $pack_details['available_data_mb'] ) . '">';
617 - print '<input type="hidden" id="wpstream_storage" value="' . esc_attr( $pack_details['available_storage_mb'] ) . '">';
618 - }
619 - } else {
620 - // Branch B: streaming-hours plans (viewer/broadcast/storage hours).
621 - if ( isset( $pack_details['available_viewer_hours'] ) && isset( $pack_details['available_broadcast_hours'] ) && isset( $pack_details['available_storage_hours'] ) ) {
622 - // Normalize viewer hours to a non-negative float.
623 - $available_viewer_hours = floatval( $pack_details['available_viewer_hours'] );
624 - if ( $available_viewer_hours < 0 ) {
625 - $available_viewer_hours = 0;
626 - }
627 -
628 - // Normalize broadcast hours to a non-negative float.
629 - $available_broadcast_hours = floatval( $pack_details['available_broadcast_hours'] );
630 - if ( $available_broadcast_hours < 0 ) {
631 - $available_broadcast_hours = 0;
632 - }
633 -
634 - // Normalize storage hours to a non-negative float.
635 - $available_storage_hours = floatval( $pack_details['available_storage_hours'] );
636 - if ( $available_storage_hours < 0 ) {
637 - $available_storage_hours = 0;
638 - }
639 -
640 - // Floor each figure to two decimals for display.
641 - $formatted_viewer_hours = $this->wpstream_floor_decimals( $available_viewer_hours, 2 );
642 - $formatted_broadcast_hours = $this->wpstream_floor_decimals( $available_broadcast_hours, 2 );
643 - $formatted_storage_hours = $this->wpstream_floor_decimals( $available_storage_hours, 2 );
644 -
645 - // Output the viewer/broadcast/storage hours summary line.
646 - print '<div class="pack_details_wrapper">'
647 - . __( 'Available streaming resources: ', 'wpstream' )
648 - . '<strong id="wpstream_available_viewer_hours">' . abs( $formatted_viewer_hours ) . ' viewer</strong> '
649 - . __( 'hours, ', 'wpstream' )
650 - . '<strong id="wpstream_available_broadcast_hours">' . abs( $formatted_broadcast_hours ) . ' broadcast</strong> '
651 - . __( 'hours, ', 'wpstream' )
652 - . '<strong id="wpstream_available_storage_hours">' . $formatted_storage_hours . ' storage</strong> '
653 - . __( 'hours', 'wpstream' ) . '.';
654 -
655 - // Upgrade link plus hidden inputs carrying the raw hour figures for JS.
656 - print '<a href="https://wpstream.net/pricing/" class="wpstream_upgrade_topbar" target="_blank">' . esc_html__( 'Upgrade Plan', 'wpstream' ) . '</a>';
657 - print '</div>';
658 - print '<input type="hidden" id="wpstream_viewer_hours" value="' . esc_attr( $pack_details['available_viewer_hours'] ) . '">';
659 - print '<input type="hidden" id="wpstream_broadcast_hours" value="' . esc_attr( $pack_details['available_broadcast_hours'] ) . '">';
660 - print '<input type="hidden" id="wpstream_storage_hours" value="' . esc_attr( $pack_details['available_storage_hours'] ) . '">';
661 - }
662 - }
663 - }
664 -
665 414
666 415 /**
667 416 * help function for media list elementor widget
668 417 *
669 - * Builds and renders a grid of media items (free CPTs or WooCommerce
670 - * products) based on widget attributes, with ordering, pagination, an
671 - * optional live-only filter, and a "no media found" fallback.
672 - *
673 418 * @since 3.0.1
674 - * @param array $attributes Widget attributes (counts, type, order, labels).
675 - * @param string|null $content Unused shortcode inner content.
676 - * @return string Rendered HTML markup for the media grid.
419 + * @return string
677 420 */
678 -
421 +
679 422 public function wpstream_media_list_elementor_function($attributes, $content = null){
680 -
681 -
682 - // Number of items to show (default 3).
423 +
424 +
683 425 $media_number=3;
684 426 if ( isset($attributes['media_number']) ){
685 427 $media_number=$attributes['media_number'];
686 428 }
687 -
688 -
689 - // Number of columns per row (default 3, capped at 4).
429 +
430 +
690 431 $row_number=3;
691 432 if ( isset($attributes['row_number']) ){
692 433 $row_number=$attributes['row_number'];
693 434 }
@@ -694,45 +435,38 @@
694 435 if($row_number>4){
695 436 $row_number=4;
696 437 }
697 438
439 +
440 + ob_start();
698 441
699 - // Buffer all output so it can be returned as a string.
700 - ob_start();
701 -
702 442 // check if is vod or live stream
703 - // Query scaffolding: meta and taxonomy query arrays.
704 443 $meta_query = array();
705 444 $tax_query_array= array();
706 445 $tax_query = array();
707 -
446 +
708 447 // check if the media is paid or free
709 - // Decide which post types to query based on free/paid and live/VOD.
710 - $event_types = array();
448 + $event_types = array();
711 449 $product_type_free_paid = 0;
712 450 if ( isset($attributes['product_type_free_paid']) ){
713 451 $product_type_free_paid=$attributes['product_type_free_paid'];
714 -
715 - // Free path: plugin CPTs (live product, or VOD when product_type == 2).
452 +
716 453 if($product_type_free_paid==0){
717 454 $event_types=array('wpstream_product');
718 -
455 +
719 456 if ( isset($attributes['product_type']) && intval($attributes['product_type'])==2){
720 457 $event_types=array('wpstream_product_vod');
721 458 }
722 459
723 460 }else{
724 - // Paid path: WooCommerce products, filtered by product_type taxonomy.
725 461 $event_types=array('product');
726 462 if ( isset($attributes['product_type']) ){
727 - // Map the numeric product_type to a WooCommerce term slug.
728 463 $product_type = $attributes['product_type'];
729 464 $product_type_slug = 'video_on_demand';
730 465 if($product_type==1){
731 466 $product_type_slug ='live_stream';
732 467 }
733 -
734 - // Restrict the WP_Query to that product_type term.
468 +
735 469 $tax_query_array = array(
736 470 'taxonomy' => 'product_type',
737 471 'field' => 'slug',
738 472 'terms' => $product_type_slug
@@ -746,24 +480,21 @@
746 480 }
747 481 }
748 482
749 483 }
750 - // Optional "see product" label rendered under each free item.
751 484 $see_product='';
752 485 if(isset($attributes['free_label'])){
753 486 $see_product=$attributes['free_label'];
754 487 }
755 -
488 +
756 489 // pagination
757 - // Current page number; the front page uses the 'page' query var instead.
758 490 $paged = (get_query_var('paged')) ? get_query_var('paged') : 1;
759 491 if( is_front_page() ){
760 492 $paged= (get_query_var('page')) ? get_query_var('page') : 1;
761 493 }
762 494
763 -
764 - //order
765 - // Sort order: map the numeric order_by attribute to orderby/order.
495 +
496 + //order
766 497 $orderby='ID';
767 498 $order ='ASC';
768 499 if ( isset($attributes['order_by']) ){
769 500 $order_by=intval($attributes['order_by']);
@@ -786,10 +517,9 @@
786 517 break;
787 518 }
788 519 }
789 520
790 - // building wp_query arg array
791 - // Assemble the WP_Query arguments from the values computed above.
521 + // building wp_query arg array
792 522 $args = array(
793 523 'post_type' => $event_types,
794 524 'post_status' => 'publish',
795 525 'meta_query' => $meta_query,
@@ -802,41 +532,35 @@
802 532
803 533
804 534
805 535 // show live events
806 - // Optional filter: restrict results to the user's currently-live channels.
807 536 if ( isset($attributes['product_show_live']) && $attributes['product_show_live']=='yes'){
808 - $live_event_for_user = $this->main->wpstream_live_connection->api20_wpstream_request_live_stream_for_user_for_shortcode('shortcode');
809 -
810 -
537 + $live_event_for_user = $this->main->wpstream_live_connection->api20_wpstream_request_live_stream_for_user_for_shortcode('shortcode');
538 +
539 +
811 540 if( is_array($live_event_for_user) ){
812 - // Append 0 so post__in is never empty (which would return all posts).
813 541 $live_event_for_user[]=0;
814 -
542 +
815 543 $args['post__in']=$live_event_for_user;
816 544 }
817 - }
545 + }
546 +
547 +
548 +
818 549
819 -
820 -
821 -
822 - // Run the query and render either a grid or a "no media" message.
823 550 $media_list= new WP_Query($args);
824 551 if($media_list->have_posts()){
825 552 print '<ul class="wpstream_media_list_wrapper products columns-'.esc_attr($row_number).'" >';
826 - // Loop over each matched post.
827 553 while($media_list->have_posts()):$media_list->the_post();
828 - // Free items: render a custom card with thumbnail and title.
829 554 if($product_type_free_paid==0 ){
830 555
831 - // Resolve the medium thumbnail, falling back to a default image.
832 556 $thumb=wp_get_attachment_image_src(get_post_thumbnail_id(),'medium');
833 -
557 +
834 558 $thumb_src='';
835 559 if( isset($thumb[0]) ){
836 560 $thumb_src=$thumb[0];
837 561 }
838 -
562 +
839 563 if(($thumb_src)==''){
840 564 $thumb_src= plugin_dir_url( dirname( __FILE__ ) ). 'img/default_300.png';
841 565 }
842 566 print '<li class="wpstream_product_unit">'
@@ -842,34 +566,28 @@
842 566 print '<li class="wpstream_product_unit">'
843 567 .'<a href="'.get_permalink().'" class="product_title" ><div class="product_image" style="background-image:url('.esc_url($thumb_src).')"></div></a>'
844 568 .'<a href="'.get_permalink().'" class="product_title" >'.get_the_title().'</a>';
845 569
846 - // Optional "see product" call-to-action link.
847 570 if($see_product!=''){
848 571 print '<a href="'.get_permalink().'"class="see_product">'.$see_product.'</a>';
849 572 }
850 573 print '</li>';
851 574 }else{
852 - // Paid items: use WooCommerce's product content template part.
853 575 wc_get_template_part( 'content', 'product' );
854 576 }
855 577 endwhile;
856 578 print '</ul>';
857 579 }else{
858 - // No results for the current query/page.
859 580 print esc_html__('No media found! ','wpstream');
860 581 }
861 -
862 -
863 - // Restore the global post/query state after the custom loop.
582 +
583 +
864 584 wp_reset_query();
865 585 wp_reset_postdata();
866 -
867 - // Append pagination controls beneath the grid.
868 - $this->wpstream_pagination($media_list->max_num_pages,$range=2);
869 - // Capture the buffered markup and return it.
586 +
587 + $this->wpstream_pagination($media_list->max_num_pages,$range=2);
870 588 $return_string= ob_get_contents();
871 - ob_end_clean();
589 + ob_end_clean();
872 590
873 591 return $return_string;
874 592 }
875 593
@@ -878,32 +596,26 @@
878 596
879 597
880 598
881 599 /*
882 - *
883 - *
600 + *
601 + *
884 602 * Pagination for media lista
885 - *
886 - *
887 - *
888 - */
603 + *
604 + *
605 + *
606 + */
607 +
608 +
889 609
890 - /**
891 - * Print a numbered pagination control for the media list.
892 - *
893 - * @param int|string $pages Total number of pages; falls back to the main query.
894 - * @param int $range How many page links to show either side of the current page.
895 - */
610 +
896 611 function wpstream_pagination($pages = '', $range = 2){
897 612
898 - // Total number of page links visible in the window.
899 613 $showitems = ($range * 2)+1;
900 - // Current page from the global; default to page 1.
901 614 global $paged;
902 615 if(empty($paged)) $paged = 1;
903 616
904 617
905 - // Fall back to the main query's page count when none was passed in.
906 618 if($pages == ''){
907 619 global $wp_query;
908 620 $pages = $wp_query->max_num_pages;
909 621 if(!$pages)
@@ -911,21 +623,16 @@
911 623 $pages = 1;
912 624 }
913 625 }
914 626
915 - // Only render pagination when there is more than one page.
916 627 if(1 != $pages){
917 628 print '<ul class="wpstream_pagination ">';
918 - // Previous-page arrow.
919 629 print '<li class="roundleft"><a href="'.get_pagenum_link($paged - 1).'"> < </a></li>';
920 630
921 - // Emit a link for each page within the visible window.
922 631 for ($i=1; $i <= $pages; $i++)
923 632 {
924 - // Show this page number only if inside the range window (or few pages total).
925 633 if (1 != $pages &&( !($i >= $paged+$range+1 || $i <= $paged-$range-1) || $pages <= $showitems ))
926 634 {
927 - // Mark the current page as active.
928 635 if ($paged == $i){
929 636 print '<li class="active"><a href="'.esc_url(get_pagenum_link($i)).'" >'.$i.'</a><li>';
930 637 }else{
931 638 print '<li><a href="'.esc_url(get_pagenum_link($i)).'" >'.$i.'</a><li>';
@@ -932,9 +639,8 @@
932 639 }
933 640 }
934 641 }
935 642
936 - // Compute the next-page URL, clamping at the last page.
937 643 $prev_page= get_pagenum_link($paged + 1);
938 644 if ( ($paged +1) > $pages){
939 645 $prev_page= get_pagenum_link($paged );
940 646 }else{
@@ -941,9 +647,8 @@
941 647 $prev_page= get_pagenum_link($paged + 1);
942 648 }
943 649
944 650
945 - // Next-page arrow.
946 651 print '<li class="roundright"><a href="'.$prev_page.'"> > </a><li>';
947 652 print '</ul>';
948 653 }
949 654 }
@@ -962,22 +667,16 @@
962 667
963 668 /**
964 669 * help function for player elementr widget
965 670 *
966 - * Renders the standard video player for a given product id, or resolves the
967 - * author's first channel when only a user_id is supplied.
968 - *
969 671 * @since 3.0.1
970 - * @param array $attributes Widget attributes ('id', 'user_id').
971 - * @param string|null $content Unused shortcode inner content.
972 - * @return string Rendered player markup.
672 + * @return string
973 673 */
974 -
674 +
975 675 public function wpstream_insert_player_elementor($attributes, $content = null){
976 - // Normalize incoming attributes with defaults.
977 676 $product_id = '';
978 677 $return_string = '';
979 - $attributes = shortcode_atts(
678 + $attributes = shortcode_atts(
980 679 array(
981 680 'id' => 0,
982 681 'user_id' => 0,
983 682 ), $attributes) ;
@@ -982,37 +681,26 @@
982 681 'user_id' => 0,
983 682 ), $attributes) ;
984 683
985 684
986 - // Explicit product id, if provided.
987 685 if ( isset($attributes['id']) ){
988 686 $product_id=$attributes['id'];
989 687 }
990 - // Optional author id used to look up a channel.
991 688 if ( isset($attributes['user_id']) ){
992 689 $user_id = intval( $attributes['user_id'] );
993 690 }
994 -
995 - // No product id but a user id: resolve that author's first channel.
691 +
996 692 if(intval($product_id)==0 && $user_id!=0 ){
997 693 $product_id= $this->wpstream_player_retrive_first_id($user_id);
998 694 }
999 -
1000 -
1001 -
1002 - // Buffer the player output so it can be returned as a string.
695 +
696 +
697 +
698 +
1003 699 ob_start();
1004 - // Render the player shortcode inside the wrapper markup below.
1005 - ?>
1006 - <div class="wpstream_insert_player_elementor_wrapper">
1007 - <?php
1008 - $this->main->wpstream_player->wpstream_video_player_shortcode($product_id);
1009 - ?>
1010 - </div>
1011 - <?php
1012 - // Capture and return the buffered markup.
700 + $this->main->wpstream_player->wpstream_video_player_shortcode($product_id);
1013 701 $return_string= ob_get_contents();
1014 - ob_end_clean();
702 + ob_end_clean();
1015 703
1016 704 return $return_string;
1017 705 }
1018 706
@@ -1018,21 +706,16 @@
1018 706
1019 707 /**
1020 708 * help function for player low latency elementor widget
1021 709 *
1022 - * Same as the standard player helper but renders the low-latency player.
1023 - *
1024 710 * @since 3.0.1
1025 - * @param array $attributes Widget attributes ('id', 'user_id').
1026 - * @param string|null $content Unused shortcode inner content.
1027 - * @return string Rendered low-latency player markup.
711 + * @return string
1028 712 */
1029 -
713 +
1030 714 public function wpstream_insert_player__low_latency_elementor($attributes, $content = null){
1031 - // Normalize incoming attributes with defaults.
1032 715 $product_id = '';
1033 716 $return_string = '';
1034 - $attributes = shortcode_atts(
717 + $attributes = shortcode_atts(
1035 718 array(
1036 719 'id' => 0,
1037 720 'user_id' => 0,
1038 721 ), $attributes) ;
@@ -1037,45 +720,33 @@
1037 720 'user_id' => 0,
1038 721 ), $attributes) ;
1039 722
1040 723
1041 - // Explicit product id, if provided.
1042 724 if ( isset($attributes['id']) ){
1043 725 $product_id=$attributes['id'];
1044 726 }
1045 -
1046 - // Optional author id used to look up a channel.
727 +
1047 728 if ( isset($attributes['user_id']) ){
1048 729 $user_id = intval( $attributes['user_id'] );
1049 730 }
1050 731
1051 - // No product id but a user id: resolve that author's first channel.
1052 732 if(intval($product_id)==0 && $user_id!=0){
1053 733 $product_id= $this->wpstream_player_retrive_first_id($user_id);
1054 734 }
1055 -
1056 -
1057 - // Buffer the low-latency player output and return it.
735 +
736 +
1058 737 ob_start();
1059 738 $this->main->wpstream_player->wpstream_video_player_shortcode_low_latency($product_id);
1060 739 $return_string= ob_get_contents();
1061 - ob_end_clean();
740 + ob_end_clean();
1062 741
1063 742 return $return_string;
1064 743 }
1065 -
1066 -
1067 -
1068 - /**
1069 - * Resolve the first channel/event id belonging to a given author.
1070 - *
1071 - * @param string|int $received_user_id Author user id.
1072 - * @return int|string Post id of the author's first channel, or 0 when none.
1073 - */
744 +
745 +
746 +
1074 747 public function wpstream_player_retrive_first_id($received_user_id=''){
1075 - // Free vs paid channel type is a site-wide option.
1076 748 $channel_type = get_option ('wpstream_user_streaming_channel_type');
1077 - // Look up the author's most relevant event id for that type.
1078 749 $product_id = $this->wpstream_get_current_event_per_author($received_user_id,$channel_type);
1079 750 return $product_id;
1080 751 }
1081 752
@@ -1083,39 +754,31 @@
1083 754
1084 755 /**
1085 756 * help function for chat elementor widget
1086 757 *
1087 - * Renders the chat widget for a product and wires up its client connection.
1088 - *
1089 758 * @since 3.0.1
1090 - * @param array $attributes Widget attributes ('id').
1091 - * @param string|null $content Unused shortcode inner content.
1092 - * @return string Rendered chat markup.
759 + * @return string
1093 760 */
1094 -
761 +
1095 762 public function wpstream_insert_chat_elementor($attributes, $content = null){
1096 - // Normalize incoming attributes with defaults.
1097 763 $product_id = '';
1098 764 $return_string = '';
1099 - $attributes = shortcode_atts(
765 + $attributes = shortcode_atts(
1100 766 array(
1101 767 'id' => 0,
1102 768 ), $attributes) ;
1103 769
1104 770
1105 - // Explicit product id, if provided.
1106 771 if ( isset($attributes['id']) ){
1107 772 $product_id=$attributes['id'];
1108 773 }
1109 774
1110 - // Open the wrapper, buffer the chat markup, then close the wrapper.
1111 775 $return_string.= '<div class="wpstream_plugin_chat_wrapper">';
1112 776 ob_start();
1113 777 $this->main->wpstream_player->wpstream_chat_wrapper($product_id);
1114 778 $return_string.= ob_get_contents();
1115 - ob_end_clean();
1116 - $return_string.='</div>';
1117 - // Emit the chat client connection script for this product.
779 + ob_end_clean();
780 + $return_string.='</div>';
1118 781 $this->main->wpstream_player->wpstream_connect_to_chat($product_id);
1119 782
1120 783 return $return_string;
1121 784 }
@@ -1129,41 +792,31 @@
1129 792 * @since 3.7
1130 793 */
1131 794
1132 795 public function wpstream_check_user_can_stream(){
1133 - // Current user for the role/capability checks below.
1134 796 $current_user = wp_get_current_user();
1135 -
1136 - // Guests can never stream.
797 +
1137 798 if( !is_user_logged_in() ){
1138 799 return false;
1139 800 exit('user not logged in');
1140 801 }
1141 -
802 +
1142 803 if(current_user_can('administrator')){
1143 804 // admins can always brodcast
1144 805 return true;
1145 806 }
1146 -
1147 - // Site-configured list of roles that are allowed to stream.
807 +
1148 808 $extra_roles = get_option( 'wpstream_stream_role', true );
1149 - // The user's primary role (first in the roles array).
1150 - $user_role = '';
1151 - if( is_array( $current_user->roles) && count( $current_user->roles ) > 0 ){
1152 - $user_role = $current_user->roles[0];
1153 - }
1154 -
1155 - // Allow when the user's role is in the configured allow-list.
1156 - if ( is_array($extra_roles) && in_array( $user_role, $extra_roles ) ) {
809 + $user_role = $current_user->roles[0];
810 +
811 + if (is_array($extra_roles) && in_array($user_role, $extra_roles)){
1157 812 return true;
1158 813 }
1159 -
1160 - // Allow when the "regular users may stream" option is enabled.
814 +
1161 815 if(function_exists('wpstream_get_option') && intval(wpstream_get_option('allow_streaming_regular_users',''))==1 ){
1162 816 return true;
1163 817 }
1164 -
1165 - // Otherwise deny.
818 +
1166 819 return false;
1167 820 }
1168 821
1169 822
@@ -1169,118 +822,66 @@
1169 822
1170 823 /**
1171 824 * Start Streaming wrapper
1172 825 *
1173 - * Ensures a channel exists (creating one for front-end streamers when
1174 - * needed), prints the error-modal scaffolding, then renders the start-
1175 - * streaming unit.
1176 - *
1177 826 * @since 3.7
1178 - * @param int $item_id Channel/product id, or 0 to auto-resolve.
1179 - * @param string $type Streaming unit type/context.
1180 827 */
828 +
1181 829 public function wpstream_live_stream_unit_wrapper($item_id,$type){
1182 - // Coerce to an integer id.
1183 830 $item_id = intval($item_id);
1184 -
831 +
1185 832 if($item_id == 0){
1186 833 //retrive or create channel for front end streamers
1187 834 $item_id=$this->wpstream_retrive_front_end_channel();
1188 835 }
1189 - // Modal backdrop and reusable error-notification markup.
1190 - print'<div class="wpstream_modal_background"></div>';
836 + print'<div class="wpstream_modal_background"></div>';
1191 837 print '<div class="wpstream_error_modal_notification"><div class="wpstream_error_content">er2</div>
1192 838 <div class="wpstream_error_ok wpstream_button" type="button">'.esc_html__('Close','wpstream').'</div>
1193 839 </div>';
1194 - // Delegate the actual start-streaming UI to the admin controller.
1195 840 $this->admin->wpstream_live_stream_unit( $item_id,$type );
1196 841 }
1197 842
1198 843
1199 - /**
1200 - * Start Streaming wrapper for wpstream theme
1201 - *
1202 - * Same as wpstream_live_stream_unit_wrapper() but renders the theme's
1203 - * variant of the start-streaming unit.
1204 - *
1205 - * @since 3.7
1206 - * @param int $item_id Channel/product id, or 0 to auto-resolve.
1207 - * @param string $type Streaming unit type/context.
1208 - */
1209 -
1210 - public function wpstream_live_stream_unit_wrapper_for_theme($item_id,$type){
1211 - // Coerce to an integer id.
1212 - $item_id = intval($item_id);
1213 -
1214 - if($item_id == 0){
1215 - //retrive or create channel for front end streamers
1216 - $item_id=$this->wpstream_retrive_front_end_channel();
1217 - }
1218 - // Modal backdrop and reusable error-notification markup.
1219 - print'<div class="wpstream_modal_background"></div>';
1220 - print '<div class="wpstream_error_modal_notification"><div class="wpstream_error_content">er2</div>
1221 - <div class="wpstream_error_ok wpstream_button" type="button">'.esc_html__('Close','wpstream').'</div>
1222 - </div>';
1223 - // Delegate to the admin controller's theme-specific renderer.
1224 - $this->admin->wpstream_live_stream_unit_for_theme( $item_id,$type );
1225 - }
1226 844
1227 845
846 +
1228 847 /**
1229 848 * retrive channel for front end streaming
1230 849 *
1231 - * Returns the current user's front-end channel id, creating a new event
1232 - * when the user does not yet have one.
1233 - *
1234 850 * @since 3.7
1235 - * @return int Channel/product id for the current user.
1236 851 */
1237 852 public function wpstream_retrive_front_end_channel(){
1238 -
1239 - // Current user plus the site-wide channel type and default price.
853 +
1240 854 $current_user = wp_get_current_user();
1241 855 $channel_type = get_option ('wpstream_user_streaming_channel_type');
1242 856 $channel_price = floatval( get_option ('wpstream_user_streaming_default_price') );
1243 -
1244 - // Look for an existing channel owned by this user.
857 +
1245 858 $front_end_streamin_channel = $this->wpstream_get_current_event_per_author($current_user->ID,$channel_type);
1246 -
1247 - // None found: create one on the fly.
859 +
1248 860 if(intval($front_end_streamin_channel) == 0){
1249 861 $front_end_streamin_channel= $this->wpstrea_create_front_end_event($current_user->ID,$current_user->user_login ,$channel_type,$channel_price);
1250 862 }
1251 863 return $front_end_streamin_channel;
1252 -
864 +
1253 865 }
1254 866
1255 867 /**
1256 868 * create the event from front end
1257 869 *
1258 - * Inserts a new channel post (free CPT or paid WooCommerce product),
1259 - * setting price/terms for paid channels, and flags it as a live event.
1260 - *
1261 870 * @since 3.7
1262 - * @param int $userID Author user id.
1263 - * @param string $userLogin Author login, used in the channel title.
1264 - * @param string $channel_type 'paid' for a WooCommerce product, else free.
1265 - * @param float $channel_price Price to set for paid channels.
1266 - * @return int|void New post id, or void when the user may not stream.
1267 871 */
1268 -
872 +
1269 873 public function wpstrea_create_front_end_event($userID,$userLogin,$channel_type,$channel_price){
1270 -
1271 - // Refuse to create a channel for users without streaming permission.
874 +
1272 875 if( !$this->wpstream_check_user_can_stream() ){
1273 876 return;
1274 877 }
1275 -
1276 - // Free channels use the plugin CPT; paid channels use WooCommerce products.
878 +
1277 879 $post_type='wpstream_product';
1278 880 if($channel_type=='paid'){
1279 881 $post_type='product';
1280 882 }
1281 -
1282 - // Build and insert the channel post.
883 +
1283 884 $post = array(
1284 885 'post_title' => sprintf( esc_html__('%s Channel','wpstream'),$userLogin),
1285 886 'post_content' => '',
1286 887 'post_type' => $post_type ,
@@ -1286,48 +887,36 @@
1286 887 'post_type' => $post_type ,
1287 888 'post_author' => $userID,
1288 889 'post_status' => 'publish',
1289 890 );
1290 - $post_id = wp_insert_post($post );
1291 - // For paid channels, configure the WooCommerce product pricing and type.
891 + $post_id = wp_insert_post($post );
1292 892 if($channel_type=='paid'){
1293 893 $product = wc_get_product($post_id);
1294 894 $price = wc_format_decimal($channel_price);
1295 -
895 +
1296 896 $product = wc_get_product( $post_id );
1297 897 // Set the product active price (regular)
1298 898 $product->set_price( $price );
1299 899 $product->set_regular_price( $price ); // To be sure
1300 900 $product->save();
1301 - // Mark as not-yet-passed and tag it as a live_stream product.
1302 901 update_post_meta ($post_id,'event_passed',0);
1303 902 wp_set_object_terms( $post_id, 'live_stream', 'product_type' );
1304 903 }
1305 - // Flag the post as a live event (product type 1).
1306 904 update_post_meta($post_id,'wpstream_product_type',1);
1307 -
905 +
1308 906 return $post_id;
1309 907 }
1310 908
1311 909
1312 - /**
1313 - * Find the first channel/event id owned by a given author.
1314 - *
1315 - * @param int $userID Author user id.
1316 - * @param string $channel_type 'paid' for a WooCommerce product, else free.
1317 - * @return int Post id of the author's first matching channel, or 0.
1318 - */
1319 910 public function wpstream_get_current_event_per_author($userID,$channel_type){
1320 -
1321 - // Free channels are CPTs; paid channels are WooCommerce products.
911 +
1322 912 $post_type='wpstream_product';
1323 913 if($channel_type=='paid'){
1324 914 $post_type='product';
1325 915 }
1326 -
1327 - // Query for a single post id owned by this author.
916 +
1328 917 $args = array(
1329 -
918 +
1330 919 'post_type' => $post_type,
1331 920 'author' => $userID,
1332 921 'posts_per_page' => 1,
1333 922 'fields' => 'ids'
@@ -1333,9 +922,8 @@
1333 922 'fields' => 'ids'
1334 923 )
1335 924 ;
1336 925 $author_posts = new WP_Query( $args );
1337 - // Use the found id, or 0 when the author has no channel.
1338 926 if( $author_posts->have_posts() ) {
1339 927 $author_posts->the_post();
1340 928 $the_id= get_the_ID();
1341 929 }else{
@@ -1340,20 +928,11 @@
1340 928 $the_id= get_the_ID();
1341 929 }else{
1342 930 $the_id= 0;
1343 931 }
1344 -
1345 - // Restore global post/query state after the custom query.
932 +
1346 933 wp_reset_query();
1347 934 wp_reset_postdata();
1348 935 return $the_id;
1349 936 }
1350 -
1351 - /**
1352 - * Cleanup old logs
1353 - */
1354 - public function cleanup_logs() {
1355 - // Delegate to the logger, which prunes entries past its retention window.
1356 - $logger = new WPStream_Logger();
1357 - $logger->clear_old_logs();
1358 - }
937 +
1359 938 }