| 1 |
<?php |
| 2 |
|
| 3 |
/** |
| 4 |
* Dashboard functions |
| 5 |
* |
| 6 |
* Helpers that build the front-end broadcaster/dashboard UI for the |
| 7 |
* hello-wpstream theme: a select of the user's own channels, the plupload |
| 8 |
* localization for image/video uploaders, and the HTML markup for the image, |
| 9 |
* profile-image, trailer and preview upload widgets plus the gallery grid. |
| 10 |
* |
| 11 |
* @package wpstream-plugin |
| 12 |
*/ |
| 13 |
|
| 14 |
|
| 15 |
// Exit if accessed directly. |
| 16 |
if ( ! defined( 'ABSPATH' ) ) { |
| 17 |
exit; |
| 18 |
} |
| 19 |
|
| 20 |
if ( ! function_exists( 'wpstream_theme_return_user_channel_list' ) ) { |
| 21 |
/** |
| 22 |
* Return user channel list. |
| 23 |
* |
| 24 |
* This function generates and returns HTML markup for a select field containing user channels. |
| 25 |
* |
| 26 |
* @param int $already_selected The ID of the already selected channel. |
| 27 |
* @param string $return_type The type of return. Default is empty. |
| 28 |
* @return string|int The HTML markup for the select field or the count of found posts. |
| 29 |
*/ |
| 30 |
function wpstream_theme_return_user_channel_list( $already_selected, $return_type = '' ) { |
| 31 |
// Current user whose channels we are listing. |
| 32 |
$current_user = wp_get_current_user(); |
| 33 |
// Cap the query at 100 channels. |
| 34 |
$limit = 100; |
| 35 |
$return_string = ''; |
| 36 |
|
| 37 |
// When WooCommerce is active, channels can be either WC products of |
| 38 |
// type live_stream or plain wpstream_product posts. |
| 39 |
if ( class_exists( 'WooCommerce' ) ) { |
| 40 |
$post_type = array( 'product', 'wpstream_product' ); |
| 41 |
// Match live_stream products OR posts with no product_type term. |
| 42 |
$taxonomy_array = array( |
| 43 |
'relation' => 'OR', |
| 44 |
array( |
| 45 |
'taxonomy' => 'product_type', |
| 46 |
'field' => 'slug', |
| 47 |
'terms' => array( 'live_stream' ), |
| 48 |
), |
| 49 |
array( |
| 50 |
'taxonomy' => 'product_type', |
| 51 |
'operator' => 'NOT EXISTS', |
| 52 |
), |
| 53 |
); |
| 54 |
} else { |
| 55 |
// Without WooCommerce, only the custom post type applies. |
| 56 |
$post_type = 'wpstream_product'; |
| 57 |
$taxonomy_array = array(); |
| 58 |
} |
| 59 |
|
| 60 |
// Query the current user's channels. |
| 61 |
$args = array( |
| 62 |
'post_type' => $post_type, |
| 63 |
'posts_per_page' => $limit, |
| 64 |
'tax_query' => $taxonomy_array, // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query |
| 65 |
'author' => $current_user->ID, |
| 66 |
); |
| 67 |
|
| 68 |
$query_list = new WP_Query( $args ); |
| 69 |
|
| 70 |
// Caller only wants the count of channels found: return it early. |
| 71 |
if ( 'found_posts' === $return_type ) { |
| 72 |
return intval( $query_list->found_posts ); |
| 73 |
} |
| 74 |
|
| 75 |
// Open the select element with a placeholder first option. |
| 76 |
$return_string .= '<select id="wpstream-user-channel-selection" name="wpstream-user-channel-selection" ' |
| 77 |
. 'class="wpstream-user-channel-selection">' |
| 78 |
. '<option value="">' . esc_html__( 'select the channel', 'hello-wpstream' ) . '</option>'; |
| 79 |
|
| 80 |
if ( $query_list->have_posts() ) { |
| 81 |
// Emit one <option> per channel in the loop. |
| 82 |
while ( $query_list->have_posts() ) : |
| 83 |
$query_list->the_post(); |
| 84 |
// Gather the channel's ID, title and post type. |
| 85 |
$the_id = get_the_ID(); |
| 86 |
$the_title = get_the_title( $the_id ); |
| 87 |
$post_type = get_post_type( $the_id ); |
| 88 |
$product_type = ''; |
| 89 |
|
| 90 |
// For WC products, read the stored product type meta. |
| 91 |
if ( get_post_type( $the_id ) === 'product' ) { |
| 92 |
$product_type = get_post_meta( $the_id, '_product_type', true ); |
| 93 |
} |
| 94 |
|
| 95 |
// Build the option, marking it selected when it matches. |
| 96 |
$image_url = ''; |
| 97 |
$return_string .= '<option value="' . intval( $the_id ) . '"'; |
| 98 |
if ( intval( $already_selected ) === $the_id ) { |
| 99 |
$return_string .= ' selected'; |
| 100 |
} |
| 101 |
// Attach the (currently empty) thumbnail data attribute and label. |
| 102 |
$return_string .= ' data-thumbnail="' . esc_url( $image_url ) . '">'; |
| 103 |
$return_string .= esc_html( $the_title ) . '</option>'; |
| 104 |
|
| 105 |
endwhile; |
| 106 |
} |
| 107 |
|
| 108 |
// Close the select element. |
| 109 |
$return_string .= '</select>'; |
| 110 |
|
| 111 |
// Restore the global post after the custom query loop. |
| 112 |
wp_reset_postdata(); |
| 113 |
|
| 114 |
// Return the assembled <select> markup. |
| 115 |
return $return_string; |
| 116 |
} |
| 117 |
} |
| 118 |
|
| 119 |
if ( ! function_exists( 'wpstream_max_gallery_images' ) ) { |
| 120 |
/** |
| 121 |
* Maximum number of images a channel or video gallery may hold. |
| 122 |
* |
| 123 |
* Read by the uploader config (client-side warning) and enforced by the |
| 124 |
* dashboard save handlers, so the two can never disagree. |
| 125 |
* |
| 126 |
* @return int Limit in [1, 100]. |
| 127 |
*/ |
| 128 |
function wpstream_max_gallery_images() { |
| 129 |
/** |
| 130 |
* Filter the maximum number of gallery images. Clamped to [1, 100]. |
| 131 |
* |
| 132 |
* @since 4.14.0 |
| 133 |
* |
| 134 |
* @param int $max Limit; default 20. |
| 135 |
*/ |
| 136 |
return wpstream_tunable( 'wpstream_max_gallery_images', 20, 100 ); |
| 137 |
} |
| 138 |
} |
| 139 |
|
| 140 |
if ( ! function_exists( 'wpstream_limit_gallery_images' ) ) { |
| 141 |
/** |
| 142 |
* Trim a submitted comma list of attachment ids to the gallery limit. |
| 143 |
* |
| 144 |
* @param string $images Comma-separated attachment ids as submitted. |
| 145 |
* @return string The first N ids, N = wpstream_max_gallery_images(). |
| 146 |
*/ |
| 147 |
function wpstream_limit_gallery_images( $images ) { |
| 148 |
// Keep positive attachment ids only, in submitted order, then the first N. |
| 149 |
$ids = array_values( array_filter( array_map( 'absint', explode( ',', (string) $images ) ) ) ); |
| 150 |
return implode( ',', array_slice( $ids, 0, wpstream_max_gallery_images() ) ); |
| 151 |
} |
| 152 |
} |
| 153 |
|
| 154 |
if ( ! function_exists( 'wpstream_theme_localize_upload_script_images' ) ) : |
| 155 |
/** |
| 156 |
* Localize the upload script for images. |
| 157 |
* |
| 158 |
* @param string $button_upload The ID of the upload button. |
| 159 |
*/ |
| 160 |
function wpstream_theme_localize_upload_script_images( $button_upload ) { |
| 161 |
// Build the admin-ajax upload endpoint URL, embedding the upload nonce. |
| 162 |
$plup_url = add_query_arg( |
| 163 |
array( |
| 164 |
'action' => 'wpstream_me_upload', |
| 165 |
'nonce' => wp_create_nonce( 'aaiu_allow' ), |
| 166 |
), |
| 167 |
esc_url( admin_url( 'admin-ajax.php' ) ) |
| 168 |
); |
| 169 |
|
| 170 |
// Maximum accepted upload size: the same cap the server enforces. |
| 171 |
$max_file_size = wpstream_max_upload_bytes( $button_upload ); |
| 172 |
|
| 173 |
// Core plupload configuration passed to the browser uploader. |
| 174 |
$plupload_values = array( |
| 175 |
'runtimes' => 'html5,flash,html4', |
| 176 |
'max_file_size' => $max_file_size . 'b', |
| 177 |
'url' => $plup_url, |
| 178 |
'file_data_name' => 'aaiu_upload_file', |
| 179 |
'flash_swf_url' => includes_url( 'js/plupload/plupload.flash.swf' ), |
| 180 |
// Client-side allowed file extensions (not a server-side guarantee). |
| 181 |
'filters' => array( |
| 182 |
array( |
| 183 |
'title' => esc_html__( 'Allowed Files', 'hello-wpstream' ), |
| 184 |
'extensions' => 'jpeg,jpg,gif,png,pdf,webp,mp4,mov', |
| 185 |
), |
| 186 |
), |
| 187 |
'multipart' => true, |
| 188 |
'urlstream_upload' => true, |
| 189 |
// Pass the originating button id so the server knows which uploader fired. |
| 190 |
'multipart_params' => array( 'button_id' => $button_upload ), |
| 191 |
); |
| 192 |
|
| 193 |
// UI wiring: which element opens the file picker and which is the container. |
| 194 |
$tmp_plupload_values = array( |
| 195 |
'browse_button' => $button_upload, |
| 196 |
'container' => 'aaiu-upload-container', |
| 197 |
); |
| 198 |
|
| 199 |
// Merge the UI wiring into the config and set the drag-and-drop target. |
| 200 |
$plupload_values = wp_parse_args( $plupload_values, $tmp_plupload_values ); |
| 201 |
$plupload_values['drop_element'] = 'drag-and-drop'; |
| 202 |
// Upper bound on the number of images allowed in the gallery uploader. |
| 203 |
$max_images = wpstream_max_gallery_images(); |
| 204 |
|
| 205 |
// Expose all upload settings/nonces/strings to the ajax-upload JS handle. |
| 206 |
wp_localize_script( |
| 207 |
'ajax-upload', |
| 208 |
'ajax_vars', |
| 209 |
array( |
| 210 |
'ajaxurl' => esc_url( admin_url( 'admin-ajax.php' ) ), |
| 211 |
'nonce' => wp_create_nonce( 'aaiu_upload' ), |
| 212 |
'remove' => wp_create_nonce( 'aaiu_remove' ), |
| 213 |
'number' => 1, |
| 214 |
'upload_enabled' => true, |
| 215 |
'warning' => __( 'Image needs to be at least 500px height x 500px wide!', 'hello-wpstream' ), |
| 216 |
'max_images' => $max_images, |
| 217 |
'warning_max' => __( 'You cannot upload more than', 'hello-wpstream' ) . ' ' . $max_images . ' ' . __( 'images', 'hello-wpstream' ), |
| 218 |
'path' => trailingslashit( WPSTREAM_PLUGIN_PATH ), |
| 219 |
'confirmMsg' => esc_html__( 'Are you sure you want to delete this?', 'hello-wpstream' ), |
| 220 |
'plupload' => $plupload_values, |
| 221 |
) |
| 222 |
); |
| 223 |
} |
| 224 |
endif; |
| 225 |
|
| 226 |
if ( ! function_exists( 'wpstream_theme_return_image_upload_markup' ) ) { |
| 227 |
/** |
| 228 |
* Return the markup for image upload. |
| 229 |
* |
| 230 |
* This function generates and returns the markup for image upload based on the provided post ID. |
| 231 |
* |
| 232 |
* @param int $user_id The ID of the user. |
| 233 |
* @param int $post_id The ID of the post. |
| 234 |
* @return string The HTML markup for image upload. |
| 235 |
*/ |
| 236 |
function wpstream_theme_return_image_upload_markup( $user_id, $post_id ) { |
| 237 |
// Determine the post type to know where the gallery data lives. |
| 238 |
$post_type = get_post_type( $post_id ); |
| 239 |
$gallery_images = ''; |
| 240 |
|
| 241 |
if ( 'product' === $post_type ) { |
| 242 |
// WooCommerce products store gallery IDs as a comma list in meta. |
| 243 |
$gallery_images_source = get_post_meta( $post_id, '_product_image_gallery', true ); |
| 244 |
$gallery_images = explode( ',', $gallery_images_source ); |
| 245 |
} else { |
| 246 |
// Other post types use the Meta Box (rwmb) gallery field, if present. |
| 247 |
if(function_exists('rwmb_meta')){ |
| 248 |
$gallery_images = rwmb_meta( 'wpstream_theme_gallery', array(), $post_id ); |
| 249 |
|
| 250 |
// rwmb returns id => data; reduce to the list of IDs. |
| 251 |
if ( is_array( $gallery_images ) ) { |
| 252 |
$gallery_images = array_keys( $gallery_images ); |
| 253 |
} |
| 254 |
} |
| 255 |
} |
| 256 |
|
| 257 |
// Canonical gallery source: overrides whatever was gathered above. |
| 258 |
$gallery_images = wpstream_theme_return_image_gallery( $post_id ); |
| 259 |
|
| 260 |
// Featured image ID and accumulator for the rendered thumbnails. |
| 261 |
$thumbid = get_post_thumbnail_id( $post_id ); |
| 262 |
$images = ''; |
| 263 |
|
| 264 |
if ( is_array( $gallery_images ) ) { |
| 265 |
// Build a thumbnail tile (with delete icon) for each gallery image. |
| 266 |
foreach ( $gallery_images as $attachment_id ) { |
| 267 |
|
| 268 |
// Resolve the card-sized preview for this attachment. |
| 269 |
$preview = wp_get_attachment_image_src( $attachment_id, 'wpstream_featured_unit_cards' ); |
| 270 |
|
| 271 |
// Only render tiles that have a usable preview URL. |
| 272 |
if ( $preview && $preview[0] != '' ) { |
| 273 |
$images .= '<div class="wpstream_uploaded_images" data-imageid="' . esc_attr( $attachment_id ) . '">' |
| 274 |
. '<img src="' . esc_url( $preview[0] ) . '" alt="' . esc_html__( 'thumb', 'hello-wpstream' ) . '" />' |
| 275 |
. '<i class="far fa-trash-alt wpstream_delete_image"></i>'; |
| 276 |
|
| 277 |
$images .= '</div>'; |
| 278 |
} |
| 279 |
} |
| 280 |
} |
| 281 |
|
| 282 |
// Flatten the gallery IDs into a comma string for the hidden field. |
| 283 |
$gallery_images_string = ''; |
| 284 |
if ( is_array( $gallery_images ) ) { |
| 285 |
$gallery_images_string = implode( ',', $gallery_images ); |
| 286 |
} |
| 287 |
|
| 288 |
// Capture the template output into a string via output buffering. |
| 289 |
$return_string = ''; |
| 290 |
ob_start(); |
| 291 |
?> |
| 292 |
|
| 293 |
<!-- Multi-image uploader (gallery) container --> |
| 294 |
<div id="upload-container" class="upload-container"> |
| 295 |
<div id="aaiu-upload-container upload-container__body"> |
| 296 |
<h3><?php echo esc_html__( 'Image list', 'hello-wpstream' ); ?></h3> |
| 297 |
<!-- Live list plupload appends queued items into --> |
| 298 |
<div id="aaiu-upload-imagelist"> |
| 299 |
<ul id="aaiu-ul-list" class="aaiu-upload-list"></ul> |
| 300 |
</div> |
| 301 |
|
| 302 |
<!-- Existing uploaded images plus the upload nonce field --> |
| 303 |
<div id="wpstream_imagelist"> |
| 304 |
<?php |
| 305 |
// Nonce consumed by the delete-image AJAX handler. |
| 306 |
$ajax_nonce = wp_create_nonce( 'wpstream_image_upload' ); |
| 307 |
print '<input type="hidden" id="wpstream_image_upload" value="' . esc_html( $ajax_nonce ) . '" /> '; |
| 308 |
// Print the pre-rendered thumbnail tiles, if any. |
| 309 |
if ( '' !== $images ) { |
| 310 |
print trim( $images ); //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped |
| 311 |
} |
| 312 |
?> |
| 313 |
</div> |
| 314 |
|
| 315 |
<!-- Actions row: drag-and-drop trigger and hidden state fields --> |
| 316 |
<div class="upload-container__actions-wrap upload-container__actions-wrap--row"> |
| 317 |
<div id="drag-and-drop" class="rh_drag_and_drop_wrapper "> |
| 318 |
<!-- "Upload More" button plupload binds to --> |
| 319 |
<div id="aaiu-uploader" class="wpstream_theme_button_dashboard"> |
| 320 |
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> |
| 321 |
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.7379 16.6273C9.96427 16.6273 9.31895 16.036 9.2514 15.2654C9.11015 13.6541 9.07441 12.0356 9.14427 10.4203C9.05994 10.4147 8.97563 10.4088 8.89133 10.4026L7.40178 10.2941C6.44973 10.2247 5.91752 9.16309 6.43151 8.35871C7.5277 6.6432 9.53693 4.72314 11.1904 3.53541C11.6742 3.18786 12.3258 3.18786 12.8097 3.53541C14.4631 4.72314 16.4723 6.64319 17.5685 8.35871C18.0825 9.16309 17.5503 10.2247 16.5983 10.2941L15.1087 10.4026C15.0244 10.4088 14.9401 10.4147 14.8558 10.4203C14.9256 12.0356 14.8899 13.6541 14.7486 15.2654C14.6811 16.036 14.0358 16.6273 13.2622 16.6273H10.7379ZM10.6815 9.76253C10.5678 11.5498 10.589 13.3431 10.745 15.1273H13.255C13.411 13.3431 13.4323 11.5498 13.3186 9.76253C13.3058 9.56216 13.3739 9.36505 13.5077 9.21531C13.6414 9.06556 13.8296 8.9757 14.0301 8.96582C14.3535 8.94989 14.6767 8.93015 14.9997 8.90661L16.0815 8.82775C15.1219 7.41445 13.9204 6.1802 12.5313 5.18235L12 4.80071L11.4687 5.18235C10.0796 6.1802 8.87813 7.41446 7.91858 8.82775L9.00038 8.90661C9.32337 8.93015 9.64656 8.94989 9.9699 8.96582C10.1704 8.9757 10.3586 9.06556 10.4924 9.21531C10.6261 9.36505 10.6942 9.56216 10.6815 9.76253Z" fill="#0F0F0F"/> |
| 322 |
<path d="M5.75 17C5.75 16.5858 5.41421 16.25 5 16.25C4.58579 16.25 4.25 16.5858 4.25 17V19C4.25 19.9665 5.0335 20.75 6 20.75H18C18.9665 20.75 19.75 19.9665 19.75 19V17C19.75 16.5858 19.4142 16.25 19 16.25C18.5858 16.25 18.25 16.5858 18.25 17V19C18.25 19.1381 18.1381 19.25 18 19.25H6C5.86193 19.25 5.75 19.1381 5.75 19V17Z" fill="#0F0F0F"/> |
| 323 |
</svg> |
| 324 |
|
| 325 |
<?php esc_html_e( 'Upload More', 'hello-wpstream' ); ?> |
| 326 |
</div> |
| 327 |
</div> |
| 328 |
|
| 329 |
<!-- Hidden fields carrying the current gallery IDs and thumbnail ID --> |
| 330 |
<input type="hidden" name="attachid" id="attachid" value="<?php print esc_html( $gallery_images_string ); ?>"> |
| 331 |
<input type="hidden" name="attachthumb" id="attachthumb" value="<?php print esc_html( $thumbid ); ?>"> |
| 332 |
<p class="full_form full_form_image"> |
| 333 |
<?php |
| 334 |
// Guidance text on recommended image dimensions/format. |
| 335 |
esc_html_e( |
| 336 |
"It's recommended to use a picture that's at least 1280 x 720 pixels and 4MB or less. |
| 337 |
Use a PNG or GIF (no animations) file.", |
| 338 |
'hello-wpstream' |
| 339 |
); |
| 340 |
?> |
| 341 |
</p> |
| 342 |
</div> |
| 343 |
</div> |
| 344 |
</div> |
| 345 |
<?php |
| 346 |
// Flush the buffered template into the return string and clean up. |
| 347 |
$return_string .= ob_get_contents(); |
| 348 |
ob_end_clean(); |
| 349 |
|
| 350 |
// Return the complete uploader markup. |
| 351 |
return $return_string; |
| 352 |
} |
| 353 |
} |
| 354 |
|
| 355 |
if ( ! function_exists( 'wpstream_theme_return_image_upload_markup_single' ) ) { |
| 356 |
/** |
| 357 |
* Return the markup for single image upload. |
| 358 |
* |
| 359 |
* This function generates and returns the markup for single image upload based on the provided post ID. |
| 360 |
* |
| 361 |
* @param int $user_id The ID of the user. |
| 362 |
* @param int $post_id The ID of the post. |
| 363 |
* @return string The HTML markup for single image upload. |
| 364 |
*/ |
| 365 |
function wpstream_theme_return_image_upload_markup_single( $post_id ) { |
| 366 |
// Current featured image (thumbnail) ID for this post. |
| 367 |
$thumbid = get_post_thumbnail_id( $post_id ); |
| 368 |
$images = ''; |
| 369 |
// Card-sized preview of the existing thumbnail, if any. |
| 370 |
$preview = wp_get_attachment_image_src( $thumbid, 'wpstream_featured_unit_cards' ); |
| 371 |
|
| 372 |
// Render the existing thumbnail tile when a valid preview URL exists. |
| 373 |
if ( isset( $preview[0] ) && '' !== $preview[0] ) { |
| 374 |
$images .= '<div class="wpstream_uploaded_images" id="wpstream_uploaded_profile_image" data-imageid="' . esc_attr( $thumbid ) . '">' |
| 375 |
. '<img src="' . esc_url( $preview[0] ) . '" alt="' . esc_html__( 'thumb', 'hello-wpstream' ) . '" /></div>'; |
| 376 |
} |
| 377 |
|
| 378 |
// Buffer the template markup into a return string. |
| 379 |
$return_string = ''; |
| 380 |
ob_start(); |
| 381 |
?> |
| 382 |
|
| 383 |
<!-- Single-image (channel thumbnail) uploader container --> |
| 384 |
<div id="upload-container"> |
| 385 |
<div id="aaiu-upload-container" class="upload-container"> |
| 386 |
<p class="upload-container__title"><?php echo esc_html__( 'Channel Thumbnail', 'hello-wpstream' ); ?></p> |
| 387 |
<div class="upload-container__row"> |
| 388 |
<div class="upload-container__image-wrap"> |
| 389 |
<!-- Live list plupload appends queued items into --> |
| 390 |
<div id="aaiu-upload-imagelist_single"> |
| 391 |
<ul id="aaiu-ul-list" class="aaiu-upload-list"></ul> |
| 392 |
</div> |
| 393 |
|
| 394 |
<!-- Existing thumbnail plus the upload nonce field --> |
| 395 |
<div id="wpstream_imagelist_single"> |
| 396 |
<?php |
| 397 |
// Nonce for the image delete/upload AJAX handler. |
| 398 |
$ajax_nonce = wp_create_nonce( 'wpstream_image_upload' ); |
| 399 |
print '<input type="hidden" id="wpstream_image_upload" value="' . esc_html( $ajax_nonce ) . '" /> '; |
| 400 |
// Print the current thumbnail tile, if present. |
| 401 |
if ( '' !== $images ) { |
| 402 |
print trim( $images ); //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped |
| 403 |
} |
| 404 |
?> |
| 405 |
</div> |
| 406 |
|
| 407 |
<!-- Hidden field carrying the current thumbnail ID --> |
| 408 |
<input type="hidden" name="attachthumb" id="attachthumb" value="<?php print esc_html( $thumbid ); ?>"> |
| 409 |
</div> |
| 410 |
|
| 411 |
<div class="upload-container__actions-wrap upload-container__actions-wrap--column"> |
| 412 |
<p class="full_form full_form_image"> |
| 413 |
<?php |
| 414 |
esc_html_e( |
| 415 |
"It's recommended to use a picture that's at least 1280 x 720 pixels and 4MB or less. |
| 416 |
Use a PNG or GIF (no animations) file.", |
| 417 |
'hello-wpstream' |
| 418 |
); |
| 419 |
?> |
| 420 |
</p> |
| 421 |
|
| 422 |
<!-- Drag-and-drop target / "Change" button for the thumbnail --> |
| 423 |
<div id="drag-and-drop" class="rh_drag_and_drop_wrapper"> |
| 424 |
<div id="aaiu-uploader-single" class="wpstream_theme_button_dashboard"> |
| 425 |
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> |
| 426 |
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.7379 16.6273C9.96427 16.6273 9.31895 16.036 9.2514 15.2654C9.11015 13.6541 9.07441 12.0356 9.14427 10.4203C9.05994 10.4147 8.97563 10.4088 8.89133 10.4026L7.40178 10.2941C6.44973 10.2247 5.91752 9.16309 6.43151 8.35871C7.5277 6.6432 9.53693 4.72314 11.1904 3.53541C11.6742 3.18786 12.3258 3.18786 12.8097 3.53541C14.4631 4.72314 16.4723 6.64319 17.5685 8.35871C18.0825 9.16309 17.5503 10.2247 16.5983 10.2941L15.1087 10.4026C15.0244 10.4088 14.9401 10.4147 14.8558 10.4203C14.9256 12.0356 14.8899 13.6541 14.7486 15.2654C14.6811 16.036 14.0358 16.6273 13.2622 16.6273H10.7379ZM10.6815 9.76253C10.5678 11.5498 10.589 13.3431 10.745 15.1273H13.255C13.411 13.3431 13.4323 11.5498 13.3186 9.76253C13.3058 9.56216 13.3739 9.36505 13.5077 9.21531C13.6414 9.06556 13.8296 8.9757 14.0301 8.96582C14.3535 8.94989 14.6767 8.93015 14.9997 8.90661L16.0815 8.82775C15.1219 7.41445 13.9204 6.1802 12.5313 5.18235L12 4.80071L11.4687 5.18235C10.0796 6.1802 8.87813 7.41446 7.91858 8.82775L9.00038 8.90661C9.32337 8.93015 9.64656 8.94989 9.9699 8.96582C10.1704 8.9757 10.3586 9.06556 10.4924 9.21531C10.6261 9.36505 10.6942 9.56216 10.6815 9.76253Z" fill="#0F0F0F"/> |
| 427 |
<path d="M5.75 17C5.75 16.5858 5.41421 16.25 5 16.25C4.58579 16.25 4.25 16.5858 4.25 17V19C4.25 19.9665 5.0335 20.75 6 20.75H18C18.9665 20.75 19.75 19.9665 19.75 19V17C19.75 16.5858 19.4142 16.25 19 16.25C18.5858 16.25 18.25 16.5858 18.25 17V19C18.25 19.1381 18.1381 19.25 18 19.25H6C5.86193 19.25 5.75 19.1381 5.75 19V17Z" fill="#0F0F0F"/> |
| 428 |
</svg> |
| 429 |
|
| 430 |
<?php esc_html_e( 'Change', 'hello-wpstream' ); ?> |
| 431 |
</div> |
| 432 |
</div> |
| 433 |
</div> |
| 434 |
</div> |
| 435 |
</div> |
| 436 |
</div> |
| 437 |
<?php |
| 438 |
// Capture the buffered markup and return it. |
| 439 |
$return_string .= ob_get_contents(); |
| 440 |
ob_end_clean(); |
| 441 |
|
| 442 |
return $return_string; |
| 443 |
} |
| 444 |
} |
| 445 |
|
| 446 |
if ( ! function_exists( 'wpstream_theme_return_trailer_upload_markup' ) ) { |
| 447 |
/** |
| 448 |
* Return the markup for trailer video upload. |
| 449 |
* |
| 450 |
* This function generates and returns the markup for trailer video upload based on the provided post ID. |
| 451 |
* |
| 452 |
* @param int $post_id The ID of the post. |
| 453 |
* @return string The HTML markup for trailer video upload. |
| 454 |
*/ |
| 455 |
function wpstream_theme_return_trailer_upload_markup( $post_id ) { |
| 456 |
// Attachment ID of the stored trailer video (from post meta). |
| 457 |
$trailer_id = get_post_meta( $post_id, 'video_trailer', true ); |
| 458 |
// Public URL of that trailer attachment, if it exists. |
| 459 |
$attachment_url = wp_get_attachment_url( $trailer_id ); |
| 460 |
$video_html = ''; |
| 461 |
|
| 462 |
// Pre-render an inline <video> preview when a trailer is present. |
| 463 |
if ( $trailer_id && $attachment_url ) { |
| 464 |
$video_html = '<div class="wpstream_uplod_video" id="wpstream_uploaded_trailer" data-videoid="' . esc_attr( $trailer_id ) . '">' |
| 465 |
.'<video height="240" controls><source src="' . esc_url( $attachment_url ) . '" type="video/mp4"></video></div>'; |
| 466 |
} |
| 467 |
|
| 468 |
// Buffer the template markup into a return string. |
| 469 |
$return_string = ''; |
| 470 |
ob_start(); |
| 471 |
?> |
| 472 |
|
| 473 |
<!-- Video trailer uploader container --> |
| 474 |
<div id="trailer-upload-container"> |
| 475 |
<div id="aaiu-trailer-container" class="upload-container"> |
| 476 |
<p class="upload-container__title"><?php echo esc_html__( 'Video Trailer', 'hello-wpstream' ); ?></p> |
| 477 |
<div class="upload-container__row"> |
| 478 |
<div class="upload-container__video-wrap"> |
| 479 |
<!-- Live list plupload appends queued items into --> |
| 480 |
<div id="aaiu-upload-trailer"> |
| 481 |
<ul id="aaiu-ul-list" class="aaiu-upload-list"></ul> |
| 482 |
</div> |
| 483 |
|
| 484 |
<!-- Existing trailer preview plus the upload nonce field --> |
| 485 |
<div id="wpstream_trailerlist"> |
| 486 |
<?php |
| 487 |
// Nonce for the trailer upload AJAX handler. |
| 488 |
$ajax_nonce = wp_create_nonce( 'wpstream_trailer_upload' ); |
| 489 |
print '<input type="hidden" id="wpstream_trailer_upload" value="' . esc_html( $ajax_nonce ) . '" /> '; |
| 490 |
// Print the pre-rendered trailer <video> preview, if any. |
| 491 |
if ( '' !== $video_html ) { |
| 492 |
print trim( $video_html ); //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped |
| 493 |
} |
| 494 |
?> |
| 495 |
</div> |
| 496 |
|
| 497 |
<input type="hidden" id="upload_trailer" class="wpstream_upload_file" /> |
| 498 |
</div> |
| 499 |
|
| 500 |
<div class="upload-container__actions-wrap upload-container__actions-wrap--column"> |
| 501 |
<p class="full_form full_form_trailer"> |
| 502 |
<?php |
| 503 |
esc_html_e( "Upload a video trailer for your content. Supported formats: MP4, MOV", 'hello-wpstream' ); |
| 504 |
?> |
| 505 |
</p> |
| 506 |
|
| 507 |
<!-- Drag-and-drop target / "Change" button for the trailer --> |
| 508 |
<div id="drag-and-drop" class="rh_drag_and_drop_wrapper"> |
| 509 |
<div id="aaiu-uploader-trailer" class="wpstream_theme_button_dashboard"> |
| 510 |
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> |
| 511 |
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.7379 16.6273C9.96427 16.6273 9.31895 16.036 9.2514 15.2654C9.11015 13.6541 9.07441 12.0356 9.14427 10.4203C9.05994 10.4147 8.97563 10.4088 8.89133 10.4026L7.40178 10.2941C6.44973 10.2247 5.91752 9.16309 6.43151 8.35871C7.5277 6.6432 9.53693 4.72314 11.1904 3.53541C11.6742 3.18786 12.3258 3.18786 12.8097 3.53541C14.4631 4.72314 16.4723 6.64319 17.5685 8.35871C18.0825 9.16309 17.5503 10.2247 16.5983 10.2941L15.1087 10.4026C15.0244 10.4088 14.9401 10.4147 14.8558 10.4203C14.9256 12.0356 14.8899 13.6541 14.7486 15.2654C14.6811 16.036 14.0358 16.6273 13.2622 16.6273H10.7379ZM10.6815 9.76253C10.5678 11.5498 10.589 13.3431 10.745 15.1273H13.255C13.411 13.3431 13.4323 11.5498 13.3186 9.76253C13.3058 9.56216 13.3739 9.36505 13.5077 9.21531C13.6414 9.06556 13.8296 8.9757 14.0301 8.96582C14.3535 8.94989 14.6767 8.93015 14.9997 8.90661L16.0815 8.82775C15.1219 7.41445 13.9204 6.1802 12.5313 5.18235L12 4.80071L11.4687 5.18235C10.0796 6.1802 8.87813 7.41446 7.91858 8.82775L9.00038 8.90661C9.32337 8.93015 9.64656 8.94989 9.9699 8.96582C10.1704 8.9757 10.3586 9.06556 10.4924 9.21531C10.6261 9.36505 10.6942 9.56216 10.6815 9.76253Z" fill="#0F0F0F"/> |
| 512 |
<path d="M5.75 17C5.75 16.5858 5.41421 16.25 5 16.25C4.58579 16.25 4.25 16.5858 4.25 17V19C4.25 19.9665 5.0335 20.75 6 20.75H18C18.9665 20.75 19.75 19.9665 19.75 19V17C19.75 16.5858 19.4142 16.25 19 16.25C18.5858 16.25 18.25 16.5858 18.25 17V19C18.25 19.1381 18.1381 19.25 18 19.25H6C5.86193 19.25 5.75 19.1381 5.75 19V17Z" fill="#0F0F0F"/> |
| 513 |
</svg> |
| 514 |
|
| 515 |
<?php esc_html_e( 'Change', 'hello-wpstream' ); ?> |
| 516 |
</div> |
| 517 |
</div> |
| 518 |
</div> |
| 519 |
</div> |
| 520 |
</div> |
| 521 |
</div> |
| 522 |
<?php |
| 523 |
// Capture the buffered markup and return it. |
| 524 |
$return_string .= ob_get_contents(); |
| 525 |
ob_end_clean(); |
| 526 |
|
| 527 |
return $return_string; |
| 528 |
} |
| 529 |
} |
| 530 |
|
| 531 |
if ( ! function_exists( 'wpstream_theme_return_preview_upload_markup' ) ) { |
| 532 |
/** |
| 533 |
* Return the markup for preview video upload. |
| 534 |
* |
| 535 |
* This function generates and returns the markup for preview video upload based on the provided post ID. |
| 536 |
* |
| 537 |
* @param int $post_id The ID of the post. |
| 538 |
* @return string The HTML markup for preview video upload. |
| 539 |
*/ |
| 540 |
function wpstream_theme_return_preview_upload_markup( $post_id ) { |
| 541 |
// Attachment ID of the stored preview video (from post meta). |
| 542 |
$preview_id = get_post_meta( $post_id, 'video_preview', true ); |
| 543 |
// Public URL of that preview attachment, if it exists. |
| 544 |
$attachment_url = wp_get_attachment_url( $preview_id ); |
| 545 |
$video_html = ''; |
| 546 |
|
| 547 |
// Pre-render an inline <video> preview when a preview clip is present. |
| 548 |
if ( $preview_id && $attachment_url ) { |
| 549 |
$video_html = '<div class="wpstream_uplod_video" id="wpstream_uploaded_preview" data-videoid="' . esc_attr( $preview_id ) . '">' |
| 550 |
.'<video height="240" controls><source src="' . esc_url( $attachment_url ) . '" type="video/mp4"></video></div>'; |
| 551 |
} |
| 552 |
|
| 553 |
// Buffer the template markup into a return string. |
| 554 |
$return_string = ''; |
| 555 |
ob_start(); |
| 556 |
?> |
| 557 |
|
| 558 |
<!-- Video preview uploader container --> |
| 559 |
<div id="preview-upload-container"> |
| 560 |
<div id="aaiu-preview-container" class="upload-container"> |
| 561 |
<p class="upload-container__title"><?php echo esc_html__( 'Video Preview', 'hello-wpstream' ); ?></p> |
| 562 |
<div class="upload-container__row"> |
| 563 |
<div class="upload-container__video-wrap"> |
| 564 |
<!-- Live list plupload appends queued items into --> |
| 565 |
<div id="aaiu-upload-preview"> |
| 566 |
<ul id="aaiu-ul-list" class="aaiu-upload-list"></ul> |
| 567 |
</div> |
| 568 |
|
| 569 |
<!-- Existing preview clip plus the upload nonce field --> |
| 570 |
<div id="wpstream_previewlist"> |
| 571 |
<?php |
| 572 |
// Nonce for the preview upload AJAX handler. |
| 573 |
$ajax_nonce = wp_create_nonce( 'wpstream_preview_upload' ); |
| 574 |
print '<input type="hidden" id="wpstream_preview_upload" value="' . esc_html( $ajax_nonce ) . '" /> '; |
| 575 |
// Print the pre-rendered preview <video>, if any. |
| 576 |
if ( '' !== $video_html ) { |
| 577 |
print trim( $video_html ); //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped |
| 578 |
} |
| 579 |
?> |
| 580 |
</div> |
| 581 |
|
| 582 |
<input type="hidden" id="upload_preview" class="wpstream_upload_file" /> |
| 583 |
</div> |
| 584 |
|
| 585 |
<div class="upload-container__actions-wrap upload-container__actions-wrap--column"> |
| 586 |
<p class="full_form full_form_trailer"> |
| 587 |
<?php |
| 588 |
esc_html_e( "Upload a video preview for your content. Supported formats: MP4, MOV", 'hello-wpstream' ); |
| 589 |
?> |
| 590 |
</p> |
| 591 |
|
| 592 |
<!-- Drag-and-drop target / "Change" button for the preview --> |
| 593 |
<div id="drag-and-drop" class="rh_drag_and_drop_wrapper"> |
| 594 |
<div id="aaiu-uploader-preview" class="wpstream_theme_button_dashboard"> |
| 595 |
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> |
| 596 |
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.7379 16.6273C9.96427 16.6273 9.31895 16.036 9.2514 15.2654C9.11015 13.6541 9.07441 12.0356 9.14427 10.4203C9.05994 10.4147 8.97563 10.4088 8.89133 10.4026L7.40178 10.2941C6.44973 10.2247 5.91752 9.16309 6.43151 8.35871C7.5277 6.6432 9.53693 4.72314 11.1904 3.53541C11.6742 3.18786 12.3258 3.18786 12.8097 3.53541C14.4631 4.72314 16.4723 6.64319 17.5685 8.35871C18.0825 9.16309 17.5503 10.2247 16.5983 10.2941L15.1087 10.4026C15.0244 10.4088 14.9401 10.4147 14.8558 10.4203C14.9256 12.0356 14.8899 13.6541 14.7486 15.2654C14.6811 16.036 14.0358 16.6273 13.2622 16.6273H10.7379ZM10.6815 9.76253C10.5678 11.5498 10.589 13.3431 10.745 15.1273H13.255C13.411 13.3431 13.4323 11.5498 13.3186 9.76253C13.3058 9.56216 13.3739 9.36505 13.5077 9.21531C13.6414 9.06556 13.8296 8.9757 14.0301 8.96582C14.3535 8.94989 14.6767 8.93015 14.9997 8.90661L16.0815 8.82775C15.1219 7.41445 13.9204 6.1802 12.5313 5.18235L12 4.80071L11.4687 5.18235C10.0796 6.1802 8.87813 7.41446 7.91858 8.82775L9.00038 8.90661C9.32337 8.93015 9.64656 8.94989 9.9699 8.96582C10.1704 8.9757 10.3586 9.06556 10.4924 9.21531C10.6261 9.36505 10.6942 9.56216 10.6815 9.76253Z" fill="#0F0F0F"/> |
| 597 |
<path d="M5.75 17C5.75 16.5858 5.41421 16.25 5 16.25C4.58579 16.25 4.25 16.5858 4.25 17V19C4.25 19.9665 5.0335 20.75 6 20.75H18C18.9665 20.75 19.75 19.9665 19.75 19V17C19.75 16.5858 19.4142 16.25 19 16.25C18.5858 16.25 18.25 16.5858 18.25 17V19C18.25 19.1381 18.1381 19.25 18 19.25H6C5.86193 19.25 5.75 19.1381 5.75 19V17Z" fill="#0F0F0F"/> |
| 598 |
</svg> |
| 599 |
|
| 600 |
<?php esc_html_e( 'Change', 'hello-wpstream' ); ?> |
| 601 |
</div> |
| 602 |
</div> |
| 603 |
</div> |
| 604 |
</div> |
| 605 |
</div> |
| 606 |
</div> |
| 607 |
<?php |
| 608 |
// Capture the buffered markup and return it. |
| 609 |
$return_string .= ob_get_contents(); |
| 610 |
ob_end_clean(); |
| 611 |
|
| 612 |
return $return_string; |
| 613 |
} |
| 614 |
} |
| 615 |
|
| 616 |
if ( ! function_exists( 'wpstream_theme_build_html_gallery_dashboard' ) ) { |
| 617 |
/** |
| 618 |
* Build HTML for the gallery in the dashboard. |
| 619 |
* |
| 620 |
* This function builds HTML for the gallery in the dashboard based on the provided array of image IDs. |
| 621 |
* |
| 622 |
* @param array $gallery_images An array of image IDs. |
| 623 |
* @return string The HTML string for the gallery. |
| 624 |
*/ |
| 625 |
function wpstream_theme_build_html_gallery_dashboard( $gallery_images ) { |
| 626 |
// Accumulator for the gallery tiles markup. |
| 627 |
$return_string = ''; |
| 628 |
|
| 629 |
if ( is_array( $gallery_images ) ) { |
| 630 |
// Render one tile per image ID in the list. |
| 631 |
foreach ( $gallery_images as $attachment_id ) { |
| 632 |
// Resolve the card-sized preview for this attachment. |
| 633 |
$preview = wp_get_attachment_image_src( $attachment_id, 'wpstream_featured_unit_cards' ); |
| 634 |
|
| 635 |
// Only output tiles that have a usable preview URL. |
| 636 |
if ( $preview && '' !== $preview[0] ) { |
| 637 |
$return_string .= '<div class="wpstream_uploaded_images" data-imageid="' . esc_attr( $attachment_id ) . '">'; |
| 638 |
$return_string .= '<img src="' . esc_url( $preview[0] ) . '" alt="' . esc_html__( 'thumb', 'hello-wpstream' ) . '" /></div>'; |
| 639 |
} |
| 640 |
} |
| 641 |
} |
| 642 |
|
| 643 |
// Return the concatenated gallery markup. |
| 644 |
return $return_string; |
| 645 |
} |
| 646 |
} |
| 647 |
if ( ! function_exists( 'wpstream_return_user_can_create_paid' ) ) { |
| 648 |
/** |
| 649 |
* Whether non-admin users may create paid (WooCommerce) channels. |
| 650 |
* |
| 651 |
* Canonical default for a capability that used to exist only in the |
| 652 |
* companion theme, which silently blocked paid auto-creation on every |
| 653 |
* other theme. Overridable by defining the function in a (child) theme. |
| 654 |
* |
| 655 |
* @return bool True when paid channel creation is allowed for the user. |
| 656 |
*/ |
| 657 |
function wpstream_return_user_can_create_paid() { |
| 658 |
// The site is configured to auto-create paid channels on the go-live |
| 659 |
// surface: paid creation is explicit site policy. |
| 660 |
if ( 'paid' === get_option( 'wpstream_user_streaming_channel_type' ) ) { |
| 661 |
return true; |
| 662 |
} |
| 663 |
|
| 664 |
// Otherwise the companion theme's customizer toggle decides (its |
| 665 |
// setting is stored as a theme mod of the active theme). |
| 666 |
return (bool) get_theme_mod( 'wpstream_user_can_create_paid', false ); |
| 667 |
} |
| 668 |
} |
| 669 |
|
| 670 |
if ( ! function_exists( 'wpstream_return_max_channels_per_user' ) ) { |
| 671 |
/** |
| 672 |
* Maximum number of channels a single non-admin user may own. |
| 673 |
* |
| 674 |
* Canonical default for the companion theme's customizer setting, so the |
| 675 |
* dashboard create-channel CTA works on any theme. An unset/zero setting |
| 676 |
* means effectively unlimited (999, the companion theme's convention). |
| 677 |
* The one accessor for the cap: the Streaming Content Creation module and |
| 678 |
* the dashboard both read it, so the filter below governs both. The plugin |
| 679 |
* loads this framework on after_setup_theme before the companion theme's |
| 680 |
* copy, which is what keeps this filtered definition the one in effect. |
| 681 |
* |
| 682 |
* @param int $owner_id User whose cap is asked for; 0 means the current user. |
| 683 |
* @return int The per-user channel cap. |
| 684 |
*/ |
| 685 |
function wpstream_return_max_channels_per_user( $owner_id = 0 ) { |
| 686 |
$value = intval( get_theme_mod( 'wpstream_return_max_channels_per_user' ) ); |
| 687 |
|
| 688 |
// Zero/unset means effectively unlimited. |
| 689 |
if ( 0 === $value ) { |
| 690 |
$value = 999; |
| 691 |
} |
| 692 |
|
| 693 |
$owner_id = intval( $owner_id ) > 0 ? intval( $owner_id ) : get_current_user_id(); |
| 694 |
|
| 695 |
/** |
| 696 |
* Filters how many live channels one non-admin user may own. |
| 697 |
* |
| 698 |
* @since 4.14.0 |
| 699 |
* |
| 700 |
* @param int $max The configured cap (customizer setting, 999 when unset). |
| 701 |
* @param int $owner_id User the cap applies to. |
| 702 |
*/ |
| 703 |
return max( 0, intval( apply_filters( 'wpstream_max_channels_per_user', $value, $owner_id ) ) ); |
| 704 |
} |
| 705 |
} |
| 706 |
|