PluginProbe ʕ •ᴥ•ʔ
Music Player for WooCommerce / 1.3.9
Music Player for WooCommerce v1.3.9
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
2034 lines
1 <?php
2 /*
3 Plugin Name: Music Player for WooCommerce
4 Plugin URI: https://wcmp.dwbooster.com
5 Version: 1.3.9
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.3.9' );
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( $post ) &&
703 in_array( $post->post_type, $post_types )
704 ) {
705 try {
706 ob_start();
707 $this->include_all_players( $post->ID );
708 $output = ob_get_contents();
709 ob_end_clean();
710
711 $class = esc_attr( isset( $atts['class'] ) ? $atts['class'] : '' );
712
713 return strpos( $output, 'wcmp-player-list' ) !== false ?
714 str_replace( 'wcmp-player-list', $class . ' wcmp-player-list', $output ) :
715 str_replace( 'wcmp-player-container', $class . ' wcmp-player-container', $output );
716 } catch ( Exception $err ) {
717 $atts['products_ids'] = $post->ID;
718 }
719 }
720
721 $atts = shortcode_atts(
722 array(
723 'products_ids' => '*',
724 'purchased_products' => 0,
725 'highlight_current_product' => 0,
726 'continue_playing' => 0,
727 'player_style' => WCMP_DEFAULT_PLAYER_LAYOUT,
728 'controls' => 'track',
729 'layout' => 'new',
730 'cover' => 0,
731 'volume' => 1,
732 'hide_purchase_buttons' => 0,
733 'class' => '',
734 'loop' => 0,
735 'purchased_times' => 0,
736 'download_links' => 0,
737 'duration' => 1,
738 ),
739 $atts
740 );
741
742 $products_ids = $atts['products_ids'];
743 $purchased_products = $atts['purchased_products'];
744 $highlight_current_product = $atts['highlight_current_product'];
745 $continue_playing = $atts['continue_playing'];
746 $player_style = $atts['player_style'];
747 $controls = $atts['controls'];
748 $layout = $atts['layout'];
749 $cover = $atts['cover'];
750 $volume = $atts['volume'];
751 $hide_purchase_buttons = $atts['hide_purchase_buttons'];
752 $class = $atts['class'];
753 $loop = $atts['loop'];
754 $purchased_times = $atts['purchased_times'];
755 $download_links_flag = $atts['download_links'];
756
757 // Typecasting variables.
758 $cover = is_numeric( $cover ) ? intval( $cover ) : 0;
759 $volume = is_numeric( $volume ) ? floatval( $volume ) : 0;
760 $purchased_products = is_numeric( $purchased_products ) ? intval( $purchased_products ) : 0;
761 $highlight_current_product = is_numeric( $highlight_current_product ) ? intval( $highlight_current_product ) : 0;
762 $continue_playing = is_numeric( $continue_playing ) ? intval( $continue_playing ) : 0;
763 $hide_purchase_buttons = is_numeric( $hide_purchase_buttons ) ? intval( $hide_purchase_buttons ) : 0;
764 $loop = is_numeric( $loop ) ? intval( $loop ) : 0;
765 $purchased_times = is_numeric( $purchased_times ) ? intval( $purchased_times ) : 0;
766
767 // get the produts ids
768 $products_ids = preg_replace( '/[^\d\,\*]/', '', $products_ids );
769 $products_ids = preg_replace( '/(\,\,)+/', '', $products_ids );
770 $products_ids = trim( $products_ids, ',' );
771
772 if ( strlen( $products_ids ) == 0 ) {
773 return $output;
774 }
775
776 // MAIN CODE GOES HERE
777 global $wpdb, $post;
778
779 $current_post_id = ! empty( $post ) ? ( is_int( $post ) ? $post : $post->ID ) : -1;
780
781 $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")';
782
783 if ( ! empty( $purchased_products ) ) {
784 // Hide the purchase buttons
785 $hide_purchase_buttons = 1;
786
787 // Getting the list of purchased products
788 $_current_user_id = get_current_user_id();
789 if ( 0 == $_current_user_id ) {
790 return $output;
791 }
792
793 // GET USER ORDERS (COMPLETED + PROCESSING)
794 $customer_orders = get_posts(
795 array(
796 'numberposts' => -1,
797 'meta_key' => '_customer_user',
798 'meta_value' => $_current_user_id,
799 'post_type' => wc_get_order_types(),
800 'post_status' => array_keys( wc_get_is_paid_statuses() ),
801 )
802 );
803
804 if ( empty( $customer_orders ) ) {
805 return $output;
806 }
807
808 // LOOP THROUGH ORDERS AND GET PRODUCT IDS
809 $products_ids = array();
810
811 foreach ( $customer_orders as $customer_order ) {
812 $order = wc_get_order( $customer_order->ID );
813 $items = $order->get_items();
814 foreach ( $items as $item ) {
815 $product_id = $item->get_product_id();
816 $products_ids[] = $product_id;
817 }
818 }
819 $products_ids = array_unique( $products_ids );
820 $products_ids_str = implode( ',', $products_ids );
821
822 $query .= ' AND posts.ID IN (' . $products_ids_str . ')';
823 $query .= ' ORDER BY FIELD(posts.ID,' . $products_ids_str . ')';
824 } else {
825 if ( strpos( '*', $products_ids ) === false ) {
826 $query .= ' AND posts.ID IN (' . $products_ids . ')';
827 $query .= ' ORDER BY FIELD(posts.ID,' . $products_ids . ')';
828 } else {
829 $query .= ' ORDER BY posts.post_title ASC';
830 }
831 }
832
833 $products = $wpdb->get_results( $query ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
834
835 if ( ! empty( $products ) ) {
836 $product_purchased_times = array();
837 if ( $purchased_times ) {
838 $products_ids_str = ( is_array( $products_ids ) ) ? implode( ',', $products_ids ) : $products_ids;
839
840 $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
841 }
842
843 // Enqueue resources
844
845 $this->enqueue_resources();
846 wp_enqueue_style( 'wcmp-playlist-widget-style', plugin_dir_url( __FILE__ ) . 'widgets/playlist_widget/css/style.css', array(), WCMP_VERSION );
847 wp_enqueue_script( 'wcmp-playlist-widget-script', plugin_dir_url( __FILE__ ) . 'widgets/playlist_widget/js/public.js', array(), WCMP_VERSION );
848 wp_localize_script(
849 'wcmp-playlist-widget-script',
850 'wcmp_widget_settings',
851 array( 'continue_playing' => $continue_playing )
852 );
853 $counter = 0;
854 $output .= '<div data-loop="' . ( $loop ? 1 : 0 ) . '">';
855 foreach ( $products as $product ) {
856 $product_obj = wc_get_product( $product->ID );
857
858 $counter++;
859 $preload = $this->get_product_attr( $product->ID, '_wcmp_preload', '' );
860 $row_class = 'wcmp-even-product';
861 if ( 1 == $counter % 2 ) {
862 $row_class = 'wcmp-odd-product';
863 }
864
865 $audio_files = $this->get_product_files( $product->ID );
866 if ( ! is_array( $audio_files ) ) {
867 continue;
868 }
869
870 if ( $cover ) {
871 $featured_image = get_the_post_thumbnail_url( $product->ID );
872 }
873
874 // Download files links
875 $download_links = '';
876
877 if ( $download_links_flag ) {
878 $download_links = $this->woocommerce_user_download( $product->ID );
879 if ( ! empty( $download_links ) ) {
880 $download_links = '<span class="wcmp-download-links">(' . $download_links . ')</span>';
881 }
882 }
883
884 if ( 'new' == $layout ) {
885 $price = $product_obj->get_price();
886 $output .= '
887 <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' : '' ) . '">
888 <div class="wcmp-widget-product-header">
889 <div class="wcmp-widget-product-title">
890 <a href="' . esc_url( get_permalink( $product->ID ) ) . '">' . $product_obj->get_name() . '</a>' .
891 (
892 $purchased_times ?
893 '<span class="wcmp-purchased-times">' .
894 sprintf(
895 /* translators: %d: purchased times */
896 __( $this->get_global_attr( '_wcmp_purchased_times_text', '- purchased %d time(s)' ), 'music-player-for-woocommerce' ), // phpcs:ignore WordPress.WP.I18n.NonSingularStringLiteralText
897 $get_times( $product->ID, $product_purchased_times )
898 ) . '</span>' : ''
899 ) .
900 $download_links .
901 '</div><!-- product title -->
902 ';
903
904 if ( 0 != @floatval( $price ) && 0 == $hide_purchase_buttons ) {
905 $product_id_for_add_to_cart = $product->ID;
906 if( $product_obj->is_type( 'variable' ) ){
907 $variations = $product_obj->get_available_variations();
908 $variations_id = wp_list_pluck( $variations, 'variation_id' );
909 if( ! empty( $variations_id ) ) $product_id_for_add_to_cart = $variations_id[0];
910 } elseif ( $product_obj->is_type( 'grouped' ) ) {
911 $children = $product_obj->get_children();
912 if( ! empty( $children ) ) $product_id_for_add_to_cart = $children[0];
913 }
914
915 $output .= '<div class="wcmp-widget-product-purchase">
916 ' . wc_price( $product_obj->get_price(), '' ) . ' <a href="?add-to-cart=' . $product_id_for_add_to_cart . '"></a>
917 </div><!-- product purchase -->
918 ';
919 }
920 $output .= '</div>
921 <div class="wcmp-widget-product-files">
922 ';
923
924 if ( ! empty( $featured_image ) ) {
925 $output .= '<img src="' . esc_attr( $featured_image ) . '" class="wcmp-widget-feature-image" /><div class="wcmp-widget-product-files-list">';
926 }
927
928 foreach ( $audio_files as $index => $file ) {
929 $audio_url = $this->generate_audio_url( $product->ID, $index, $file );
930 $duration = $this->_get_duration_by_url( $file['file'] );
931 $audio_tag = apply_filters(
932 'wcmp_widget_audio_tag',
933 $this->get_player(
934 $audio_url,
935 array(
936 'player_controls' => $controls,
937 'player_style' => $player_style,
938 'media_type' => $file['media_type'],
939 'id' => $index,
940 'duration' => $duration,
941 'preload' => $preload,
942 'volume' => $volume,
943 )
944 ),
945 $product->ID,
946 $index,
947 $audio_url
948 );
949 $file_title = esc_html( apply_filters( 'wcmp_widget_file_name', $file['name'], $product->ID, $index ) );
950 $output .= '
951 <div class="wcmp-widget-product-file">
952 ' . $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>
953 </div><!--product file -->
954 ';
955 }
956
957 if ( ! empty( $featured_image ) ) {
958 $output .= '</div>';
959 }
960
961 $output .= '
962 </div><!-- product-files -->
963 </div><!-- product -->
964 ';
965 } else // Load the previous playlist layout
966 {
967 $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' : '' ) . '">';
968
969 if ( ! empty( $featured_image ) ) {
970 $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>';
971 }
972
973 foreach ( $audio_files as $index => $file ) {
974 $audio_url = $this->generate_audio_url( $product->ID, $index, $file );
975 $duration = $this->_get_duration_by_url( $file['file'] );
976 $audio_tag = apply_filters(
977 'wcmp_widget_audio_tag',
978 $this->get_player(
979 $audio_url,
980 array(
981 'player_controls' => $controls,
982 'player_style' => $player_style,
983 'media_type' => $file['media_type'],
984 'id' => $index,
985 'duration' => $duration,
986 'preload' => $preload,
987 'volume' => $volume,
988 )
989 ),
990 $product->ID,
991 $index,
992 $audio_url
993 );
994 $file_title = esc_html( apply_filters( 'wcmp_widget_file_name', ( ( ! empty( $file['name'] ) ) ? $file['name'] : $product->post_title ), $product->ID, $index ) );
995
996 $output .= '<li class="wcmp-widget-playlist-item">' . $audio_tag . '<a href="' . esc_url( get_permalink( $product->ID ) ) . '">' . $file_title . '</a>' .
997 (
998 $purchased_times ?
999 '<span class="wcmp-purchased-times">' .
1000 sprintf(
1001 /* translators: %d: purchased times */
1002 __( $this->get_global_attr( '_wcmp_purchased_times_text', '- purchased %d time(s)' ), 'music-player-for-woocommerce' ), // phpcs:ignore WordPress.WP.I18n.NonSingularStringLiteralText
1003 $get_times( $product->ID, $product_purchased_times )
1004 ) . '</span>' : ''
1005 )
1006 . ( ! isset( $atts['duration'] ) || $atts['duration'] == 1 ? '<span class="wcmp-file-duration">' . esc_html( $duration ) . '</span>' : '' )
1007 . '<div style="clear:both;"/></li>';
1008 }
1009 if ( ! empty( $featured_image ) ) {
1010 $output .= '</ul></div></li>';
1011 }
1012
1013 $output .= $download_links; // Download links
1014
1015 $output .= '</ul>';
1016 }
1017 }
1018 $output .= '</div>';
1019 }
1020 return $output;
1021 } // End replace_playlist_shortcode
1022
1023 /**
1024 * Used for accepting the <source> tags
1025 */
1026 public function allowed_html_tags( $allowedposttags, $context ) {
1027 if ( ! in_array( 'source', $allowedposttags ) ) {
1028 $allowedposttags['source'] = array(
1029 'src' => true,
1030 'type' => true,
1031 );
1032 }
1033 return $allowedposttags;
1034 } // End allowed_html_tags
1035
1036 public function preload( $preload, $audio_url ) {
1037 $result = $preload;
1038 if ( strpos( $audio_url, 'wcmp-action=play' ) !== false ) {
1039 if ( $this->_preload_times ) {
1040 $result = 'none';
1041 }
1042 $this->_preload_times++;
1043 }
1044 return $result;
1045 } // End preload
1046
1047 // ******************** WOOCOMMERCE ACTIONS ************************
1048
1049 public function woocommerce_user_download( $product_id ) {
1050 $download_links = '';
1051 if ( is_user_logged_in() ) {
1052 if ( empty( $this->_current_user_downloads ) && function_exists( 'wc_get_customer_available_downloads' ) ) {
1053 $current_user = wp_get_current_user();
1054 $this->_current_user_downloads = wc_get_customer_available_downloads( $current_user->ID );
1055 }
1056 foreach ( $this->_current_user_downloads as $download ) {
1057 if ( $download['product_id'] == $product_id ) {
1058 $download_links = '<a href="' . $download['download_url'] . '" target="_blank" class="wcmp-download-link">' . esc_html__( 'download', 'music-player-for-woocommerce' ) . '</a>';
1059 break;
1060 }
1061 }
1062 }
1063
1064 return $download_links;
1065
1066 }
1067
1068 public function woocommerce_product_title( $title, $product ) {
1069 global $wp;
1070 if ( ! empty( $wp->query_vars['wcfm-products-manage'] )) {
1071 return $title;
1072 }
1073 $player = '';
1074 if ( false === stripos( $title, '<audio' ) ) {
1075 $player .= $this->include_main_player( $product, false );
1076 }
1077 return $player . $title;
1078 } // End woocommerce_product_title
1079
1080 /**
1081 * Load the additional attributes to select the player layout
1082 */
1083 public function woocommerce_player_settings() {
1084 include_once 'views/player_options.php';
1085 } // End woocommerce_player_settings
1086
1087 public function get_player(
1088 $audio_url,
1089 $args = array()
1090 ) {
1091 $default_args = array(
1092 'media_type' => 'mp3',
1093 'player_style' => WCMP_DEFAULT_PLAYER_LAYOUT,
1094 'player_controls' => WCMP_DEFAULT_PLAYER_CONTROLS,
1095 'duration' => false,
1096 'volume' => 1,
1097 );
1098
1099 $args = array_merge( $default_args, $args );
1100 $id = ( ! empty( $args['id'] ) ) ? 'id="' . esc_attr( $args['id'] ) . '"' : '';
1101
1102 $preload = ( ! empty( $args['preload'] ) ) ? $args['preload'] : $GLOBALS['WooCommerceMusicPlayer']->get_global_attr(
1103 '_wcmp_preload',
1104 // This option is only for compatibility with versions previous to 1.0.28
1105 $GLOBALS['WooCommerceMusicPlayer']->get_global_attr( 'preload', 'none' )
1106 );
1107 $preload = apply_filters( 'wcmp_preload', $preload, $audio_url );
1108
1109 return '<audio ' . (
1110 (
1111 isset( $args['volume'] ) &&
1112 is_numeric( $args['volume'] ) &&
1113 0 <= $args['volume'] * 1 &&
1114 $args['volume'] * 1 <= 1
1115 ) ? 'volume="' . esc_attr( $args['volume'] ) . '"' : ''
1116 ) . ' ' . $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>';
1117
1118 } // End get_player
1119
1120 public function get_product_files( $id ) {
1121 $product = wc_get_product( $id );
1122 if ( ! empty( $product ) ) {
1123 return $this->_get_product_files(
1124 array(
1125 'product' => $product,
1126 'all' => 1,
1127 )
1128 );
1129 }
1130 return array();
1131 }
1132
1133 public function generate_audio_url( $product_id, $file_id, $file_data = array() ) {
1134 return $this->_generate_audio_url( $product_id, $file_id, $file_data );
1135 }
1136
1137 public function include_main_player_filter( $value, $id ) {
1138 global $wp;
1139 if (
1140 $this->_force_hook_title &&
1141 did_action('woocommerce_init') &&
1142 false === stripos( $value, '<audio' )
1143 ) {
1144 try {
1145 if (
1146 ( wp_doing_ajax() || ! is_admin() ) &&
1147 (
1148 ! function_exists( 'is_product' ) ||
1149 ! is_product() ||
1150 ( is_product() && get_queried_object_id() != $id )
1151 ) &&
1152 ! is_cart() &&
1153 ! is_page( 'cart' ) &&
1154 ! is_checkout() &&
1155 is_int( $id ) &&
1156 empty( $_REQUEST['wcmp_nonce'] ) &&
1157 empty( $wp->query_vars['wcfm-products-manage'] )
1158 ) {
1159 $p = wc_get_product( $id );
1160 if ( ! empty( $p ) ) {
1161 add_filter( 'esc_html', array( &$this, 'esc_html' ), 10, 2 );
1162
1163 $player = '';
1164 $player = $this->include_main_player( $p, false );
1165 $value = $player . $value;
1166 }
1167 }
1168 } catch ( Exception $err ) {
1169 error_log( $err->getMessage() );
1170 }
1171 }
1172 return $value;
1173 }
1174
1175 public function include_players( ...$args ) {
1176 if ( ! $this->_inserted_player ) {
1177 $this->_inserted_player = true;
1178 if ( ! empty( $args ) ) {
1179 $this->include_all_players( $args[0] );
1180 } else {
1181 $this->include_all_players();
1182 }
1183 }
1184
1185 if ( ! empty( $args ) ) {
1186 return $args[0];
1187 }
1188 } // End include_players
1189
1190 public function include_main_player( $product = '', $_echo = true ) {
1191 $output = '';
1192
1193 if ( is_admin() ) return $output;
1194
1195 if ( ! $this->_insert_player || ! $this->_insert_main_player ) {
1196 return $output;
1197 }
1198 if ( is_numeric( $product ) ) {
1199 $product = wc_get_product( $product );
1200 }
1201 if ( ! is_object( $product ) ) {
1202 $product = wc_get_product();
1203 }
1204
1205 if ( empty( $product ) ) {
1206 return '';
1207 }
1208
1209 $files = $this->_get_product_files(
1210 array(
1211 'product' => $product,
1212 'first' => true,
1213 )
1214 );
1215 if ( ! empty( $files ) ) {
1216 $id = $product->get_id();
1217
1218 $show_in = $this->get_product_attr( $id, '_wcmp_show_in', 'all' );
1219 if (
1220 ( 'single' == $show_in && ( ! function_exists( 'is_product' ) || ! is_product() ) ) ||
1221 ( 'multiple' == $show_in && ( function_exists( 'is_product' ) && is_product() ) && get_queried_object_id() == $id )
1222 ) {
1223 return $output;
1224 }
1225 $preload = $this->get_product_attr( $id, '_wcmp_preload', '' );
1226 $this->enqueue_resources();
1227
1228 $player_style = $this->get_product_attr( $id, '_wcmp_player_layout', WCMP_DEFAULT_PLAYER_LAYOUT );
1229 $player_controls = ( $this->get_product_attr( $id, '_wcmp_player_controls', WCMP_DEFAULT_PLAYER_CONTROLS ) != 'all' ) ? 'track' : '';
1230 $volume = @floatval( $this->get_product_attr( $id, '_wcmp_player_volume', WCMP_DEFAULT_PLAYER_VOLUME ) );
1231
1232 $file = reset( $files );
1233 $index = key( $files );
1234 $audio_url = $this->_generate_audio_url( $id, $index, $file );
1235 $duration = $this->_get_duration_by_url( $file['file'] );
1236 $audio_tag = apply_filters(
1237 'wcmp_audio_tag',
1238 $this->get_player(
1239 $audio_url,
1240 array(
1241 'player_controls' => $player_controls,
1242 'player_style' => $player_style,
1243 'media_type' => $file['media_type'],
1244 'duration' => $duration,
1245 'preload' => $preload,
1246 'volume' => $volume,
1247 )
1248 ),
1249 $id,
1250 $index,
1251 $audio_url
1252 );
1253
1254 do_action( 'wcmp_before_player_shop_page', $id );
1255
1256 $output = '<div class="wcmp-player-container product-' . esc_attr( $file['product'] ) . '">' . $audio_tag . '</div>';
1257 if ( $_echo ) {
1258 print $output; // phpcs:ignore WordPress.Security.EscapeOutput
1259 }
1260
1261 do_action( 'wcmp_after_player_shop_page', $id );
1262
1263 return $output; // phpcs:ignore WordPress.Security.EscapeOutput
1264 }
1265 } // End include_main_player
1266
1267 public function include_all_players( $product = '' ) {
1268
1269 if ( ! $this->_insert_player || ! $this->_insert_all_players || is_admin() ) {
1270 return;
1271 }
1272
1273 if ( ! is_object( $product ) ) {
1274 $product = wc_get_product();
1275 }
1276
1277 if ( empty( $product ) ) {
1278 return;
1279 }
1280
1281 $files = $this->_get_product_files(
1282 array(
1283 'product' => $product,
1284 'all' => true,
1285 )
1286 );
1287 if ( ! empty( $files ) ) {
1288 $id = $product->get_id();
1289
1290 $show_in = $this->get_product_attr( $id, '_wcmp_show_in', 'all' );
1291 if (
1292 ( 'single' == $show_in && ! is_singular() ) ||
1293 ( 'multiple' == $show_in && is_singular() )
1294 ) {
1295 return;
1296 }
1297 $preload = $this->get_product_attr( $id, '_wcmp_preload', '' );
1298 $this->enqueue_resources();
1299 $player_style = $this->get_product_attr( $id, '_wcmp_player_layout', WCMP_DEFAULT_PLAYER_LAYOUT );
1300 $volume = @floatval( $this->get_product_attr( $id, '_wcmp_player_volume', WCMP_DEFAULT_PLAYER_VOLUME ) );
1301 $player_controls = $this->get_product_attr( $id, '_wcmp_player_controls', WCMP_DEFAULT_PLAYER_CONTROLS );
1302 $player_title = intval( $this->get_product_attr( $id, '_wcmp_player_title', WCMP_DEFAULT_PlAYER_TITLE ) );
1303 $loop = intval( $this->get_product_attr( $id, '_wcmp_loop', 0 ) );
1304 $merge_grouped = intval( $this->get_product_attr( $id, '_wcmp_merge_in_grouped', 0 ) );
1305 $merge_grouped_clss = ( $merge_grouped ) ? 'merge_in_grouped_products' : '';
1306
1307 $counter = count( $files );
1308
1309 do_action( 'wcmp_before_players_product_page', $id );
1310 if ( 1 == $counter ) {
1311 $player_controls = ( 'button' == $player_controls ) ? 'track' : '';
1312 $file = reset( $files );
1313 $index = key( $files );
1314 $audio_url = $this->_generate_audio_url( $id, $index, $file );
1315 $duration = $this->_get_duration_by_url( $file['file'] );
1316 $audio_tag = apply_filters(
1317 'wcmp_audio_tag',
1318 $this->get_player(
1319 $audio_url,
1320 array(
1321 'player_controls' => $player_controls,
1322 'player_style' => $player_style,
1323 'media_type' => $file['media_type'],
1324 'duration' => $duration,
1325 'preload' => $preload,
1326 'volume' => $volume,
1327 )
1328 ),
1329 $id,
1330 $index,
1331 $audio_url
1332 );
1333 $title = esc_html( ( $player_title ) ? apply_filters( 'wcmp_file_name', $file['name'], $id, $index ) : '' );
1334 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
1335 } elseif ( $counter > 1 ) {
1336
1337 $single_player = intval( $this->get_product_attr( $id, '_wcmp_single_player', WCMP_DEFAULT_SINGLE_PLAYER ) );
1338
1339 $before = '<table class="wcmp-player-list ' . $merge_grouped_clss . ( $single_player ? ' wcmp-single-player ' : '' ) . '" ' . ( $loop ? 'data-loop="1"' : '' ) . '>';
1340 $first_player_class = 'wcmp-first-player';
1341 $after = '';
1342 foreach ( $files as $index => $file ) {
1343 $evenOdd = ( 1 == $counter % 2 ) ? 'wcmp-odd-row' : 'wcmp-even-row';
1344 $counter--;
1345 $audio_url = $this->_generate_audio_url( $id, $index, $file );
1346 $duration = $this->_get_duration_by_url( $file['file'] );
1347 $audio_tag = apply_filters(
1348 'wcmp_audio_tag',
1349 $this->get_player(
1350 $audio_url,
1351 array(
1352 'player_style' => $player_style,
1353 'player_controls' => ( 'all' != $player_controls ) ? 'track' : '',
1354 'media_type' => $file['media_type'],
1355 'duration' => $duration,
1356 'preload' => $preload,
1357 'volume' => $volume,
1358 )
1359 ),
1360 $id,
1361 $index,
1362 $audio_url
1363 );
1364 $title = esc_html( ( $player_title ) ? apply_filters( 'wcmp_file_name', $file['name'], $id, $index ) : '' );
1365
1366 print $before; // phpcs:ignore WordPress.Security.EscapeOutput
1367 $before = '';
1368 $after = '</table>';
1369 if ( 'all' != $player_controls ) {
1370 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
1371 } else {
1372 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
1373 }
1374 $first_player_class = '';
1375 }
1376 print $after; // phpcs:ignore WordPress.Security.EscapeOutput
1377 }
1378 do_action( 'wcmp_after_players_product_page', $id );
1379 }
1380 } // End include_all_players
1381
1382 public function player_in_cart( $cart_item, $cart_item_key ) {
1383 $product = wc_get_product( $cart_item['product_id'] );
1384 $this->include_all_players( $product );
1385 } // player_in_cart
1386
1387 // Integration with woocommerce-product-table by barn2media
1388 public function product_table_data_name( $name, $product ) {
1389 if ( false === stripos( $name, '<audio' ) ) {
1390 $player = $this->include_main_player( $product, false );
1391 $player = str_replace( '<div ', '<div style="display:inline-block" ', $player );
1392 $name = $player . $name;
1393 }
1394 return $name;
1395 } // product_table_data_name
1396
1397 public function add_data_product( $player, $product_id, $index, $url ) {
1398 $player = preg_replace( '/<audio\b/i', '<audio controlslist="nodownload" data-product="' . esc_attr( $product_id ) . '" ', $player );
1399 return $player;
1400 } // End add_data_product
1401
1402 public function add_class_attachment( $html, $product, $size, $attr, $placeholder, $image ) {
1403 $id = $product->get_id();
1404 $html = $this->_add_class( $html, $product );
1405 return $html;
1406 } // End add_class_attachment
1407
1408 public function add_class_single_product_image( $html, $post_thumbnail_id ) {
1409 global $product;
1410
1411 if ( ! empty( $product ) ) {
1412 $html = $this->_add_class( $html, $product );
1413 }
1414 return $html;
1415 } // add_class_single_product_image
1416
1417 public function init_force_in_title( $v = null ) {
1418 if ( is_admin() ) {
1419 $this->_force_hook_title = 0;
1420 return;
1421 }
1422
1423 if ( is_numeric( $v ) ) {
1424 $this->_force_hook_title = intval( $v );
1425 return;
1426 }
1427
1428 $this->_force_hook_title = $this->get_global_attr( '_wcmp_main_player_hook_title', 1 );
1429
1430 // Integration with "WOOF – Products Filter for WooCommerce" by realmag777
1431 if ( isset( $_REQUEST['action'] ) && 'woof_draw_products' == $_REQUEST['action'] ) {
1432 $this->_force_hook_title = 1;
1433 }
1434
1435 } // End init_force_in_title
1436
1437 // ******************** PRIVATE METHODS ************************
1438
1439 private function get_ip_address() {
1440 if( ! empty( $_SERVER['HTTP_CLIENT_IP'] ) ) { //whether ip is from the share internet
1441 $ip = $_SERVER['HTTP_CLIENT_IP'];
1442 } elseif (! empty( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) { //whether ip is from the proxy
1443 $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
1444 } else{ //whether ip is from the remote address
1445 $ip = $_SERVER['REMOTE_ADDR'];
1446 }
1447 return $ip;
1448 } // End update_playback_counter
1449
1450 private function clear_expired_transients() {
1451 $transient = get_transient( 'wcmp_clear_expired_transients' );
1452 if( ! $transient || 24 * 60 * 60 <= time() - intval( $transient ) ) {
1453 set_transient( 'wcmp_clear_expired_transients', time() );
1454 delete_expired_transients();
1455 }
1456 } // End clear_expired_transients
1457
1458 private function update_playback_counter( $product_id ) {
1459
1460 $ip = $this->get_ip_address();
1461 $transient_name = 'wcmp-playback-record-' . md5( $ip ) . '-' . $product_id;
1462 $transient = get_transient( $transient_name );
1463 if ( ! get_transient( $transient_name ) ) {
1464 set_transient( $transient_name, 1, 12 * 60 * 60 );
1465
1466 $counter = get_post_meta( $product_id, '_wcmp_playback_counter', true );
1467
1468 if ( is_numeric( $counter ) ) $counter = intval( $counter );
1469 else $counter = 0;
1470
1471 $counter++;
1472 update_post_meta( $product_id, '_wcmp_playback_counter', $counter );
1473 }
1474 } // End update_playback_counter
1475
1476 private function _get_post_types( $mysql_in = false ) {
1477 $post_types = array( 'product' );
1478 if ( ! empty( $GLOBALS['wcmp_post_types'] ) && is_array( $GLOBALS['wcmp_post_types'] ) ) {
1479 $post_types = $GLOBALS['wcmp_post_types'];
1480 }
1481 if ( $mysql_in ) {
1482 return '"' . implode( '","', $post_types ) . '"';
1483 }
1484 return $post_types;
1485 } // End _get_post_types
1486
1487 private function _load_addons() {
1488 $path = __DIR__ . '/addons';
1489 $wcmp = $this;
1490
1491 if ( file_exists( $path ) ) {
1492 $addons = dir( $path );
1493 while ( false !== ( $entry = $addons->read() ) ) {
1494 if ( strlen( $entry ) > 3 && strtolower( pathinfo( $entry, PATHINFO_EXTENSION ) ) == 'php' ) {
1495 include_once $addons->path . '/' . $entry;
1496 }
1497 }
1498 }
1499 } // End _load_addons
1500
1501 private function _preview() {
1502 $user = wp_get_current_user();
1503 $allowed_roles = array( 'editor', 'administrator', 'author' );
1504
1505 if ( array_intersect( $allowed_roles, $user->roles ) ) {
1506 if ( ! empty( $_REQUEST['wcmp-preview'] ) ) {
1507 // Sanitizing variable
1508 $preview = sanitize_text_field( wp_unslash( $_REQUEST['wcmp-preview'] ) );
1509
1510 // Remove every shortcode that is not in the plugin
1511 remove_all_shortcodes();
1512 add_shortcode( 'wcmp-playlist', array( &$this, 'replace_playlist_shortcode' ) );
1513
1514 if ( has_shortcode( $preview, 'wcmp-playlist' ) ) {
1515 print '<!DOCTYPE html>';
1516 $if_empty = __( 'There are no products that satisfy the block\'s settings', 'music-player-for-woocommerce' );
1517 wp_enqueue_script( 'jquery' );
1518 $output = do_shortcode( $preview );
1519 if ( preg_match( '/^\s*$/', $output ) ) {
1520 $output = '<div>' . $if_empty . '</div>';
1521 }
1522
1523 // Deregister all scripts and styles for loading only the plugin styles.
1524 global $wp_styles, $wp_scripts;
1525 if ( ! empty( $wp_scripts ) ) {
1526 $wp_scripts->reset();
1527 }
1528 $this->enqueue_resources();
1529 if ( ! empty( $wp_styles ) ) {
1530 $wp_styles->do_items();
1531 }
1532 if ( ! empty( $wp_scripts ) ) {
1533 $wp_scripts->do_items();
1534 }
1535
1536 print '<div class="wcmp-preview-container">' . $output . '</div>'; // phpcs:ignore WordPress.Security.EscapeOutput
1537 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>';
1538 exit;
1539 }
1540 }
1541 }
1542 } // End _preview
1543
1544 private function _createDir() {
1545 // Generate upload dir
1546 $_files_directory = wp_upload_dir();
1547 $this->_files_directory_path = rtrim( $_files_directory['basedir'], '/' ) . '/wcmp/';
1548 $this->_files_directory_url = rtrim( $_files_directory['baseurl'], '/' ) . '/wcmp/';
1549 $this->_files_directory_url = preg_replace( '/^http(s)?:\/\//', '//', $this->_files_directory_url );
1550 if ( ! file_exists( $this->_files_directory_path ) ) {
1551 @mkdir( $this->_files_directory_path, 0755 );
1552 }
1553 } // End _createDir
1554
1555 private function _clearDir( $dirPath ) {
1556 try {
1557 if ( empty( $dirPath ) || ! file_exists( $dirPath ) || ! is_dir( $dirPath ) ) {
1558 return;
1559 }
1560 $dirPath = rtrim( $dirPath, '\\/' ) . '/';
1561 $files = glob( $dirPath . '*', GLOB_MARK );
1562 foreach ( $files as $file ) {
1563 if ( is_dir( $file ) ) {
1564 $this->_clearDir( $file );
1565 } else {
1566 unlink( $file );
1567 }
1568 }
1569 } catch ( Exception $err ) {
1570 return;
1571 }
1572 } // End _clearDir
1573
1574 private function _get_duration_by_url( $url ) {
1575 global $wpdb;
1576 try {
1577 $attachment = $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE guid RLIKE %s;", $url ) );
1578 if ( empty( $attachment ) ) {
1579 $uploads_dir = wp_upload_dir();
1580 $uploads_url = $uploads_dir['baseurl'];
1581 $parsed_url = explode( parse_url( $uploads_url, PHP_URL_PATH ), $url );
1582 $this_host = str_ireplace( 'www.', '', parse_url( home_url(), PHP_URL_HOST ) );
1583 $file_host = str_ireplace( 'www.', '', parse_url( $url, PHP_URL_HOST ) );
1584 if ( ! isset( $parsed_url[1] ) || empty( $parsed_url[1] ) || ( $this_host != $file_host ) ) {
1585 return false;
1586 }
1587 $file = trim( $parsed_url[1], '/' );
1588 $attachment = $wpdb->get_col( $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta WHERE meta_key='_wp_attached_file' AND meta_value RLIKE %s;", $file ) );
1589 }
1590 if ( ! empty( $attachment ) && ! empty( $attachment[0] ) ) {
1591 $metadata = wp_get_attachment_metadata( $attachment[0] );
1592 if ( false !== $metadata && ! empty( $metadata['length_formatted'] ) ) {
1593 return $metadata['length_formatted'];
1594 }
1595 }
1596 } catch ( Exception $err ) {
1597 error_log( $err->getMessage() );
1598 }
1599 return false;
1600 } // End _get_duration_by_url
1601
1602 private function _generate_audio_url( $product_id, $file_index, $file_data = array() ) {
1603 if ( ! empty( $file_data['file'] ) ) {
1604 $file_url = $file_data['file'];
1605 if ( ! empty( $file_data['play_src'] ) || $this->_is_playlist( $file_url ) ) {
1606 return $file_url; // Play src audio file, without copying or truncate it.
1607 }
1608
1609 // If the playback of music are tracked with Google Analytics, should not be loaded directly the audio files.
1610 $_wcmp_analytics_property = trim( $this->get_global_attr( '_wcmp_analytics_property', '' ) );
1611 if ( '' == $_wcmp_analytics_property ) {
1612 $file_name = $this->_demo_file_name( $file_url );
1613
1614 $file_path = $this->_files_directory_path . $file_name;
1615
1616 if ( $this->_valid_demo( $file_path ) ) {
1617 return 'http' . ( ( is_ssl() ) ? 's:' : ':' ) . $this->_files_directory_url . $file_name;
1618 }
1619 }
1620 }
1621 $url = WCMP_WEBSITE_URL; //isset( $_SERVER['REQUEST_URI'] ) ? esc_url_raw( wp_unslash( $_SERVER['REQUEST_URI'] ) ) : '';
1622 $url .= ( ( strpos( $url, '?' ) === false ) ? '?' : '&' ) . 'wcmp-action=play&wcmp-product=' . $product_id . '&wcmp-file=' . $file_index;
1623 return $url;
1624 } // End _generate_audio_url
1625
1626 private function _delete_truncated_files( $product_id ) {
1627 $files_arr = get_post_meta( $product_id, '_downloadable_files', true );
1628 if ( ! empty( $files_arr ) && is_array( $files_arr ) ) {
1629 foreach ( $files_arr as $file ) {
1630 if ( is_array( $file ) && ! empty( $file['file'] ) ) {
1631 $ext = pathinfo( $file['file'], PATHINFO_EXTENSION );
1632 $file_name = md5( $file['file'] ) . ( ( ! empty( $ext ) ) ? '.' . $ext : '' );
1633 if ( file_exists( $this->_files_directory_path . $file_name ) ) {
1634 @unlink( $this->_files_directory_path . $file_name );
1635 }
1636 }
1637 }
1638 }
1639
1640 } // End _delete_truncated_files
1641
1642 /**
1643 * Check if the file is an m3u or m3u8 playlist
1644 */
1645 private function _is_playlist( $file_path ) {
1646 return preg_match( '/\.(m3u|m3u8)$/i', $file_path );
1647 } // End _is_playlist
1648
1649 /**
1650 * Check if the file is an audio file and return its type or false
1651 */
1652 private function _is_audio( $file_path ) {
1653 if ( preg_match( '/\.(mp3|ogg|oga|wav|wma|mp4)$/i', $file_path, $match ) ) {
1654 return $match[1];
1655 }
1656 if ( preg_match( '/\.m4a$/i', $file_path ) ) {
1657 return 'mp4';
1658 }
1659 if ( $this->_is_playlist( $file_path ) ) {
1660 return 'hls';
1661 }
1662
1663 // From troubleshoot
1664 $extension = pathinfo( $file_path, PATHINFO_EXTENSION );
1665 $troubleshoot_default_extension = $GLOBALS['WooCommerceMusicPlayer']->get_global_attr( '_wcmp_default_extension', false );
1666 if ( ( empty( $extension ) || ! preg_match( '/^[a-z\d]{3,4}$/i', $extension ) ) && $troubleshoot_default_extension ) {
1667 return 'mp3';
1668 }
1669
1670 return false;
1671 } // End _is_audio
1672
1673 private function _sort_list( $product_a, $product_b ) {
1674 if (
1675 ! is_object( $product_a ) || ! method_exists( $product_a, 'get_menu_order' ) ||
1676 ! is_object( $product_b ) || ! method_exists( $product_b, 'get_menu_order' )
1677 ) {
1678 return 0;
1679 }
1680
1681 $menu_order_a = $product_a->get_menu_order();
1682 $menu_order_b = $product_b->get_menu_order();
1683 if ( $menu_order_a == $menu_order_b ) {
1684 if (
1685 ! method_exists( $product_a, 'get_name' ) ||
1686 ! method_exists( $product_b, 'get_name' )
1687 ) {
1688 return 0;
1689 }
1690
1691 $name_a = $product_a->get_name();
1692 $name_b = $product_b->get_name();
1693 if ( $name_a == $name_b ) {
1694 return 0;
1695 }
1696 return ( $name_a < $name_b ) ? -1 : 1;
1697 }
1698 return ( $menu_order_a < $menu_order_b ) ? -1 : 1;
1699 } // End _sort_list
1700
1701 private function _edit_files_array( $product_id, $files, $play_src = 0 ) {
1702 $p_files = array();
1703 foreach ( $files as $key => $file ) {
1704 $p_key = $key . '_' . $product_id;
1705 if ( gettype( $file ) == 'object' ) {
1706 $file = (array) $file->get_data();
1707 }
1708 $file['product'] = $product_id;
1709 $file['play_src'] = $play_src;
1710 $p_files[ $p_key ] = $file;
1711 }
1712 return $p_files;
1713 } // end _edit_files_array
1714
1715 private function _get_recursive_product_files( $product, $files_arr ) {
1716 if ( ! is_object( $product ) || ! method_exists( $product, 'get_type' ) ) {
1717 return $files_arr;
1718 }
1719
1720 $product_type = $product->get_type();
1721 $id = $product->get_id();
1722
1723 if ( 'variation' == $product_type ) {
1724 // $_files = $product->get_files();
1725 $_files = $product->get_downloads();
1726 $_files = $this->_edit_files_array( $id, $_files );
1727 $files_arr = array_merge( $files_arr, $_files );
1728 } else {
1729
1730 if ( ! $this->get_product_attr( $id, '_wcmp_enable_player', false ) ) {
1731 return $files_arr;
1732 }
1733
1734 switch ( $product_type ) {
1735 case 'variable':
1736 case 'grouped':
1737 $children = $product->get_children();
1738
1739 foreach ( $children as $key => $child_id ) {
1740 $children[ $key ] = wc_get_product( $child_id );
1741 }
1742
1743 uasort( $children, array( &$this, '_sort_list' ) );
1744
1745 foreach ( $children as $child_obj ) {
1746 $files_arr = $this->_get_recursive_product_files( $child_obj, $files_arr );
1747 }
1748 break;
1749 default:
1750 $_files = $product->get_downloads();
1751 $_files = $this->_edit_files_array( $id, $_files );
1752 $files_arr = array_merge( $files_arr, $_files );
1753 break;
1754 }
1755 }
1756 return $files_arr;
1757 } // End _get_recursive_product_files
1758
1759 private function _get_product_files( $args ) {
1760 if ( empty( $args['product'] ) ) {
1761 return false;
1762 }
1763
1764 $product = $args['product'];
1765 $files = $this->_get_recursive_product_files( $product, array() );
1766
1767 if ( empty( $files ) ) {
1768 return false;
1769 }
1770
1771 $audio_files = array();
1772 foreach ( $files as $index => $file ) {
1773 if ( ! empty( $file['file'] ) && false !== ( $media_type = $this->_is_audio( $file['file'] ) ) ) { // phpcs:ignore Squiz.PHP.DisallowMultipleAssignments
1774 $file['media_type'] = $media_type;
1775
1776 if ( ! empty( $args['file_id'] ) ) {
1777 if ( $args['file_id'] == $index ) {
1778 $audio_files[ $index ] = $file;
1779 return $audio_files;
1780 }
1781 } elseif ( ! empty( $args['first'] ) ) {
1782 $audio_files[ $index ] = $file;
1783 return $audio_files;
1784 } elseif ( ! empty( $args['all'] ) ) {
1785 $audio_files[ $index ] = $file;
1786 }
1787 }
1788 }
1789
1790 return $audio_files;
1791 } // End _get_product_files
1792
1793 private function _demo_file_name( $url ) {
1794 $file_extension = pathinfo( $url, PATHINFO_EXTENSION );
1795 $file_name = md5( $url ) . ( ( ! empty( $file_extension ) && preg_match( '/^[a-z\d]{3,4}$/i', $file_extension ) ) ? '.' . $file_extension : '.mp3' );
1796 return $file_name;
1797 } // End _demo_file_name
1798
1799 private function _valid_demo( $file_path ) {
1800 if ( ! file_exists( $file_path ) || filesize( $file_path ) == 0 ) {
1801 return false;
1802 }
1803 if ( function_exists( 'finfo_open' ) ) {
1804 $finfo = finfo_open( FILEINFO_MIME );
1805 return substr( finfo_file( $finfo, $file_path ), 0, 4 ) !== 'text';
1806 }
1807 return true;
1808 } // End _valid_demo
1809
1810 /**
1811 * Create a temporal file and redirect to the new file
1812 */
1813 private function _output_file( $args ) {
1814 if ( empty( $args['url'] ) ) {
1815 return;
1816 }
1817 $url = $args['url'];
1818 $url = do_shortcode( $url );
1819
1820 if ( file_exists( $url ) ) {
1821 $url_fixed = $url;
1822 } elseif ( strpos( $url, '//' ) === 0 ) {
1823 $url_fixed = 'http' . ( is_ssl() ? 's:' : ':' ) . $url;
1824 } elseif ( strpos( $url, '/' ) === 0 ) {
1825 $url_fixed = rtrim( WCMP_WEBSITE_URL, '/' ) . $url;
1826 } else {
1827 $url_fixed = $url;
1828 }
1829
1830 $file_name = $this->_demo_file_name( $url );
1831 $text = 'The requested URL was not found on this server';
1832 $file_path = $this->_files_directory_path . $file_name;
1833
1834 if ( $this->_valid_demo( $file_path ) ) {
1835 header( 'location: http' . ( ( is_ssl() ) ? 's:' : ':' ) . $this->_files_directory_url . $file_name );
1836 exit;
1837 } else {
1838 try {
1839 $c = false;
1840 if ( ( $path = $this->_is_local( $url_fixed ) ) !== false ) { // phpcs:ignore Squiz.PHP.DisallowMultipleAssignments
1841 $c = copy( $path, $file_path );
1842 } else {
1843 $response = wp_remote_get(
1844 $url_fixed,
1845 array(
1846 'timeout' => WCMP_REMOTE_TIMEOUT,
1847 'stream' => true,
1848 'filename' => $file_path,
1849 )
1850 );
1851 if ( ! is_wp_error( $response ) && 200 == $response['response']['code'] ) {
1852 $c = true;
1853 }
1854 }
1855
1856 if ( true === $c ) {
1857
1858 if ( ! function_exists( 'mime_content_type' ) || false === ( $mime_type = mime_content_type( $file_path ) ) ) $mime_type = 'audio/mpeg';
1859
1860 if ( ! headers_sent() ) {
1861 if ( ! $this->get_global_attr( '_wcmp_disable_302', 0 ) ) {
1862 header( "location: " . $this->_files_directory_url . $file_name, true, 302 );
1863 exit;
1864 }
1865
1866 header( "Content-Type: " . $mime_type );
1867 header( "Content-length: " . filesize( $file_path ) );
1868 header( 'Content-Disposition: filename="' . $file_name . '"' );
1869 header( "Accept-Ranges: " . ( stripos( $mime_type, 'wav' ) ? 'none' : 'bytes' ) );
1870 header( "Content-Transfer-Encoding: binary" );
1871 }
1872
1873 readfile($file_path);
1874 exit;
1875 }
1876 } catch ( Exception $err ) {
1877 error_log( $err->getMessage() );
1878 }
1879 $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.';
1880 }
1881 $this->_print_page_not_found( $text );
1882 } // End _output_file
1883
1884 /**
1885 * Add the class name: product-<product id> to cover images associated to the products.
1886 *
1887 * @param $html, a html piece of code that includes the <img> tag.
1888 * @param $product, the product object.
1889 */
1890 private function _add_class( $html, $product ) {
1891 if ( preg_match( '/<img\b[^>]*>/i', $html, $image ) ) {
1892 $id = $product->get_id();
1893 if ( $GLOBALS['WooCommerceMusicPlayer']->get_product_attr( $id, '_wcmp_on_cover', 0 ) ) {
1894 if ( preg_match( '/\bclass\s*=/i', $image[0] ) ) {
1895 $tmp_image = preg_replace( '/\bclass\s*=\s*[\'"]/i', "$0product-$id ", $image[0] );
1896 } else {
1897 $tmp_image = preg_replace( '/<img\b/i', "<img $0 class=\"product-$id\" ", $image[0] );
1898 }
1899
1900 $html = str_replace( $image[0], $tmp_image, $html );
1901 }
1902 }
1903
1904 return $html;
1905 } // End _add_class
1906
1907 /**
1908 * Print not found page if file it is not accessible
1909 */
1910 private function _print_page_not_found( $text = 'The requested URL was not found on this server' ) {
1911 header( 'Status: 404 Not Found' );
1912 echo '<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
1913 <HTML><HEAD>
1914 <TITLE>404 Not Found</TITLE>
1915 </HEAD><BODY>
1916 <H1>Not Found</H1>
1917 <P>' . esc_html( $text ) . '</P>
1918 </BODY></HTML>
1919 ';
1920 } // End _print_page_not_found
1921
1922 private function _is_local( $url ) {
1923 $file_path = false;
1924 if ( file_exists( $url ) ) {
1925 $file_path = $url;
1926 }
1927
1928 if ( false === $file_path ) {
1929 $attachment_id = attachment_url_to_postid( $url );
1930 if ( $attachment_id ) {
1931 $attachment_path = get_attached_file( $attachment_id );
1932 if ( $attachment_path && file_exists( $attachment_path ) ) {
1933 $file_path = $attachment_path;
1934 }
1935 }
1936 }
1937
1938 if ( false === $file_path && defined( 'ABSPATH' ) ) {
1939 $path_component = parse_url( $url, PHP_URL_PATH );
1940 $path = rtrim( ABSPATH, '/' ) . '/' . ltrim( $path_component, '/' );
1941 if ( file_exists( $path ) ) {
1942 $file_path = $path;
1943 }
1944
1945 if ( false === $file_path ) {
1946 $site_url = get_site_url( get_current_blog_id() );
1947 $file_path = str_ireplace( $site_url . '/', ABSPATH, $url );
1948 if ( ! file_exists( $file_path ) ) {
1949 $file_path = false;
1950 }
1951 }
1952 }
1953
1954 return apply_filters( 'wcmp_is_local', $file_path, $url );
1955 } // End _is_local
1956
1957 private function _tracking_play_event( $product_id, $file_url ) {
1958 $_wcmp_analytics_integration = $this->get_global_attr( '_wcmp_analytics_integration', 'ua' );
1959 $_wcmp_analytics_property = trim( $this->get_global_attr( '_wcmp_analytics_property', '' ) );
1960 $_wcmp_analytics_api_secret = trim( $this->get_global_attr( '_wcmp_analytics_api_secret', '' ) );
1961 if ( ! empty( $_wcmp_analytics_property ) ) {
1962 $cid = isset( $_SERVER['REMOTE_ADDR'] ) ? sanitize_text_field( wp_unslash( $_SERVER['REMOTE_ADDR'] ) ) : 555;
1963 try {
1964 if ( isset( $_COOKIE['_ga'] ) ) {
1965 $cid_parts = explode( '.', sanitize_text_field( wp_unslash( $_COOKIE['_ga'] ) ), 3 );
1966 $cid = $cid_parts[2];
1967 }
1968 } catch ( Exception $err ) {
1969 error_log( $err->getMessage() );
1970 }
1971
1972 if ( 'ua' == $_wcmp_analytics_integration ) {
1973 $_response = wp_remote_post(
1974 'http://www.google-analytics.com/collect',
1975 array(
1976 'body' => array(
1977 'v' => 1,
1978 'tid' => $_wcmp_analytics_property,
1979 'cid' => $cid,
1980 't' => 'event',
1981 'ec' => 'Music Player for WooCommerce',
1982 'ea' => 'play',
1983 'el' => $file_url,
1984 'ev' => $product_id,
1985 ),
1986 )
1987 );
1988 } else {
1989 $_response = wp_remote_post(
1990 'https://www.google-analytics.com/mp/collect?api_secret=' . $_wcmp_analytics_api_secret . '&measurement_id=' . $_wcmp_analytics_property,
1991 array(
1992 'sslverify' => true,
1993 'headers' => array(
1994 'Content-Type' => 'application/json',
1995 ),
1996 'body' => json_encode(
1997 array(
1998 'client_id' => $cid,
1999 'events' => array(
2000 array(
2001 'name' => 'play',
2002 'params' => array(
2003 'event_category' => 'Music Player for WooCommerce',
2004 'event_label' => $file_url,
2005 'event_value' => $product_id,
2006 ),
2007 ),
2008 ),
2009 )
2010 ),
2011 )
2012 );
2013 }
2014
2015 if ( is_wp_error( $_response ) ) {
2016 error_log( $_response->get_error_message() );
2017 }
2018 }
2019 } // _tracking_play_event
2020
2021 public static function troubleshoot( $option ) {
2022 if ( ! is_admin() ) {
2023 // Solves a conflict caused by the "Speed Booster Pack" plugin
2024 if ( is_array( $option ) && isset( $option['jquery_to_footer'] ) ) {
2025 unset( $option['jquery_to_footer'] );
2026 }
2027 }
2028 return $option;
2029 } // End troubleshoot
2030 } // End Class WooCommerceMusicPlayer
2031
2032 $GLOBALS['WooCommerceMusicPlayer'] = new WooCommerceMusicPlayer();
2033 }
2034