PluginProbe
WpStream – Live Streaming, Video on Demand, Pay Per View / 3.8
WpStream – Live Streaming, Video on Demand, Pay Per View v3.8
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 +161 -867 4.13.23.8 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.
101 - if ( defined( 'WPSTREAM_PLUGIN_VERSION' ) ) {
102 - $this->version = WPSTREAM_PLUGIN_VERSION;
84 + $this->main = $this;
85 + if ( defined( 'WPSTREAM_VERSION' ) ) {
86 + $this->version = WPSTREAM_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 + $this->xtest = "this is test2";
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,132 +208,86 @@
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 );
212 + $this->admin= $plugin_admin = new Wpstream_Admin( $this->get_plugin_name(), $this->get_version(), $this->main );
326 213
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' );
331 - $this->loader->add_action( 'admin_enqueue_scripts', $plugin_admin, 'enqueue_scripts' );
214 +
215 +
216 + $this->loader->add_action( 'admin_enqueue_scripts', $plugin_admin, 'enqueue_styles' );
217 + $this->loader->add_action( 'admin_enqueue_scripts', $plugin_admin, 'enqueue_scripts' );
332 218 $this->loader->add_action( 'admin_menu', $plugin_admin, 'wpstream_manage_admin_menu',999);
333 -
334 - // Register the custom post types on init.
219 +
335 220 $plugin_post_types = new Wpstream_Product();
336 221 $this->loader->add_action( 'init', $plugin_post_types, 'create_custom_post_type', 999 );
337 -
222 +
338 223 // 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 -
224 + $this->loader->add_action( 'admin_init', $plugin_admin, 'add_wpstream_product_metaboxes' );
225 + $this->loader->add_action( 'save_post', $plugin_admin, 'wpstream_free_product_update_post',1,2 );
226 +
349 227 // make product virtual
350 228 $this->loader->add_action( 'save_post', $plugin_admin, 'wpstream_make_product_virtual', 99999, 2 );
351 -
352 -
353 -
229 +
230 +
231 +
354 232 // show streaming controls on sidebar
355 233 $this->loader->add_action('add_meta_boxes', $plugin_admin, 'wpstream_startstreaming_sidebar_meta');
356 -
357 - // on boarding actions
358 - // Onboarding wizard markup plus its AJAX channel/VOD/login/register endpoints.
359 - $this->loader->add_action('admin_footer',$plugin_admin, 'wpstream_admin_footer_onboarding');
360 - $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' );
364 -
365 -
366 - // Onboarding login/registration plus the captcha challenge (logged-in and guest).
367 - $this->loader->add_action( 'wp_ajax_wpstream_on_board_login', $plugin_admin,'wpstream_on_board_login' );
368 - $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 234
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 -
376 - // General and plugin-update admin notices.
377 - $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 - $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' );
383 -
384 -
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 -
235 +
236 + $this->loader->add_action( 'admin_notices', $plugin_admin,'wpstream_admin_notice' );
237 + $this->loader->add_action( 'wp_ajax_wpstream_update_cache_notice', $plugin_admin,'wpstream_update_cache_notice' );
238 +
388 239 // add and save category extra fields
389 - // The same add/edit/create/save callbacks are shared across every taxonomy below.
390 240 $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' );
241 + $this->loader->add_action( 'category_add_form_fields', $plugin_post_types, 'wpstream_category_callback_add_function', 10, 2 );
392 242 $this->loader->add_action( 'created_category', $plugin_post_types, 'wpstream_category_save_extra_fields_callback', 10, 2);
393 243 $this->loader->add_action( 'edited_category', $plugin_post_types, 'wpstream_category_save_extra_fields_callback', 10, 2);
394 244
395 - // Same extra fields on the WooCommerce product category taxonomy.
396 245 $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' );
246 + $this->loader->add_action( 'product_cat_add_form_fields', $plugin_post_types, 'wpstream_category_callback_add_function', 10, 2 );
398 247 $this->loader->add_action( 'created_product_cat', $plugin_post_types, 'wpstream_category_save_extra_fields_callback', 10, 2);
399 248 $this->loader->add_action( 'edited_product_cat', $plugin_post_types, 'wpstream_category_save_extra_fields_callback', 10, 2);
400 249
401 250
402 - // Same extra fields on the plugin's own wpstream_category taxonomy.
403 251 $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' );
252 + $this->loader->add_action( 'wpstream_category_add_form_fields', $plugin_post_types, 'wpstream_category_callback_add_function', 10, 2 );
405 253 $this->loader->add_action( 'created_wpstream_category', $plugin_post_types, 'wpstream_category_save_extra_fields_callback', 10, 2);
406 254 $this->loader->add_action( 'edited_wpstream_category', $plugin_post_types, 'wpstream_category_save_extra_fields_callback', 10, 2);
407 255
408 256
409 - // Same extra fields on the wpstream_actors taxonomy.
410 257 $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' );
258 + $this->loader->add_action( 'wpstream_actors_add_form_fields', $plugin_post_types, 'wpstream_category_callback_add_function', 10, 2 );
412 259 $this->loader->add_action( 'created_wpstream_actors', $plugin_post_types, 'wpstream_category_save_extra_fields_callback', 10, 2);
413 260 $this->loader->add_action( 'edited_wpstream_actors', $plugin_post_types, 'wpstream_category_save_extra_fields_callback', 10, 2);
414 261
415 - // Same extra fields on the wpstream_movie_rating taxonomy.
416 262 $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' );
263 + $this->loader->add_action( 'wpstream_movie_rating_add_form_fields', $plugin_post_types, 'wpstream_category_callback_add_function', 10, 2 );
418 264 $this->loader->add_action( 'created_wpstream_movie_rating', $plugin_post_types, 'wpstream_category_save_extra_fields_callback', 10, 2);
419 265 $this->loader->add_action( 'edited_wpstream_movie_rating', $plugin_post_types, 'wpstream_category_save_extra_fields_callback', 10, 2);
266 +
267 +
420 268
421 269
422 - // WooCommerce-only admin hooks: register the custom product types,
423 - // their data tabs/fields, pricing visibility, and add-to-cart handling.
424 270 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' );
271 +
428 272 $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 );
273 + $this->loader->add_action( 'admin_footer', $plugin_admin, 'wpstream_products_custom_js' );
432 274 $this->loader->add_filter( 'woocommerce_product_data_tabs', $plugin_admin, 'wpstream_hide_attributes_data_panel',10,1 );
433 - $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 );
275 +
276 + $this->loader->add_filter( 'woocommerce_product_options_general_product_data',$plugin_admin, 'wpstream_add_custom_general_fields', 10,1);
437 277 $this->loader->add_filter( 'woocommerce_process_product_meta',$plugin_admin, 'wpstream_add_custom_general_fields_save',10,1 );
438 278 $this->loader->add_action( 'woocommerce_live_stream_add_to_cart', $plugin_admin, 'wpstream_add_to_cart',10,1);
439 279 $this->loader->add_action( 'woocommerce_video_on_demand_add_to_cart', $plugin_admin, 'wpstream_add_to_cart',10,1);
440 280 $this->loader->add_filter( 'woocommerce_loop_add_to_cart_link', $plugin_admin,'replacing_add_to_cart_button', 10, 2 );
441 281 }
442 - }
282 +
283 +
284 +
285 +
443 286
444 287
288 + }
445 289
446 -
447 -
448 290 /**
449 291 * Register all of the hooks related to the public-facing functionality
450 292 * of the plugin.
451 293 *
@@ -453,66 +295,38 @@
453 295 * @access private
454 296 */
455 297 private function define_public_hooks() {
456 298
457 - // Build the public-facing controller.
458 299 $plugin_public = new Wpstream_Public( $this->get_plugin_name(), $this->get_version(), $this->main );
459 300
460 - // Front-end styles.
461 301 $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' );
302 + $this->loader->add_action( 'wp_enqueue_scripts', $plugin_public, 'enqueue_scripts' );
303 +
304 + $this->loader->add_action( 'init', $plugin_public,'wpstream_my_custom_endpoints' );
305 + $this->loader->add_filter( 'query_vars',$plugin_public, 'wpstream_my_custom_query_vars', 0 );
306 +
307 + //live stream action
308 + $this->loader->add_action('init',$plugin_public,'wpstream_set_cookies',0);
309 + $this->loader->add_action('init',$plugin_public,'wpstream_live_streaming_key');
310 + $this->loader->add_action('init',$plugin_public,'wpstream_live_streaming_key_for_3rdparty');
311 + $this->loader->add_action('init',$plugin_public,'wpstream_live_streaming_key_vod');
312 + // woo action
313 +
314 + $this->loader->add_action( 'woocommerce_before_single_product', $plugin_public,'wpstream_non_image_content_wrapper_start', 20 );
315 + $this->loader->add_action( 'woocommerce_after_single_product', $plugin_public,'wpstream_non_image_content_wrapper_end', 20 );
316 +
317 + $this->loader->add_filter( 'woocommerce_account_menu_items', $plugin_public,'wpstream_custom_my_account_menu_items' );
318 + $this->loader->add_action( 'woocommerce_account_event-list_endpoint', $plugin_public,'wpstream_custom_endpoint_content_event_list' );
319 + $this->loader->add_action( 'woocommerce_account_video-list_endpoint', $plugin_public,'wpstream_custom_endpoint_video_list' );
320 +
466 321
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 );
322 + $this->loader->add_action( 'after_switch_theme', $plugin_public,'wpstream_custom_flush_rewrite_rules' );
323 + $this->loader->add_action('init', $plugin_public,'wpstream_shortcodes');
324 +
325 + $this->loader->add_action('wo_before_api', 'wpstream_cors_check_and_response',10,1);
326 +
327 +
328 +
515 329 }
516 330
517 331 /**
518 332 * Run the loader to execute all of the hooks with WordPress.
@@ -519,9 +333,8 @@
519 333 *
520 334 * @since 3.0.1
521 335 */
522 336 public function run() {
523 - // Hand off to the loader, which calls add_action/add_filter for every hook.
524 337 $this->loader->run();
525 338 }
526 339
527 340 /**
@@ -531,9 +344,8 @@
531 344 * @since 3.0.1
532 345 * @return string The name of the plugin.
533 346 */
534 347 public function get_plugin_name() {
535 - // Return the stored text-domain / identifier string.
536 348 return $this->plugin_name;
537 349 }
538 350
539 351 /**
@@ -542,9 +354,8 @@
542 354 * @since 3.0.1
543 355 * @return Wpstream_Loader Orchestrates the hooks of the plugin.
544 356 */
545 357 public function get_loader() {
546 - // Return the hook loader instance.
547 358 return $this->loader;
548 359 }
549 360
550 361 /**
@@ -553,431 +364,40 @@
553 364 * @since 3.0.1
554 365 * @return string The version number of the plugin.
555 366 */
556 367 public function get_version() {
557 - // Return the resolved plugin version string.
558 368 return $this->version;
559 369 }
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 -
370 +
371 +
582 372
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 373 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 - }
598 -
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 - }
604 -
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 -
666 - /**
667 - * help function for media list elementor widget
668 - *
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 - * @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.
677 - */
678 -
679 - public function wpstream_media_list_elementor_function($attributes, $content = null){
680 -
681 -
682 - // Number of items to show (default 3).
683 - $media_number=3;
684 - if ( isset($attributes['media_number']) ){
685 - $media_number=$attributes['media_number'];
686 - }
687 -
688 -
689 - // Number of columns per row (default 3, capped at 4).
690 - $row_number=3;
691 - if ( isset($attributes['row_number']) ){
692 - $row_number=$attributes['row_number'];
693 - }
694 - if($row_number>4){
695 - $row_number=4;
696 - }
697 -
698 -
699 - // Buffer all output so it can be returned as a string.
700 - ob_start();
701 -
702 - // check if is vod or live stream
703 - // Query scaffolding: meta and taxonomy query arrays.
704 - $meta_query = array();
705 - $tax_query_array= array();
706 - $tax_query = array();
707 -
708 - // 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();
711 - $product_type_free_paid = 0;
712 - if ( isset($attributes['product_type_free_paid']) ){
713 - $product_type_free_paid=$attributes['product_type_free_paid'];
714 -
715 - // Free path: plugin CPTs (live product, or VOD when product_type == 2).
716 - if($product_type_free_paid==0){
717 - $event_types=array('wpstream_product');
718 -
719 - if ( isset($attributes['product_type']) && intval($attributes['product_type'])==2){
720 - $event_types=array('wpstream_product_vod');
721 - }
722 -
723 - }else{
724 - // Paid path: WooCommerce products, filtered by product_type taxonomy.
725 - $event_types=array('product');
726 - if ( isset($attributes['product_type']) ){
727 - // Map the numeric product_type to a WooCommerce term slug.
728 - $product_type = $attributes['product_type'];
729 - $product_type_slug = 'video_on_demand';
730 - if($product_type==1){
731 - $product_type_slug ='live_stream';
732 - }
733 -
734 - // Restrict the WP_Query to that product_type term.
735 - $tax_query_array = array(
736 - 'taxonomy' => 'product_type',
737 - 'field' => 'slug',
738 - 'terms' => $product_type_slug
739 - );
740 -
741 - $tax_query= array(
742 - 'relation' => 'AND',
743 - $tax_query_array
744 - );
745 -
746 - }
747 - }
748 -
749 - }
750 - // Optional "see product" label rendered under each free item.
751 - $see_product='';
752 - if(isset($attributes['free_label'])){
753 - $see_product=$attributes['free_label'];
754 - }
755 -
756 - // pagination
757 - // Current page number; the front page uses the 'page' query var instead.
758 - $paged = (get_query_var('paged')) ? get_query_var('paged') : 1;
759 - if( is_front_page() ){
760 - $paged= (get_query_var('page')) ? get_query_var('page') : 1;
761 - }
762 -
763 -
764 - //order
765 - // Sort order: map the numeric order_by attribute to orderby/order.
766 - $orderby='ID';
767 - $order ='ASC';
768 - if ( isset($attributes['order_by']) ){
769 - $order_by=intval($attributes['order_by']);
770 - switch ($order_by) {
771 - case 0:
772 - $orderby='ID';
773 - $order ='ASC';
774 - break;
775 - case 1:
776 - $orderby='ID';
777 - $order ='DESC';
778 - break;
779 - case 2:
780 - $orderby='title';
781 - $order ='ASC';
782 - break;
783 - case 3:
784 - $orderby='title';
785 - $order ='DESC';
786 - break;
787 - }
788 - }
374 + if( isset($pack_details['band']) && isset( $pack_details['storage']) ){
375 + $wpstream_convert_band = $this->wpstream_convert_band($pack_details['band']);
376 + if($wpstream_convert_band<0)$wpstream_convert_band=0;
789 377
790 - // building wp_query arg array
791 - // Assemble the WP_Query arguments from the values computed above.
792 - $args = array(
793 - 'post_type' => $event_types,
794 - 'post_status' => 'publish',
795 - 'meta_query' => $meta_query,
796 - 'posts_per_page' => $media_number,
797 - 'paged' => $paged,
798 - 'orderby' => $orderby,
799 - 'order' => $order,
800 - 'tax_query' => $tax_query
801 - );
378 + $wpstream_convert_storage = $this->wpstream_convert_band($pack_details['storage']);
379 + if($wpstream_convert_storage<0)$wpstream_convert_storage=0;
802 380
803 -
804 -
805 - // show live events
806 - // Optional filter: restrict results to the user's currently-live channels.
807 - 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');
381 + print '<div class="pack_details_wrapper"><strong>'.__('Your account information: ','wpstream').'</strong> '.__('You have','wpstream').'<strong> '.$wpstream_convert_band.' Gb</strong> '.__('available streaming bandwidth and','wpstream').' <strong>'.$wpstream_convert_storage.' Gb</strong> '.__('available media storage','wpstream').'.</div>';
382 + print'<input type="hidden" id="wpstream_band" value="'.$pack_details['band'].'">';
383 + print'<input type="hidden" id="wpstream_storage" value="'.$pack_details['storage'].'">';
809 384
810 -
811 - if( is_array($live_event_for_user) ){
812 - // Append 0 so post__in is never empty (which would return all posts).
813 - $live_event_for_user[]=0;
814 -
815 - $args['post__in']=$live_event_for_user;
816 - }
817 - }
818 -
819 -
820 -
821 -
822 - // Run the query and render either a grid or a "no media" message.
823 - $media_list= new WP_Query($args);
824 - if($media_list->have_posts()){
825 - print '<ul class="wpstream_media_list_wrapper products columns-'.esc_attr($row_number).'" >';
826 - // Loop over each matched post.
827 - while($media_list->have_posts()):$media_list->the_post();
828 - // Free items: render a custom card with thumbnail and title.
829 - if($product_type_free_paid==0 ){
830 -
831 - // Resolve the medium thumbnail, falling back to a default image.
832 - $thumb=wp_get_attachment_image_src(get_post_thumbnail_id(),'medium');
833 -
834 - $thumb_src='';
835 - if( isset($thumb[0]) ){
836 - $thumb_src=$thumb[0];
837 - }
838 -
839 - if(($thumb_src)==''){
840 - $thumb_src= plugin_dir_url( dirname( __FILE__ ) ). 'img/default_300.png';
841 - }
842 - print '<li class="wpstream_product_unit">'
843 - .'<a href="'.get_permalink().'" class="product_title" ><div class="product_image" style="background-image:url('.esc_url($thumb_src).')"></div></a>'
844 - .'<a href="'.get_permalink().'" class="product_title" >'.get_the_title().'</a>';
845 -
846 - // Optional "see product" call-to-action link.
847 - if($see_product!=''){
848 - print '<a href="'.get_permalink().'"class="see_product">'.$see_product.'</a>';
849 - }
850 - print '</li>';
851 - }else{
852 - // Paid items: use WooCommerce's product content template part.
853 - wc_get_template_part( 'content', 'product' );
854 - }
855 - endwhile;
856 - print '</ul>';
857 - }else{
858 - // No results for the current query/page.
859 - print esc_html__('No media found! ','wpstream');
860 - }
861 -
862 -
863 - // Restore the global post/query state after the custom loop.
864 - wp_reset_query();
865 - 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.
870 - $return_string= ob_get_contents();
871 - ob_end_clean();
872 -
873 - return $return_string;
874 - }
875 -
876 -
877 -
878 -
879 -
880 -
881 - /*
882 - *
883 - *
884 - * Pagination for media lista
885 - *
886 - *
887 - *
888 - */
889 -
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 - */
896 - function wpstream_pagination($pages = '', $range = 2){
897 -
898 - // Total number of page links visible in the window.
899 - $showitems = ($range * 2)+1;
900 - // Current page from the global; default to page 1.
901 - global $paged;
902 - if(empty($paged)) $paged = 1;
903 -
904 -
905 - // Fall back to the main query's page count when none was passed in.
906 - if($pages == ''){
907 - global $wp_query;
908 - $pages = $wp_query->max_num_pages;
909 - if(!$pages)
910 - {
911 - $pages = 1;
912 385 }
913 386 }
914 387
915 - // Only render pagination when there is more than one page.
916 - if(1 != $pages){
917 - print '<ul class="wpstream_pagination ">';
918 - // Previous-page arrow.
919 - print '<li class="roundleft"><a href="'.get_pagenum_link($paged - 1).'"> < </a></li>';
920 -
921 - // Emit a link for each page within the visible window.
922 - for ($i=1; $i <= $pages; $i++)
923 - {
924 - // Show this page number only if inside the range window (or few pages total).
925 - if (1 != $pages &&( !($i >= $paged+$range+1 || $i <= $paged-$range-1) || $pages <= $showitems ))
926 - {
927 - // Mark the current page as active.
928 - if ($paged == $i){
929 - print '<li class="active"><a href="'.esc_url(get_pagenum_link($i)).'" >'.$i.'</a><li>';
930 - }else{
931 - print '<li><a href="'.esc_url(get_pagenum_link($i)).'" >'.$i.'</a><li>';
932 - }
933 - }
934 - }
935 -
936 - // Compute the next-page URL, clamping at the last page.
937 - $prev_page= get_pagenum_link($paged + 1);
938 - if ( ($paged +1) > $pages){
939 - $prev_page= get_pagenum_link($paged );
940 - }else{
941 - $prev_page= get_pagenum_link($paged + 1);
942 - }
943 -
944 -
945 - // Next-page arrow.
946 - print '<li class="roundright"><a href="'.$prev_page.'"> > </a><li>';
947 - print '</ul>';
948 - }
949 - }
950 -
951 388
952 -
953 -
954 -
955 -
956 -
957 -
958 -
959 -
960 -
961 -
962 -
963 389 /**
964 390 * help function for player elementr widget
965 391 *
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 392 * @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.
393 + * @return string
973 394 */
974 -
395 +
975 396 public function wpstream_insert_player_elementor($attributes, $content = null){
976 - // Normalize incoming attributes with defaults.
977 397 $product_id = '';
978 398 $return_string = '';
979 - $attributes = shortcode_atts(
399 + $attributes = shortcode_atts(
980 400 array(
981 401 'id' => 0,
982 402 'user_id' => 0,
983 403 ), $attributes) ;
@@ -982,37 +402,26 @@
982 402 'user_id' => 0,
983 403 ), $attributes) ;
984 404
985 405
986 - // Explicit product id, if provided.
987 406 if ( isset($attributes['id']) ){
988 407 $product_id=$attributes['id'];
989 408 }
990 - // Optional author id used to look up a channel.
991 409 if ( isset($attributes['user_id']) ){
992 410 $user_id = intval( $attributes['user_id'] );
993 411 }
994 -
995 - // No product id but a user id: resolve that author's first channel.
412 +
996 413 if(intval($product_id)==0 && $user_id!=0 ){
997 414 $product_id= $this->wpstream_player_retrive_first_id($user_id);
998 415 }
999 -
1000 -
1001 -
1002 - // Buffer the player output so it can be returned as a string.
416 +
417 +
418 +
419 +
1003 420 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.
421 + $this->main->wpstream_player->wpstream_video_player_shortcode($product_id);
1013 422 $return_string= ob_get_contents();
1014 - ob_end_clean();
423 + ob_end_clean();
1015 424
1016 425 return $return_string;
1017 426 }
1018 427
@@ -1018,21 +427,16 @@
1018 427
1019 428 /**
1020 429 * help function for player low latency elementor widget
1021 430 *
1022 - * Same as the standard player helper but renders the low-latency player.
1023 - *
1024 431 * @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.
432 + * @return string
1028 433 */
1029 -
434 +
1030 435 public function wpstream_insert_player__low_latency_elementor($attributes, $content = null){
1031 - // Normalize incoming attributes with defaults.
1032 436 $product_id = '';
1033 437 $return_string = '';
1034 - $attributes = shortcode_atts(
438 + $attributes = shortcode_atts(
1035 439 array(
1036 440 'id' => 0,
1037 441 'user_id' => 0,
1038 442 ), $attributes) ;
@@ -1037,45 +441,33 @@
1037 441 'user_id' => 0,
1038 442 ), $attributes) ;
1039 443
1040 444
1041 - // Explicit product id, if provided.
1042 445 if ( isset($attributes['id']) ){
1043 446 $product_id=$attributes['id'];
1044 447 }
1045 -
1046 - // Optional author id used to look up a channel.
448 +
1047 449 if ( isset($attributes['user_id']) ){
1048 450 $user_id = intval( $attributes['user_id'] );
1049 451 }
1050 452
1051 - // No product id but a user id: resolve that author's first channel.
1052 453 if(intval($product_id)==0 && $user_id!=0){
1053 454 $product_id= $this->wpstream_player_retrive_first_id($user_id);
1054 455 }
1055 -
1056 -
1057 - // Buffer the low-latency player output and return it.
456 +
457 +
1058 458 ob_start();
1059 459 $this->main->wpstream_player->wpstream_video_player_shortcode_low_latency($product_id);
1060 460 $return_string= ob_get_contents();
1061 - ob_end_clean();
461 + ob_end_clean();
1062 462
1063 463 return $return_string;
1064 464 }
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 - */
465 +
466 +
467 +
1074 468 public function wpstream_player_retrive_first_id($received_user_id=''){
1075 - // Free vs paid channel type is a site-wide option.
1076 469 $channel_type = get_option ('wpstream_user_streaming_channel_type');
1077 - // Look up the author's most relevant event id for that type.
1078 470 $product_id = $this->wpstream_get_current_event_per_author($received_user_id,$channel_type);
1079 471 return $product_id;
1080 472 }
1081 473
@@ -1083,39 +475,31 @@
1083 475
1084 476 /**
1085 477 * help function for chat elementor widget
1086 478 *
1087 - * Renders the chat widget for a product and wires up its client connection.
1088 - *
1089 479 * @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.
480 + * @return string
1093 481 */
1094 -
482 +
1095 483 public function wpstream_insert_chat_elementor($attributes, $content = null){
1096 - // Normalize incoming attributes with defaults.
1097 484 $product_id = '';
1098 485 $return_string = '';
1099 - $attributes = shortcode_atts(
486 + $attributes = shortcode_atts(
1100 487 array(
1101 488 'id' => 0,
1102 489 ), $attributes) ;
1103 490
1104 491
1105 - // Explicit product id, if provided.
1106 492 if ( isset($attributes['id']) ){
1107 493 $product_id=$attributes['id'];
1108 494 }
1109 495
1110 - // Open the wrapper, buffer the chat markup, then close the wrapper.
1111 496 $return_string.= '<div class="wpstream_plugin_chat_wrapper">';
1112 497 ob_start();
1113 498 $this->main->wpstream_player->wpstream_chat_wrapper($product_id);
1114 499 $return_string.= ob_get_contents();
1115 - ob_end_clean();
1116 - $return_string.='</div>';
1117 - // Emit the chat client connection script for this product.
500 + ob_end_clean();
501 + $return_string.='</div>';
1118 502 $this->main->wpstream_player->wpstream_connect_to_chat($product_id);
1119 503
1120 504 return $return_string;
1121 505 }
@@ -1121,10 +505,8 @@
1121 505 }
1122 506
1123 507
1124 508 /**
1125 - * edited 4.0
1126 - *
1127 509 * Check if user is allowed to stream
1128 510 *
1129 511 * @since 3.7
1130 512 */
@@ -1129,41 +511,31 @@
1129 511 * @since 3.7
1130 512 */
1131 513
1132 514 public function wpstream_check_user_can_stream(){
1133 - // Current user for the role/capability checks below.
1134 515 $current_user = wp_get_current_user();
1135 -
1136 - // Guests can never stream.
516 +
1137 517 if( !is_user_logged_in() ){
1138 518 return false;
1139 - exit('user not logged in');
519 + exit('user not logged in 497');
1140 520 }
1141 -
521 +
1142 522 if(current_user_can('administrator')){
1143 523 // admins can always brodcast
1144 524 return true;
1145 525 }
1146 -
1147 - // Site-configured list of roles that are allowed to stream.
526 +
1148 527 $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 ) ) {
528 + $user_role = $current_user->roles[0];
529 +
530 + if (is_array($extra_roles) && in_array($user_role, $extra_roles)){
1157 531 return true;
1158 532 }
1159 -
1160 - // Allow when the "regular users may stream" option is enabled.
533 +
1161 534 if(function_exists('wpstream_get_option') && intval(wpstream_get_option('allow_streaming_regular_users',''))==1 ){
1162 535 return true;
1163 536 }
1164 -
1165 - // Otherwise deny.
537 +
1166 538 return false;
1167 539 }
1168 540
1169 541
@@ -1169,118 +541,63 @@
1169 541
1170 542 /**
1171 543 * Start Streaming wrapper
1172 544 *
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 545 * @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 546 */
547 +
1181 548 public function wpstream_live_stream_unit_wrapper($item_id,$type){
1182 - // Coerce to an integer id.
1183 549 $item_id = intval($item_id);
1184 -
550 +
1185 551 if($item_id == 0){
1186 552 //retrive or create channel for front end streamers
1187 553 $item_id=$this->wpstream_retrive_front_end_channel();
1188 554 }
1189 - // Modal backdrop and reusable error-notification markup.
1190 - print'<div class="wpstream_modal_background"></div>';
1191 - print '<div class="wpstream_error_modal_notification"><div class="wpstream_error_content">er2</div>
1192 - <div class="wpstream_error_ok wpstream_button" type="button">'.esc_html__('Close','wpstream').'</div>
1193 - </div>';
1194 - // Delegate the actual start-streaming UI to the admin controller.
555 +
1195 556 $this->admin->wpstream_live_stream_unit( $item_id,$type );
1196 557 }
1197 558
1198 559
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 560
1227 561
562 +
1228 563 /**
1229 564 * retrive channel for front end streaming
1230 565 *
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 566 * @since 3.7
1235 - * @return int Channel/product id for the current user.
1236 567 */
1237 568 public function wpstream_retrive_front_end_channel(){
1238 -
1239 - // Current user plus the site-wide channel type and default price.
569 +
1240 570 $current_user = wp_get_current_user();
1241 571 $channel_type = get_option ('wpstream_user_streaming_channel_type');
1242 572 $channel_price = floatval( get_option ('wpstream_user_streaming_default_price') );
1243 -
1244 - // Look for an existing channel owned by this user.
573 +
1245 574 $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.
575 +
1248 576 if(intval($front_end_streamin_channel) == 0){
1249 577 $front_end_streamin_channel= $this->wpstrea_create_front_end_event($current_user->ID,$current_user->user_login ,$channel_type,$channel_price);
1250 578 }
1251 579 return $front_end_streamin_channel;
1252 -
580 +
1253 581 }
1254 582
1255 583 /**
1256 584 * create the event from front end
1257 585 *
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 586 * @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 587 */
1268 -
588 +
1269 589 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.
590 +
1272 591 if( !$this->wpstream_check_user_can_stream() ){
1273 592 return;
1274 593 }
1275 -
1276 - // Free channels use the plugin CPT; paid channels use WooCommerce products.
594 +
1277 595 $post_type='wpstream_product';
1278 596 if($channel_type=='paid'){
1279 597 $post_type='product';
1280 598 }
1281 -
1282 - // Build and insert the channel post.
599 +
1283 600 $post = array(
1284 601 'post_title' => sprintf( esc_html__('%s Channel','wpstream'),$userLogin),
1285 602 'post_content' => '',
1286 603 'post_type' => $post_type ,
@@ -1286,48 +603,36 @@
1286 603 'post_type' => $post_type ,
1287 604 'post_author' => $userID,
1288 605 'post_status' => 'publish',
1289 606 );
1290 - $post_id = wp_insert_post($post );
1291 - // For paid channels, configure the WooCommerce product pricing and type.
607 + $post_id = wp_insert_post($post );
1292 608 if($channel_type=='paid'){
1293 609 $product = wc_get_product($post_id);
1294 610 $price = wc_format_decimal($channel_price);
1295 -
611 +
1296 612 $product = wc_get_product( $post_id );
1297 613 // Set the product active price (regular)
1298 614 $product->set_price( $price );
1299 615 $product->set_regular_price( $price ); // To be sure
1300 616 $product->save();
1301 - // Mark as not-yet-passed and tag it as a live_stream product.
1302 617 update_post_meta ($post_id,'event_passed',0);
1303 618 wp_set_object_terms( $post_id, 'live_stream', 'product_type' );
1304 619 }
1305 - // Flag the post as a live event (product type 1).
1306 620 update_post_meta($post_id,'wpstream_product_type',1);
1307 -
621 +
1308 622 return $post_id;
1309 623 }
1310 624
1311 625
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 626 public function wpstream_get_current_event_per_author($userID,$channel_type){
1320 -
1321 - // Free channels are CPTs; paid channels are WooCommerce products.
627 +
1322 628 $post_type='wpstream_product';
1323 629 if($channel_type=='paid'){
1324 630 $post_type='product';
1325 631 }
1326 -
1327 - // Query for a single post id owned by this author.
632 +
1328 633 $args = array(
1329 -
634 +
1330 635 'post_type' => $post_type,
1331 636 'author' => $userID,
1332 637 'posts_per_page' => 1,
1333 638 'fields' => 'ids'
@@ -1333,27 +638,16 @@
1333 638 'fields' => 'ids'
1334 639 )
1335 640 ;
1336 641 $author_posts = new WP_Query( $args );
1337 - // Use the found id, or 0 when the author has no channel.
1338 642 if( $author_posts->have_posts() ) {
1339 643 $author_posts->the_post();
1340 - $the_id= get_the_ID();
644 + return get_the_ID();
1341 645 }else{
1342 - $the_id= 0;
646 + return 0;
1343 647 }
1344 -
1345 - // Restore global post/query state after the custom query.
648 +
1346 649 wp_reset_query();
1347 650 wp_reset_postdata();
1348 - return $the_id;
1349 651 }
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 - }
652 +
1359 653 }