PluginProbe
WpStream – Live Streaming, Video on Demand, Pay Per View / trunk
WpStream – Live Streaming, Video on Demand, Pay Per View vtrunk
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
wpstream / includes / class-wpstream.php

class-wpstream.php in WpStream – Live Streaming, Video on Demand, Pay Per View trunk, at includes/class-wpstream.php

1,184 lines 52.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * The file that defines the core plugin class
4 *
5 * A class definition that includes attributes and functions used across both the
6 * public-facing side of the site and the admin area.
7 *
8 * @link http://wpstream.net
9 * @since 3.0.1
10 *
11 * @package Wpstream
12 * @subpackage Wpstream/includes
13 */
14
15
16 // Exit if accessed directly.
17 if ( ! defined( 'ABSPATH' ) ) {
18 exit;
19 }
20
21 /**
22 * The core plugin class.
23 *
24 * This is used to define internationalization, admin-specific hooks, and
25 * public-facing site hooks.
26 *
27 * Also maintains the unique identifier of this plugin as well as the current
28 * version of the plugin.
29 *
30 * @since 3.0.1
31 * @package Wpstream
32 * @subpackage Wpstream/includes
33 * @author wpstream <office@wpstream.net>
34 */
35 class Wpstream {
36
37 /**
38 * Store plugin main class to allow public access.
39 *
40 * @since 3.0.1
41 * @var object The main class.
42 */
43 public $main;
44 /** @var Wpstream_Admin The admin-area controller instance. */
45 public $admin;
46
47 /**
48 * The loader that's responsible for maintaining and registering all hooks that power
49 * the plugin.
50 *
51 * @since 3.0.1
52 * @access protected
53 * @var Wpstream_Loader $loader Maintains and registers all hooks for the plugin.
54 */
55 protected $loader;
56
57 /**
58 * The unique identifier of this plugin.
59 *
60 * @since 3.0.1
61 * @access protected
62 * @var string $plugin_name The string used to uniquely identify this plugin.
63 */
64 protected $plugin_name;
65
66 /**
67 * The current version of the plugin.
68 *
69 * @since 3.0.1
70 * @access protected
71 * @var string $version The current version of the plugin.
72 */
73 protected $version;
74
75 /**
76 * Define the core functionality of the plugin.
77 *
78 * Set the plugin name and the plugin version that can be used throughout the plugin.
79 * Load the dependencies, define the locale, and set the hooks for the admin area and
80 * the public-facing side of the site.
81 *
82 * @since 3.0.1
83 */
84
85 /** @var Wpstream_Live_Api_Connection Cloud API client for channels/quota. */
86 public $wpstream_live_connection;
87 /** @var Wpstream_Player Player/rendering service. */
88 public $wpstream_player;
89 /** @var Wpstream_Quota_Manager Quota cache manager. */
90 public $quota_manager;
91 /** @var Wpstream_Channel_Settings Deep Module for per-Channel streaming settings. */
92 public $channel_settings;
93 /** @var Wpstream_Streaming_Content_Creation Deep Module for Live Channel and VOD creation. */
94 public $streaming_content_creation;
95 /** @var Wpstream_Drm_Key_Delivery Deep Module for live and VOD DRM Key delivery. */
96 public $drm_key_delivery;
97 /** @var Wpstream_Media_List Deep Module for Channel and VOD lists. */
98 public $media_list;
99 /** @var Wpstream_Playback_Presentation Deep Module for approved player presentation. */
100 public $playback_presentation;
101 /** @var object User quota service resolved from the live connection. */
102 public $user_quota_service;
103 /** @var mixed Unused/reserved property. */
104 public $xtest;
105 /** @var Wpstream_Admin Admin controller (also stored in $admin). */
106 public $plugin_admin;
107 /** @var Wpstream_Onboarding|null Lazily-created onboarding workflow module. */
108 private $onboarding;
109 /** @var Wpstream_Live_Channel_Presentation|null Lazily-created Live Channel presentation module. */
110 private $live_channel_presentation;
111
112 /**
113 * Bootstrap the plugin: resolve version/name, load dependencies, then wire
114 * all admin, public, AJAX, template, and service objects together.
115 */
116 public function __construct() {
117 // Expose this instance as the shared "main" service locator.
118 $this->main = $this;
119
120 // Resolve the plugin version from the defined constant, else fall back.
121 if ( defined( 'WPSTREAM_PLUGIN_VERSION' ) ) {
122 $this->version = WPSTREAM_PLUGIN_VERSION;
123 } else {
124 $this->version = '3.0.1';
125 }
126
127 // Text-domain / unique plugin identifier.
128 $this->plugin_name = 'wpstream';
129
130 // Require class files and instantiate the hook loader.
131 $this->load_dependencies();
132 // Register admin-area hooks (menus, metaboxes, WooCommerce, onboarding).
133 $this->define_admin_hooks();
134 // Register public-facing hooks (scripts, endpoints, shortcodes).
135 $this->define_public_hooks();
136 // Register AJAX handlers.
137 $this->define_ajax_hooks();
138 // Register the front-end page/single template loader.
139 $this->wpstream_load_page_templates();
140 // Register the "theme update available" admin notice.
141 $this->wpstream_load_theme_notice();
142
143 // Instantiate the cloud API connection (and user quota service).
144 $this->wpstream_connection();
145 // Compose the deep Channel Settings Module with its WordPress and Baker Adapters.
146 $this->channel_settings = new Wpstream_Channel_Settings(
147 new Wpstream_WordPress_Channel_Settings_Storage(),
148 new Wpstream_Baker_Channel_Settings_Adapter( $this->wpstream_live_connection )
149 );
150 $this->wpstream_live_connection->set_channel_settings( $this->channel_settings );
151 $this->drm_key_delivery = new Wpstream_Drm_Key_Delivery(
152 $this->channel_settings,
153 new Wpstream_WordPress_Drm_Key_Remote_Fetch()
154 );
155 $this->media_list = new Wpstream_Media_List(
156 new Wpstream_Baker_Media_List_Active_Catalog( $this->wpstream_live_connection )
157 );
158 $this->playback_presentation = new Wpstream_Playback_Presentation( $this );
159 $this->streaming_content_creation = new Wpstream_Streaming_Content_Creation(
160 $this,
161 $this->channel_settings,
162 new Wpstream_Baker_Streaming_Content_Provisioning( $this->wpstream_live_connection ),
163 new Wpstream_Baker_Streaming_Content_Recording_Catalog( $this->wpstream_live_connection )
164 );
165 $this->wpstream_live_connection->set_streaming_content_creation( $this->streaming_content_creation );
166 // Instantiate the player service.
167 $this->wpstream_player();
168 // Instantiate the quota cache manager.
169 $this->wpstream_init_quota_manager();
170
171 }
172
173
174
175
176
177 /**
178 * Convert a quota figure from megabytes to gigabytes.
179 *
180 * @param float|int $megabytes Value in megabytes.
181 * @return float Value in gigabytes, floored to two decimals.
182 */
183 public function wpstream_convert_band( $megabytes ) {
184 // Quota payloads use binary megabytes. Never round remaining allowance up.
185 return $this->wpstream_floor_decimals( (float) $megabytes / 1024, 2 );
186 }
187
188 /**
189 * Floor a number to a given number of decimal places.
190 *
191 * @param float $value The number to floor.
192 * @param int $decimals Number of decimal places.
193 * @return float
194 */
195 public function wpstream_floor_decimals( $value, $decimals = 2 ) {
196 // Clamp decimals to a non-negative integer.
197 $decimals = max( 0, (int) $decimals );
198 // Scale factor for the requested precision.
199 $factor = pow( 10, $decimals );
200
201 // Multiply, floor, divide back, then format to fixed precision.
202 return floatval( sprintf( '%.' . $decimals . 'f', floor( (float) $value * $factor ) / $factor ) );
203 }
204
205
206 /** @var WpStream_Ajax The AJAX handler service. */
207 public $wpstream_ajax;
208
209 /**
210 * Load and instantiate the AJAX handler service.
211 */
212 private function define_ajax_hooks() {
213 // Construct the AJAX service with the main instance (class autoloads).
214 $this->wpstream_ajax = new WpStream_Ajax( $this->main );
215 }
216
217
218 /**
219 * Load the cloud API connection and resolve the user quota service.
220 */
221 private function wpstream_connection(){
222 // Instantiate the live/cloud API client (class autoloads).
223 $this->wpstream_live_connection = new Wpstream_Live_Api_Connection();
224 // Cache the user quota service exposed by the connection.
225 $this->user_quota_service = $this->wpstream_live_connection->get_user_quota_service();
226 }
227
228
229 /**
230 * Load and instantiate the player service.
231 */
232 private function wpstream_player(){
233 // Build the player service with the main instance (class autoloads).
234 $this->wpstream_player = new Wpstream_Player($this->main);
235 }
236
237 /**
238 * Load and instantiate the quota cache manager.
239 */
240 private function wpstream_init_quota_manager() {
241 // Build the quota cache manager with this main instance (class autoloads).
242 $this->quota_manager = new Wpstream_Quota_Manager( $this );
243 }
244
245
246 /**
247 * Load and register the front-end template loader.
248 */
249 private function wpstream_load_page_templates() {
250 // Register the template loader's hooks by constructing it (class autoloads).
251 new WpStream_Template_Loader();
252 }
253
254 /**
255 * Load and register the companion-theme update admin notice.
256 */
257 private function wpstream_load_theme_notice() {
258 // Register the notice by constructing it (class autoloads).
259 new WPStream_Theme_Notice();
260 }
261
262
263 /**
264 * Load the dependencies the classmap autoloader cannot serve.
265 *
266 * Plugin classes resolve through Wpstream_Autoloader on first use, so this
267 * only requires what an autoloader can never load: the WooCommerce product
268 * types (kept behind a WooCommerce guard because they extend WC_Product)
269 * and the function-only helper files. It then creates the hook loader that
270 * the define_*_hooks() methods populate.
271 *
272 * @since 3.0.1
273 * @access private
274 */
275 private function load_dependencies() {
276
277 // WooCommerce product-type classes extend WC_Product, so loading them
278 // without WooCommerce active would fatal at class-link time; they stay
279 // behind this guard instead of the classmap.
280 if( class_exists( 'WooCommerce' ) ){
281 // Paid live-stream product type.
282 require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/class-wc-product-live-stream.php';
283 // Paid video-on-demand product type.
284 require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/class-wc-product-video-on-demand.php';
285 }
286
287 // Function-only helper files: no class inside, so the autoloader can
288 // never serve them and they must be required eagerly.
289
290 // Channel-ownership authorization helper (wpstream_can_manage_channel),
291 // used by every live/broadcast handler to enforce per-channel ownership.
292 require_once plugin_dir_path(__FILE__) . 'Helpers/wpstream-authorization.php';
293
294 // Viewing-entitlement helper (wpstream_user_entitled_for_product),
295 // the single rule every playback access gate must call.
296 require_once plugin_dir_path(__FILE__) . 'Helpers/wpstream-entitlement.php';
297
298 // WpStream account credential accessors (constant override + options).
299 require_once plugin_dir_path(__FILE__) . 'Helpers/wpstream-credentials.php';
300
301 // Viewer-facing presentation strings (wpstream_not_live_message), shared by
302 // the player, the public JS config and the bundled theme framework.
303 require_once plugin_dir_path(__FILE__) . 'Helpers/wpstream-presentation.php';
304
305 // My Account list collector (wpstream_account_list_products) shared by the
306 // event-list and video-list templates.
307 require_once plugin_dir_path(__FILE__) . 'Helpers/wpstream-account-lists.php';
308
309 // Tunables (wpstream_tunable): cache TTLs, poll intervals and limits run
310 // through their filter and are clamped in one place.
311 require_once plugin_dir_path(__FILE__) . 'Helpers/wpstream-tunables.php';
312
313 // Create the hook loader that other define_*_hooks() methods populate.
314 $this->loader = new Wpstream_Loader();
315
316 }
317
318 /**
319 * Register all of the hooks related to the admin area functionality
320 * of the plugin.
321 *
322 * @since 3.0.1
323 * @access private
324 */
325 /**
326 * Whether a post edit route can present Live Channel controls.
327 *
328 * @param string $post_type Current post type.
329 * @param WP_Post|null $post Current post, when one exists.
330 * @return bool
331 */
332 private function is_live_channel_admin_post( $post_type, $post = null ) {
333 if ( 'wpstream_product' === $post_type ) {
334 return true;
335 }
336
337 if ( 'product' !== $post_type ) {
338 return false;
339 }
340
341 $post_id = $post instanceof WP_Post ? intval( $post->ID ) : 0;
342 if ( ! $post_id && isset( $_GET['post'] ) ) {
343 $post_id = absint( wp_unslash( $_GET['post'] ) );
344 }
345
346 if ( $post_id ) {
347 $product_type = wpstream_get_product_type_slug( $post_id );
348 return 'live_stream' === $product_type
349 || ( 'subscription' === $product_type && 'yes' === get_post_meta( $post_id, '_subscript_live_event', true ) );
350 }
351
352 return isset( $_GET['new_stream'] ) && 'new' === sanitize_key( wp_unslash( $_GET['new_stream'] ) );
353 }
354
355 /**
356 * Whether the current wp-admin screen presents Live Channel controls.
357 *
358 * @param WP_Screen|null $screen Current WordPress screen.
359 * @return bool
360 */
361 private function is_live_channel_admin_screen( $screen ) {
362 if ( ! $screen ) {
363 return false;
364 }
365
366 if ( 'wpstream_page_wpstream_live_channels' === $screen->base ) {
367 return true;
368 }
369
370 global $post;
371 return $this->is_live_channel_admin_post( $screen->post_type, $post instanceof WP_Post ? $post : null );
372 }
373
374 private function define_admin_hooks() {
375
376 // Build the admin controller and keep a reference to it.
377 $plugin_admin = new Wpstream_Admin( $this->get_plugin_name(), $this->get_version(), $this->main );
378
379 $this->admin = $plugin_admin;
380
381 // Admin CSS/JS and the plugin's admin menu (late priority).
382 $this->loader->add_action( 'admin_enqueue_scripts', $plugin_admin, 'enqueue_styles' );
383 $this->loader->add_action( 'admin_enqueue_scripts', $plugin_admin, 'enqueue_scripts' );
384 add_action(
385 'admin_enqueue_scripts',
386 function () {
387 $screen = get_current_screen();
388 if ( $this->is_live_channel_admin_screen( $screen ) ) {
389 $this->get_live_channel_presentation()->enqueue_assets();
390 }
391 },
392 20
393 );
394 $this->loader->add_action( 'admin_menu', $plugin_admin, 'wpstream_manage_admin_menu',999);
395
396 // "Chat Room" metabox: bind an existing Better Messages room to a channel.
397 new Wpstream_Chat_Room_Binding();
398
399 // Register the custom post types on init.
400 $plugin_post_types = new Wpstream_Product();
401 $this->loader->add_action( 'init', $plugin_post_types, 'create_custom_post_type', 999 );
402
403 // save and render metaboxed
404 // Register product metaboxes; persist their values on save; and,
405 // on publish, create the remote streaming channel.
406 $this->loader->add_action( 'add_meta_boxes', $plugin_admin, 'add_wpstream_product_metaboxes' );
407 $this->loader->add_action( 'save_post', $plugin_admin, 'wpstream_free_product_update_post',1,2 );
408 $this->loader->add_action( 'publish_wpstream_product', $plugin_admin, 'wpstream_publish_wpstream_product',1,2 );
409 $this->loader->add_action( 'publish_wpstream_product', $plugin_admin, 'wpstream_create_remote_channel_on_publish',20,2 );
410 $this->loader->add_action( 'publish_wpstream_product_vod', $plugin_admin, 'wpstream_create_remote_channel_on_publish', 20, 2 );
411 $this->loader->add_action( 'publish_product', $plugin_admin, 'wpstream_create_remote_channel_on_publish', 20, 2 );
412 // Mirror of the publish hooks above: a permanently deleted Live
413 // Channel is deleted at the service too (trash is untouched).
414 $this->loader->add_action( 'before_delete_post', $plugin_admin, 'wpstream_delete_remote_channel_on_delete', 10, 2 );
415 $this->loader->add_action( 'before_delete_post', $plugin_admin, 'wpstream_invalidate_vod_drm_on_delete', 5, 2 );
416 $this->loader->add_action( 'transition_post_status', $plugin_admin, 'wpstream_invalidate_vod_drm_on_status_change', 10, 3 );
417 // WooCommerce restores products to their previous published status.
418 // Paid Live Channels follow the safer channel lifecycle instead:
419 // restore as draft and require an explicit republish.
420 $this->loader->add_filter( 'wp_untrash_post_status', $plugin_admin, 'wpstream_paid_live_untrash_status', 20, 3 );
421
422
423
424 // make product virtual
425 $this->loader->add_action( 'save_post', $plugin_admin, 'wpstream_make_product_virtual', 99999, 2 );
426
427
428
429 // Add Live Channel controls only on edit screens that can own them.
430 add_action(
431 'add_meta_boxes',
432 function ( $post_type, $post ) {
433 if ( $this->is_live_channel_admin_post( $post_type, $post ) ) {
434 $this->get_live_channel_presentation()->register_metaboxes();
435 }
436 },
437 10,
438 2
439 );
440
441 // Load onboarding only when its page assets or one of its AJAX routes runs.
442 add_action(
443 'admin_enqueue_scripts',
444 function () {
445 $screen = get_current_screen();
446 $is_quickstart = $screen && 'wpstream_page_wpstream_onboard' === $screen->base;
447 $is_post_edit = isset( $_GET['onboard'] ) && 'yes' === $_GET['onboard'];
448
449 if ( $is_quickstart || $is_post_edit ) {
450 $this->get_onboarding()->enqueue_assets();
451 }
452 },
453 20
454 );
455
456 $onboarding_ajax_actions = array(
457 'wpstream_on_board_create_channel',
458 'wpstream_on_board_create_channel_ppv',
459 'wpstream_on_board_create_free_vod',
460 'wpstream_on_board_create_ppv_vod',
461 'wpstream_on_board_login',
462 'wpstream_on_board_register',
463 'wpstream_get_captcha_challenge',
464 );
465 foreach ( $onboarding_ajax_actions as $onboarding_ajax_action ) {
466 add_action(
467 'wp_ajax_' . $onboarding_ajax_action,
468 function () use ( $onboarding_ajax_action ) {
469 return $this->get_onboarding()->handle_ajax( $onboarding_ajax_action );
470 }
471 );
472 }
473
474 // Register AJAX actions for multipart uploads
475 $this->loader->add_action( 'wp_ajax_wpstream_initiate_multipart_upload', $plugin_admin, 'handle_initiate_multipart_upload' );
476 $this->loader->add_action( 'wp_ajax_wpstream_complete_multipart_upload', $plugin_admin, 'handle_complete_multipart_upload' );
477
478 // General and plugin-update admin notices.
479 $this->loader->add_action( 'admin_notices', $plugin_admin,'wpstream_admin_notice' );
480 $this->loader->add_action( 'admin_notices', $plugin_admin,'wpstream_plugin_update_available_notice' );
481
482 // Dismiss-cache-notice AJAX endpoint.
483 $this->loader->add_action( 'wp_ajax_wpstream_update_cache_notice', $plugin_admin,'wpstream_update_cache_notice' );
484 // $this->loader->add_action( 'wp_ajax_wpstream_get_videos_list', $plugin_admin,'wpstream_get_videos_list' );
485
486
487 // Settings-tab "update plugin" AJAX endpoint.
488 $this->loader->add_action( 'wp_ajax_wpstream_settings_tab_update_plugin', $plugin_admin, 'wpstream_settings_tab_update_plugin' );
489
490 // add and save category extra fields
491 // The same add/edit/create/save callbacks are shared across every taxonomy below.
492 $this->loader->add_action( 'category_edit_form_fields', $plugin_post_types, 'wpstream_category_callback_function', 10, 2);
493 $this->loader->add_action( 'category_add_form_fields', $plugin_post_types, 'wpstream_category_callback_add_function' );
494 $this->loader->add_action( 'created_category', $plugin_post_types, 'wpstream_category_save_extra_fields_callback', 10, 2);
495 $this->loader->add_action( 'edited_category', $plugin_post_types, 'wpstream_category_save_extra_fields_callback', 10, 2);
496
497 // Same extra fields on the WooCommerce product category taxonomy.
498 $this->loader->add_action( 'product_cat_edit_form_fields', $plugin_post_types, 'wpstream_category_callback_function', 10, 2);
499 $this->loader->add_action( 'product_cat_add_form_fields', $plugin_post_types, 'wpstream_category_callback_add_function' );
500 $this->loader->add_action( 'created_product_cat', $plugin_post_types, 'wpstream_category_save_extra_fields_callback', 10, 2);
501 $this->loader->add_action( 'edited_product_cat', $plugin_post_types, 'wpstream_category_save_extra_fields_callback', 10, 2);
502
503
504 // Same extra fields on the plugin's own wpstream_category taxonomy.
505 $this->loader->add_action( 'wpstream_category_edit_form_fields', $plugin_post_types, 'wpstream_category_callback_function', 10, 2);
506 $this->loader->add_action( 'wpstream_category_add_form_fields', $plugin_post_types, 'wpstream_category_callback_add_function' );
507 $this->loader->add_action( 'created_wpstream_category', $plugin_post_types, 'wpstream_category_save_extra_fields_callback', 10, 2);
508 $this->loader->add_action( 'edited_wpstream_category', $plugin_post_types, 'wpstream_category_save_extra_fields_callback', 10, 2);
509
510
511 // Same extra fields on the wpstream_actors taxonomy.
512 $this->loader->add_action( 'wpstream_actors_edit_form_fields', $plugin_post_types, 'wpstream_category_callback_function', 10, 2);
513 $this->loader->add_action( 'wpstream_actors_add_form_fields', $plugin_post_types, 'wpstream_category_callback_add_function' );
514 $this->loader->add_action( 'created_wpstream_actors', $plugin_post_types, 'wpstream_category_save_extra_fields_callback', 10, 2);
515 $this->loader->add_action( 'edited_wpstream_actors', $plugin_post_types, 'wpstream_category_save_extra_fields_callback', 10, 2);
516
517 // Same extra fields on the wpstream_movie_rating taxonomy.
518 $this->loader->add_action( 'wpstream_movie_rating_edit_form_fields', $plugin_post_types, 'wpstream_category_callback_function', 10, 2);
519 $this->loader->add_action( 'wpstream_movie_rating_add_form_fields', $plugin_post_types, 'wpstream_category_callback_add_function' );
520 $this->loader->add_action( 'created_wpstream_movie_rating', $plugin_post_types, 'wpstream_category_save_extra_fields_callback', 10, 2);
521 $this->loader->add_action( 'edited_wpstream_movie_rating', $plugin_post_types, 'wpstream_category_save_extra_fields_callback', 10, 2);
522
523
524 // WooCommerce-only admin hooks: register the custom product types,
525 // their data tabs/fields, pricing visibility, and add-to-cart handling.
526 // Deferred to plugins_loaded because WooCommerce may load after this
527 // plugin, and detection uses class_exists (not the active_plugins
528 // option) so network-activated WooCommerce on multisite is seen too.
529 // Registered directly (not via the loader) because the loader runs
530 // before plugins_loaded fires; every hook below fires later than
531 // plugins_loaded, so nothing is missed by the deferral.
532 add_action( 'plugins_loaded', function () use ( $plugin_admin ) {
533 // Without WooCommerce none of these hooks have anything to do.
534 if ( ! class_exists( 'WooCommerce' ) ) {
535 return;
536 }
537
538 // Register product types and map them to their PHP classes.
539 add_action( 'init', array( $plugin_admin, 'wpstream_add_custom_wc_products' ) );
540 add_filter( 'product_type_selector', array( $plugin_admin, 'wpstream_add_products' ) );
541 add_filter( 'woocommerce_product_class', array( $plugin_admin, 'wpstream_add_products_class' ), 10, 2 );
542 // Pricing-field visibility, tab hiding, and purchasability rules.
543 add_action( 'admin_enqueue_scripts', array( $plugin_admin, 'wpstream_enqueue_wc_product_pricing_visibility' ), 20 );
544 add_filter( 'woocommerce_product_data_tabs', array( $plugin_admin, 'wpstream_hide_attributes_data_panel' ), 10, 1 );
545 add_filter( 'woocommerce_is_purchasable', array( $plugin_admin, 'wpstream_hide_buy_now_subscription_mode' ), 10, 2 );
546
547 // Custom general-tab fields (render + save) and add-to-cart wiring.
548 add_action( 'woocommerce_product_options_general_product_data', array( $plugin_admin, 'wpstream_add_custom_general_fields' ), 20 );
549 add_filter( 'woocommerce_process_product_meta', array( $plugin_admin, 'wpstream_add_custom_general_fields_save' ), 10, 1 );
550 add_action( 'woocommerce_process_product_meta', array( $plugin_admin, 'wpstream_initialize_paid_streaming_product' ), 30, 1 );
551 add_action( 'woocommerce_live_stream_add_to_cart', array( $plugin_admin, 'wpstream_add_to_cart' ), 10, 1 );
552 add_action( 'woocommerce_video_on_demand_add_to_cart', array( $plugin_admin, 'wpstream_add_to_cart' ), 10, 1 );
553 add_filter( 'woocommerce_loop_add_to_cart_link', array( $plugin_admin, 'replacing_add_to_cart_button' ), 10, 2 );
554 } );
555 }
556
557
558
559
560
561 /**
562 * Register all of the hooks related to the public-facing functionality
563 * of the plugin.
564 *
565 * @since 3.0.1
566 * @access private
567 */
568 private function define_public_hooks() {
569
570 // Build the public-facing controller.
571 $plugin_public = new Wpstream_Public( $this->get_plugin_name(), $this->get_version(), $this->main );
572
573 // Front-end styles.
574 $this->loader->add_action( 'wp_enqueue_scripts', $plugin_public, 'enqueue_styles' );
575 // Registered on `wp` (not `wp_enqueue_scripts`/`wp_head`) because block themes render
576 // the Post Content block - and thus our `the_content` filter that enqueues/localizes
577 // these scripts - before `wp_head` ever fires, leaving the handles unregistered.
578 $this->loader->add_action( 'wp', $plugin_public, 'enqueue_scripts' );
579
580 // Custom rewrite endpoints and their query vars.
581 $this->loader->add_action( 'init', $plugin_public,'wpstream_my_custom_endpoints' );
582 $this->loader->add_filter( 'query_vars',$plugin_public, 'wpstream_my_custom_query_vars', 0 );
583
584 //live stream action
585 // Streaming cookies plus the RTMP/3rd-party/VOD streaming-key handlers.
586 $this->loader->add_action('init',$plugin_public,'wpstream_set_cookies',0);
587 $this->loader->add_action('init',$plugin_public,'wpstream_live_streaming_key');
588 $this->loader->add_action('init',$plugin_public,'wpstream_live_streaming_key_for_3rdparty');
589 $this->loader->add_action('init',$plugin_public,'wpstream_live_streaming_key_vod',10);
590
591 // woo action
592 // Product-page content wrappers and order/email extras.
593 $this->loader->add_action( 'woocommerce_before_single_product', $plugin_public,'wpstream_non_image_content_wrapper_start', 20 );
594 $this->loader->add_action( 'woocommerce_after_single_product', $plugin_public,'wpstream_non_image_content_wrapper_end', 20 );
595 $this->loader->add_action( 'woocommerce_thankyou_order_received_text', $plugin_public,'wpstream_thankyou_extra', 20,2 );
596 $this->loader->add_action( 'woocommerce_email_order_details', $plugin_public,'wpstream_email_order_details', 20,4 );
597
598 // My Account: add the Events/Videos menu items and their endpoint content.
599 // Run after themes have built their account navigation so a theme that
600 // replaces the menu cannot discard the plugin-owned Events/Videos links.
601 $this->loader->add_filter( 'woocommerce_account_menu_items', $plugin_public, 'wpstream_custom_my_account_menu_items', 99 );
602 $this->loader->add_action( 'woocommerce_account_event-list_endpoint', $plugin_public,'wpstream_custom_endpoint_content_event_list' );
603 $this->loader->add_action( 'woocommerce_account_video-list_endpoint', $plugin_public,'wpstream_custom_endpoint_video_list' );
604
605 // Flush rewrite rules on theme switch; register plugin and WPBakery shortcodes.
606 $this->loader->add_action( 'after_switch_theme', $plugin_public,'wpstream_custom_flush_rewrite_rules' );
607 $this->loader->add_action('init', $plugin_public,'wpstream_shortcodes');
608 $this->loader->add_action('vc_before_init', $plugin_public,'wpstream_bakery_shortcodes');
609
610 // CORS preflight check for the API (uses a plain function callback).
611 $this->loader->add_action('wo_before_api', 'wpstream_cors_check_and_response',10,1);
612
613 // Theme-integration filters/actions: search, sidebars, archives, and
614 // author/episode/past-broadcast content resolution by post type.
615 $this->loader->add_filter( 'wpstream_search_template_item_post_type', $plugin_public, 'wpstream_search_template_add_item_post_type' );
616 $this->loader->add_filter( 'wpstream_sidebar_id_by_post_type', $plugin_public, 'wpstream_sidebar_id_by_post_type' );
617 $this->loader->add_filter( 'wpstream_header_search_values', $plugin_public, 'wpstream_header_search_values' );
618 $this->loader->add_filter( 'wpstream_extend_category_archive_query_filter', $plugin_public, 'wpstream_extend_category_archive_query_filter_callback' );
619 $this->loader->add_filter( 'wpstream_archives_lists_taxonomy_labels', $plugin_public, 'wpstream_archives_lists_taxonomy_labels_callback' );
620 $this->loader->add_filter( 'wpstream_author_archive_list_taxonomy_labels', $plugin_public, 'wpstream_author_archive_list_taxonomy_labels_callback' );
621 $this->loader->add_action( 'wpstream_vod_attached_to_channel', $plugin_public, 'wpstream_vod_attached_to_channel' );
622 $this->loader->add_action( 'wpstream_additional_content_post_type', $plugin_public, 'wpstream_additional_content_post_type_callback' );
623 $this->loader->add_action( 'wpstream_post_author_content_post_type_list', $plugin_public, 'wpstream_post_author_content_post_type_list_callback' );
624 $this->loader->add_action( 'wpstream_author_content_simple_post_type_message', $plugin_public, 'wpstream_author_content_simple_post_type_message_callback', 10, 2 );
625 $this->loader->add_action( 'wpstream_author_content_post_type_message', $plugin_public, 'wpstream_author_content_post_type_message_callback', 10, 2 );
626 $this->loader->add_action( 'wpstream_show_sidebar_for_post_type', $plugin_public, 'wpstream_show_sidebar_for_post_type_callback', 10, 2 );
627 $this->loader->add_action( 'wpstream_video_episodes_post_type', $plugin_public, 'wpstream_video_episodes_post_type_callback' );
628 $this->loader->add_action( 'wpstream_video_past_broadcast_post_type', $plugin_public, 'wpstream_video_past_broadcast_post_type_callback' );
629 $this->loader->add_action( 'wpstream_additional_content_post_type_label', $plugin_public, 'wpstream_additional_content_post_type_label_callback', 10, 2 );
630 }
631
632 /**
633 * Run the loader to execute all of the hooks with WordPress.
634 *
635 * @since 3.0.1
636 */
637 public function run() {
638 // Hand off to the loader, which calls add_action/add_filter for every hook.
639 $this->loader->run();
640 }
641
642 /**
643 * The name of the plugin used to uniquely identify it within the context of
644 * WordPress and to define internationalization functionality.
645 *
646 * @since 3.0.1
647 * @return string The name of the plugin.
648 */
649 public function get_plugin_name() {
650 // Return the stored text-domain / identifier string.
651 return $this->plugin_name;
652 }
653
654 /**
655 * The reference to the class that orchestrates the hooks with the plugin.
656 *
657 * @since 3.0.1
658 * @return Wpstream_Loader Orchestrates the hooks of the plugin.
659 */
660 public function get_loader() {
661 // Return the hook loader instance.
662 return $this->loader;
663 }
664
665 /**
666 * Retrieve the version number of the plugin.
667 *
668 * @since 3.0.1
669 * @return string The version number of the plugin.
670 */
671 public function get_version() {
672 // Return the resolved plugin version string.
673 return $this->version;
674 }
675
676 /**
677 * Return the onboarding workflow, creating it only when an onboarding route
678 * actually needs it.
679 *
680 * @return Wpstream_Onboarding
681 */
682 public function get_onboarding() {
683 if ( ! $this->onboarding ) {
684 $this->onboarding = new Wpstream_Onboarding( $this );
685 }
686
687 return $this->onboarding;
688 }
689
690 /**
691 * Return the Live Channel admin presentation, creating it only when a
692 * relevant screen or shared go-live card needs it.
693 *
694 * @return Wpstream_Live_Channel_Presentation
695 */
696 public function get_live_channel_presentation() {
697 if ( ! $this->live_channel_presentation ) {
698 $this->live_channel_presentation = new Wpstream_Live_Channel_Presentation( $this );
699 }
700
701 return $this->live_channel_presentation;
702 }
703
704 /**
705 * Whether WordPress currently reports a pending update for this plugin.
706 *
707 * @return bool True when an update is available in the update_plugins transient.
708 */
709 public function is_plugin_outdated(){
710 // WordPress caches pending plugin updates in this site transient.
711 $update_data = get_site_transient('update_plugins');
712 // The plugin's basename key within that transient.
713 $plugin_path = 'wpstream/wpstream.php';
714
715 // Presence of a response entry means an update is offered.
716 if (isset($update_data->response[$plugin_path])) {
717 return true;
718 }
719
720 // No entry -> up to date.
721 return false;
722 }
723
724
725
726 /**
727 * Print the account resource summary (data/storage or hours) shown in the UI.
728 *
729 * @param array $pack_details Quota payload for the current account.
730 */
731 public function show_user_data($pack_details){
732 // Branch A: data/storage (megabyte) plans - when NOT using streaming hours.
733 if ( ! isset( $pack_details['use_streaming_hours'] ) || $pack_details['use_streaming_hours'] !== true ) {
734 // Only render when both data and storage figures are present.
735 if ( isset( $pack_details['available_data_mb'] ) && isset( $pack_details['available_storage_mb'] ) ) {
736 // Convert available data MB to GB, clamping negatives to zero.
737 $wpstream_convert_band = $this->wpstream_convert_band( $pack_details['available_data_mb'] );
738 if ( $wpstream_convert_band < 0 ) {
739 $wpstream_convert_band = 0;
740 }
741
742 // Convert available storage MB to GB, clamping negatives to zero.
743 $wpstream_convert_storage = $this->wpstream_convert_band( $pack_details['available_storage_mb'] );
744 if ( $wpstream_convert_storage < 0 ) {
745 $wpstream_convert_storage = 0;
746 }
747
748 // Output the cloud data + storage summary line.
749 print '<div class="pack_details_wrapper">'
750 . '<strong>' . __( 'Your account information: ', 'wpstream' ) . '</strong> '
751 . __( 'You have ', 'wpstream' ) . '<strong id="wpstream_available_data">' . abs( $wpstream_convert_band ) . ' GB</strong> '
752 . __( 'available cloud data and ', 'wpstream' )
753 . '<strong id="wpstream_available_storage">' . abs( $wpstream_convert_storage ) . ' GB</strong> '
754 . __( 'available cloud storage', 'wpstream' ) . '.';
755
756 // Upgrade link plus hidden inputs carrying the raw MB figures for JS.
757 print '<a href="https://wpstream.net/pricing/" class="wpstream_upgrade_topbar" target="_blank">' . esc_html__( 'Upgrade Plan', 'wpstream' ) . '</a>';
758 print '</div>';
759 print '<input type="hidden" id="wpstream_band" value="' . esc_attr( $pack_details['available_data_mb'] ) . '">';
760 print '<input type="hidden" id="wpstream_storage" value="' . esc_attr( $pack_details['available_storage_mb'] ) . '">';
761 }
762 } else {
763 // Branch B: streaming-hours plans (viewer/broadcast/storage hours).
764 if ( isset( $pack_details['available_viewer_hours'] ) && isset( $pack_details['available_broadcast_hours'] ) && isset( $pack_details['available_storage_hours'] ) ) {
765 // Normalize viewer hours to a non-negative float.
766 $available_viewer_hours = floatval( $pack_details['available_viewer_hours'] );
767 if ( $available_viewer_hours < 0 ) {
768 $available_viewer_hours = 0;
769 }
770
771 // Normalize broadcast hours to a non-negative float.
772 $available_broadcast_hours = floatval( $pack_details['available_broadcast_hours'] );
773 if ( $available_broadcast_hours < 0 ) {
774 $available_broadcast_hours = 0;
775 }
776
777 // Normalize storage hours to a non-negative float.
778 $available_storage_hours = floatval( $pack_details['available_storage_hours'] );
779 if ( $available_storage_hours < 0 ) {
780 $available_storage_hours = 0;
781 }
782
783 // Floor each figure to two decimals for display.
784 $formatted_viewer_hours = $this->wpstream_floor_decimals( $available_viewer_hours, 2 );
785 $formatted_broadcast_hours = $this->wpstream_floor_decimals( $available_broadcast_hours, 2 );
786 $formatted_storage_hours = $this->wpstream_floor_decimals( $available_storage_hours, 2 );
787
788 // Output the viewer/broadcast/storage hours summary line.
789 print '<div class="pack_details_wrapper">'
790 . __( 'Available streaming resources: ', 'wpstream' )
791 . '<strong id="wpstream_available_viewer_hours">' . abs( $formatted_viewer_hours ) . ' viewer</strong> '
792 . __( 'hours, ', 'wpstream' )
793 . '<strong id="wpstream_available_broadcast_hours">' . abs( $formatted_broadcast_hours ) . ' broadcast</strong> '
794 . __( 'hours, ', 'wpstream' )
795 . '<strong id="wpstream_available_storage_hours">' . $formatted_storage_hours . ' storage</strong> '
796 . __( 'hours', 'wpstream' ) . '.';
797
798 // Upgrade link plus hidden inputs carrying the raw hour figures for JS.
799 print '<a href="https://wpstream.net/pricing/" class="wpstream_upgrade_topbar" target="_blank">' . esc_html__( 'Upgrade Plan', 'wpstream' ) . '</a>';
800 print '</div>';
801 print '<input type="hidden" id="wpstream_viewer_hours" value="' . esc_attr( $pack_details['available_viewer_hours'] ) . '">';
802 print '<input type="hidden" id="wpstream_broadcast_hours" value="' . esc_attr( $pack_details['available_broadcast_hours'] ) . '">';
803 print '<input type="hidden" id="wpstream_storage_hours" value="' . esc_attr( $pack_details['available_storage_hours'] ) . '">';
804 }
805 }
806 }
807
808
809 /**
810 * help function for media list elementor widget
811 *
812 * Compatibility delegate for customer themes that call the historical
813 * renderer on the main plugin object.
814 *
815 * @since 3.0.1
816 * @param array $attributes Widget attributes (counts, type, order, labels).
817 * @param string|null $content Unused shortcode inner content.
818 * @return string Rendered HTML markup for the media grid.
819 */
820
821 public function wpstream_media_list_elementor_function($attributes, $content = null){
822 $kind = isset( $attributes['product_type'] ) && 2 === intval( $attributes['product_type'] )
823 ? 'vod'
824 : 'live_channel';
825 return $this->media_list->render( $kind, is_array( $attributes ) ? $attributes : array() );
826 }
827
828
829
830
831
832
833
834
835
836
837
838
839
840 /**
841 * help function for player elementr widget
842 *
843 * Renders the standard video player for a given product id, or resolves the
844 * author's first channel when only a user_id is supplied.
845 *
846 * @since 3.0.1
847 * @param array $attributes Widget attributes ('id', 'user_id').
848 * @param string|null $content Unused shortcode inner content.
849 * @return string Rendered player markup.
850 */
851
852 public function wpstream_insert_player_elementor($attributes, $content = null){
853 // Normalize incoming attributes with defaults.
854 $product_id = '';
855 $return_string = '';
856 $attributes = shortcode_atts(
857 array(
858 'id' => 0,
859 'user_id' => 0,
860 ), $attributes) ;
861
862
863 // Explicit product id, if provided.
864 if ( isset($attributes['id']) ){
865 $product_id=$attributes['id'];
866 }
867 // Optional author id used to look up a channel.
868 if ( isset($attributes['user_id']) ){
869 $user_id = intval( $attributes['user_id'] );
870 }
871
872 // No product id but a user id: resolve that author's first channel.
873 if(intval($product_id)==0 && $user_id!=0 ){
874 $product_id= $this->wpstream_player_retrieve_first_id($user_id);
875 }
876
877
878
879 // Buffer the player output so it can be returned as a string.
880 ob_start();
881 // Render the player shortcode inside the wrapper markup below.
882 ?>
883 <div class="wpstream_insert_player_elementor_wrapper">
884 <?php
885 $this->main->wpstream_player->wpstream_video_player_shortcode($product_id);
886 ?>
887 </div>
888 <?php
889 // Capture and return the buffered markup.
890 $return_string= ob_get_contents();
891 ob_end_clean();
892
893 return $return_string;
894 }
895
896
897 /**
898 * Resolve the first channel/event id belonging to a given author.
899 *
900 * @param string|int $received_user_id Author user id.
901 * @return int|string Post id of the author's first channel, or 0 when none.
902 */
903 public function wpstream_player_retrieve_first_id($received_user_id=''){
904 // Free vs paid channel type is a site-wide option.
905 $channel_type = get_option ('wpstream_user_streaming_channel_type');
906 // Look up the author's most relevant event id for that type.
907 $product_id = $this->wpstream_get_current_event_per_author($received_user_id,$channel_type);
908 return $product_id;
909 }
910
911 /**
912 * Deprecated misspelled alias of wpstream_player_retrieve_first_id().
913 *
914 * Kept because the method is public and may be called by external code.
915 *
916 * @deprecated 4.13.4 Use wpstream_player_retrieve_first_id() instead.
917 */
918 public function wpstream_player_retrive_first_id($received_user_id=''){
919 return $this->wpstream_player_retrieve_first_id($received_user_id);
920 }
921
922
923
924 /**
925 * edited 4.0
926 *
927 * Check if the current user is allowed to stream.
928 *
929 * The one broadcasting-permission rule: administrators always may; other
930 * users need their primary role on the "streamer roles" list or the
931 * "regular users may stream" option. The verdict passes through the
932 * wpstream_user_can_stream filter, so membership plugins replace the
933 * role rule in one place. Guests are refused before the filter.
934 *
935 * @since 3.7
936 * @return bool
937 */
938
939 public function wpstream_check_user_can_stream(){
940 // Current user for the role/capability checks below.
941 $current_user = wp_get_current_user();
942
943 // Guests can never stream.
944 if( !is_user_logged_in() ){
945 return false;
946 }
947
948 // Admins can always broadcast.
949 $can = current_user_can( 'administrator' );
950
951 if ( ! $can ) {
952 // Site-configured list of roles that are allowed to stream.
953 $extra_roles = get_option( 'wpstream_stream_role', true );
954 // The user's primary role (first in the roles array).
955 $user_role = '';
956 if( is_array( $current_user->roles) && count( $current_user->roles ) > 0 ){
957 $user_role = $current_user->roles[0];
958 }
959
960 // Allow when the user's role is in the configured allow-list.
961 if ( is_array($extra_roles) && in_array( $user_role, $extra_roles ) ) {
962 $can = true;
963 }
964
965 // Allow when the "regular users may stream" option is enabled.
966 if(function_exists('wpstream_get_option') && intval(wpstream_get_option('allow_streaming_regular_users',''))==1 ){
967 $can = true;
968 }
969 }
970
971 /**
972 * Filters whether the current (logged-in) user may broadcast.
973 *
974 * Gates every go-live surface: the start/stop endpoints, the
975 * start-streaming dashboard and channel creation.
976 *
977 * @since 4.14.0
978 *
979 * @param bool $can The built-in verdict (administrator, streamer
980 * role list, or the regular-users option).
981 * @param int $user_id Current user ID.
982 */
983 return (bool) apply_filters( 'wpstream_user_can_stream', $can, intval( $current_user->ID ) );
984 }
985
986
987 /**
988 * Start Streaming wrapper
989 *
990 * Ensures a channel exists (creating one for front-end streamers when
991 * needed), prints the error-modal scaffolding, then renders the start-
992 * streaming unit.
993 *
994 * @since 3.7
995 * @param int $item_id Channel/product id, or 0 to auto-resolve.
996 * @param string $type Streaming unit type/context.
997 */
998 public function wpstream_live_stream_unit_wrapper($item_id,$type){
999 // Coerce to an integer id.
1000 $item_id = intval($item_id);
1001
1002 // The unit's controller script (+ its QR dependency chain) and the shared
1003 // admin stylesheet are registered on every page but only enqueued here,
1004 // where the go-live unit actually renders (scripts print in the footer).
1005 wp_enqueue_script( 'wpstream-start-streaming' );
1006 wp_enqueue_style( 'wpstream_front_style' );
1007
1008 if($item_id == 0){
1009 //retrive or create channel for front end streamers
1010 $item_id=$this->wpstream_retrieve_front_end_channel();
1011 }
1012 // Modal backdrop and reusable error-notification markup.
1013 print'<div class="wpstream_modal_background"></div>';
1014 print '<div class="wpstream_error_modal_notification"><div class="wpstream_error_content">er2</div>
1015 <div class="wpstream_error_ok wpstream_button" type="button">'.esc_html__('Close','wpstream').'</div>
1016 </div>';
1017 // Render through the shared Live Channel presentation module.
1018 $this->get_live_channel_presentation()->render_channel( $item_id, $type );
1019 }
1020
1021
1022 /**
1023 * Start Streaming wrapper for wpstream theme
1024 *
1025 * Same as wpstream_live_stream_unit_wrapper() but renders the theme's
1026 * variant of the start-streaming unit.
1027 *
1028 * @since 3.7
1029 * @param int $item_id Channel/product id, or 0 to auto-resolve.
1030 * @param string $type Streaming unit type/context.
1031 */
1032
1033 public function wpstream_live_stream_unit_wrapper_for_theme($item_id,$type){
1034 // Coerce to an integer id.
1035 $item_id = intval($item_id);
1036
1037 // Same render-time asset loading as wpstream_live_stream_unit_wrapper().
1038 wp_enqueue_script( 'wpstream-start-streaming' );
1039 wp_enqueue_style( 'wpstream_front_style' );
1040
1041 if($item_id == 0){
1042 //retrive or create channel for front end streamers
1043 $item_id=$this->wpstream_retrieve_front_end_channel();
1044 }
1045 // Modal backdrop and reusable error-notification markup.
1046 print'<div class="wpstream_modal_background"></div>';
1047 print '<div class="wpstream_error_modal_notification"><div class="wpstream_error_content">er2</div>
1048 <div class="wpstream_error_ok wpstream_button" type="button">'.esc_html__('Close','wpstream').'</div>
1049 </div>';
1050 // Render the companion-theme variant through the same presentation module.
1051 $this->get_live_channel_presentation()->render_channel( $item_id, 'theme' );
1052 }
1053
1054
1055 /**
1056 * retrive channel for front end streaming
1057 *
1058 * Returns the current user's front-end channel id, creating a new event
1059 * when the user does not yet have one.
1060 *
1061 * @since 3.7
1062 * @return int Channel/product id for the current user.
1063 */
1064 public function wpstream_retrieve_front_end_channel(){
1065
1066 // Current user plus the site-wide channel type and default price.
1067 $current_user = wp_get_current_user();
1068 $channel_type = get_option ('wpstream_user_streaming_channel_type');
1069 $channel_price = floatval( get_option ('wpstream_user_streaming_default_price') );
1070
1071 // Look for an existing channel owned by this user.
1072 $front_end_streamin_channel = $this->wpstream_get_current_event_per_author($current_user->ID,$channel_type);
1073
1074 // None found: create one on the fly.
1075 if(intval($front_end_streamin_channel) == 0){
1076 $front_end_streamin_channel= $this->wpstream_create_front_end_event($current_user->ID,$current_user->user_login ,$channel_type,$channel_price);
1077 }
1078 return $front_end_streamin_channel;
1079
1080 }
1081
1082 /**
1083 * Deprecated misspelled alias of wpstream_retrieve_front_end_channel().
1084 *
1085 * Kept because the method is public and may be called by external code.
1086 *
1087 * @deprecated 4.13.4 Use wpstream_retrieve_front_end_channel() instead.
1088 */
1089 public function wpstream_retrive_front_end_channel(){
1090 return $this->wpstream_retrieve_front_end_channel();
1091 }
1092
1093 /**
1094 * create the event from front end
1095 *
1096 * Inserts a new channel post (free CPT or paid WooCommerce product),
1097 * setting price/terms for paid channels, and flags it as a live event.
1098 *
1099 * @since 3.7
1100 * @param int $userID Author user id.
1101 * @param string $userLogin Author login, used in the channel title.
1102 * @param string $channel_type 'paid' for a WooCommerce product, else free.
1103 * @param float $channel_price Price to set for paid channels.
1104 * @return int|void New post id, or void when the user may not stream.
1105 */
1106
1107 public function wpstream_create_front_end_event($userID,$userLogin,$channel_type,$channel_price){
1108 $request = array(
1109 'actor_id' => intval( $userID ),
1110 'owner_id' => intval( $userID ),
1111 'kind' => 'live_channel',
1112 'access' => 'paid' === $channel_type ? 'paid' : 'free',
1113 'title' => sprintf( esc_html__( '%s Channel', 'wpstream' ), $userLogin ),
1114 );
1115 if ( 'paid' === $request['access'] ) {
1116 $request['price'] = $channel_price;
1117 }
1118
1119 $result = $this->streaming_content_creation->create( $request );
1120 return ! empty( $result['success'] ) ? intval( $result['content_id'] ) : null;
1121 }
1122
1123 /**
1124 * Deprecated misspelled alias of wpstream_create_front_end_event().
1125 *
1126 * Kept because the method is public and may be called by external code.
1127 *
1128 * @deprecated 4.13.4 Use wpstream_create_front_end_event() instead.
1129 */
1130 public function wpstrea_create_front_end_event($userID,$userLogin,$channel_type,$channel_price){
1131 return $this->wpstream_create_front_end_event($userID,$userLogin,$channel_type,$channel_price);
1132 }
1133
1134
1135
1136 /**
1137 * Find the first channel/event id owned by a given author.
1138 *
1139 * @param int $userID Author user id.
1140 * @param string $channel_type 'paid' for a WooCommerce product, else free.
1141 * @return int Post id of the author's first matching channel, or 0.
1142 */
1143 public function wpstream_get_current_event_per_author($userID,$channel_type){
1144
1145 // Free channels are CPTs; paid channels are WooCommerce products.
1146 $post_type='wpstream_product';
1147 if($channel_type=='paid'){
1148 $post_type='product';
1149 }
1150
1151 // Query for a single post id owned by this author.
1152 $args = array(
1153
1154 'post_type' => $post_type,
1155 'author' => $userID,
1156 'posts_per_page' => 1,
1157 'fields' => 'ids'
1158 )
1159 ;
1160 $author_posts = new WP_Query( $args );
1161 // Use the found id, or 0 when the author has no channel.
1162 if( $author_posts->have_posts() ) {
1163 $author_posts->the_post();
1164 $the_id= get_the_ID();
1165 }else{
1166 $the_id= 0;
1167 }
1168
1169 // Restore global post/query state after the custom query.
1170 wp_reset_query();
1171 wp_reset_postdata();
1172 return $the_id;
1173 }
1174
1175 /**
1176 * Cleanup old logs
1177 */
1178 public function cleanup_logs() {
1179 // Delegate to the logger, which prunes entries past its retention window.
1180 $logger = new WPStream_Logger();
1181 $logger->clear_old_logs();
1182 }
1183 }
1184