PluginProbe ʕ •ᴥ•ʔ
Music Player for WooCommerce / 1.4.0
Music Player for WooCommerce v1.4.0
1.8.3 1.8.2 1.8.1 1.1.10 1.1.11 1.1.2 1.1.3 1.1.4 1.1.5 1.1.6 1.1.7 1.1.8 1.1.9 1.2.0 1.2.1 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 1.3.0 1.3.1 1.3.10 1.3.11 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.5.0 1.5.1 1.6.0 1.6.1 1.6.2 1.6.3 1.7.0 1.7.1 1.7.2 1.7.3 1.7.4 1.7.5 1.7.6 1.7.7 1.7.8 1.7.9 1.8.0 trunk 1.0.173 1.0.174 1.0.175 1.0.176 1.0.177 1.0.178 1.0.179 1.0.180 1.0.181 1.0.182 1.0.183 1.0.184 1.0.185 1.0.186 1.0.187 1.0.188 1.0.189 1.0.190 1.0.191 1.0.192 1.0.193 1.0.194 1.0.195 1.0.196 1.0.197 1.1.0 1.1.1
music-player-for-woocommerce / wcmp.php
music-player-for-woocommerce Last commit date
addons 1 year ago css 1 year ago feedback 1 year ago js 1 year ago languages 1 year ago pagebuilders 1 year ago vendors 1 year ago views 1 year ago widgets 1 year ago banner.php 1 year ago readme.txt 1 year ago wcmp.php 1 year ago
wcmp.php
2105 lines
1 <?php
2 /*
3 Plugin Name: Music Player for WooCommerce
4 Plugin URI: https://wcmp.dwbooster.com
5 Version: 1.4.0
6 Text Domain: music-player-for-woocommerce
7 Author: CodePeople
8 Author URI: https://wcmp.dwbooster.com
9 Description: Music Player for WooCommerce includes the MediaElement.js music player in the pages of the products with audio files associated, and in the store's pages, furthermore, the plugin allows selecting between multiple skins.
10 License: GPLv2 or later
11 License URI: http://www.gnu.org/licenses/gpl-2.0.html
12 */
13
14 require_once 'banner.php';
15 $codepeople_promote_banner_plugins['codepeople-music-player-for-woocommerce'] = array(
16 'plugin_name' => 'Music Player for WooCommerce',
17 'plugin_url' => 'https://wordpress.org/support/plugin/music-player-for-woocommerce/reviews/#new-post',
18 );
19
20 add_action( 'init', function(){
21 add_filter( 'get_post_metadata', function( $v, $object_id, $meta_key, $single, $meta_type = '' ){
22 if ( '_elementor_element_cache' == $meta_key ) {
23 global $wpdb;
24 if ( $wpdb->get_var( $wpdb->prepare('SELECT COUNT(*) FROM ' . $wpdb->postmeta . ' WHERE post_id=%d AND meta_key="_elementor_element_cache" AND meta_value LIKE "%wcmp%";', $object_id ) ) ) return false;
25 }
26 return $v;
27 }, 10, 5 );
28 } );
29
30 // Feedback system
31 require_once 'feedback/cp-feedback.php';
32 new WCMP_FEEDBACK( 'music-player-for-woocommerce', __FILE__, 'https://wcmp.dwbooster.com/contact-us' );
33
34 // CONSTANTS
35
36 define( 'WCMP_WEBSITE_URL', get_home_url( get_current_blog_id(), '', is_ssl() ? 'https' : 'http' ) );
37 define( 'WCMP_PLUGIN_URL', plugins_url( '', __FILE__ ) );
38 define( 'WCMP_DEFAULT_PLAYER_LAYOUT', 'mejs-classic' );
39 define( 'WCMP_DEFAULT_SINGLE_PLAYER', 0 );
40 define( 'WCMP_DEFAULT_PLAYER_VOLUME', 1 );
41 define( 'WCMP_DEFAULT_PLAYER_CONTROLS', 'default' );
42 define( 'WCMP_DEFAULT_PlAYER_TITLE', 1 );
43 define( 'WCMP_REMOTE_TIMEOUT', 120 );
44 define( 'WCMP_VERSION', '1.4.0' );
45
46 // Load widgets
47 require_once 'widgets/playlist_widget.php';
48
49 add_filter( 'option_sbp_settings', array( 'WooCommerceMusicPlayer', 'troubleshoot' ) );
50 if ( ! class_exists( 'WooCommerceMusicPlayer' ) ) {
51 class WooCommerceMusicPlayer {
52
53 // ******************** ATTRIBUTES ************************
54
55 private $_products_attrs = array();
56 private $_global_attrs = array();
57 private $_player_layouts = array( 'mejs-classic', 'mejs-ted', 'mejs-wmp' );
58 private $_player_controls = array( 'button', 'all', 'default' );
59 private $_files_directory_path;
60 private $_files_directory_url;
61 private $_enqueued_resources = false;
62 private $_inserted_player = false;
63 private $_insert_player = true;
64
65 private $_insert_main_player = true;
66 private $_insert_all_players = true;
67
68 private $_force_hook_title = 0;
69
70 private $_current_user_downloads = array();
71
72 private $_preload_times = 0; // Multiple preloads with demo generators can affect the server performance
73
74 private $_hooks = array();
75
76 /**
77 * WCMP constructor
78 *
79 * @access public
80 * @return void
81 */
82 public function __construct() {
83
84 // Initialize $_hooks list
85 $this->_hooks = array(
86 'main_player' => array(),
87 'all_players' => array(
88 // 'woocommerce_before_single_product_summary' => 1,
89 'woocommerce_single_product_summary' => 1,
90 'woocommerce_after_single_product_summary' => 1,
91 'woocommerce_before_add_to_cart_form' => 1,
92 'woocommerce_after_add_to_cart_form' => 1,
93 )
94 );
95
96 $this->_createDir();
97 register_activation_hook( __FILE__, array( &$this, 'activation' ) );
98 register_deactivation_hook( __FILE__, array( &$this, 'deactivation' ) );
99
100 add_action( 'plugins_loaded', array( &$this, 'plugins_loaded' ) );
101 add_action( 'init', array( &$this, 'init' ) );
102 add_action( 'admin_init', array( &$this, 'admin_init' ), 99 );
103
104 // EXPORT / IMPORT PRODUCTS
105
106 add_filter( 'woocommerce_product_export_meta_value', function( $value, $meta, $product, $row ){
107 if (
108 preg_match( '/^' . preg_quote( '_wcmp_' ) . '/i', $meta->key ) &&
109 ! is_scalar( $value )
110 ) {
111 $value = serialize( $value );
112 }
113 return $value;
114 }, 10, 4 );
115
116 add_filter( 'woocommerce_product_importer_pre_expand_data', function( $data ){
117 foreach ( $data as $_key => $_value ) {
118 if (
119 preg_match( '/^' . preg_quote( 'meta:_wcmp_' ) . '/i', $_key ) &&
120 function_exists( 'is_serialized' ) &&
121 is_serialized( $_value )
122 ) {
123 try {
124 $data[ $_key ] = unserialize( $_value );
125 } catch ( Exception $err ) {
126 $data[ $_key ] = $_value;
127 } catch ( Error $err ) {
128 $data[ $_key ] = $_value;
129 }
130 }
131 }
132 return $data;
133 }, 10 );
134
135 /** WooCommerce Product Table by Barn2 Plugins integration **/
136 add_filter( 'wc_product_table_data_name', function( $title, $product ) {
137 return ( false === stripos( $title, '<audio' ) ? $this->include_main_player( $product, false ) : '' ) . $title;
138 }, 10, 2 );
139
140 add_action( 'wc_product_table_before_get_data', function( $table ) {
141 $GLOBALS['_insert_all_players_BK'] = $this->_insert_all_players;
142 $this->_insert_all_players = false;
143 }, 10 );
144
145 add_action( 'wc_product_table_after_get_data', function( $table ) {
146 if ( isset( $GLOBALS['_insert_all_players_BK'] ) ) {
147 $this->_insert_all_players = $GLOBALS['_insert_all_players_BK'];
148 unset( $GLOBALS['_insert_all_players_BK'] );
149 } else {
150 $this->_insert_all_players = true;
151 }
152 }, 10 );
153
154 add_filter( 'pre_do_shortcode_tag', function( $output, $tag, $attr, $m ){
155 if( strtolower( $tag ) == 'product_table' ) {
156 $this->enqueue_resources();
157 }
158 return $output;
159 }, 10, 4 );
160
161 /** ListeSpeed Cache integration **/
162 add_filter( 'litespeed_optimize_js_excludes', function( $p ){
163 $p[] = 'jquery.js';
164 $p[] = 'jquery.min.js';
165 $p[] = '/mediaelement/';
166 $p[] = plugin_dir_url( __FILE__ ) . 'js/public.js';
167 return $p;
168 } );
169 add_filter( 'litespeed_optm_js_defer_exc', function( $p ){
170 $p[] = 'jquery.js';
171 $p[] = 'jquery.min.js';
172 $p[] = '/mediaelement/';
173 $p[] = plugin_dir_url( __FILE__ ) . 'js/public.js';
174 return $p;
175 } );
176
177 } // End __constructor
178
179 public function activation() {
180 $this->_clearDir( $this->_files_directory_path );
181 $this->_createDir();
182 }
183
184 public function deactivation() {
185 $this->_clearDir( $this->_files_directory_path );
186 }
187
188 public function plugins_loaded() {
189 if ( ! class_exists( 'woocommerce' ) ) {
190 return;
191 }
192
193 add_action( 'init', function() {
194 load_plugin_textdomain( 'music-player-for-woocommerce', false, basename( dirname( __FILE__ ) ) . '/languages/' );
195 });
196
197 add_filter( 'the_title', array( &$this, 'include_main_player_filter' ), 11, 2 );
198 $this->init_force_in_title();
199 $this->_load_addons();
200
201 // Integration with the content editors
202 require_once dirname( __FILE__ ) . '/pagebuilders/builders.php';
203 WCMP_BUILDERS::run();
204 }
205
206 public function get_product_attr( $product_id, $attr, $default = false ) {
207 if ( ! isset( $this->_products_attrs[ $product_id ] ) ) {
208 $this->_products_attrs[ $product_id ] = array();
209 }
210 if ( ! isset( $this->_products_attrs[ $product_id ][ $attr ] ) ) {
211 if ( metadata_exists( 'post', $product_id, $attr ) ) {
212 $this->_products_attrs[ $product_id ][ $attr ] = get_post_meta( $product_id, $attr, true );
213 } else {
214 $this->_products_attrs[ $product_id ][ $attr ] = $this->get_global_attr( $attr, $default );
215 }
216 }
217 return apply_filters( 'wcmp_product_attr', $this->_products_attrs[ $product_id ][ $attr ], $product_id, $attr );
218
219 } // End get_product_attr
220
221 public function get_global_attr( $attr, $default = false ) {
222 if ( empty( $this->_global_attrs ) ) {
223 $this->_global_attrs = get_option( 'wcmp_global_settings', array() );
224 }
225 if ( ! isset( $this->_global_attrs[ $attr ] ) ) {
226 $this->_global_attrs[ $attr ] = $default;
227 }
228 return apply_filters( 'wcmp_global_attr', $this->_global_attrs[ $attr ], $attr );
229
230 } // End get_global_attr
231
232 // ******************** WordPress ACTIONS **************************
233
234 public function init() {
235 // Check if WooCommerce is installed or not
236 if ( ! class_exists( 'woocommerce' ) ) {
237 add_shortcode(
238 'wcmp-playlist',
239 function( $atts ) {
240 return '';
241 }
242 );
243 return; }
244 $_current_user_id = get_current_user_id();
245 if (
246 $this->get_global_attr( '_wcmp_registered_only', 0 ) &&
247 0 == $_current_user_id
248 ) {
249 $this->_insert_player = false;
250 }
251
252 if ( ! is_admin() ) {
253 add_filter( 'wcmp_preload', array( $this, 'preload' ), 10, 2 );
254
255 // Define the shortcode for the playlist_widget
256 add_shortcode( 'wcmp-playlist', array( &$this, 'replace_playlist_shortcode' ) );
257 $this->_preview();
258 if ( isset( $_REQUEST['wcmp-action'] ) && 'play' == $_REQUEST['wcmp-action'] ) {
259 if ( isset( $_REQUEST['wcmp-product'] ) ) {
260 $product_id = @intval( $_REQUEST['wcmp-product'] );
261 if ( ! empty( $product_id ) ) {
262 $product = wc_get_product( $product_id );
263 if ( false !== $product ){
264 $this->update_playback_counter( $product_id );
265 if ( isset( $_REQUEST['wcmp-file'] ) ) {
266 $files = $this->_get_product_files(
267 array(
268 'product' => $product,
269 'file_id' => sanitize_key( $_REQUEST['wcmp-file'] ),
270 )
271 );
272
273 if ( ! empty( $files ) ) {
274 $file_url = $files[ sanitize_key( $_REQUEST['wcmp-file'] ) ]['file'];
275 $this->_tracking_play_event( $product_id, $file_url );
276 $this->_output_file( array( 'url' => $file_url ) );
277 }
278 }
279 }
280 }
281 }
282 exit;
283 } else {
284 // To allow customize the hooks
285 $include_main_player_hook = preg_replace( '/[\t\s]/', '', $this->get_global_attr( '_wcmp_main_player_hook', '' ) );
286 $include_all_players_hook = preg_replace( '/[\t\s]/', '', $this->get_global_attr( '_wcmp_all_players_hook', '' ) );
287
288 if ( empty( $include_main_player_hook ) ) {
289 $include_main_player_hook = 'woocommerce_shop_loop_item_title';
290 }
291
292 if ( empty( $include_all_players_hook ) ) {
293 foreach ( $this->_hooks['all_players'] as $_hook_name => $_hook_data ) {
294 add_action( $_hook_name, array( $this, 'include_players' ), 10, $_hook_data );
295 }
296 } else {
297 $include_all_players_hook = explode( ',', $include_all_players_hook );
298 foreach ( $include_all_players_hook as $_hook_name ) {
299 if ( ! empty( $_hook_name ) ) {
300 add_action( $_hook_name, array( &$this, 'include_all_players' ), 11 );
301 }
302 }
303 }
304
305 if ( 0 == $this->_force_hook_title ) {
306 $include_main_player_hook = explode( ',', $include_main_player_hook );
307 foreach ( $include_main_player_hook as $_hook_name ) {
308 if ( ! empty( $_hook_name ) ) {
309 add_action( $_hook_name, array( &$this, 'include_main_player' ), 11 );
310 }
311 }
312 }
313
314 // Allows to call the players directly by themes
315 add_action( 'wcmp_main_player', array( &$this, 'include_main_player' ), 11 );
316 add_action( 'wcmp_all_players', array( &$this, 'include_all_players' ), 11 );
317
318 // Integration with woocommerce-product-table by barn2media
319 add_filter( 'wc_product_table_data_name', array( &$this, 'product_table_data_name' ), 11, 2 );
320
321 $players_in_cart = $this->get_global_attr( '_wcmp_players_in_cart', false );
322 if ( $players_in_cart ) {
323 add_action( 'woocommerce_after_cart_item_name', array( &$this, 'player_in_cart' ), 11, 2 );
324 }
325
326 // Add product id to audio tag
327 add_filter( 'wcmp_audio_tag', array( &$this, 'add_data_product' ), 99, 4 );
328
329 // Add class name to the feature image of product
330 add_filter( 'woocommerce_product_get_image', array( &$this, 'add_class_attachment' ), 99, 6 );
331 add_filter( 'woocommerce_single_product_image_thumbnail_html', array( &$this, 'add_class_single_product_image' ), 99, 2 );
332
333 // Include players with the titles
334 if (
335 $this->get_global_attr( '_wcmp_force_main_player_in_title', 1 ) &&
336 ! empty( $_SERVER['REQUEST_URI'] )
337 /*
338 ! empty( $_SERVER['REQUEST_URI'] ) &&
339 stripos( esc_url_raw( wp_unslash( $_SERVER['REQUEST_URI'] ) ), 'wc/store' ) !== false */
340 ) {
341 add_filter( 'woocommerce_product_title', array( &$this, 'woocommerce_product_title' ), 10, 2 );
342
343 add_filter( 'esc_html', array( &$this, 'esc_html' ), 10, 2 );
344 }
345
346 // For accepting the <source> tags
347 add_filter( 'wp_kses_allowed_html', array( &$this, 'allowed_html_tags' ), 10, 2 );
348 }
349 } else {
350 add_action( 'admin_menu', array( &$this, 'menu_links' ), 10 );
351 }
352
353 } // End init
354
355 public function admin_init() {
356 // Check if WooCommerce is installed or not
357 if ( ! class_exists( 'woocommerce' ) ) {
358 return;
359 }
360
361 $this->clear_expired_transients();
362
363 add_meta_box( 'wcmp_woocommerce_metabox', __( 'Music Player for WooCommerce', 'music-player-for-woocommerce' ), array( &$this, 'woocommerce_player_settings' ), $this->_get_post_types(), 'normal' );
364 add_action( 'save_post', array( &$this, 'save_post' ), 10, 3 );
365 add_action( 'delete_post', array( &$this, 'delete_post' ) );
366 add_filter( 'plugin_action_links_' . plugin_basename( __FILE__ ), array( &$this, 'help_link' ) );
367
368 // Products list "Playback Counter"
369
370 $manage_product_posts_columns = function( $columns ) {
371 if ( $this->get_global_attr( '_wcmp_playback_counter_column', 1 ) ) {
372 wp_enqueue_style( 'wcmp-Playback-counter', plugin_dir_url( __FILE__ ) . 'css/style.admin.css', array(), '1.0.175' );
373 $columns = array_merge( $columns, [ 'wcmp_playback_counter' => __( 'Playback Counter', 'music-player-for-woocommerce' ) ] );
374 }
375 return $columns;
376 };
377 add_filter( 'manage_product_posts_columns', $manage_product_posts_columns );
378
379 $manage_product_posts_custom_column = function( $column_key, $product_id ) {
380 if (
381 $this->get_global_attr( '_wcmp_playback_counter_column', 1 ) &&
382 'wcmp_playback_counter' == $column_key
383 ) {
384 $counter = get_post_meta( $product_id, '_wcmp_playback_counter', true);
385 echo '<span class="wcmp-playback-counter">' . esc_html( ! empty( $counter ) ? $counter : '' ) . '</span>';
386 }
387 };
388 add_action( 'manage_product_posts_custom_column', $manage_product_posts_custom_column, 10, 2 );
389 } // End admin_init
390
391 public function help_link( $links ) {
392 array_unshift(
393 $links,
394 '<a href="https://wordpress.org/support/plugin/music-player-for-woocommerce/#new-post" target="_blank">' . __( 'Help' ) . '</a>'
395 );
396 return $links;
397 } // End help_link
398
399 public function menu_links() {
400 add_options_page( 'Music Player for WooCommerce', 'Music Player for WooCommerce', 'manage_options', 'music-player-for-woocommerce-settings', array( &$this, 'settings_page' ) );
401 } // End menu_links
402
403 public function settings_page() {
404 if (
405 isset( $_POST['wcmp_nonce'] ) &&
406 wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['wcmp_nonce'] ) ), 'wcmp_updating_plugin_settings' )
407 ) {
408 $_REQUEST = stripslashes_deep( $_REQUEST );
409 // Save the player settings
410 $registered_only = ( isset( $_REQUEST['_wcmp_registered_only'] ) ) ? 1 : 0;
411 $fade_out = ( isset( $_REQUEST['_wcmp_fade_out'] ) ) ? 1 : 0;
412 $purchased_times_text = sanitize_text_field( isset( $_REQUEST['_wcmp_purchased_times_text'] ) ? wp_unslash( $_REQUEST['_wcmp_purchased_times_text'] ) : '' );
413 $troubleshoot_default_extension = ( isset( $_REQUEST['_wcmp_default_extension'] ) ) ? true : false;
414 $force_main_player_in_title = ( isset( $_REQUEST['_wcmp_force_main_player_in_title'] ) ) ? 1 : 0;
415 $ios_controls = ( isset( $_REQUEST['_wcmp_ios_controls'] ) ) ? true : false;
416 $troubleshoot_onload = ( isset( $_REQUEST['_wcmp_onload'] ) ) ? true : false;
417 $include_main_player_hook = ( isset( $_REQUEST['_wcmp_main_player_hook'] ) ) ? sanitize_text_field( wp_unslash( $_REQUEST['_wcmp_main_player_hook'] ) ) : '';
418 $main_player_hook_title = ( isset( $_REQUEST['_wcmp_main_player_hook_title'] ) ) ? 1 : 0;
419 $disable_302 = ( isset( $_REQUEST['_wcmp_disable_302'] ) ) ? 1 : 0;
420 $include_all_players_hook = ( isset( $_REQUEST['_wcmp_all_players_hook'] ) ) ? sanitize_text_field( wp_unslash( $_REQUEST['_wcmp_all_players_hook'] ) ) : '';
421
422 $enable_player = ( isset( $_REQUEST['_wcmp_enable_player'] ) ) ? 1 : 0;
423 $show_in = ( isset( $_REQUEST['_wcmp_show_in'] ) && in_array( $_REQUEST['_wcmp_show_in'], array( 'single', 'multiple' ) ) ) ? sanitize_text_field( wp_unslash( $_REQUEST['_wcmp_show_in'] ) ) : 'all';
424 $players_in_cart = ( isset( $_REQUEST['_wcmp_players_in_cart'] ) ) ? true : false;
425 $player_style = (
426 isset( $_REQUEST['_wcmp_player_layout'] ) &&
427 in_array( $_REQUEST['_wcmp_player_layout'], $this->_player_layouts )
428 ) ? sanitize_text_field( wp_unslash( $_REQUEST['_wcmp_player_layout'] ) ) : WCMP_DEFAULT_PLAYER_LAYOUT;
429 $single_player = ( isset( $_REQUEST['_wcmp_single_player'] ) ) ? 1 : 0;
430 $player_controls = (
431 isset( $_REQUEST['_wcmp_player_controls'] ) &&
432 in_array( $_REQUEST['_wcmp_player_controls'], $this->_player_controls )
433 ) ? sanitize_text_field( wp_unslash( $_REQUEST['_wcmp_player_controls'] ) ) : WCMP_DEFAULT_PLAYER_CONTROLS;
434
435 $on_cover = ( ( 'button' == $player_controls || 'default' == $player_controls ) && isset( $_REQUEST['_wcmp_player_on_cover'] ) ) ? 1 : 0;
436
437 $player_title = ( isset( $_REQUEST['_wcmp_player_title'] ) ) ? 1 : 0;
438 $merge_grouped = ( isset( $_REQUEST['_wcmp_merge_in_grouped'] ) ) ? 1 : 0;
439 $play_all = ( isset( $_REQUEST['_wcmp_play_all'] ) ) ? 1 : 0;
440 $loop = ( isset( $_REQUEST['_wcmp_loop'] ) ) ? 1 : 0;
441 $play_simultaneously = ( isset( $_REQUEST['_wcmp_play_simultaneously'] ) ) ? 1 : 0;
442 $volume = ( isset( $_REQUEST['_wcmp_player_volume'] ) && is_numeric( $_REQUEST['_wcmp_player_volume'] ) ) ? floatval( $_REQUEST['_wcmp_player_volume'] ) : 1;
443 $preload = (
444 isset( $_REQUEST['_wcmp_preload'] ) &&
445 in_array( $_REQUEST['_wcmp_preload'], array( 'none', 'metadata', 'auto' ) )
446 ) ? sanitize_text_field( wp_unslash( $_REQUEST['_wcmp_preload'] ) ) : 'none';
447
448 $apply_to_all_players = ( isset( $_REQUEST['_wcmp_apply_to_all_players'] ) ) ? 1 : 0;
449
450 $global_settings = array(
451 '_wcmp_registered_only' => $registered_only,
452 '_wcmp_fade_out' => $fade_out,
453 '_wcmp_purchased_times_text' => $purchased_times_text,
454 '_wcmp_enable_player' => $enable_player,
455 '_wcmp_show_in' => $show_in,
456 '_wcmp_players_in_cart' => $players_in_cart,
457 '_wcmp_player_layout' => $player_style,
458 '_wcmp_player_volume' => $volume,
459 '_wcmp_single_player' => $single_player,
460 '_wcmp_player_controls' => $player_controls,
461 '_wcmp_player_title' => $player_title,
462 '_wcmp_merge_in_grouped' => $merge_grouped,
463 '_wcmp_play_all' => $play_all,
464 '_wcmp_loop' => $loop,
465 '_wcmp_play_simultaneously' => $play_simultaneously,
466 '_wcmp_preload' => $preload,
467 '_wcmp_on_cover' => $on_cover,
468 '_wcmp_default_extension' => $troubleshoot_default_extension,
469 '_wcmp_force_main_player_in_title' => $force_main_player_in_title,
470 '_wcmp_ios_controls' => $ios_controls,
471 '_wcmp_onload' => $troubleshoot_onload,
472 '_wcmp_main_player_hook' => $include_main_player_hook,
473 '_wcmp_main_player_hook_title' => $main_player_hook_title,
474 '_wcmp_disable_302' => $disable_302,
475 '_wcmp_all_players_hook' => $include_all_players_hook,
476 '_wcmp_playback_counter_column' => ( isset( $_REQUEST['_wcmp_playback_counter_column'] ) ) ? sanitize_text_field( wp_unslash( $_REQUEST['_wcmp_playback_counter_column'] ) ) : 0,
477 '_wcmp_analytics_integration' => ( isset( $_REQUEST['_wcmp_analytics_integration'] ) ) ? sanitize_text_field( wp_unslash( $_REQUEST['_wcmp_analytics_integration'] ) ) : 'ua',
478 '_wcmp_analytics_property' => ( isset( $_REQUEST['_wcmp_analytics_property'] ) ) ? sanitize_text_field( wp_unslash( $_REQUEST['_wcmp_analytics_property'] ) ) : '',
479 '_wcmp_analytics_api_secret' => ( isset( $_REQUEST['_wcmp_analytics_api_secret'] ) ) ? sanitize_text_field( wp_unslash( $_REQUEST['_wcmp_analytics_api_secret'] ) ) : '',
480 '_wcmp_apply_to_all_players' => $apply_to_all_players,
481 );
482
483 if ( $apply_to_all_players ) {
484 $this->_clearDir( $this->_files_directory_path );
485
486 $products_ids = array(
487 'post_type' => $this->_get_post_types(),
488 'numberposts' => -1,
489 'post_status' => array( 'publish', 'pending', 'draft', 'future' ),
490 'fields' => 'ids',
491 'cache_results' => false,
492 );
493
494 $products = get_posts( $products_ids );
495 foreach ( $products as $product_id ) {
496 update_post_meta( $product_id, '_wcmp_enable_player', $enable_player );
497 update_post_meta( $product_id, '_wcmp_show_in', $show_in );
498 update_post_meta( $product_id, '_wcmp_player_layout', $player_style );
499 update_post_meta( $product_id, '_wcmp_single_player', $single_player );
500 update_post_meta( $product_id, '_wcmp_player_controls', $player_controls );
501 update_post_meta( $product_id, '_wcmp_player_volume', $volume );
502 update_post_meta( $product_id, '_wcmp_player_title', $player_title );
503 update_post_meta( $product_id, '_wcmp_merge_in_grouped', $merge_grouped );
504 update_post_meta( $product_id, '_wcmp_play_all', $play_all );
505 update_post_meta( $product_id, '_wcmp_loop', $loop );
506 update_post_meta( $product_id, '_wcmp_preload', $preload );
507 update_post_meta( $product_id, '_wcmp_on_cover', $on_cover );
508 }
509 }
510
511 update_option( 'wcmp_global_settings', $global_settings );
512 $this->_global_attrs = $global_settings;
513 do_action( 'wcmp_save_setting' );
514
515 /** Purge LiteSpeed Cache **/
516 if (class_exists('\LiteSpeed\Purge')) {
517 \LiteSpeed\Purge::purge_all();
518 }
519 } // Save settings
520
521 print '<div class="wrap">'; // Open Wrap
522 include_once dirname( __FILE__ ) . '/views/global_options.php';
523 print '</div>'; // Close Wrap
524 } // End settings_page
525
526 public function save_post( $post_id, $post, $update ) {
527 if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
528 return;
529 }
530 if ( empty( $_POST['wcmp_nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['wcmp_nonce'] ) ), 'wcmp_updating_product' ) ) {
531 return;
532 }
533 $post_types = $this->_get_post_types();
534 if ( ! isset( $post ) || ! in_array( $post->post_type, $post_types ) || ! current_user_can( 'edit_post', $post_id ) ) {
535 return;
536 }
537
538 $this->delete_post( $post_id );
539
540 // Save the player options
541 $enable_player = ( isset( $_REQUEST['_wcmp_enable_player'] ) ) ? 1 : 0;
542 $show_in = ( isset( $_REQUEST['_wcmp_show_in'] ) && in_array( $_REQUEST['_wcmp_show_in'], array( 'single', 'multiple' ) ) ) ? sanitize_text_field( wp_unslash( $_REQUEST['_wcmp_show_in'] ) ) : 'all';
543 $player_style = (
544 isset( $_REQUEST['_wcmp_player_layout'] ) &&
545 in_array( $_REQUEST['_wcmp_player_layout'], $this->_player_layouts )
546 ) ? sanitize_text_field( wp_unslash( $_REQUEST['_wcmp_player_layout'] ) ) : WCMP_DEFAULT_PLAYER_LAYOUT;
547
548 $single_player = ( isset( $_DATA['_wcmp_single_player'] ) ) ? 1 : 0;
549 $player_controls = (
550 isset( $_REQUEST['_wcmp_player_controls'] ) &&
551 in_array( $_REQUEST['_wcmp_player_controls'], $this->_player_controls )
552 ) ? sanitize_text_field( wp_unslash( $_REQUEST['_wcmp_player_controls'] ) ) : WCMP_DEFAULT_PLAYER_CONTROLS;
553
554 $player_title = ( isset( $_REQUEST['_wcmp_player_title'] ) ) ? 1 : 0;
555 $merge_grouped = ( isset( $_REQUEST['_wcmp_merge_in_grouped'] ) ) ? 1 : 0;
556 $play_all = ( isset( $_REQUEST['_wcmp_play_all'] ) ) ? 1 : 0;
557 $loop = ( isset( $_REQUEST['_wcmp_loop'] ) ) ? 1 : 0;
558 $volume = ( isset( $_REQUEST['_wcmp_player_volume'] ) && is_numeric( $_REQUEST['_wcmp_player_volume'] ) ) ? floatval( $_REQUEST['_wcmp_player_volume'] ) : 1;
559 $preload = (
560 isset( $_REQUEST['_wcmp_preload'] ) &&
561 in_array( $_REQUEST['_wcmp_preload'], array( 'none', 'metadata', 'auto' ) )
562 ) ? sanitize_text_field( wp_unslash( $_REQUEST['_wcmp_preload'] ) ) : 'none';
563
564 $on_cover = ( ( 'button' == $player_controls || 'default' == $player_controls ) && isset( $_REQUEST['_wcmp_player_on_cover'] ) ) ? 1 : 0;
565
566 add_post_meta( $post_id, '_wcmp_enable_player', $enable_player, true );
567 add_post_meta( $post_id, '_wcmp_show_in', $show_in, true );
568 add_post_meta( $post_id, '_wcmp_player_layout', $player_style, true );
569 add_post_meta( $post_id, '_wcmp_player_volume', $volume, true );
570 add_post_meta( $post_id, '_wcmp_single_player', $single_player, true );
571 add_post_meta( $post_id, '_wcmp_player_controls', $player_controls, true );
572 add_post_meta( $post_id, '_wcmp_player_title', $player_title, true );
573 add_post_meta( $post_id, '_wcmp_merge_in_grouped', $merge_grouped, true );
574 add_post_meta( $post_id, '_wcmp_preload', $preload, true );
575 add_post_meta( $post_id, '_wcmp_play_all', $play_all, true );
576 add_post_meta( $post_id, '_wcmp_loop', $loop, true );
577 add_post_meta( $post_id, '_wcmp_on_cover', $on_cover, true );
578 } // End save_post
579
580 public function delete_post( $post_id ) {
581 $post = get_post( $post_id );
582 $post_types = $this->_get_post_types();
583 if ( ! isset( $post ) || ! in_array( $post->post_type, $post_types ) || ! current_user_can( 'edit_post', $post_id ) ) {
584 return;
585 }
586
587 // Delete truncated version of the audio file
588 $this->_delete_truncated_files( $post_id );
589
590 delete_post_meta( $post_id, '_wcmp_enable_player' );
591 delete_post_meta( $post_id, '_wcmp_show_in' );
592 delete_post_meta( $post_id, '_wcmp_merge_in_grouped' );
593 delete_post_meta( $post_id, '_wcmp_player_layout' );
594 delete_post_meta( $post_id, '_wcmp_player_volume' );
595 delete_post_meta( $post_id, '_wcmp_single_player' );
596 delete_post_meta( $post_id, '_wcmp_player_controls' );
597 delete_post_meta( $post_id, '_wcmp_player_title' );
598 delete_post_meta( $post_id, '_wcmp_preload' );
599 delete_post_meta( $post_id, '_wcmp_play_all' );
600 delete_post_meta( $post_id, '_wcmp_loop' );
601 delete_post_meta( $post_id, '_wcmp_on_cover' );
602
603 delete_post_meta( $post_id, '_wcmp_playback_counter' );
604 } // End delete_post
605
606 public function esc_html( $safe_text, $text ) {
607 if ( strpos( $safe_text, 'wcmp-player-container' ) !== false ) {
608 return $text;
609 }
610 return $safe_text;
611 } // End esc_html
612
613 public function enqueue_resources() {
614 if ( $this->_enqueued_resources ) {
615 return;
616 }
617 $this->_enqueued_resources = true;
618
619 if ( function_exists( 'wp_add_inline_script' ) ) {
620 wp_add_inline_script( 'wp-mediaelement', 'try{if(mejs && mejs.i18n && "undefined" == typeof mejs.i18n.locale) mejs.i18n.locale={};}catch(mejs_err){if(console) console.log(mejs_err);};' );
621 }
622
623 // Registering resources
624 wp_enqueue_style( 'wp-mediaelement' );
625 wp_enqueue_style( 'wp-mediaelement-skins', plugin_dir_url( __FILE__ ) . 'vendors/mejs-skins/mejs-skins.min.css', array(), WCMP_VERSION );
626 wp_enqueue_style( 'wcmp-style', plugin_dir_url( __FILE__ ) . 'css/style.css', array(), WCMP_VERSION );
627 wp_enqueue_script( 'jquery' );
628 wp_enqueue_script( 'wp-mediaelement' );
629 wp_enqueue_script( 'wcmp-script', plugin_dir_url( __FILE__ ) . 'js/public.js', array( 'jquery', 'wp-mediaelement' ), WCMP_VERSION );
630
631 $play_all = $GLOBALS['WooCommerceMusicPlayer']->get_global_attr(
632 '_wcmp_play_all',
633 // This option is only for compatibility with versions previous to 1.0.28
634 $GLOBALS['WooCommerceMusicPlayer']->get_global_attr( 'play_all', 0 )
635 );
636
637 $play_simultaneously = $GLOBALS['WooCommerceMusicPlayer']->get_global_attr( '_wcmp_play_simultaneously', 0 );
638
639 if ( function_exists( 'is_product' ) && is_product() ) {
640 global $post;
641 $post_types = $this->_get_post_types();
642 if ( ! empty( $post ) && in_array( $post->post_type, $post_types ) ) {
643 $play_all = $GLOBALS['WooCommerceMusicPlayer']->get_product_attr(
644 $post->ID,
645 '_wcmp_play_all',
646 // This option is only for compatibility with versions previous to 1.0.28
647 $GLOBALS['WooCommerceMusicPlayer']->get_product_attr(
648 $post->ID,
649 'play_all',
650 $play_all
651 )
652 );
653 }
654 }
655
656 wp_localize_script(
657 'wcmp-script',
658 'wcmp_global_settings',
659 array(
660 'fade_out' => $GLOBALS['WooCommerceMusicPlayer']->get_global_attr( '_wcmp_fade_out', 1 ),
661 'play_all' => intval( $play_all ),
662 'play_simultaneously' => intval( $play_simultaneously ),
663 'ios_controls' => $GLOBALS['WooCommerceMusicPlayer']->get_global_attr( '_wcmp_ios_controls', false ),
664 'onload' => $GLOBALS['WooCommerceMusicPlayer']->get_global_attr( '_wcmp_onload', false ),
665 )
666 );
667 } // End enqueue_resources
668
669 /**
670 * Replace the shortcode to display a playlist with all songs.
671 */
672 public function replace_playlist_shortcode( $atts ) {
673 if ( ! class_exists( 'woocommerce' ) || is_admin() ) {
674 return '';
675 }
676
677 $get_times = function( $product_id, $products_list ) {
678 if ( ! empty( $products_list ) ) {
679 foreach ( $products_list as $product ) {
680 if ( $product->product_id == $product_id ) {
681 return $product->times;
682 }
683 }
684 }
685 return 0;
686 };
687
688 global $post;
689
690 $output = '';
691 if ( ! $this->_insert_player ) {
692 return $output;
693 }
694
695 if ( ! is_array( $atts ) ) {
696 $atts = array();
697 }
698 $post_types = $this->_get_post_types();
699 if (
700 empty( $atts['products_ids'] ) &&
701 empty( $atts['purchased_products'] ) &&
702 empty( $atts['product_categories'] ) &&
703 empty( $atts['product_tags'] ) &&
704 ! empty( $post ) &&
705 in_array( $post->post_type, $post_types )
706 ) {
707 try {
708 ob_start();
709 $this->include_all_players( $post->ID );
710 $output = ob_get_contents();
711 ob_end_clean();
712
713 $class = esc_attr( isset( $atts['class'] ) ? $atts['class'] : '' );
714
715 return strpos( $output, 'wcmp-player-list' ) !== false ?
716 str_replace( 'wcmp-player-list', $class . ' wcmp-player-list', $output ) :
717 str_replace( 'wcmp-player-container', $class . ' wcmp-player-container', $output );
718 } catch ( Exception $err ) {
719 $atts['products_ids'] = $post->ID;
720 }
721 }
722
723 $atts = shortcode_atts(
724 array(
725 'products_ids' => '*',
726 'purchased_products' => 0,
727 'highlight_current_product' => 0,
728 'continue_playing' => 0,
729 'player_style' => WCMP_DEFAULT_PLAYER_LAYOUT,
730 'controls' => 'track',
731 'layout' => 'new',
732 'cover' => 0,
733 'volume' => 1,
734 'hide_purchase_buttons' => 0,
735 'class' => '',
736 'loop' => 0,
737 'purchased_times' => 0,
738 'download_links' => 0,
739 'duration' => 1,
740 'product_categories' => '',
741 'product_tags' => '',
742 ),
743 $atts
744 );
745
746 $products_ids = $atts['products_ids'];
747 $product_categories = $atts['product_categories'];
748 $product_tags = $atts['product_tags'];
749 $purchased_products = $atts['purchased_products'];
750 $highlight_current_product = $atts['highlight_current_product'];
751 $continue_playing = $atts['continue_playing'];
752 $player_style = $atts['player_style'];
753 $controls = $atts['controls'];
754 $layout = $atts['layout'];
755 $cover = $atts['cover'];
756 $volume = $atts['volume'];
757 $hide_purchase_buttons = $atts['hide_purchase_buttons'];
758 $class = $atts['class'];
759 $loop = $atts['loop'];
760 $purchased_times = $atts['purchased_times'];
761 $download_links_flag = $atts['download_links'];
762
763 // Typecasting variables.
764 $cover = is_numeric( $cover ) ? intval( $cover ) : 0;
765 $volume = is_numeric( $volume ) ? floatval( $volume ) : 0;
766 $purchased_products = is_numeric( $purchased_products ) ? intval( $purchased_products ) : 0;
767 $highlight_current_product = is_numeric( $highlight_current_product ) ? intval( $highlight_current_product ) : 0;
768 $continue_playing = is_numeric( $continue_playing ) ? intval( $continue_playing ) : 0;
769 $hide_purchase_buttons = is_numeric( $hide_purchase_buttons ) ? intval( $hide_purchase_buttons ) : 0;
770 $loop = is_numeric( $loop ) ? intval( $loop ) : 0;
771 $purchased_times = is_numeric( $purchased_times ) ? intval( $purchased_times ) : 0;
772
773 // get the produts ids
774 $products_ids = preg_replace( '/[^\d\,\*]/', '', $products_ids );
775 $products_ids = preg_replace( '/\,+/', ',', $products_ids );
776 $products_ids = trim( $products_ids, ',' );
777
778 // get the produt categories
779 $product_categories = preg_replace( '/\s*\,\s*/', ',', $product_categories );
780 $product_categories = preg_replace( '/\,+/', ',', $product_categories );
781 $product_categories = trim( $product_categories, ',' );
782
783 // get the produt tags
784 $product_tags = preg_replace( '/\s*\,\s*/', ',', $product_tags );
785 $product_tags = preg_replace( '/\,+/', ',', $product_tags );
786 $product_tags = trim( $product_tags, ',' );
787
788 if (
789 strlen( $products_ids ) == 0 &&
790 strlen( $product_categories ) == 0 &&
791 strlen( $product_tags ) == 0
792 ) {
793 return $output;
794 }
795
796 // MAIN CODE GOES HERE
797 global $wpdb, $post;
798
799 $current_post_id = ! empty( $post ) ? ( is_int( $post ) ? $post : $post->ID ) : -1;
800
801 $query = 'SELECT posts.ID, posts.post_title FROM ' . $wpdb->posts . ' AS posts, ' . $wpdb->postmeta . ' as postmeta WHERE posts.post_status="publish" AND posts.post_type IN (' . $this->_get_post_types( true ) . ') AND posts.ID = postmeta.post_id AND postmeta.meta_key="_wcmp_enable_player" AND (postmeta.meta_value="yes" OR postmeta.meta_value="1")';
802
803 if ( ! empty( $purchased_products ) ) {
804 // Hide the purchase buttons
805 $hide_purchase_buttons = 1;
806
807 // Getting the list of purchased products
808 $_current_user_id = get_current_user_id();
809 if ( 0 == $_current_user_id ) {
810 return $output;
811 }
812
813 // GET USER ORDERS (COMPLETED + PROCESSING)
814 $customer_orders = get_posts(
815 array(
816 'numberposts' => -1,
817 'meta_key' => '_customer_user',
818 'meta_value' => $_current_user_id,
819 'post_type' => wc_get_order_types(),
820 'post_status' => array_keys( wc_get_is_paid_statuses() ),
821 )
822 );
823
824 if ( empty( $customer_orders ) ) {
825 return $output;
826 }
827
828 // LOOP THROUGH ORDERS AND GET PRODUCT IDS
829 $products_ids = array();
830
831 foreach ( $customer_orders as $customer_order ) {
832 $order = wc_get_order( $customer_order->ID );
833 $items = $order->get_items();
834 foreach ( $items as $item ) {
835 $product_id = $item->get_product_id();
836 $products_ids[] = $product_id;
837 }
838 }
839 $products_ids = array_unique( $products_ids );
840 $products_ids_str = implode( ',', $products_ids );
841
842 $query .= ' AND posts.ID IN (' . $products_ids_str . ')';
843 $query .= ' ORDER BY FIELD(posts.ID,' . $products_ids_str . ')';
844 } else {
845 if ( strpos( '*', $products_ids ) === false ) {
846 $query .= ' AND posts.ID IN (' . $products_ids . ')';
847 $query .= ' ORDER BY FIELD(posts.ID,' . $products_ids . ')';
848 } else {
849
850 $tax_query = [];
851
852 // Product categories
853 if ( '' != $product_categories ) {
854 $product_cat_slugs = explode( ',', $product_categories );
855
856 $tax_query = [
857 'taxonomy' => 'product_cat',
858 'field' => 'slug',
859 'terms' => $product_cat_slugs,
860 'operator' => 'IN',
861 ];
862 }
863
864 // Product tags
865 if ( '' != $product_tags ) {
866 $product_tags_slugs = explode( ',', $product_tags );
867
868 if ( empty( $tax_query ) ) {
869 $tax_query = [
870 'taxonomy' => 'product_cat',
871 'field' => 'slug',
872 'terms' => $product_cat_slugs,
873 'operator' => 'IN',
874 ];
875 } else {
876 $tax_query = [
877 'relation' => 'AND',
878 $tax_query,
879 ['taxonomy' => 'product_tag',
880 'field' => 'slug',
881 'terms' => $product_tags_slugs,
882 'operator' => 'IN',]
883 ];
884 }
885 }
886
887 if ( ! empty( $tax_query ) ) {
888 $products_ids_args = [
889 'post_type' => $this->_get_post_types( false ),
890 'posts_per_page' => -1,
891 'fields' => 'ids',
892 'tax_query' => $tax_query,
893 ];
894
895 $query_products_ids = new WP_Query( $products_ids_args );
896 $products_ids = $query_products_ids->posts;
897 $query .= ' AND posts.ID IN (' . implode( ',', $products_ids ) . ')';
898 }
899
900 $query .= ' ORDER BY posts.post_title ASC';
901 }
902 }
903
904 $products = $wpdb->get_results( $query ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
905
906 if ( ! empty( $products ) ) {
907 $product_purchased_times = array();
908 if ( $purchased_times ) {
909 $products_ids_str = ( is_array( $products_ids ) ) ? implode( ',', $products_ids ) : $products_ids;
910
911 $product_purchased_times = $wpdb->get_results( 'SELECT order_itemmeta.meta_value product_id, COUNT(order_itemmeta.meta_value) as times FROM ' . $wpdb->prefix . 'posts as orders INNER JOIN ' . $wpdb->prefix . 'woocommerce_order_items as order_items ON (orders.ID=order_items.order_id) INNER JOIN ' . $wpdb->prefix . 'woocommerce_order_itemmeta as order_itemmeta ON (order_items.order_item_id=order_itemmeta.order_item_id) WHERE orders.post_type="shop_order" AND orders.post_status="wc-completed" AND order_itemmeta.meta_key="_product_id" ' . ( strlen( $products_ids_str ) && false === strpos( '*', $products_ids_str ) ? ' AND order_itemmeta.meta_value IN (' . $products_ids_str . ')' : '' ) . ' GROUP BY order_itemmeta.meta_value' ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
912 }
913
914 // Enqueue resources
915
916 $this->enqueue_resources();
917 wp_enqueue_style( 'wcmp-playlist-widget-style', plugin_dir_url( __FILE__ ) . 'widgets/playlist_widget/css/style.css', array(), WCMP_VERSION );
918 wp_enqueue_script( 'wcmp-playlist-widget-script', plugin_dir_url( __FILE__ ) . 'widgets/playlist_widget/js/public.js', array(), WCMP_VERSION );
919 wp_localize_script(
920 'wcmp-playlist-widget-script',
921 'wcmp_widget_settings',
922 array( 'continue_playing' => $continue_playing )
923 );
924 $counter = 0;
925 $output .= '<div data-loop="' . ( $loop ? 1 : 0 ) . '">';
926 foreach ( $products as $product ) {
927 $product_obj = wc_get_product( $product->ID );
928
929 $counter++;
930 $preload = $this->get_product_attr( $product->ID, '_wcmp_preload', '' );
931 $row_class = 'wcmp-even-product';
932 if ( 1 == $counter % 2 ) {
933 $row_class = 'wcmp-odd-product';
934 }
935
936 $audio_files = $this->get_product_files( $product->ID );
937 if ( ! is_array( $audio_files ) ) {
938 continue;
939 }
940
941 if ( $cover ) {
942 $featured_image = get_the_post_thumbnail_url( $product->ID );
943 }
944
945 // Download files links
946 $download_links = '';
947
948 if ( $download_links_flag ) {
949 $download_links = $this->woocommerce_user_download( $product->ID );
950 if ( ! empty( $download_links ) ) {
951 $download_links = '<span class="wcmp-download-links">(' . $download_links . ')</span>';
952 }
953 }
954
955 if ( 'new' == $layout ) {
956 $price = $product_obj->get_price();
957 $output .= '
958 <div class="wcmp-new-layout wcmp-widget-product controls-' . esc_attr( $controls ) . ' ' . esc_attr( $class ) . ' ' . esc_attr( $row_class ) . ' ' . esc_attr( ( $product->ID == $current_post_id && $highlight_current_product ) ? 'wcmp-current-product' : '' ) . '">
959 <div class="wcmp-widget-product-header">
960 <div class="wcmp-widget-product-title">
961 <a href="' . esc_url( get_permalink( $product->ID ) ) . '">' . $product_obj->get_name() . '</a>' .
962 (
963 $purchased_times ?
964 '<span class="wcmp-purchased-times">' .
965 sprintf(
966 /* translators: %d: purchased times */
967 __( $this->get_global_attr( '_wcmp_purchased_times_text', '- purchased %d time(s)' ), 'music-player-for-woocommerce' ), // phpcs:ignore WordPress.WP.I18n.NonSingularStringLiteralText
968 $get_times( $product->ID, $product_purchased_times )
969 ) . '</span>' : ''
970 ) .
971 $download_links .
972 '</div><!-- product title -->
973 ';
974
975 if ( 0 != @floatval( $price ) && 0 == $hide_purchase_buttons ) {
976 $product_id_for_add_to_cart = $product->ID;
977 if( $product_obj->is_type( 'variable' ) ){
978 $variations = $product_obj->get_available_variations();
979 $variations_id = wp_list_pluck( $variations, 'variation_id' );
980 if( ! empty( $variations_id ) ) $product_id_for_add_to_cart = $variations_id[0];
981 } elseif ( $product_obj->is_type( 'grouped' ) ) {
982 $children = $product_obj->get_children();
983 if( ! empty( $children ) ) $product_id_for_add_to_cart = $children[0];
984 }
985
986 $output .= '<div class="wcmp-widget-product-purchase">
987 ' . wc_price( $product_obj->get_price(), '' ) . ' <a href="?add-to-cart=' . $product_id_for_add_to_cart . '"></a>
988 </div><!-- product purchase -->
989 ';
990 }
991 $output .= '</div>
992 <div class="wcmp-widget-product-files">
993 ';
994
995 if ( ! empty( $featured_image ) ) {
996 $output .= '<img src="' . esc_attr( $featured_image ) . '" class="wcmp-widget-feature-image" /><div class="wcmp-widget-product-files-list">';
997 }
998
999 foreach ( $audio_files as $index => $file ) {
1000 $audio_url = $this->generate_audio_url( $product->ID, $index, $file );
1001 $duration = $this->_get_duration_by_url( $file['file'] );
1002 $audio_tag = apply_filters(
1003 'wcmp_widget_audio_tag',
1004 $this->get_player(
1005 $audio_url,
1006 array(
1007 'player_controls' => $controls,
1008 'player_style' => $player_style,
1009 'media_type' => $file['media_type'],
1010 'id' => $index,
1011 'duration' => $duration,
1012 'preload' => $preload,
1013 'volume' => $volume,
1014 )
1015 ),
1016 $product->ID,
1017 $index,
1018 $audio_url
1019 );
1020 $file_title = esc_html( apply_filters( 'wcmp_widget_file_name', $file['name'], $product->ID, $index ) );
1021 $output .= '
1022 <div class="wcmp-widget-product-file">
1023 ' . $audio_tag . '<span class="wcmp-file-name">' . $file_title . '</span>' . ( ! isset( $atts['duration'] ) || $atts['duration'] == 1 ? '<span class="wcmp-file-duration">' . esc_html( $duration ) . '</span>' : '' ) . '<div style="clear:both;"></div>
1024 </div><!--product file -->
1025 ';
1026 }
1027
1028 if ( ! empty( $featured_image ) ) {
1029 $output .= '</div>';
1030 }
1031
1032 $output .= '
1033 </div><!-- product-files -->
1034 </div><!-- product -->
1035 ';
1036 } else // Load the previous playlist layout
1037 {
1038 $output .= '<ul class="wcmp-widget-playlist wcmp-classic-layout controls-' . esc_attr( $controls ) . ' ' . esc_attr( $class ) . ' ' . esc_attr( $row_class ) . ' ' . esc_attr( ( $product->ID == $current_post_id && $highlight_current_product ) ? 'wcmp-current-product' : '' ) . '">';
1039
1040 if ( ! empty( $featured_image ) ) {
1041 $output .= '<li style="display:table-row;"><img src="' . esc_attr( $featured_image ) . '" class="wcmp-widget-feature-image" /><div class="wcmp-widget-product-files-list"><ul>';
1042 }
1043
1044 foreach ( $audio_files as $index => $file ) {
1045 $audio_url = $this->generate_audio_url( $product->ID, $index, $file );
1046 $duration = $this->_get_duration_by_url( $file['file'] );
1047 $audio_tag = apply_filters(
1048 'wcmp_widget_audio_tag',
1049 $this->get_player(
1050 $audio_url,
1051 array(
1052 'player_controls' => $controls,
1053 'player_style' => $player_style,
1054 'media_type' => $file['media_type'],
1055 'id' => $index,
1056 'duration' => $duration,
1057 'preload' => $preload,
1058 'volume' => $volume,
1059 )
1060 ),
1061 $product->ID,
1062 $index,
1063 $audio_url
1064 );
1065 $file_title = esc_html( apply_filters( 'wcmp_widget_file_name', ( ( ! empty( $file['name'] ) ) ? $file['name'] : $product->post_title ), $product->ID, $index ) );
1066
1067 $output .= '<li class="wcmp-widget-playlist-item">' . $audio_tag . '<a href="' . esc_url( get_permalink( $product->ID ) ) . '">' . $file_title . '</a>' .
1068 (
1069 $purchased_times ?
1070 '<span class="wcmp-purchased-times">' .
1071 sprintf(
1072 /* translators: %d: purchased times */
1073 __( $this->get_global_attr( '_wcmp_purchased_times_text', '- purchased %d time(s)' ), 'music-player-for-woocommerce' ), // phpcs:ignore WordPress.WP.I18n.NonSingularStringLiteralText
1074 $get_times( $product->ID, $product_purchased_times )
1075 ) . '</span>' : ''
1076 )
1077 . ( ! isset( $atts['duration'] ) || $atts['duration'] == 1 ? '<span class="wcmp-file-duration">' . esc_html( $duration ) . '</span>' : '' )
1078 . '<div style="clear:both;"/></li>';
1079 }
1080 if ( ! empty( $featured_image ) ) {
1081 $output .= '</ul></div></li>';
1082 }
1083
1084 $output .= $download_links; // Download links
1085
1086 $output .= '</ul>';
1087 }
1088 }
1089 $output .= '</div>';
1090 }
1091 return $output;
1092 } // End replace_playlist_shortcode
1093
1094 /**
1095 * Used for accepting the <source> tags
1096 */
1097 public function allowed_html_tags( $allowedposttags, $context ) {
1098 if ( ! in_array( 'source', $allowedposttags ) ) {
1099 $allowedposttags['source'] = array(
1100 'src' => true,
1101 'type' => true,
1102 );
1103 }
1104 return $allowedposttags;
1105 } // End allowed_html_tags
1106
1107 public function preload( $preload, $audio_url ) {
1108 $result = $preload;
1109 if ( strpos( $audio_url, 'wcmp-action=play' ) !== false ) {
1110 if ( $this->_preload_times ) {
1111 $result = 'none';
1112 }
1113 $this->_preload_times++;
1114 }
1115 return $result;
1116 } // End preload
1117
1118 // ******************** WOOCOMMERCE ACTIONS ************************
1119
1120 public function woocommerce_user_download( $product_id ) {
1121 $download_links = '';
1122 if ( is_user_logged_in() ) {
1123 if ( empty( $this->_current_user_downloads ) && function_exists( 'wc_get_customer_available_downloads' ) ) {
1124 $current_user = wp_get_current_user();
1125 $this->_current_user_downloads = wc_get_customer_available_downloads( $current_user->ID );
1126 }
1127 foreach ( $this->_current_user_downloads as $download ) {
1128 if ( $download['product_id'] == $product_id ) {
1129 $download_links = '<a href="' . $download['download_url'] . '" target="_blank" class="wcmp-download-link">' . esc_html__( 'download', 'music-player-for-woocommerce' ) . '</a>';
1130 break;
1131 }
1132 }
1133 }
1134
1135 return $download_links;
1136
1137 }
1138
1139 public function woocommerce_product_title( $title, $product ) {
1140 global $wp;
1141 if ( ! empty( $wp->query_vars['wcfm-products-manage'] )) {
1142 return $title;
1143 }
1144 $player = '';
1145 if ( false === stripos( $title, '<audio' ) ) {
1146 $player .= $this->include_main_player( $product, false );
1147 }
1148 return $player . $title;
1149 } // End woocommerce_product_title
1150
1151 /**
1152 * Load the additional attributes to select the player layout
1153 */
1154 public function woocommerce_player_settings() {
1155 include_once 'views/player_options.php';
1156 } // End woocommerce_player_settings
1157
1158 public function get_player(
1159 $audio_url,
1160 $args = array()
1161 ) {
1162 $default_args = array(
1163 'media_type' => 'mp3',
1164 'player_style' => WCMP_DEFAULT_PLAYER_LAYOUT,
1165 'player_controls' => WCMP_DEFAULT_PLAYER_CONTROLS,
1166 'duration' => false,
1167 'volume' => 1,
1168 );
1169
1170 $args = array_merge( $default_args, $args );
1171 $id = ( ! empty( $args['id'] ) ) ? 'id="' . esc_attr( $args['id'] ) . '"' : '';
1172
1173 $preload = ( ! empty( $args['preload'] ) ) ? $args['preload'] : $GLOBALS['WooCommerceMusicPlayer']->get_global_attr(
1174 '_wcmp_preload',
1175 // This option is only for compatibility with versions previous to 1.0.28
1176 $GLOBALS['WooCommerceMusicPlayer']->get_global_attr( 'preload', 'none' )
1177 );
1178 $preload = apply_filters( 'wcmp_preload', $preload, $audio_url );
1179
1180 return '<audio ' . (
1181 (
1182 isset( $args['volume'] ) &&
1183 is_numeric( $args['volume'] ) &&
1184 0 <= $args['volume'] * 1 &&
1185 $args['volume'] * 1 <= 1
1186 ) ? 'volume="' . esc_attr( $args['volume'] ) . '"' : ''
1187 ) . ' ' . $id . ' preload="none" data-lazyloading="' . esc_attr( $preload ) . '" class="wcmp-player ' . esc_attr( $args['player_controls'] ) . ' ' . esc_attr( $args['player_style'] ) . '" ' . ( ( ! empty( $args['duration'] ) ) ? 'data-duration="' . esc_attr( $args['duration'] ) . '"' : '' ) . '><source src="' . esc_url( $audio_url ) . '" type="audio/' . esc_attr( $args['media_type'] ) . '" /></audio>';
1188
1189 } // End get_player
1190
1191 public function get_product_files( $id ) {
1192 $product = wc_get_product( $id );
1193 if ( ! empty( $product ) ) {
1194 return $this->_get_product_files(
1195 array(
1196 'product' => $product,
1197 'all' => 1,
1198 )
1199 );
1200 }
1201 return array();
1202 }
1203
1204 public function generate_audio_url( $product_id, $file_id, $file_data = array() ) {
1205 return $this->_generate_audio_url( $product_id, $file_id, $file_data );
1206 }
1207
1208 public function include_main_player_filter( $value, $id ) {
1209 global $wp;
1210 if (
1211 $this->_force_hook_title &&
1212 did_action('woocommerce_init') &&
1213 false === stripos( $value, '<audio' )
1214 ) {
1215 try {
1216 if (
1217 ( wp_doing_ajax() || ! is_admin() ) &&
1218 (
1219 ! function_exists( 'is_product' ) ||
1220 ! is_product() ||
1221 ( is_product() && get_queried_object_id() != $id )
1222 ) &&
1223 ! is_cart() &&
1224 ! is_page( 'cart' ) &&
1225 ! is_checkout() &&
1226 is_int( $id ) &&
1227 empty( $_REQUEST['wcmp_nonce'] ) &&
1228 empty( $wp->query_vars['wcfm-products-manage'] )
1229 ) {
1230 $p = wc_get_product( $id );
1231 if ( ! empty( $p ) ) {
1232 add_filter( 'esc_html', array( &$this, 'esc_html' ), 10, 2 );
1233
1234 $player = '';
1235 $player = $this->include_main_player( $p, false );
1236 $value = $player . $value;
1237 }
1238 }
1239 } catch ( Exception $err ) {
1240 error_log( $err->getMessage() );
1241 }
1242 }
1243 return $value;
1244 }
1245
1246 public function include_players( ...$args ) {
1247 if ( ! $this->_inserted_player ) {
1248 $this->_inserted_player = true;
1249 if ( ! empty( $args ) ) {
1250 $this->include_all_players( $args[0] );
1251 } else {
1252 $this->include_all_players();
1253 }
1254 }
1255
1256 if ( ! empty( $args ) ) {
1257 return $args[0];
1258 }
1259 } // End include_players
1260
1261 public function include_main_player( $product = '', $_echo = true ) {
1262 $output = '';
1263
1264 if ( is_admin() ) return $output;
1265
1266 if ( ! $this->_insert_player || ! $this->_insert_main_player ) {
1267 return $output;
1268 }
1269 if ( is_numeric( $product ) ) {
1270 $product = wc_get_product( $product );
1271 }
1272 if ( ! is_object( $product ) ) {
1273 $product = wc_get_product();
1274 }
1275
1276 if ( empty( $product ) ) {
1277 return '';
1278 }
1279
1280 $files = $this->_get_product_files(
1281 array(
1282 'product' => $product,
1283 'first' => true,
1284 )
1285 );
1286 if ( ! empty( $files ) ) {
1287 $id = $product->get_id();
1288
1289 $show_in = $this->get_product_attr( $id, '_wcmp_show_in', 'all' );
1290 if (
1291 ( 'single' == $show_in && ( ! function_exists( 'is_product' ) || ! is_product() ) ) ||
1292 ( 'multiple' == $show_in && ( function_exists( 'is_product' ) && is_product() ) && get_queried_object_id() == $id )
1293 ) {
1294 return $output;
1295 }
1296 $preload = $this->get_product_attr( $id, '_wcmp_preload', '' );
1297 $this->enqueue_resources();
1298
1299 $player_style = $this->get_product_attr( $id, '_wcmp_player_layout', WCMP_DEFAULT_PLAYER_LAYOUT );
1300 $player_controls = ( $this->get_product_attr( $id, '_wcmp_player_controls', WCMP_DEFAULT_PLAYER_CONTROLS ) != 'all' ) ? 'track' : '';
1301 $volume = @floatval( $this->get_product_attr( $id, '_wcmp_player_volume', WCMP_DEFAULT_PLAYER_VOLUME ) );
1302
1303 $file = reset( $files );
1304 $index = key( $files );
1305 $audio_url = $this->_generate_audio_url( $id, $index, $file );
1306 $duration = $this->_get_duration_by_url( $file['file'] );
1307 $audio_tag = apply_filters(
1308 'wcmp_audio_tag',
1309 $this->get_player(
1310 $audio_url,
1311 array(
1312 'player_controls' => $player_controls,
1313 'player_style' => $player_style,
1314 'media_type' => $file['media_type'],
1315 'duration' => $duration,
1316 'preload' => $preload,
1317 'volume' => $volume,
1318 )
1319 ),
1320 $id,
1321 $index,
1322 $audio_url
1323 );
1324
1325 do_action( 'wcmp_before_player_shop_page', $id );
1326
1327 $output = '<div class="wcmp-player-container product-' . esc_attr( $file['product'] ) . '">' . $audio_tag . '</div>';
1328 if ( $_echo ) {
1329 print $output; // phpcs:ignore WordPress.Security.EscapeOutput
1330 }
1331
1332 do_action( 'wcmp_after_player_shop_page', $id );
1333
1334 return $output; // phpcs:ignore WordPress.Security.EscapeOutput
1335 }
1336 } // End include_main_player
1337
1338 public function include_all_players( $product = '' ) {
1339
1340 if ( ! $this->_insert_player || ! $this->_insert_all_players || is_admin() ) {
1341 return;
1342 }
1343
1344 if ( ! is_object( $product ) ) {
1345 $product = wc_get_product();
1346 }
1347
1348 if ( empty( $product ) ) {
1349 return;
1350 }
1351
1352 $files = $this->_get_product_files(
1353 array(
1354 'product' => $product,
1355 'all' => true,
1356 )
1357 );
1358 if ( ! empty( $files ) ) {
1359 $id = $product->get_id();
1360
1361 $show_in = $this->get_product_attr( $id, '_wcmp_show_in', 'all' );
1362 if (
1363 ( 'single' == $show_in && ! is_singular() ) ||
1364 ( 'multiple' == $show_in && is_singular() )
1365 ) {
1366 return;
1367 }
1368 $preload = $this->get_product_attr( $id, '_wcmp_preload', '' );
1369 $this->enqueue_resources();
1370 $player_style = $this->get_product_attr( $id, '_wcmp_player_layout', WCMP_DEFAULT_PLAYER_LAYOUT );
1371 $volume = @floatval( $this->get_product_attr( $id, '_wcmp_player_volume', WCMP_DEFAULT_PLAYER_VOLUME ) );
1372 $player_controls = $this->get_product_attr( $id, '_wcmp_player_controls', WCMP_DEFAULT_PLAYER_CONTROLS );
1373 $player_title = intval( $this->get_product_attr( $id, '_wcmp_player_title', WCMP_DEFAULT_PlAYER_TITLE ) );
1374 $loop = intval( $this->get_product_attr( $id, '_wcmp_loop', 0 ) );
1375 $merge_grouped = intval( $this->get_product_attr( $id, '_wcmp_merge_in_grouped', 0 ) );
1376 $merge_grouped_clss = ( $merge_grouped ) ? 'merge_in_grouped_products' : '';
1377
1378 $counter = count( $files );
1379
1380 do_action( 'wcmp_before_players_product_page', $id );
1381 if ( 1 == $counter ) {
1382 $player_controls = ( 'button' == $player_controls ) ? 'track' : '';
1383 $file = reset( $files );
1384 $index = key( $files );
1385 $audio_url = $this->_generate_audio_url( $id, $index, $file );
1386 $duration = $this->_get_duration_by_url( $file['file'] );
1387 $audio_tag = apply_filters(
1388 'wcmp_audio_tag',
1389 $this->get_player(
1390 $audio_url,
1391 array(
1392 'player_controls' => $player_controls,
1393 'player_style' => $player_style,
1394 'media_type' => $file['media_type'],
1395 'duration' => $duration,
1396 'preload' => $preload,
1397 'volume' => $volume,
1398 )
1399 ),
1400 $id,
1401 $index,
1402 $audio_url
1403 );
1404 $title = esc_html( ( $player_title ) ? apply_filters( 'wcmp_file_name', $file['name'], $id, $index ) : '' );
1405 print '<div class="wcmp-player-container ' . esc_attr( $merge_grouped_clss ) . ' product-' . esc_attr( $file['product'] ) . '" ' . ( $loop ? 'data-loop="1"' : '' ) . '>' . $audio_tag . '</div><div class="wcmp-player-title" data-audio-url="' . esc_attr( $audio_url ) . '">' . wp_kses_post( $title ) . '</div><div style="clear:both;"></div>'; // phpcs:ignore WordPress.Security.EscapeOutput
1406 } elseif ( $counter > 1 ) {
1407
1408 $single_player = intval( $this->get_product_attr( $id, '_wcmp_single_player', WCMP_DEFAULT_SINGLE_PLAYER ) );
1409
1410 $before = '<table class="wcmp-player-list ' . $merge_grouped_clss . ( $single_player ? ' wcmp-single-player ' : '' ) . '" ' . ( $loop ? 'data-loop="1"' : '' ) . '>';
1411 $first_player_class = 'wcmp-first-player';
1412 $after = '';
1413 foreach ( $files as $index => $file ) {
1414 $evenOdd = ( 1 == $counter % 2 ) ? 'wcmp-odd-row' : 'wcmp-even-row';
1415 $counter--;
1416 $audio_url = $this->_generate_audio_url( $id, $index, $file );
1417 $duration = $this->_get_duration_by_url( $file['file'] );
1418 $audio_tag = apply_filters(
1419 'wcmp_audio_tag',
1420 $this->get_player(
1421 $audio_url,
1422 array(
1423 'player_style' => $player_style,
1424 'player_controls' => ( 'all' != $player_controls ) ? 'track' : '',
1425 'media_type' => $file['media_type'],
1426 'duration' => $duration,
1427 'preload' => $preload,
1428 'volume' => $volume,
1429 )
1430 ),
1431 $id,
1432 $index,
1433 $audio_url
1434 );
1435 $title = esc_html( ( $player_title ) ? apply_filters( 'wcmp_file_name', $file['name'], $id, $index ) : '' );
1436
1437 print $before; // phpcs:ignore WordPress.Security.EscapeOutput
1438 $before = '';
1439 $after = '</table>';
1440 if ( 'all' != $player_controls ) {
1441 print '<tr class="' . esc_attr( $evenOdd ) . ' product-' . esc_attr( $file['product'] ) . '"><td class="wcmp-column-player-' . esc_attr( $player_style ) . '"><div class="wcmp-player-container ' . $first_player_class . '" data-wcfm-pair="' . esc_attr( $counter ) . '">' . $audio_tag . '</div></td><td class="wcmp-player-title wcmp-column-player-title" data-wcfm-pair="' . esc_attr( $counter ) . '">' . wp_kses_post( $title ) . '</td><td class="wcmp-file-duration" style="text-align:right;font-size:16px;">' . esc_html( $duration ) . '</td></tr>'; // phpcs:ignore WordPress.Security.EscapeOutput
1442 } else {
1443 print '<tr class="' . esc_attr( $evenOdd ) . ' product-' . esc_attr( $file['product'] ) . '"><td><div class="wcmp-player-container ' . $first_player_class . '" data-wcfm-pair="' . esc_attr( $counter ) . '">' . $audio_tag . '</div><div class="wcmp-player-title wcmp-column-player-title" data-wcfm-pair="' . esc_attr( $counter ) . '">' . wp_kses_post( $title ) . ( $single_player ? '<span class="wcmp-file-duration">' . esc_html( $duration ) . '</span>' : '' ) . '</div></td></tr>'; // phpcs:ignore WordPress.Security.EscapeOutput
1444 }
1445 $first_player_class = '';
1446 }
1447 print $after; // phpcs:ignore WordPress.Security.EscapeOutput
1448 }
1449 do_action( 'wcmp_after_players_product_page', $id );
1450 }
1451 } // End include_all_players
1452
1453 public function player_in_cart( $cart_item, $cart_item_key ) {
1454 $product = wc_get_product( $cart_item['product_id'] );
1455 $this->include_all_players( $product );
1456 } // player_in_cart
1457
1458 // Integration with woocommerce-product-table by barn2media
1459 public function product_table_data_name( $name, $product ) {
1460 if ( false === stripos( $name, '<audio' ) ) {
1461 $player = $this->include_main_player( $product, false );
1462 $player = str_replace( '<div ', '<div style="display:inline-block" ', $player );
1463 $name = $player . $name;
1464 }
1465 return $name;
1466 } // product_table_data_name
1467
1468 public function add_data_product( $player, $product_id, $index, $url ) {
1469 $player = preg_replace( '/<audio\b/i', '<audio controlslist="nodownload" data-product="' . esc_attr( $product_id ) . '" ', $player );
1470 return $player;
1471 } // End add_data_product
1472
1473 public function add_class_attachment( $html, $product, $size, $attr, $placeholder, $image ) {
1474 $id = $product->get_id();
1475 $html = $this->_add_class( $html, $product );
1476 return $html;
1477 } // End add_class_attachment
1478
1479 public function add_class_single_product_image( $html, $post_thumbnail_id ) {
1480 global $product;
1481
1482 if ( ! empty( $product ) ) {
1483 $html = $this->_add_class( $html, $product );
1484 }
1485 return $html;
1486 } // add_class_single_product_image
1487
1488 public function init_force_in_title( $v = null ) {
1489 if ( is_admin() ) {
1490 $this->_force_hook_title = 0;
1491 return;
1492 }
1493
1494 if ( is_numeric( $v ) ) {
1495 $this->_force_hook_title = intval( $v );
1496 return;
1497 }
1498
1499 $this->_force_hook_title = $this->get_global_attr( '_wcmp_main_player_hook_title', 1 );
1500
1501 // Integration with "WOOF – Products Filter for WooCommerce" by realmag777
1502 if ( isset( $_REQUEST['action'] ) && 'woof_draw_products' == $_REQUEST['action'] ) {
1503 $this->_force_hook_title = 1;
1504 }
1505
1506 } // End init_force_in_title
1507
1508 // ******************** PRIVATE METHODS ************************
1509
1510 private function get_ip_address() {
1511 if( ! empty( $_SERVER['HTTP_CLIENT_IP'] ) ) { //whether ip is from the share internet
1512 $ip = $_SERVER['HTTP_CLIENT_IP'];
1513 } elseif (! empty( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) { //whether ip is from the proxy
1514 $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
1515 } else{ //whether ip is from the remote address
1516 $ip = $_SERVER['REMOTE_ADDR'];
1517 }
1518 return $ip;
1519 } // End update_playback_counter
1520
1521 private function clear_expired_transients() {
1522 $transient = get_transient( 'wcmp_clear_expired_transients' );
1523 if( ! $transient || 24 * 60 * 60 <= time() - intval( $transient ) ) {
1524 set_transient( 'wcmp_clear_expired_transients', time() );
1525 delete_expired_transients();
1526 }
1527 } // End clear_expired_transients
1528
1529 private function update_playback_counter( $product_id ) {
1530
1531 $ip = $this->get_ip_address();
1532 $transient_name = 'wcmp-playback-record-' . md5( $ip ) . '-' . $product_id;
1533 $transient = get_transient( $transient_name );
1534 if ( ! get_transient( $transient_name ) ) {
1535 set_transient( $transient_name, 1, 12 * 60 * 60 );
1536
1537 $counter = get_post_meta( $product_id, '_wcmp_playback_counter', true );
1538
1539 if ( is_numeric( $counter ) ) $counter = intval( $counter );
1540 else $counter = 0;
1541
1542 $counter++;
1543 update_post_meta( $product_id, '_wcmp_playback_counter', $counter );
1544 }
1545 } // End update_playback_counter
1546
1547 private function _get_post_types( $mysql_in = false ) {
1548 $post_types = array( 'product' );
1549 if ( ! empty( $GLOBALS['wcmp_post_types'] ) && is_array( $GLOBALS['wcmp_post_types'] ) ) {
1550 $post_types = $GLOBALS['wcmp_post_types'];
1551 }
1552 if ( $mysql_in ) {
1553 return '"' . implode( '","', $post_types ) . '"';
1554 }
1555 return $post_types;
1556 } // End _get_post_types
1557
1558 private function _load_addons() {
1559 $path = __DIR__ . '/addons';
1560 $wcmp = $this;
1561
1562 if ( file_exists( $path ) ) {
1563 $addons = dir( $path );
1564 while ( false !== ( $entry = $addons->read() ) ) {
1565 if ( strlen( $entry ) > 3 && strtolower( pathinfo( $entry, PATHINFO_EXTENSION ) ) == 'php' ) {
1566 include_once $addons->path . '/' . $entry;
1567 }
1568 }
1569 }
1570 } // End _load_addons
1571
1572 private function _preview() {
1573 $user = wp_get_current_user();
1574 $allowed_roles = array( 'editor', 'administrator', 'author' );
1575
1576 if ( array_intersect( $allowed_roles, $user->roles ) ) {
1577 if ( ! empty( $_REQUEST['wcmp-preview'] ) ) {
1578 // Sanitizing variable
1579 $preview = sanitize_text_field( wp_unslash( $_REQUEST['wcmp-preview'] ) );
1580
1581 // Remove every shortcode that is not in the plugin
1582 remove_all_shortcodes();
1583 add_shortcode( 'wcmp-playlist', array( &$this, 'replace_playlist_shortcode' ) );
1584
1585 if ( has_shortcode( $preview, 'wcmp-playlist' ) ) {
1586 print '<!DOCTYPE html>';
1587 $if_empty = __( 'There are no products that satisfy the block\'s settings', 'music-player-for-woocommerce' );
1588 wp_enqueue_script( 'jquery' );
1589 $output = do_shortcode( $preview );
1590 if ( preg_match( '/^\s*$/', $output ) ) {
1591 $output = '<div>' . $if_empty . '</div>';
1592 }
1593
1594 // Deregister all scripts and styles for loading only the plugin styles.
1595 global $wp_styles, $wp_scripts;
1596 if ( ! empty( $wp_scripts ) ) {
1597 $wp_scripts->reset();
1598 }
1599 $this->enqueue_resources();
1600 if ( ! empty( $wp_styles ) ) {
1601 $wp_styles->do_items();
1602 }
1603 if ( ! empty( $wp_scripts ) ) {
1604 $wp_scripts->do_items();
1605 }
1606
1607 print '<div class="wcmp-preview-container">' . $output . '</div>'; // phpcs:ignore WordPress.Security.EscapeOutput
1608 print '<script type="text/javascript">jQuery(window).on("load", function(){ var frameEl = window.frameElement; if(frameEl) frameEl.height = jQuery(".wcmp-preview-container").outerHeight(true)+25; });</script>';
1609 exit;
1610 }
1611 }
1612 }
1613 } // End _preview
1614
1615 private function _createDir() {
1616 // Generate upload dir
1617 $_files_directory = wp_upload_dir();
1618 $this->_files_directory_path = rtrim( $_files_directory['basedir'], '/' ) . '/wcmp/';
1619 $this->_files_directory_url = rtrim( $_files_directory['baseurl'], '/' ) . '/wcmp/';
1620 $this->_files_directory_url = preg_replace( '/^http(s)?:\/\//', '//', $this->_files_directory_url );
1621 if ( ! file_exists( $this->_files_directory_path ) ) {
1622 @mkdir( $this->_files_directory_path, 0755 );
1623 }
1624 } // End _createDir
1625
1626 private function _clearDir( $dirPath ) {
1627 try {
1628 if ( empty( $dirPath ) || ! file_exists( $dirPath ) || ! is_dir( $dirPath ) ) {
1629 return;
1630 }
1631 $dirPath = rtrim( $dirPath, '\\/' ) . '/';
1632 $files = glob( $dirPath . '*', GLOB_MARK );
1633 foreach ( $files as $file ) {
1634 if ( is_dir( $file ) ) {
1635 $this->_clearDir( $file );
1636 } else {
1637 unlink( $file );
1638 }
1639 }
1640 } catch ( Exception $err ) {
1641 return;
1642 }
1643 } // End _clearDir
1644
1645 private function _get_duration_by_url( $url ) {
1646 global $wpdb;
1647 try {
1648 $attachment = $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE guid RLIKE %s;", $url ) );
1649 if ( empty( $attachment ) ) {
1650 $uploads_dir = wp_upload_dir();
1651 $uploads_url = $uploads_dir['baseurl'];
1652 $parsed_url = explode( parse_url( $uploads_url, PHP_URL_PATH ), $url );
1653 $this_host = str_ireplace( 'www.', '', parse_url( home_url(), PHP_URL_HOST ) );
1654 $file_host = str_ireplace( 'www.', '', parse_url( $url, PHP_URL_HOST ) );
1655 if ( ! isset( $parsed_url[1] ) || empty( $parsed_url[1] ) || ( $this_host != $file_host ) ) {
1656 return false;
1657 }
1658 $file = trim( $parsed_url[1], '/' );
1659 $attachment = $wpdb->get_col( $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta WHERE meta_key='_wp_attached_file' AND meta_value RLIKE %s;", $file ) );
1660 }
1661 if ( ! empty( $attachment ) && ! empty( $attachment[0] ) ) {
1662 $metadata = wp_get_attachment_metadata( $attachment[0] );
1663 if ( false !== $metadata && ! empty( $metadata['length_formatted'] ) ) {
1664 return $metadata['length_formatted'];
1665 }
1666 }
1667 } catch ( Exception $err ) {
1668 error_log( $err->getMessage() );
1669 }
1670 return false;
1671 } // End _get_duration_by_url
1672
1673 private function _generate_audio_url( $product_id, $file_index, $file_data = array() ) {
1674 if ( ! empty( $file_data['file'] ) ) {
1675 $file_url = $file_data['file'];
1676 if ( ! empty( $file_data['play_src'] ) || $this->_is_playlist( $file_url ) ) {
1677 return $file_url; // Play src audio file, without copying or truncate it.
1678 }
1679
1680 // If the playback of music are tracked with Google Analytics, should not be loaded directly the audio files.
1681 $_wcmp_analytics_property = trim( $this->get_global_attr( '_wcmp_analytics_property', '' ) );
1682 if ( '' == $_wcmp_analytics_property ) {
1683 $file_name = $this->_demo_file_name( $file_url );
1684
1685 $file_path = $this->_files_directory_path . $file_name;
1686
1687 if ( $this->_valid_demo( $file_path ) ) {
1688 return 'http' . ( ( is_ssl() ) ? 's:' : ':' ) . $this->_files_directory_url . $file_name;
1689 }
1690 }
1691 }
1692 $url = WCMP_WEBSITE_URL; //isset( $_SERVER['REQUEST_URI'] ) ? esc_url_raw( wp_unslash( $_SERVER['REQUEST_URI'] ) ) : '';
1693 $url .= ( ( strpos( $url, '?' ) === false ) ? '?' : '&' ) . 'wcmp-action=play&wcmp-product=' . $product_id . '&wcmp-file=' . $file_index;
1694 return $url;
1695 } // End _generate_audio_url
1696
1697 private function _delete_truncated_files( $product_id ) {
1698 $files_arr = get_post_meta( $product_id, '_downloadable_files', true );
1699 if ( ! empty( $files_arr ) && is_array( $files_arr ) ) {
1700 foreach ( $files_arr as $file ) {
1701 if ( is_array( $file ) && ! empty( $file['file'] ) ) {
1702 $ext = pathinfo( $file['file'], PATHINFO_EXTENSION );
1703 $file_name = md5( $file['file'] ) . ( ( ! empty( $ext ) ) ? '.' . $ext : '' );
1704 if ( file_exists( $this->_files_directory_path . $file_name ) ) {
1705 @unlink( $this->_files_directory_path . $file_name );
1706 }
1707 }
1708 }
1709 }
1710
1711 } // End _delete_truncated_files
1712
1713 /**
1714 * Check if the file is an m3u or m3u8 playlist
1715 */
1716 private function _is_playlist( $file_path ) {
1717 return preg_match( '/\.(m3u|m3u8)$/i', $file_path );
1718 } // End _is_playlist
1719
1720 /**
1721 * Check if the file is an audio file and return its type or false
1722 */
1723 private function _is_audio( $file_path ) {
1724 if ( preg_match( '/\.(mp3|ogg|oga|wav|wma|mp4)$/i', $file_path, $match ) ) {
1725 return $match[1];
1726 }
1727 if ( preg_match( '/\.m4a$/i', $file_path ) ) {
1728 return 'mp4';
1729 }
1730 if ( $this->_is_playlist( $file_path ) ) {
1731 return 'hls';
1732 }
1733
1734 // From troubleshoot
1735 $extension = pathinfo( $file_path, PATHINFO_EXTENSION );
1736 $troubleshoot_default_extension = $GLOBALS['WooCommerceMusicPlayer']->get_global_attr( '_wcmp_default_extension', false );
1737 if ( ( empty( $extension ) || ! preg_match( '/^[a-z\d]{3,4}$/i', $extension ) ) && $troubleshoot_default_extension ) {
1738 return 'mp3';
1739 }
1740
1741 return false;
1742 } // End _is_audio
1743
1744 private function _sort_list( $product_a, $product_b ) {
1745 if (
1746 ! is_object( $product_a ) || ! method_exists( $product_a, 'get_menu_order' ) ||
1747 ! is_object( $product_b ) || ! method_exists( $product_b, 'get_menu_order' )
1748 ) {
1749 return 0;
1750 }
1751
1752 $menu_order_a = $product_a->get_menu_order();
1753 $menu_order_b = $product_b->get_menu_order();
1754 if ( $menu_order_a == $menu_order_b ) {
1755 if (
1756 ! method_exists( $product_a, 'get_name' ) ||
1757 ! method_exists( $product_b, 'get_name' )
1758 ) {
1759 return 0;
1760 }
1761
1762 $name_a = $product_a->get_name();
1763 $name_b = $product_b->get_name();
1764 if ( $name_a == $name_b ) {
1765 return 0;
1766 }
1767 return ( $name_a < $name_b ) ? -1 : 1;
1768 }
1769 return ( $menu_order_a < $menu_order_b ) ? -1 : 1;
1770 } // End _sort_list
1771
1772 private function _edit_files_array( $product_id, $files, $play_src = 0 ) {
1773 $p_files = array();
1774 foreach ( $files as $key => $file ) {
1775 $p_key = $key . '_' . $product_id;
1776 if ( gettype( $file ) == 'object' ) {
1777 $file = (array) $file->get_data();
1778 }
1779 $file['product'] = $product_id;
1780 $file['play_src'] = $play_src;
1781 $p_files[ $p_key ] = $file;
1782 }
1783 return $p_files;
1784 } // end _edit_files_array
1785
1786 private function _get_recursive_product_files( $product, $files_arr ) {
1787 if ( ! is_object( $product ) || ! method_exists( $product, 'get_type' ) ) {
1788 return $files_arr;
1789 }
1790
1791 $product_type = $product->get_type();
1792 $id = $product->get_id();
1793
1794 if ( 'variation' == $product_type ) {
1795 // $_files = $product->get_files();
1796 $_files = $product->get_downloads();
1797 $_files = $this->_edit_files_array( $id, $_files );
1798 $files_arr = array_merge( $files_arr, $_files );
1799 } else {
1800
1801 if ( ! $this->get_product_attr( $id, '_wcmp_enable_player', false ) ) {
1802 return $files_arr;
1803 }
1804
1805 switch ( $product_type ) {
1806 case 'variable':
1807 case 'grouped':
1808 $children = $product->get_children();
1809
1810 foreach ( $children as $key => $child_id ) {
1811 $children[ $key ] = wc_get_product( $child_id );
1812 }
1813
1814 uasort( $children, array( &$this, '_sort_list' ) );
1815
1816 foreach ( $children as $child_obj ) {
1817 $files_arr = $this->_get_recursive_product_files( $child_obj, $files_arr );
1818 }
1819 break;
1820 default:
1821 $_files = $product->get_downloads();
1822 $_files = $this->_edit_files_array( $id, $_files );
1823 $files_arr = array_merge( $files_arr, $_files );
1824 break;
1825 }
1826 }
1827 return $files_arr;
1828 } // End _get_recursive_product_files
1829
1830 private function _get_product_files( $args ) {
1831 if ( empty( $args['product'] ) ) {
1832 return false;
1833 }
1834
1835 $product = $args['product'];
1836 $files = $this->_get_recursive_product_files( $product, array() );
1837
1838 if ( empty( $files ) ) {
1839 return false;
1840 }
1841
1842 $audio_files = array();
1843 foreach ( $files as $index => $file ) {
1844 if ( ! empty( $file['file'] ) && false !== ( $media_type = $this->_is_audio( $file['file'] ) ) ) { // phpcs:ignore Squiz.PHP.DisallowMultipleAssignments
1845 $file['media_type'] = $media_type;
1846
1847 if ( ! empty( $args['file_id'] ) ) {
1848 if ( $args['file_id'] == $index ) {
1849 $audio_files[ $index ] = $file;
1850 return $audio_files;
1851 }
1852 } elseif ( ! empty( $args['first'] ) ) {
1853 $audio_files[ $index ] = $file;
1854 return $audio_files;
1855 } elseif ( ! empty( $args['all'] ) ) {
1856 $audio_files[ $index ] = $file;
1857 }
1858 }
1859 }
1860
1861 return $audio_files;
1862 } // End _get_product_files
1863
1864 private function _demo_file_name( $url ) {
1865 $file_extension = pathinfo( $url, PATHINFO_EXTENSION );
1866 $file_name = md5( $url ) . ( ( ! empty( $file_extension ) && preg_match( '/^[a-z\d]{3,4}$/i', $file_extension ) ) ? '.' . $file_extension : '.mp3' );
1867 return $file_name;
1868 } // End _demo_file_name
1869
1870 private function _valid_demo( $file_path ) {
1871 if ( ! file_exists( $file_path ) || filesize( $file_path ) == 0 ) {
1872 return false;
1873 }
1874 if ( function_exists( 'finfo_open' ) ) {
1875 $finfo = finfo_open( FILEINFO_MIME );
1876 return substr( finfo_file( $finfo, $file_path ), 0, 4 ) !== 'text';
1877 }
1878 return true;
1879 } // End _valid_demo
1880
1881 /**
1882 * Create a temporal file and redirect to the new file
1883 */
1884 private function _output_file( $args ) {
1885 if ( empty( $args['url'] ) ) {
1886 return;
1887 }
1888 $url = $args['url'];
1889 $url = do_shortcode( $url );
1890
1891 if ( file_exists( $url ) ) {
1892 $url_fixed = $url;
1893 } elseif ( strpos( $url, '//' ) === 0 ) {
1894 $url_fixed = 'http' . ( is_ssl() ? 's:' : ':' ) . $url;
1895 } elseif ( strpos( $url, '/' ) === 0 ) {
1896 $url_fixed = rtrim( WCMP_WEBSITE_URL, '/' ) . $url;
1897 } else {
1898 $url_fixed = $url;
1899 }
1900
1901 $file_name = $this->_demo_file_name( $url );
1902 $text = 'The requested URL was not found on this server';
1903 $file_path = $this->_files_directory_path . $file_name;
1904
1905 if ( $this->_valid_demo( $file_path ) ) {
1906 header( 'location: http' . ( ( is_ssl() ) ? 's:' : ':' ) . $this->_files_directory_url . $file_name );
1907 exit;
1908 } else {
1909 try {
1910 $c = false;
1911 if ( ( $path = $this->_is_local( $url_fixed ) ) !== false ) { // phpcs:ignore Squiz.PHP.DisallowMultipleAssignments
1912 $c = copy( $path, $file_path );
1913 } else {
1914 $response = wp_remote_get(
1915 $url_fixed,
1916 array(
1917 'timeout' => WCMP_REMOTE_TIMEOUT,
1918 'stream' => true,
1919 'filename' => $file_path,
1920 )
1921 );
1922 if ( ! is_wp_error( $response ) && 200 == $response['response']['code'] ) {
1923 $c = true;
1924 }
1925 }
1926
1927 if ( true === $c ) {
1928
1929 if ( ! function_exists( 'mime_content_type' ) || false === ( $mime_type = mime_content_type( $file_path ) ) ) $mime_type = 'audio/mpeg';
1930
1931 if ( ! headers_sent() ) {
1932 if ( ! $this->get_global_attr( '_wcmp_disable_302', 0 ) ) {
1933 header( "location: " . $this->_files_directory_url . $file_name, true, 302 );
1934 exit;
1935 }
1936
1937 header( "Content-Type: " . $mime_type );
1938 header( "Content-length: " . filesize( $file_path ) );
1939 header( 'Content-Disposition: filename="' . $file_name . '"' );
1940 header( "Accept-Ranges: " . ( stripos( $mime_type, 'wav' ) ? 'none' : 'bytes' ) );
1941 header( "Content-Transfer-Encoding: binary" );
1942 }
1943
1944 readfile($file_path);
1945 exit;
1946 }
1947 } catch ( Exception $err ) {
1948 error_log( $err->getMessage() );
1949 }
1950 $text = 'It is not possible to generate the file for demo. Possible causes are: - the amount of memory allocated to the php script on the web server is not enough, - the execution time is too short, - or the "uploads/wcmp" directory does not have write permissions.';
1951 }
1952 $this->_print_page_not_found( $text );
1953 } // End _output_file
1954
1955 /**
1956 * Add the class name: product-<product id> to cover images associated to the products.
1957 *
1958 * @param $html, a html piece of code that includes the <img> tag.
1959 * @param $product, the product object.
1960 */
1961 private function _add_class( $html, $product ) {
1962 if ( preg_match( '/<img\b[^>]*>/i', $html, $image ) ) {
1963 $id = $product->get_id();
1964 if ( $GLOBALS['WooCommerceMusicPlayer']->get_product_attr( $id, '_wcmp_on_cover', 0 ) ) {
1965 if ( preg_match( '/\bclass\s*=/i', $image[0] ) ) {
1966 $tmp_image = preg_replace( '/\bclass\s*=\s*[\'"]/i', "$0product-$id ", $image[0] );
1967 } else {
1968 $tmp_image = preg_replace( '/<img\b/i', "<img $0 class=\"product-$id\" ", $image[0] );
1969 }
1970
1971 $html = str_replace( $image[0], $tmp_image, $html );
1972 }
1973 }
1974
1975 return $html;
1976 } // End _add_class
1977
1978 /**
1979 * Print not found page if file it is not accessible
1980 */
1981 private function _print_page_not_found( $text = 'The requested URL was not found on this server' ) {
1982 header( 'Status: 404 Not Found' );
1983 echo '<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
1984 <HTML><HEAD>
1985 <TITLE>404 Not Found</TITLE>
1986 </HEAD><BODY>
1987 <H1>Not Found</H1>
1988 <P>' . esc_html( $text ) . '</P>
1989 </BODY></HTML>
1990 ';
1991 } // End _print_page_not_found
1992
1993 private function _is_local( $url ) {
1994 $file_path = false;
1995 if ( file_exists( $url ) ) {
1996 $file_path = $url;
1997 }
1998
1999 if ( false === $file_path ) {
2000 $attachment_id = attachment_url_to_postid( $url );
2001 if ( $attachment_id ) {
2002 $attachment_path = get_attached_file( $attachment_id );
2003 if ( $attachment_path && file_exists( $attachment_path ) ) {
2004 $file_path = $attachment_path;
2005 }
2006 }
2007 }
2008
2009 if ( false === $file_path && defined( 'ABSPATH' ) ) {
2010 $path_component = parse_url( $url, PHP_URL_PATH );
2011 $path = rtrim( ABSPATH, '/' ) . '/' . ltrim( $path_component, '/' );
2012 if ( file_exists( $path ) ) {
2013 $file_path = $path;
2014 }
2015
2016 if ( false === $file_path ) {
2017 $site_url = get_site_url( get_current_blog_id() );
2018 $file_path = str_ireplace( $site_url . '/', ABSPATH, $url );
2019 if ( ! file_exists( $file_path ) ) {
2020 $file_path = false;
2021 }
2022 }
2023 }
2024
2025 return apply_filters( 'wcmp_is_local', $file_path, $url );
2026 } // End _is_local
2027
2028 private function _tracking_play_event( $product_id, $file_url ) {
2029 $_wcmp_analytics_integration = $this->get_global_attr( '_wcmp_analytics_integration', 'ua' );
2030 $_wcmp_analytics_property = trim( $this->get_global_attr( '_wcmp_analytics_property', '' ) );
2031 $_wcmp_analytics_api_secret = trim( $this->get_global_attr( '_wcmp_analytics_api_secret', '' ) );
2032 if ( ! empty( $_wcmp_analytics_property ) ) {
2033 $cid = isset( $_SERVER['REMOTE_ADDR'] ) ? sanitize_text_field( wp_unslash( $_SERVER['REMOTE_ADDR'] ) ) : 555;
2034 try {
2035 if ( isset( $_COOKIE['_ga'] ) ) {
2036 $cid_parts = explode( '.', sanitize_text_field( wp_unslash( $_COOKIE['_ga'] ) ), 3 );
2037 $cid = $cid_parts[2];
2038 }
2039 } catch ( Exception $err ) {
2040 error_log( $err->getMessage() );
2041 }
2042
2043 if ( 'ua' == $_wcmp_analytics_integration ) {
2044 $_response = wp_remote_post(
2045 'http://www.google-analytics.com/collect',
2046 array(
2047 'body' => array(
2048 'v' => 1,
2049 'tid' => $_wcmp_analytics_property,
2050 'cid' => $cid,
2051 't' => 'event',
2052 'ec' => 'Music Player for WooCommerce',
2053 'ea' => 'play',
2054 'el' => $file_url,
2055 'ev' => $product_id,
2056 ),
2057 )
2058 );
2059 } else {
2060 $_response = wp_remote_post(
2061 'https://www.google-analytics.com/mp/collect?api_secret=' . $_wcmp_analytics_api_secret . '&measurement_id=' . $_wcmp_analytics_property,
2062 array(
2063 'sslverify' => true,
2064 'headers' => array(
2065 'Content-Type' => 'application/json',
2066 ),
2067 'body' => json_encode(
2068 array(
2069 'client_id' => $cid,
2070 'events' => array(
2071 array(
2072 'name' => 'play',
2073 'params' => array(
2074 'event_category' => 'Music Player for WooCommerce',
2075 'event_label' => $file_url,
2076 'event_value' => $product_id,
2077 ),
2078 ),
2079 ),
2080 )
2081 ),
2082 )
2083 );
2084 }
2085
2086 if ( is_wp_error( $_response ) ) {
2087 error_log( $_response->get_error_message() );
2088 }
2089 }
2090 } // _tracking_play_event
2091
2092 public static function troubleshoot( $option ) {
2093 if ( ! is_admin() ) {
2094 // Solves a conflict caused by the "Speed Booster Pack" plugin
2095 if ( is_array( $option ) && isset( $option['jquery_to_footer'] ) ) {
2096 unset( $option['jquery_to_footer'] );
2097 }
2098 }
2099 return $option;
2100 } // End troubleshoot
2101 } // End Class WooCommerceMusicPlayer
2102
2103 $GLOBALS['WooCommerceMusicPlayer'] = new WooCommerceMusicPlayer();
2104 }
2105