PluginProbe
PowerPress Podcasting plugin by Blubrry / 11.17.2
PowerPress Podcasting plugin by Blubrry v11.17.2
11.17.9 11.17.8 11.17.7 11.17.6 11.17.4 11.17.3 11.17.2 11.17.1 11.17 11.16.11 11.16.10 11.16.9 11.16.8 11.16.7 11.16.6 11.16.5 11.16.4 11.16.3 11.16.2 11.16.1 11.9.13 11.9.14 11.9.15 11.9.16 11.9.17 All 383 releases
powerpress / powerpress.php

powerpress.php in PowerPress Podcasting plugin by Blubrry 11.17.2, at powerpress.php

6,236 lines 261.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /*
3 Plugin Name: Blubrry PowerPress
4 Plugin URI: https://blubrry.com/services/powerpress-plugin/
5 Description: <a href="https://blubrry.com/services/powerpress-plugin/" target="_blank">Blubrry PowerPress</a> is the No. 1 Podcasting plugin for WordPress. Developed by podcasters for podcasters; features include Simple and Advanced modes, multiple audio/video player options, subscribe to podcast tools, podcast SEO features, and more! Fully supports Apple Podcasts (previously iTunes), Google Podcasts, Spotify, and Blubrry Podcasting directories, as well as all podcast applications and clients.
6 Version: 11.17.2
7 Author: Blubrry
8 Author URI: https://blubrry.com/
9 Requires at least: 3.6
10 Tested up to: 7.0
11 Text Domain: powerpress
12 Change Log:
13 Please see readme.txt for detailed change log.
14
15 Contributors:
16 Angelo Mandato, CIO Blubrry - Plugin founder, architect and lead developer
17 See readme.txt for full list of contributors.
18
19 Credits:
20 getID3(), License: GPL 2.0+ by James Heinrich <info [at] getid3.org> http://www.getid3.org
21 Note: getid3.php analyze() function modified to prevent redundant filesize() function call.
22
23 Copyright 2008-2019 Blubrry (https://blubrry.com)
24
25 License: GPL (http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt)
26
27 This project uses source that is GPL licensed.
28 */
29
30 use Mpdf\Tag\A;
31
32 if( !function_exists('add_action') ) {
33 header( 'Status: 403 Forbidden' );
34 header( 'HTTP/1.1 403 Forbidden' );
35 exit();
36 }
37
38 /**
39 * Updated version of a function originally added by the WordPress.org Plugins Review team in response to an incident with versions 11.9.3 to 11.9.4 where users were auto-created
40 * This resets passwords for these auto-created users. Query was updated for efficiency.
41 */
42 function PowerPress_PRT_incidence_response_notice() {
43 global $PowerPress_PRT_incidence_response_usernames;
44 ?>
45 <div class="notice notice-warning">
46 <h3><?php esc_html_e( 'Action Required: Please verify user accounts', 'powerpress' ); ?></h3>
47 <p><?php esc_html_e( 'On June 28th, an unauthorized update of PowerPress was released using a compromised account.
48 That version (11.9.3 to 11.9.4), contained malicious code that created users with administrative privileges. It was quickly replaced with a fixed version about an hour later.
49 As a security measure, the passwords of all such accounts were invalidated to prevent access.
50 ', 'powerpress' ); ?>
51 <?php printf(
52 esc_html__( 'To remove this message, please verify all admin users and remove users with login names %s.', 'powerpress' ),
53 esc_html(implode(', ', $PowerPress_PRT_incidence_response_usernames))
54 ); ?>
55
56 <?php if(function_exists('add_footer_script')){
57 esc_html_e( 'In addition, a function called "add_footer_script" may have been modified/added to the functions.php file in your theme. This will have to be manually checked. Updating to a new version or re-installing your theme will also fix this issue.', 'powerpress' );
58 } ?> </p>
59 <p><?php esc_html_e( 'We would like to thank the community and the WordPress team for their help in getting this detected and fixed quickly.', 'powerpress' ); ?></p>
60 <p><?php _e( 'Our support lines are open. If you need help or have any questions, please reach out via our <a href="https://blubrry.com/contact"> contact form. </a>', 'powerpress' ); ?></p>
61 </div>
62 <?php
63 }
64 function PowerPress_PRT_incidence_response() {
65 global $PowerPress_PRT_incidence_response_usernames;
66 $check_completed = get_option('powerpress_user_check_completed');
67 if ($check_completed) {
68 return;
69 }
70 // They tried to create those users.
71 $affectedusernames = ['PluginAUTH', 'PluginGuest', 'Options'];
72
73 $page = 1;
74 $showWarning = false;
75
76 do {
77 $args = array (
78 'role' => 'administrator',
79 'date_query' => array(
80 array(
81 'after' => '2024-06-27 00:00:00',
82 'inclusive' => true,
83 ),
84 ),
85 'number' => 5000,
86 'paged' => $page
87 );
88
89 $user_query = new WP_User_Query($args);
90 $users = $user_query->get_results();
91 if (!$users) {
92 break;
93 }
94 foreach ($users as $user) {
95 if (7 === strlen($user->user_login)) {
96 $affectedusernames[] = $user->user_login;
97 }
98 }
99
100 if (!empty($affectedusernames)) {
101 foreach ($affectedusernames as $affectedusername) {
102 $user = get_user_by('login', $affectedusername);
103 if ($user) {
104 // Affected users had an email on the form <username>@example.com
105 if ($user->user_email === $affectedusername . '@example.com') {
106 // We set an invalid password hash to invalidate the user login.
107 $temphash = 'PRT_incidence_response_230624';
108 if ($user->user_pass !== $temphash) {
109 global $wpdb;
110 $wpdb->update(
111 $wpdb->users,
112 array(
113 'user_pass' => $temphash,
114 'user_activation_key' => '',
115 ),
116 array('ID' => $user->ID)
117 );
118 clean_user_cache($user);
119 }
120 $PowerPress_PRT_incidence_response_usernames[] = $user->user_login;
121 $showWarning = true;
122 }
123 }
124 }
125 }
126 $page++;
127 } while (!empty($users));
128 if($showWarning){
129 add_action( 'admin_notices', 'PowerPress_PRT_incidence_response_notice' );
130 } else {
131 add_option('powerpress_user_check_completed', true);
132 }
133 }
134 add_action('init', 'PowerPress_PRT_incidence_response');
135
136 // WP_PLUGIN_DIR (REMEMBER TO USE THIS DEFINE IF NEEDED)
137 define('POWERPRESS_VERSION', '11.17.2' );
138
139 // Translation support:
140 if ( !defined('POWERPRESS_ABSPATH') )
141 define('POWERPRESS_ABSPATH', dirname(__FILE__) );
142
143
144
145 /////////////////////////////////////////////////////
146 // The following define options should be placed in your
147 // wp-config.php file so the setting is not disrupted when
148 // you upgrade the plugin.
149 /////////////////////////////////////////////////////
150
151 if( !defined('POWERPRESS_BLUBRRY_API_URL') )
152 define('POWERPRESS_BLUBRRY_API_URL', 'http://api.blubrry.com/');
153
154 // Replace validator service with one that is more reliable here:
155 define('POWERPRESS_FEEDVALIDATOR_URL', 'https://castfeedvalidator.com/?url=');
156
157 if( !defined('POWERPRESS_CONTENT_ACTION_PRIORITY') )
158 define('POWERPRESS_CONTENT_ACTION_PRIORITY', 10 );
159
160 // Added so administrators can customize what capability is needed for PowerPress
161 if( !defined('POWERPRESS_CAPABILITY_MANAGE_OPTIONS') )
162 define('POWERPRESS_CAPABILITY_MANAGE_OPTIONS', 'manage_options');
163 if( !defined('POWERPRESS_CAPABILITY_EDIT_PAGES') )
164 define('POWERPRESS_CAPABILITY_EDIT_PAGES', 'edit_pages');
165
166 // Define variables, advanced users could define these in their own wp-config.php so lets not try to re-define
167 if( !defined('POWERPRESS_LINK_SEPARATOR') )
168 define('POWERPRESS_LINK_SEPARATOR', '|');
169 if( !defined('POWERPRESS_TEXT_SEPARATOR') )
170 define('POWERPRESS_TEXT_SEPARATOR', ':');
171 if( !defined('PHP_EOL') )
172 define('PHP_EOL', "\n"); // We need this variable defined for new lines.
173 if( defined('POWERPRESS_DEBUG') ) {
174 if( !defined('PHP_EOL_WEB') ) {
175 define('PHP_EOL_WEB', "\n"); // Helps with readability
176 }
177 } else {
178 if( !defined('PHP_EOL_WEB') ) {
179 define('PHP_EOL_WEB', ''); // We don't necessarily need new lines for web output
180 }
181 }
182
183 if( !defined('POWERPRESS_SUBSCRIBE') )
184 define('POWERPRESS_SUBSCRIBE', true);
185 if(!defined('POWERPRESS_NEW_APPLE_CATEGORIES')) {
186 define('POWERPRESS_NEW_APPLE_CATEGORIES', true);
187 }
188 // Set regular expression values for determining mobile devices
189 if( !defined('POWERPRESS_MOBILE_REGEX') )
190 define('POWERPRESS_MOBILE_REGEX', 'iphone|ipod|ipad|aspen|android|blackberry|opera mini|webos|incognito|webmate|silk');
191
192 // TRUSTED DOMAINS
193 if( !defined('POWERPRESS_TRUSTED_DOMAINS') ) {
194 if( defined('POWERPRESS_LOCAL_DEV') && POWERPRESS_LOCAL_DEV ) {
195 define('POWERPRESS_TRUSTED_DOMAINS', array('blubrry.com', 'blubrry.biz', 'blubrry.local'));
196 } else {
197 define('POWERPRESS_TRUSTED_DOMAINS', array('blubrry.com'));
198 }
199 }
200
201 $powerpress_feed = NULL; // DO NOT CHANGE
202
203 function powerpress_content($content)
204 {
205 global $post, $g_powerpress_excerpt_post_id;
206
207 if( defined('PODPRESS_VERSION') || isset($GLOBALS['podcasting_player_id']) || isset($GLOBALS['podcast_channel_active']) || defined('PODCASTING_VERSION') )
208 return $content;
209
210 if( empty($post->ID) || !is_object($post) )
211 return $content;
212
213 if( defined('POWERPRESS_DO_ENCLOSE_FIX') )
214 $content = preg_replace('/\<!--.*added by PowerPress.*-->/im', '', $content );
215
216 if( is_feed() )
217 return $content; // We don't want to do anything to the feed
218
219 if( function_exists('post_password_required') )
220 {
221 if( post_password_required($post) )
222 return $content;
223 }
224
225 // PowerPress settings:
226 $GeneralSettings = get_option('powerpress_general', array());
227
228 // No player or links to add to content...
229 if( !empty($GeneralSettings['disable_appearance']) )
230 return $content;
231
232 // check for themes/plugins where we know we need to do this...
233 if( empty($GeneralSettings['player_aggressive']) )
234 {
235 if( !empty($GLOBALS['fb_ver']) && version_compare($GLOBALS['fb_ver'], '1.0', '<=') ) {
236 $GeneralSettings['player_aggressive'] = 1;
237 }
238 if( defined('JETPACK__VERSION') && version_compare(JETPACK__VERSION, '2.0', '>=') ) {
239 $GeneralSettings['player_aggressive'] = 1; // Jet pack still doesn't behave with PowerPress the_content
240 }
241 if( defined('WPSEO_VERSION') ) {
242 $GeneralSettings['player_aggressive'] = 4;
243 }
244 }
245
246 if( !empty($GeneralSettings['player_aggressive']) )
247 {
248 if( $GeneralSettings['player_aggressive'] == 4 )
249 {
250 $in_http_head = powerpress_in_wp_head();
251 if( $in_http_head === true )
252 return $content;
253 }
254 else if( $GeneralSettings['player_aggressive'] == 2 ) // If we do not have theme issues then lets keep this logic clean. and only display playes after the wp_head only
255 {
256 if( empty($GLOBALS['powerpress_wp_head_completed']) )
257 return $content;
258 }
259 else // method 1 or 3...
260 {
261 if( strstr($content, '<!--powerpress_player-->') !== false )
262 return $content; // The players were already added to the content
263
264 if( $GeneralSettings['player_aggressive'] != 3 && $g_powerpress_excerpt_post_id > 0 )
265 $g_powerpress_excerpt_post_id = 0; // Hack, set this to zero so it always goes past...
266
267 if( $GeneralSettings['player_aggressive'] == 3 )
268 $GeneralSettings['player_aggressive'] = 1; // remainder of the system will function as normal
269 }
270 }
271
272 // Problem: If the_excerpt is used instead of the_content, both the_exerpt and the_content will be called here.
273 // Important to note, get_the_excerpt will be called before the_content is called, so we add a simple little hack
274 if( current_filter() == 'get_the_excerpt' )
275 {
276 $g_powerpress_excerpt_post_id = $post->ID;
277 return $content; // We don't want to do anything to this content yet...
278 }
279 else if( current_filter() == 'the_content' && $g_powerpress_excerpt_post_id == $post->ID )
280 {
281 return $content; // We don't want to do anything to this excerpt content in this call either...
282 }
283 else if( class_exists('custom_post_widget') && powerpress_in_custom_post_widget() )
284 {
285 return $content; // Custom Post Widget compatibility
286 }
287
288
289 if( !isset($GeneralSettings['custom_feeds']) )
290 $GeneralSettings['custom_feeds'] = array('podcast'=>'Default Podcast Feed');
291 if( empty($GeneralSettings['custom_feeds']['podcast']) )
292 $GeneralSettings['custom_feeds']['podcast'] = 'Default Podcast Feed';
293
294 // Re-order so the default podcast episode is the top most...
295 $Temp = $GeneralSettings['custom_feeds'];
296 $GeneralSettings['custom_feeds'] = array();
297 $GeneralSettings['custom_feeds']['podcast'] = 'Default Podcast Feed';
298 foreach( $Temp as $feed_slug=> $feed_title )
299 {
300 if( $feed_slug == 'podcast' )
301 continue;
302 $GeneralSettings['custom_feeds'][ $feed_slug ] = $feed_title;
303 }
304
305 // Handle post type feeds....
306 if( !empty($GeneralSettings['posttype_podcasting']) )
307 {
308 $post_type = get_query_var('post_type');
309 if ( is_array( $post_type ) ) {
310 $post_type = reset( $post_type ); // get first element in array
311 }
312
313 // Get the feed slugs and titles for this post type
314 $PostTypeSettingsArray = get_option('powerpress_posttype_'.$post_type, array());
315 // Loop through this array of post type settings...
316 if( !empty($PostTypeSettingsArray) )
317 {
318 switch($post_type)
319 {
320 case 'post':
321 case 'page': {
322 // Do nothing!, we want the default podcast to appear in these post types
323 }; break;
324 default: {
325 if( !empty($post_type) && empty($PostTypeSettingsArray['podcast']) )
326 unset($GeneralSettings['custom_feeds']['podcast']); // special case, we do not want an accidental podcast episode to appear in a custom post type if the feature is enabled
327 }; break;
328 }
329
330 if (is_array($PostTypeSettingsArray)) {
331 foreach ($PostTypeSettingsArray as $feed_slug => $postTypeSettings) {
332 if (!empty($postTypeSettings['title']))
333 $GeneralSettings['custom_feeds'][$feed_slug] = $postTypeSettings['title'];
334 else
335 $GeneralSettings['custom_feeds'][$feed_slug] = $feed_slug;
336 }
337 }
338 }
339 }
340
341 if( !isset($GeneralSettings['display_player']) )
342 $GeneralSettings['display_player'] = 1;
343 if( !isset($GeneralSettings['player_function']) )
344 $GeneralSettings['player_function'] = 1;
345 if( !isset($GeneralSettings['podcast_link']) )
346 $GeneralSettings['podcast_link'] = 1;
347
348 // The blog owner doesn't want anything displayed, so don't bother wasting anymore CPU cycles
349 if( $GeneralSettings['display_player'] == 0 )
350 return $content;
351
352 if( current_filter() == 'the_excerpt' && empty($GeneralSettings['display_player_excerpt']) )
353 return $content; // We didn't want to modify this since the user didn't enable it for excerpts
354
355 if( !empty($GeneralSettings['hide_player_more']) && strstr($content, 'class="more-link"') )
356 return $content; // We do not want to add players and links if the read-more class found
357
358 // Figure out which players are alerady in the body of the page...
359 $ExcludePlayers = array();
360 if( isset($GeneralSettings['disable_player']) )
361 $ExcludePlayers = $GeneralSettings['disable_player']; // automatically disable the players configured
362
363 if( !empty($GeneralSettings['process_podpress']) && strstr($content, '[display_podcast]') )
364 return $content;
365
366 if( preg_match_all('/(.?)\[(powerpress)\b(.*?)(?:(\/))?\](?:(.+?)\[\/\2\])?(.?)/s', $content, $matches) )
367 {
368 if( isset($matches[3]) && is_array($matches[3]) )
369 {
370 foreach ($matches[3] as $key => $row) {
371 $attributes = shortcode_parse_atts($row);
372 if (isset($attributes['url'])) {
373 // not a problem...
374 } else if (isset($attributes['feed'])) {
375 // we want to exclude this feed from the links aera...
376 $ExcludePlayers[$attributes['feed']] = true;
377 } else {
378 // we don't want to include any players below...
379 $ExcludePlayers = $GeneralSettings['custom_feeds'];
380 }
381 }
382 }
383 }
384
385 $new_content = '';
386 if ( is_array($GeneralSettings['custom_feeds']) ) {
387 // LOOP HERE TO DISPLAY EACH MEDIA TYPE
388 foreach ($GeneralSettings['custom_feeds'] as $feed_slug => $feed_title) {
389 // Get the enclosure data
390 $EpisodeData = powerpress_get_enclosure_data($post->ID, $feed_slug);
391
392 if (!$EpisodeData && !empty($GeneralSettings['process_podpress']) && $feed_slug == 'podcast')
393 $EpisodeData = powerpress_get_enclosure_data_podpress($post->ID);
394
395 if (!$EpisodeData || !$EpisodeData['url'])
396 continue;
397
398 // Just in case, if there's no URL lets escape!
399 if (!$EpisodeData['url'])
400 continue;
401
402 // If the player is not already inserted in the body of the post using the shortcode...
403 //if( preg_match('/\[powerpress(.*)\]/is', $content) == 0 )
404 if (!isset($ExcludePlayers[$feed_slug])) // If the player is not in our exclude list because it's already in the post body somewhere...
405 {
406 if (isset($GeneralSettings['premium_caps']) && $GeneralSettings['premium_caps'] && !powerpress_premium_content_authorized($feed_slug)) {
407 $new_content .= powerpress_premium_content_message($post->ID, $feed_slug, $EpisodeData);
408 } else {
409 if ($GeneralSettings['player_function'] != 3 && $GeneralSettings['player_function'] != 0) // Play in new window only or disabled
410 {
411 do_action('wp_powerpress_player_scripts');
412 $AddDefaultPlayer = empty($EpisodeData['no_player']);
413
414 if ($EpisodeData && !empty($EpisodeData['embed'])) {
415 $new_content .= SanitizeEmbed(trim($EpisodeData['embed']));
416 if (!empty($GeneralSettings['embed_replace_player']))
417 $AddDefaultPlayer = false;
418 }
419
420 if ($AddDefaultPlayer) {
421 $image = '';
422 if (isset($EpisodeData['image']) && $EpisodeData['image'] != '')
423 $image = $EpisodeData['image'];
424
425 $new_content .= apply_filters('powerpress_player', '', powerpress_add_flag_to_redirect_url($EpisodeData['url'], 'p'), $EpisodeData);
426 }
427 }
428
429 if (!isset($EpisodeData['no_links'])) {
430 do_action('wp_powerpress_player_scripts');
431 $new_content .= apply_filters('powerpress_player_links', '', powerpress_add_flag_to_redirect_url($EpisodeData['url'], 'p'), $EpisodeData);
432 $new_content .= apply_filters('powerpress_player_subscribe_links', '', powerpress_add_flag_to_redirect_url($EpisodeData['url'], 'p'), $EpisodeData);
433 }
434 }
435 }
436 }
437 }
438
439 if( $new_content == '' )
440 return $content;
441
442 switch( $GeneralSettings['display_player'] )
443 {
444 case 1: { // Below posts
445 return $content.$new_content.( !empty($GeneralSettings['player_aggressive']) && $GeneralSettings['player_aggressive'] == 1 ?'<!--powerpress_player-->':'');
446 }; break;
447 case 2: { // Above posts
448 return ( !empty($GeneralSettings['player_aggressive']) && $GeneralSettings['player_aggressive'] == 1 ?'<!--powerpress_player-->':'').$new_content.$content;
449 }; break;
450 }
451 return $content;
452 }//end function
453
454
455 add_filter('get_the_excerpt', 'powerpress_content', (POWERPRESS_CONTENT_ACTION_PRIORITY - 1) );
456 add_filter('the_content', 'powerpress_content', POWERPRESS_CONTENT_ACTION_PRIORITY);
457 if( !defined('POWERPRESS_NO_THE_EXCERPT') )
458 add_filter('the_excerpt', 'powerpress_content', POWERPRESS_CONTENT_ACTION_PRIORITY);
459
460 /* Specail case fix Yoast bug which messes up the HTML */
461 function powerpress_yoast_gawp_fix($content)
462 {
463 $content= preg_replace(
464 array('/return powerpress\_pinw\(\"/', '/return powerpress\_embed\_winplayer\(\"/', '/return powerpress\_show\_embed\(\"/', '/return powerpress\_embed\_html5v\(\"/', '/return powerpress\_embed\_html5a\(\"/', ),
465 array('return powerpress_pinw(\'', 'return powerpress_embed_winplayer(\'', 'return powerpress_show_embed(\'', 'return powerpress_embed_html5v(\'', 'return powerpress_embed_html5a(\'' ),
466 $content);
467
468 return $content;
469 }
470
471 function powerpress_header()
472 {
473 // PowerPress settings:
474 $Powerpress = get_option('powerpress_general', array());
475 if( !isset($Powerpress['custom_feeds']) )
476 $Powerpress['custom_feeds'] = array('podcast'=>'Default Podcast Feed');
477
478 if( empty($Powerpress['disable_appearance']) || $Powerpress['disable_appearance'] == false )
479 {
480 if( !isset($Powerpress['player_function']) || $Powerpress['player_function'] > 0 ) // Don't include the player in the header if it is not needed...
481 {
482 $PowerpressPluginURL = powerpress_get_root_url();
483 ?>
484 <script type="text/javascript"><!--
485 <?php
486 $new_window_width = 420;
487 $new_window_height = 240;
488
489 if( isset($Powerpress['new_window_width']) && $Powerpress['new_window_width'] > 0 )
490 $new_window_width = $Powerpress['new_window_width'];
491 else if( isset($Powerpress['new_window_width']) )
492 $new_window_width = 420;
493
494 if( isset($Powerpress['new_window_height']) && $Powerpress['new_window_height'] > 0 )
495 $new_window_height = $Powerpress['new_window_height'];
496 else if( isset($Powerpress['new_window_height']) )
497 $new_window_height = 240;
498
499 if( empty($Powerpress['new_window_nofactor']) )
500 {
501 $new_window_width += 40;
502 $new_window_height += 80;
503 }
504
505 ?>
506 function powerpress_pinw(pinw_url){window.open(pinw_url, 'PowerPressPlayer','toolbar=0,status=0,resizable=1,width=<?php echo ($new_window_width); ?>,height=<?php echo ($new_window_height); ?>'); return false;}
507 //-->
508
509 // tabnab protection
510 window.addEventListener('load', function () {
511 // make all links have rel="noopener noreferrer"
512 document.querySelectorAll('a[target="_blank"]').forEach(link => {
513 link.setAttribute('rel', 'noopener noreferrer');
514 });
515 });
516 </script>
517 <?php
518 }
519 }
520
521 if( !empty($Powerpress['feed_links']) )
522 {
523 if( is_home() ) {
524 $feed_slug = 'podcast';
525 $href = get_feed_link($feed_slug);
526 // Podcast default and channel feed settings
527 $Settings = get_option('powerpress_feed_'. $feed_slug, array());
528
529 if( empty($Settings) && $feed_slug == 'podcast' )
530 $Settings = get_option('powerpress_feed', array()); // Get the main feed settings
531
532 if( empty($Settings['title']) )
533 $Settings['title'] = get_bloginfo_rss('name'); // Get blog title
534
535 // Get the default podcast feed...
536 echo '<link rel="alternate" type="' . feed_content_type() . '" title="' . esc_attr( $Settings['title'] ) . '" href="' . esc_url( $href ) . '" />' . "\n";
537 } else if( is_category() ) {
538
539 $category_id = get_query_var('cat');
540 if( $category_id ) {
541 $Settings = get_option('powerpress_cat_feed_'.$category_id, array() );
542 if( empty($Settings['title']) ) {
543 $Settings['title'] = get_cat_name( $category_id ); // Get category title
544 $Settings['title'] .= ' '. apply_filters( 'document_title_separator', '-' ) .' ';
545 $Settings['title'] .= get_bloginfo_rss('name');
546 }
547 if( empty($Settings['title']) ) {
548 $Settings['title'] = get_bloginfo_rss('name'); // Get blog title, best we can do
549 }
550
551 if( !empty($Settings['feed_redirect_url']) )
552 $Settings['feed_url'] = $Settings['feed_redirect_url'];
553 else if( !empty($Powerpress['cat_casting_podcast_feeds']) )
554 $Settings['feed_url'] = get_category_feed_link($category_id, 'podcast');
555 else
556 $Settings['feed_url'] = get_category_feed_link( $category_id ); // Get category feed URL
557
558 // Get the category podcast feed...
559 echo '<link rel="alternate" type="' . feed_content_type() . '" title="' . esc_attr( $Settings['title'] ) . '" href="' . esc_url( $Settings['feed_url'] ) . '" />' . "\n";
560 }
561 }
562 }
563 }
564
565 add_action('wp_head', 'powerpress_header');
566
567 function powerpress_wp_head_completed()
568 {
569 $GLOBALS['powerpress_wp_head_completed'] = true;
570 }
571
572 add_action('wp_head', 'powerpress_wp_head_completed', 100000);
573
574 function powerpress_exit_on_http_head($return)
575 {
576 if( is_feed() )
577 {
578 // Set the content type for HTTP headers...
579 header('Content-Type: ' . feed_content_type('rss-http') . '; charset=' . get_option('blog_charset'), true);
580
581 // Needs authentication?
582 $GeneralSettings = get_option('powerpress_general', array());
583 if( !empty($GeneralSettings['premium_caps']) )
584 {
585 $feed_slug = get_query_var('feed');
586 $FeedSettings = get_option('powerpress_feed_'.$feed_slug, array());
587 if( !empty($FeedSettings['premium']) )
588 {
589 return false; // Let the logic further into PowerPress authenticate this HEAD request
590 }
591 }
592 }
593 return $return;
594 }
595
596 add_filter('exit_on_http_head', 'powerpress_exit_on_http_head' );
597
598 function powerpress_rss2_ns()
599 {
600 if( !powerpress_is_podcast_feed() )
601 return;
602
603 // Okay, lets add the namespace
604 echo 'xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd"'.PHP_EOL;
605
606 // Add the Podcast Index namespace
607 echo 'xmlns:podcast="https://podcastindex.org/namespace/1.0"'.PHP_EOL;
608
609 if( !defined('POWERPRESS_RAWVOICE_RSS') || POWERPRESS_RAWVOICE_RSS != false )
610 {
611 echo 'xmlns:rawvoice="https://blubrry.com/developer/rawvoice-rss/"'.PHP_EOL;
612 }
613 }
614
615 function SanitizeEmbed($html) {
616 $allowed_attrs = [
617 'src' => true,
618 'width' => true,
619 'height' => true,
620 'frameborder' => true,
621 'allow' => true,
622 'sandbox' => true,
623 'referrerpolicy' => true,
624 'loading' => true,
625 'allowfullscreen' => true,
626 'title' => true,
627 'scrolling' => true,
628 'alt' => true,
629 ];
630 $allowed_html = [
631 'iframe' => $allowed_attrs,
632 'div' => $allowed_attrs,
633 ];
634 return wp_kses($html, $allowed_html, ['http', 'https']);
635 }
636
637
638 function powerpress_check_for_chartable()
639 {
640 $found_chartable = false;
641 $General = get_option('powerpress_general');
642 if (!empty($General['redirect1'])) {
643 if (is_chartable_url($General['redirect1'])) {
644 update_option('powerpress_chartable_check', 'has_chartable');
645 $found_chartable = true;
646 }
647 }
648 if (!empty($General['redirect2'])) {
649 if (is_chartable_url($General['redirect2'])) {
650 update_option('powerpress_chartable_check', 'has_chartable');
651 $found_chartable = true;
652 }
653 }
654 if (!empty($General['redirect3'])) {
655 if (is_chartable_url($General['redirect3'])) {
656 update_option('powerpress_chartable_check', 'has_chartable');
657 $found_chartable = true;
658 }
659 }
660
661 // if we haven't found chartable in the saved redirects, check all media just to be safe
662 if (!$found_chartable) {
663 global $wpdb;
664 $query = "SELECT meta_id, post_id, meta_key, meta_value FROM {$wpdb->postmeta} WHERE meta_key LIKE \"%enclosure\"";
665 $results_data = $wpdb->get_results($query, ARRAY_A);
666 foreach ($results_data as $idx => $data) {
667 $meta_parts = explode("\n", $data['meta_value']);
668 $post_enclosure_url = $meta_parts[0];
669 if (strpos($post_enclosure_url, 'chrt.fm') !== false || strpos($post_enclosure_url, 'chtbl.com') !== false) {
670 update_option('powerpress_chartable_check', 'has_chartable');
671 $found_chartable = true;
672 }
673 }
674 }
675
676 if (!$found_chartable) {
677 update_option('powerpress_chartable_check', 'no_chartable');
678 }
679 }
680 add_action('powerpress_check_for_chartable_hook', 'powerpress_check_for_chartable');
681
682 if (!function_exists('buildRedirect')) {
683 function buildRedirect($redirects)
684 {
685 $redirect_result = '';
686 for ($x = 3; $x >= 0; $x--) {
687 $key = sprintf('redirect%d', $x);
688 if (!empty($redirects[$key])) {
689 if (preg_match('/^https?:\/\/(.*)$/', trim($redirects[$key]), $matches) == 0)
690 continue;
691
692 if (is_chartable_url($redirects[$key])) {
693 continue;
694 }
695
696 $redirectClean = $matches[1];
697 if (substr($redirectClean, -1, 1) != '/') // Rediercts need to end with a slash /.
698 $redirectClean .= '/';
699
700 if (!empty($redirectClean)) {
701 if (strpos($redirectClean, '/') == 0) // Not a valid redirect URL
702 continue;
703
704 if (!strstr($redirect_result, $redirectClean)) // If the redirect is not already added...
705 $redirect_result = $redirectClean . $redirect_result;
706 }
707 }
708 }
709 return 'https://' . $redirect_result;
710 }
711 }
712
713 if (!function_exists('powerpress_getAccessToken')) {
714 function powerpress_getAccessToken()
715 {
716 // Look at the creds and use the latest access token, if its not the latest refresh it...
717 $creds = get_option('powerpress_creds', array());
718 if (!empty($creds['access_token']) && !empty($creds['access_expires']) && $creds['access_expires'] > time()) { // If access token did not expire
719 return $creds['access_token'];
720 }
721
722 if (!empty($creds['refresh_token']) && !empty($creds['client_id']) && !empty($creds['client_secret'])) {
723
724 // Create new access token with refresh token here...
725 require_once('powerpressadmin-auth.class.php');
726 $auth = new PowerPressAuth();
727 $resultTokens = $auth->getAccessTokenFromRefreshToken($creds['refresh_token'], $creds['client_id'], $creds['client_secret']);
728
729 if (!empty($resultTokens['access_token']) && !empty($resultTokens['expires_in'])) {
730 powerpress_save_settings(
731 array(
732 'access_token' => $resultTokens['access_token'],
733 'access_expires' => (time() + $resultTokens['expires_in'] - 10)
734 ),
735 'powerpress_creds'
736 );
737
738 return $resultTokens['access_token'];
739 } else {
740 //if their refresh token is expired, sign them out so they can re-authenticate
741 delete_option('powerpress_creds');
742 powerpress_page_message_add_error(__('Your account has been logged out due to inactivity with Blubrry services.', 'powerpress'));
743 powerpress_page_message_print();
744 }
745 }
746
747 // If we failed to get credentials, return false
748 return false;
749 }
750 }
751
752 if (!function_exists('powerpress_clear_blubrry_caches')) {
753 function powerpress_clear_blubrry_caches($program_keyword = '') {
754 delete_transient('powerpress_programs_list');
755 delete_transient('powerpress_programs_api_error');
756 delete_transient('powerpress_no_stats_programs');
757 if (!empty($program_keyword)) {
758 delete_transient('powerpress_program_info_' . md5($program_keyword));
759 }
760 }
761 }
762
763 if (!function_exists('powerpress_save_settings')) {
764 function powerpress_save_settings($SettingsNew = false, $field = 'powerpress_general')
765 {
766 if ($field == 'powerpress_taxonomy_podcasting' || $field == 'powerpress_itunes_featured') { // No merging settings for these fields...
767 update_option($field, $SettingsNew);
768 return;
769 }
770 // Save general settings
771 if ($SettingsNew) {
772 $Settings = get_option($field);
773 if (!is_array($Settings))
774 $Settings = [];
775 foreach ($SettingsNew as $key => $value) {
776 $Settings[$key] = $value;
777 }
778 if ($field == 'powerpress_general' && !isset($Settings['timestamp']))
779 $Settings['timestamp'] = time();
780
781 if (isset($Settings['value_recipients'])) {
782 unset(
783 $Settings['value_pubkey'],
784 $Settings['value_split'],
785 $Settings['value_lightning'],
786 $Settings['value_custom_key'],
787 $Settings['value_custom_value'],
788 $Settings['value_is_fee'],
789 $Settings['value_fee']
790 );
791 }
792
793 // Special case fields, if they are empty, we can delete them., this will keep the Settings array uncluttered
794 if (isset($Settings['feed_links']) && $Settings['feed_links'] == 0) // If set to default value, no need to save it in the database
795 unset($Settings['feed_links']);
796 // We can unset settings that are set to their defaults to save database size...
797 if ($field == 'powerpress_general') {
798 if (isset($SettingsNew['new_episode_box_flag'])) {
799 /* Switch the settings over to the actual field name (to fix FCGI mode problem with older versions of PHP.
800 if (isset($SettingsNew['ebititle'])) {
801 if ($SettingsNew['ebititle'] == 'false') {
802 $Settings['new_episode_box_itunes_title'] = 2;
803 } else {
804 $Settings['new_episode_box_itunes_title'] = 1;
805 $SettingsNew['new_episode_box_itunes_title'] = 1;
806 }
807 unset($Settings['ebititle']);
808 }
809
810 if (isset($SettingsNew['ebinst'])) {
811 if ($SettingsNew['ebinst'] == 'false') {
812 $Settings['new_episode_box_itunes_nst'] = 2;
813 } else {
814 $Settings['new_episode_box_itunes_nst'] = 1;
815 $SettingsNew['new_episode_box_itunes_nst'] = 1;
816 }
817 unset($Settings['ebinst']);
818 }*/
819
820 if (!isset($SettingsNew['new_episode_box_embed']))
821 $Settings['new_episode_box_embed'] = 2;
822 if (!isset($SettingsNew['new_embed_replace_player']))
823 $Settings['new_embed_replace_player'] = 2;
824 if (!isset($SettingsNew['new_episode_box_no_player']))
825 $Settings['new_episode_box_no_player'] = 2;
826 if (!isset($SettingsNew['new_episode_box_no_links']))
827 $Settings['new_episode_box_no_links'] = 2;
828 if (!isset($SettingsNew['new_episode_box_no_player_and_links']))
829 $Settings['new_episode_box_no_player_and_links'] = 2;
830 if (!isset($SettingsNew['new_episode_box_cover_image']))
831 $Settings['new_episode_box_cover_image'] = 2;
832 if (!isset($SettingsNew['new_episode_box_player_size']))
833 $Settings['new_episode_box_player_size'] = 2;
834 if (!isset($SettingsNew['new_episode_box_subtitle']))
835 $Settings['new_episode_box_subtitle'] = 2;
836 if (!isset($SettingsNew['new_episode_box_summary']))
837 $Settings['new_episode_box_summary'] = 2;
838 if (!isset($SettingsNew['new_episode_box_author']))
839 $Settings['new_episode_box_author'] = 2;
840 if (!isset($SettingsNew['new_episode_box_explicit']))
841 $Settings['new_episode_box_explicit'] = 2;
842 if (!isset($SettingsNew['new_episode_box_pci']))
843 $Settings['new_episode_box_pci'] = 2;
844 if (!isset($SettingsNew['new_episode_box_block']))
845 $Settings['new_episode_box_block'] = 2;
846 if (!isset($SettingsNew['new_episode_box_itunes_image']))
847 $Settings['new_episode_box_itunes_image'] = 2;
848 if (!isset($SettingsNew['new_episode_box_order']))
849 $Settings['new_episode_box_order'] = 2;
850 if (!isset($SettingsNew['new_episode_box_itunes_title']))
851 $Settings['new_episode_box_itunes_title'] = 2;
852 if (!isset($SettingsNew['new_episode_box_itunes_nst']))
853 $Settings['new_episode_box_itunes_nst'] = 2;
854 if (!isset($SettingsNew['new_episode_box_gp_explicit']))
855 $Settings['new_episode_box_gp_explicit'] = 2;
856 if (!isset($SettingsNew['new_episode_box_feature_in_itunes']))
857 $Settings['new_episode_box_feature_in_itunes'] = 2;
858 } elseif (isset($SettingsNew['pp-gen-settings-tabs'])) {
859 if (!isset($SettingsNew['skip_to_episode_settings']) || empty($SettingsNew['skip_to_episode_settings']))
860 unset($Settings['skip_to_episode_settings']);
861 if (!isset($SettingsNew['display_player_excerpt']) || empty($SettingsNew['display_player_excerpt']))
862 unset($Settings['display_player_excerpt']);
863 if (!isset($SettingsNew['hide_player_more']) || empty($SettingsNew['hide_player_more']))
864 unset($Settings['hide_player_more']);
865 if (!isset($SettingsNew['podcast_embed']) || empty($SettingsNew['podcast_embed']))
866 unset($Settings['podcast_embed']);
867 if (!isset($SettingsNew['subscribe_links']) || empty($SettingsNew['subscribe_links']))
868 unset($Settings['subscribe_links']);
869 if (!isset($SettingsNew['new_window_no_factor']) || empty($SettingsNew['new_window_no_factor']))
870 unset($Settings['new_window_no_factor']);
871 } elseif (isset($SettingsNew['powerpress_bplayer_settings'])) {
872 unset($Settings['powerpress_bplayer_settings']);
873 if (!isset($SettingsNew['new_episode_box_itunes_image']) || empty($SettingsNew['new_episode_box_itunes_image']))
874 $Settings['new_episode_box_itunes_image'] = 2;
875 if (isset($SettingsNew['bp_episode_image']) && empty($SettingsNew['bp_episode_image']))
876 unset($Settings['bp_episode_image']);
877 }
878
879
880 if (isset($Settings['videojs_css_class']) && empty($Settings['videojs_css_class']))
881 unset($Settings['videojs_css_class']);
882 if (isset($Settings['cat_casting']) && empty($Settings['cat_casting']))
883 unset($Settings['cat_casting']);
884 if (isset($Settings['posttype_podcasting']) && empty($Settings['posttype_podcasting']))
885 unset($Settings['posttype_podcasting']);
886 if (isset($Settings['taxonomy_podcasting']) && empty($Settings['taxonomy_podcasting']))
887 unset($Settings['taxonomy_podcasting']);
888 if (isset($Settings['playlist_player']) && empty($Settings['playlist_player']))
889 unset($Settings['playlist_player']);
890 if (isset($Settings['seo_feed_title']) && empty($Settings['seo_feed_title']))
891 unset($Settings['seo_feed_title']);
892 if (isset($Settings['subscribe_feature_email']) && empty($Settings['subscribe_feature_email']))
893 unset($Settings['subscribe_feature_email']);
894 if (isset($Settings['poster_image_video']) && empty($Settings['poster_image_video']))
895 unset($Settings['poster_image_video']);
896 if (isset($Settings['poster_image_audio']) && empty($Settings['poster_image_audio']))
897 unset($Settings['poster_image_audio']);
898 if (isset($Settings['itunes_image_audio']) && empty($Settings['itunes_image_audio']))
899 unset($Settings['itunes_image_audio']);
900 if (isset($Settings['network_mode']) && empty($Settings['network_mode']))
901 unset($Settings['network_mode']);
902 if (isset($Settings['use_caps']) && empty($Settings['use_caps']))
903 unset($Settings['use_caps']);
904 } else // Feed or player settings...
905 {
906 if (isset($Settings['itunes_block']) && $Settings['itunes_block'] == 0)
907 unset($Settings['itunes_block']);
908 if (isset($Settings['itunes_complete']) && $Settings['itunes_complete'] == 0)
909 unset($Settings['itunes_complete']);
910 if (isset($Settings['maximize_feed']) && $Settings['maximize_feed'] == 0)
911 unset($Settings['maximize_feed']);
912 if (isset($Settings['unlock_podcast']) && $Settings['unlock_podcast'] == 0)
913 unset($Settings['unlock_podcast']);
914 if (isset($Settings['donate_link']) && $Settings['donate_link'] == 0)
915 unset($Settings['donate_link']);
916 if (empty($Settings['donate_url']))
917 unset($Settings['donate_url']);
918 if (empty($Settings['donate_label']))
919 unset($Settings['donate_label']);
920 if (isset($Settings['allow_feed_comments']) && $Settings['allow_feed_comments'] == 0)
921 unset($Settings['allow_feed_comments']);
922 if (empty($Settings['episode_itunes_image']))
923 unset($Settings['episode_itunes_image']);
924 }
925
926 if (!empty($Settings)) {
927 if (isset($Settings['player'])) {
928 if ($Settings['player'] == 'blubrrymodern') {
929 if (!empty($_POST)) {
930 if (isset($_POST['ModernPlayer']['progress']) && isset($_POST['ModernPlayer']['border']) && isset($_POST['mode'])) {
931 if ($_POST['mode'] == 'Light' || $_POST['mode'] == 'Dark') {
932 if (preg_match('/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/i', $_POST['ModernPlayer']['progress']) && preg_match('/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/i', $_POST['ModernPlayer']['border'])) {
933 $updatedPlayerSettings = ['mode' => $_POST['mode'], 'border' => $_POST['ModernPlayer']['border'], 'progress' => $_POST['ModernPlayer']['progress']];
934 update_option('powerpress_bplayer', json_encode($updatedPlayerSettings));
935 }
936 }
937 }
938 }
939 }
940 }
941 }
942
943 update_option($field, $Settings);
944 }
945 }
946 }
947
948 function powerpress_sync_progad() {
949
950 // grab the redirect url prefixes for each feed slug and make an array
951 $General = get_option('powerpress_general');
952 // append general redirects to each other (starting with redirect1)
953 $redirects = array('redirect0'=>'', 'redirect1'=>'', 'redirect2'=>'', 'redirect3'=>'');
954 if( !empty($General['redirect1']) )
955 $redirects['redirect1'] = $General['redirect1'];
956 if( !empty($General['redirect2']) )
957 $redirects['redirect2'] = $General['redirect2'];
958 if( !empty($General['redirect3']) )
959 $redirects['redirect3'] = $General['redirect3'];
960
961 // add to redirect array with key 'enclosure'
962 $main_redirect = buildRedirect($redirects);
963 $redirect_array = array('enclosure' => $main_redirect);
964
965 // then append custom feed redirects to beginning of main feed redirect with _slug:enclosure for each custom feed
966 // channels
967 if (!empty($General['custom_feeds'])) {
968 foreach ($General['custom_feeds'] as $slug => $title) {
969 $Feed = get_option('powerpress_feed_' . $slug, array());
970 if (!empty($Feed['redirect'])) {
971 $redirects['redirect0'] = $Feed['redirect'];
972 $redirect_array += array('_' . $slug . ':enclosure' => buildRedirect($redirects));
973 $redirects['redirect0'] = '';
974 } else {
975 $redirect_array += array('_' . $slug . ':enclosure' => $main_redirect);
976 // default stats redirect
977 }
978 }
979 }
980
981 // categories
982 if (!empty($General['custom_cat_feeds'])) {
983 foreach ($General['custom_cat_feeds'] as $idx => $id) {
984 $category = get_category($id);
985 // $category['slug']
986 $Feed = get_option('powerpress_cat_feed_' . $id, array());
987 if (!empty($Feed['redirect'])) {
988 $redirects['redirect0'] = $Feed['redirect'];
989 $redirect_array += array('_' . $category->slug . ':enclosure' => buildRedirect($redirects));
990 $redirects['redirect0'] = '';
991 } else {
992 $redirect_array += array('_' . $category->slug . ':enclosure' => $main_redirect);
993 // default stats redirect
994 }
995 }
996 }
997
998 // taxonomies
999 $PowerPressTaxonomies = get_option('powerpress_taxonomy_podcasting', array());
1000 if (!empty($PowerPressTaxonomies)) {
1001 foreach ($PowerPressTaxonomies as $tt_id => $null) {
1002
1003 $taxonomy_type = '';
1004 $term_ID = '';
1005 $tt_id = intval($tt_id); // sanitize for sql
1006
1007 global $wpdb;
1008 $term_info = $wpdb->get_results("SELECT term_id, taxonomy FROM $wpdb->term_taxonomy WHERE term_taxonomy_id = $tt_id", ARRAY_A);
1009 if (!empty($term_info[0]['term_id'])) {
1010 $term_ID = $term_info[0]['term_id'];
1011 $taxonomy_type = $term_info[0]['taxonomy'];
1012 } else {
1013 continue; // we didn't find this taxonomy relationship
1014 }
1015
1016 $Feed = get_option('powerpress_taxonomy_' . $tt_id);
1017 $term_object = get_term( $term_ID, $taxonomy_type, OBJECT, 'edit');
1018 if (!empty($Feed['redirect'])) {
1019 $redirects['redirect0'] = $Feed['redirect'];
1020 $redirect_array += array('_' . $term_object->slug . ':enclosure' => buildRedirect($redirects));
1021 $redirects['redirect0'] = '';
1022 } else {
1023 $redirect_array += array('_' . $term_object->slug . ':enclosure' => $main_redirect);
1024 // default stats redirect
1025 }
1026 }
1027 }
1028
1029 // post types
1030
1031 $post_types = array();
1032 $post_types_wp = get_post_types();
1033 foreach( $post_types_wp as $index => $post_type )
1034 {
1035 if( $post_type == 'redirect_rule' || $post_type == 'attachment' || $post_type == 'nav_menu_item' || $post_type == 'revision' || $post_type == 'action' )
1036 continue;
1037
1038 $post_types[] = $post_type;
1039
1040 }
1041 if (!empty($post_types)) {
1042 foreach ($post_types as $null => $post_type) {
1043 $PostTypeSettingsArray = get_option('powerpress_posttype_' . $post_type, array());
1044 if (empty($PostTypeSettingsArray))
1045 continue;
1046
1047 foreach ($PostTypeSettingsArray as $feed_slug => $Feed) {
1048 if (!empty($Feed['redirect'])) {
1049 $redirects['redirect0'] = $Feed['redirect'];
1050 $redirect_array += array('_' . $feed_slug . ':enclosure' => buildRedirect($redirects));
1051 $redirects['redirect0'] = '';
1052 } else {
1053 $redirect_array += array('_' . $feed_slug . ':enclosure' => $main_redirect);
1054 // default stats redirect
1055 }
1056 }
1057 }
1058 }
1059
1060 // figure out which shows we are enabling/disabling
1061 require_once('powerpressadmin-auth.class.php');
1062 $progad_error = '';
1063 $progad_enable_urls = array();
1064 $progad_disable_urls = array();
1065 $auth = new PowerPressAuth();
1066 $accessToken = powerpress_getAccessToken();
1067 $req_url = sprintf('/2/media/prog_ad_status.json?cache=' . md5(rand(0, 999) . time()));
1068 $req_url .= (defined('POWERPRESS_BLUBRRY_API_QSA') ? '?' . POWERPRESS_BLUBRRY_API_QSA : '');
1069 $req_url .= (defined('POWERPRESS_PUBLISH_PROTECTED') ? '&protected=true' : '');
1070 $progad_enabled_shows = $auth->api($accessToken, $req_url, array(), false, 60 * 30);
1071 if (!$progad_enabled_shows) {
1072 $progad_error = $auth->getLastError();
1073 }
1074 $past_shows_with_progad = get_option('pp_programmatic_enabled_shows');
1075 if (!empty($past_shows_with_progad) && !empty($progad_enabled_shows['programs'])) {
1076 $shows_to_enable = array_diff($progad_enabled_shows['programs'], $past_shows_with_progad);
1077 $shows_to_disable = array_diff($past_shows_with_progad, $progad_enabled_shows['programs']);
1078 } elseif (!empty($past_shows_with_progad) && empty($progad_enabled_shows['programs'])) {
1079 $shows_to_disable = $past_shows_with_progad;
1080 } elseif (!empty($progad_enabled_shows['programs']) && empty($past_shows_with_progad)) {
1081 $shows_to_enable = $progad_enabled_shows['programs'];
1082 }
1083 update_option('pp_programmatic_enabled_shows', $progad_enabled_shows['programs']);
1084
1085 // use the API to get associated URLs for all URLs in any program whose ads were just enabled
1086 if (!empty($shows_to_enable)) {
1087 foreach ($shows_to_enable as $idx => $keyword) {
1088 $req_url = sprintf('/2/media/' . $keyword . '/prog_ad_urls.json?cache=' . md5(rand(0, 999) . time()));
1089 if (defined('POWERPRESS_PROGRAMMATIC_FIX')) {
1090 $req_url .= '&pp_first_release_fix=true';
1091 }
1092 $req_url .= (defined('POWERPRESS_BLUBRRY_API_QSA') ? '?' . POWERPRESS_BLUBRRY_API_QSA : '');
1093 $req_url .= (defined('POWERPRESS_PUBLISH_PROTECTED') ? '&protected=true' : '');
1094 $result_prog = $auth->api($accessToken, $req_url, array(), false, 60 * 30);
1095 if (isset($result_prog['urls']) && is_array($result_prog['urls'])) {
1096 foreach ($result_prog['urls'] as $i => $url_pair) {
1097 // add the redirect to the key before adding this pair
1098 $progad_enable_urls += $url_pair;
1099 }
1100 } elseif (isset($result_prog['message']) && $result_prog['message'] == 'no media') {
1101 // no error--continue
1102 }
1103 else {
1104 $progad_error = $auth->getLastError();
1105 }
1106 }
1107 }
1108
1109 // use the API to get associated URLs for all URLs in any program whose ads were just disabled
1110 if (!empty($shows_to_disable)) {
1111 foreach ($shows_to_disable as $idx => $keyword) {
1112 $req_url = sprintf('/2/media/' . $keyword . '/prog_ad_urls.json?disable=true&cache=' . md5(rand(0, 999) . time()));
1113 $req_url .= (defined('POWERPRESS_BLUBRRY_API_QSA') ? '?' . POWERPRESS_BLUBRRY_API_QSA : '');
1114 $req_url .= (defined('POWERPRESS_PUBLISH_PROTECTED') ? '&protected=true' : '');
1115 $result_prog = $auth->api($accessToken, $req_url, array(), false, 60 * 30);
1116 $progad_error = $auth->getLastError();
1117 if (isset($result_prog['urls']) && is_array($result_prog['urls'])) {
1118 foreach ($result_prog['urls'] as $i => $url_pair) {
1119 // add the redirect to the key before adding this pair
1120 $progad_disable_urls += $url_pair;
1121 }
1122 } elseif (isset($result_prog['message']) && $result_prog['message'] == 'no media') {
1123 // no error--continue
1124 }
1125 else {
1126 $progad_error = $auth->getLastError();
1127 }
1128 }
1129 }
1130
1131 // query the wordpress database to match up the URLs that we need to update
1132 global $wpdb;
1133 $query = "SELECT meta_id, post_id, meta_key, meta_value FROM {$wpdb->postmeta} WHERE meta_key LIKE \"%enclosure\"";
1134 $results_data = $wpdb->get_results($query, ARRAY_A);
1135 foreach ($results_data as $idx => $data) {
1136 $meta_parts = explode("\n", $data['meta_value']);
1137
1138 if (strpos($meta_parts[0], 'ins.blubrry.com')) {
1139 $parts_array = explode('ins.blubrry.com', $meta_parts[0]);
1140 } else if (strpos($meta_parts[0], 'content3.blubrry.biz')) {
1141 $parts_array = explode('content3.blubrry.biz', $meta_parts[0]);
1142 } else if (strpos($meta_parts[0], 'mc.blubrry.com')) {
1143 $parts_array = explode('mc.blubrry.com', $meta_parts[0]);
1144 } elseif (strpos($meta_parts[0], 'content.blubrry.com')) {
1145 $parts_array = explode('content.blubrry.com', $meta_parts[0]);
1146 } else {
1147 // not Blubrry hosted
1148 continue;
1149 }
1150 $url_without_prefix = $parts_array[1];
1151 $parts_drop_qs = explode('?', $url_without_prefix);
1152 if (!empty($progad_enable_urls) && array_key_exists($parts_drop_qs[0], $progad_enable_urls)) {
1153 // now, if they have a redirect for the feed that this url is in, we need to replace the https://media.blubrry.com/{keyword}/ with those redirects
1154 $progad_url_with_pp_redirect = preg_replace('#https://media.blubrry.com/(.*)/#U', $redirect_array[$data['meta_key']], $progad_enable_urls[$parts_drop_qs[0]]);
1155 // replace the url in the meta_parts array, implode it back together, and update the program meta
1156 $meta_parts[0] = $progad_url_with_pp_redirect;
1157 $new_meta_value = implode("\n", $meta_parts);
1158 update_post_meta($data['post_id'], $data['meta_key'], $new_meta_value);
1159 } else if (!empty($progad_disable_urls) && array_key_exists($parts_drop_qs[0], $progad_disable_urls)) {
1160 $hosting_url_with_pp_redirect = preg_replace('#http(s?)://#U', $redirect_array[$data['meta_key']], $progad_disable_urls[$parts_drop_qs[0]]);
1161 // replace the url in the meta_parts array, implode it back together, and update the program meta
1162 $meta_parts[0] = $hosting_url_with_pp_redirect;
1163 $new_meta_value = implode("\n", $meta_parts);
1164 update_post_meta($data['post_id'], $data['meta_key'], $new_meta_value);
1165 }
1166 }
1167
1168 if ($progad_error) {
1169 update_option("pp_progad_sync_error", __("Error syncing Programmatic Advertising Settings:", 'powerpress') . " " . $progad_error);
1170 } else {
1171 update_option("pp_progad_sync_success", __("Successfully synced Programmatic Advertising Settings from Blubrry.", 'powerpress'));
1172 }
1173 }
1174 add_action('powerpress_sync_progad_hook', 'powerpress_sync_progad');
1175
1176 add_action('rss2_ns', 'powerpress_rss2_ns');
1177 add_action('rss2_ns_powerpress', 'powerpress_rss2_ns');
1178
1179 function powerpress_rss2_head()
1180 {
1181 // disable php notices inside feeds
1182 error_reporting(0);
1183 global $powerpress_feed;
1184
1185 if( !powerpress_is_podcast_feed() )
1186 return; // Not a feed we manage
1187
1188 $feed_slug = get_query_var( 'feed' );
1189 $cat_ID = get_query_var('cat');
1190
1191 $Feed = get_option('powerpress_feed', array()); // Get the main feed settings
1192 $General = get_option('powerpress_general', array());
1193
1194 $feed_url = "";
1195 if( !empty($powerpress_feed['category']) )
1196 {
1197 $CustomFeed = get_option('powerpress_cat_feed_'.$powerpress_feed['category'], array()); // Get the custom podcast feed settings saved in the database
1198 if( !empty($CustomFeed) )
1199 $Feed = powerpress_merge_empty_feed_settings($CustomFeed, $Feed);
1200
1201 if( !empty($General['cat_casting_podcast_feeds']) )
1202 $feed_url = get_category_feed_link($powerpress_feed['category'], 'podcast');
1203 else // Use the old link
1204 $feed_url = get_category_feed_link($powerpress_feed['category']);
1205 }
1206 else if( !empty($powerpress_feed['term_taxonomy_id']) )
1207 {
1208 $CustomFeed = get_option('powerpress_taxonomy_'.$powerpress_feed['term_taxonomy_id'], array()); // Get the taxonomy podcast settings saved in the database
1209 if( !empty($CustomFeed) )
1210 $Feed = powerpress_merge_empty_feed_settings($CustomFeed, $Feed);
1211
1212 global $wpdb;
1213 $term_info = $wpdb->get_results("SELECT term_id, taxonomy FROM $wpdb->term_taxonomy WHERE term_taxonomy_id = " . intval($powerpress_feed['term_taxonomy_id']), ARRAY_A);
1214 $taxonomy_type = $term_info[0]['taxonomy'];
1215 $feed_url = get_term_feed_link($powerpress_feed['term_taxonomy_id'], $taxonomy_type, 'rss2');
1216 }
1217 else if( !empty($powerpress_feed['post_type']) )
1218 {
1219 $PostTypeSettingsArray = get_option('powerpress_posttype_'.$powerpress_feed['post_type'], array()); // Get the post type podcast feed settings saved in the database
1220 if( !empty($PostTypeSettingsArray[ $feed_slug ]) )
1221 {
1222 $CustomFeed = $PostTypeSettingsArray[ $feed_slug ];
1223 $Feed = powerpress_merge_empty_feed_settings($CustomFeed, $Feed, ($feed_slug == 'podcast') );
1224 }
1225
1226 $feed_url = get_post_type_archive_feed_link($powerpress_feed['post_type'], $feed_slug);
1227 }
1228 else if( powerpress_is_custom_podcast_feed() ) // If we're handling a custom podcast feed...
1229 {
1230 $CustomFeed = get_option('powerpress_feed_'.$feed_slug, array()); // Get the custom podcast feed settings saved in the database
1231 $Feed = powerpress_merge_empty_feed_settings($CustomFeed, $Feed, ($feed_slug == 'podcast') );
1232 $feed_url = get_feed_link($feed_slug);
1233 }
1234
1235 if( !isset($Feed['url']) || trim($Feed['url']) == '' )
1236 {
1237 if( is_category() )
1238 $Feed['url'] = get_category_link($cat_ID);
1239 else {
1240
1241 $blogHomepage = get_option('page_for_posts');
1242 if( !empty($blogHomepage) ) {
1243 $Feed['url'] = get_permalink( $blogHomepage );
1244 }
1245
1246 if( empty($Feed['url']) )
1247 $Feed['url'] = get_bloginfo('url');
1248 }
1249 }
1250
1251 $General = get_option('powerpress_general', array());
1252
1253 $feedComment = apply_filters('powerpress_feed_comment', '');
1254 $feedComment = trim($feedComment);
1255 if( !empty($feedComment) )
1256 echo $feedComment.' ';
1257
1258
1259 // Websub!
1260 if(!(defined('POWERPRESS_DISABLE_WEBSUB') && POWERPRESS_DISABLE_WEBSUB )) {
1261 echo "\t<atom:link rel=\"hub\" href=\"https://pubsubhubbub.appspot.com/\" />" . PHP_EOL;
1262 }
1263
1264 // Podcast Index Locked Tag
1265 if (!empty($Feed['pp_enable_feed_lock'])) {
1266 echo "\t<podcast:locked>";
1267 if (!empty($Feed['unlock_podcast'])) {
1268 echo "False";
1269 } else {
1270 echo "True";
1271 }
1272 echo "</podcast:locked>" . PHP_EOL;
1273 }
1274
1275 // add the itunes:new-feed-url tag to feed
1276 if( powerpress_is_custom_podcast_feed() )
1277 {
1278 if( !empty($Feed['itunes_new_feed_url']) )
1279 {
1280 $Feed['itunes_new_feed_url'] = str_replace('&amp;', '&', $Feed['itunes_new_feed_url']);
1281 echo "\t<itunes:new-feed-url>". htmlspecialchars(trim($Feed['itunes_new_feed_url'])) .'</itunes:new-feed-url>'.PHP_EOL;
1282 }
1283 }
1284 else if( !empty($Feed['itunes_new_feed_url']) && ($feed_slug == 'feed' || $feed_slug == 'rss2') ) // If it is the default feed (We don't wnat to apply this to category or tag feeds
1285 {
1286 $Feed['itunes_new_feed_url'] = str_replace('&amp;', '&', $Feed['itunes_new_feed_url']);
1287 echo "\t<itunes:new-feed-url>". htmlspecialchars(trim($Feed['itunes_new_feed_url'])) .'</itunes:new-feed-url>'.PHP_EOL;
1288 }
1289
1290 if( !empty($powerpress_feed['itunes_talent_name']) )
1291 echo "\t<itunes:author>" . esc_html($powerpress_feed['itunes_talent_name']) . '</itunes:author>'.PHP_EOL;
1292
1293 // itunes:explicit is REQUIRED by Apple on channel level
1294 if( !empty($powerpress_feed['explicit']) )
1295 echo "\t".'<itunes:explicit>' . $powerpress_feed['explicit'] . '</itunes:explicit>'.PHP_EOL;
1296
1297 if( !empty($Feed['itunes_block']) )
1298 echo "\t<itunes:block>yes</itunes:block>".PHP_EOL;
1299
1300 if( !empty($Feed['itunes_complete']) )
1301 echo "\t<itunes:complete>yes</itunes:complete>".PHP_EOL;
1302
1303 if( !empty($Feed['itunes_image']) )
1304 {
1305 echo "\t".'<itunes:image href="' . esc_html( powerpress_url_in_feed(str_replace(' ', '+', $Feed['itunes_image'])), 'double') . '" />'.PHP_EOL;
1306 }
1307 else
1308 {
1309 echo "\t".'<itunes:image href="' . powerpress_url_in_feed(powerpress_get_root_url()) . 'itunes_default.jpg" />'.PHP_EOL;
1310 }
1311
1312 if( !empty($Feed['itunes_type']) ) {
1313 echo "\t".'<itunes:type>'. esc_html($Feed['itunes_type']) .'</itunes:type>'.PHP_EOL;
1314 }
1315
1316 if( !empty($Feed['email']) && (!isset($Feed['pp_enable_email']) || $Feed['pp_enable_email'] == 1) && !empty($powerpress_feed['itunes_talent_name']) )
1317 {
1318 echo "\t".'<itunes:owner>'.PHP_EOL;
1319 echo "\t\t".'<itunes:name>' . esc_html($powerpress_feed['itunes_talent_name']) . '</itunes:name>'.PHP_EOL;
1320 echo "\t\t".'<itunes:email>' . esc_html($Feed['email']) . '</itunes:email>'.PHP_EOL;
1321 echo "\t".'</itunes:owner>'.PHP_EOL;
1322 }
1323
1324 if ( !empty($Feed['apple_claim_token'])) {
1325 echo "\t"."<itunes:applepodcastsverify>".esc_html($Feed['apple_claim_token'])."</itunes:applepodcastsverify>".PHP_EOL;
1326 echo "\t".'<podcast:txt purpose="applepodcastsverify">'.esc_html($Feed['apple_claim_token'])."</podcast:txt>".PHP_EOL;
1327 }
1328
1329 if( isset( $Feed['copyright'] ) && strlen($Feed['copyright']) > 1 )
1330 {
1331 $Feed['copyright'] = str_replace(array('&copy;', '(c)', '(C)', chr(194) . chr(169), chr(169) ), '&#xA9;', $Feed['copyright']);
1332 echo "\t".'<copyright>'. esc_html($Feed['copyright']) . '</copyright>'.PHP_EOL;
1333 if ( isset( $Feed['copyright_url'] ) && strlen($Feed['copyright_url']) > 1 ) {
1334 echo "\t".'<podcast:license url="' . esc_attr(powerpress_url_in_feed($Feed['copyright_url'])) . '">'. esc_html($Feed['copyright']) . '</podcast:license>'.PHP_EOL;
1335 } else {
1336 echo "\t".'<podcast:license>'. esc_html($Feed['copyright']) . '</podcast:license>'.PHP_EOL;
1337 }
1338 }
1339
1340 if (!empty($Feed['txt_tag']) && is_array($Feed['txt_tag']))
1341 {
1342 foreach ($Feed['txt_tag'] as $txt_tag) {
1343 if (!empty($txt_tag['tag'])) {
1344 $tag_output = "\t" . '<podcast:txt';
1345
1346 if (!empty($txt_tag['purpose'])) {
1347 $tag_output .= ' purpose="' . esc_attr($txt_tag['purpose']) . '"';
1348 }
1349
1350 $tag_output .= '>' . esc_html($txt_tag['tag']) . '</podcast:txt>' . PHP_EOL;
1351
1352 echo $tag_output;
1353 }
1354 }
1355 }
1356
1357 echo "\t".'<podcast:medium>'. esc_html($Feed['medium'] ?? 'podcast') . '</podcast:medium>'.PHP_EOL;
1358 $podcast_title_safe = '';
1359 if( version_compare($GLOBALS['wp_version'], '4.4', '<' ) ) {
1360 $podcast_title_safe .= get_bloginfo_rss('name');
1361 }
1362 $podcast_title_safe .= get_wp_title_rss();
1363 if( empty($General['disable_rss_image']) )
1364 {
1365 if(!empty($Feed['itunes_image']) )
1366 {
1367 $rss_image = $Feed['itunes_image'];
1368
1369 echo "\t". '<image>' .PHP_EOL;
1370 echo "\t\t".'<title>' . $podcast_title_safe . '</title>'.PHP_EOL;
1371 echo "\t\t".'<url>' . esc_html( str_replace(' ', '+', $rss_image)) . '</url>'.PHP_EOL;
1372 echo "\t\t".'<link>'. $Feed['url'] . '</link>' . PHP_EOL;
1373 echo "\t".'</image>' . PHP_EOL;
1374 }
1375 else // Use the default image
1376 {
1377 echo "\t". '<image>' .PHP_EOL;
1378 echo "\t\t".'<title>' . $podcast_title_safe . '</title>'.PHP_EOL;
1379 echo "\t\t".'<url>' . powerpress_get_root_url() . 'rss_default.jpg</url>'.PHP_EOL;
1380 echo "\t\t".'<link>'. $Feed['url'] . '</link>' . PHP_EOL;
1381 echo "\t".'</image>' . PHP_EOL;
1382 }
1383 }
1384
1385 // Handle iTunes categories
1386 $Cat1 = false; $Cat2 = false; $Cat3 = false; $SubCat1 = false; $SubCat2 = false; $SubCat3 = false;
1387 if(defined('POWERPRESS_NEW_APPLE_CATEGORIES') && POWERPRESS_NEW_APPLE_CATEGORIES == true) {
1388 $Categories = powerpress_apple_categories();
1389 for ($i = 1; $i <= 3; $i++) {
1390 if(!empty($Feed['itunes_cat_'.$i]) && empty($Feed['apple_cat_'.$i])) {
1391 $mappings = array('01-00' => '01-00', '01-01' => '01-02', '01-02' => '01-03', '01-03' => '01-04', '01-04' => '01-01',
1392 '01-05' => '01-05', '01-06' => '01-06', '02-00' => '02-00', '02-01' => '12-01', '02-02' => '02-01', '02-03' => '02-03',
1393 '02-04' => '02-00', '02-05' => '02-00', '03-00' => '03-00', '04-00' => '04-00', '04-01' => '04-00', '04-02' => '04-00',
1394 '04-03' => '09-01', '04-04' => '04-03', '04-05' => '04-00', '05-00' => '10-00', '05-01' => '10-02', '05-02' => '10-03',
1395 '05-03' => '10-06', '05-04' => '10-05', '05-05' => '10-05', '06-00' => '06-00', '06-01' => '06-00', '06-02' => '06-00',
1396 '06-03' => '06-00', '06-04' => '06-00', '07-00' => '07-00', '07-01' => '07-01', '07-02' => '07-00', '07-03' => '04-04',
1397 '07-04' => '07-06', '08-00' => '09-00', '09-00' => '11-00', '11-00' => '13-00', '11-01' => '13-01', '11-02' => '13-02',
1398 '11-03' => '13-03', '11-04' => '13-04', '11-05' => '13-05', '11-06' => '13-06', '11-07' => '13-07', '12-00' => '14-00',
1399 '12-01' => '07-03', '12-02' => '14-06', '12-03' => '14-09', '13-00' => '15-00', '13-01' => '08-00', '13-02' => '15-02',
1400 '13-03' => '15-03', '13-04' => '15-04', '14-00' => '16-00', '14-01' => '16-00', '14-02' => '16-00', '14-03' => '16-15',
1401 '14-04' => '16-00', '15-00' => '17-00', '15-01' => '17-00', '15-02' => '12-07', '15-03' => '17-00', '15-04' => '17-00', '16-00' => '19-00');
1402 $Feed['apple_cat_'. $i] = $mappings[$Feed['itunes_cat_'.$i]];
1403
1404 }
1405 }
1406 if (!empty($Feed['apple_cat_1']))
1407 list($Cat1, $SubCat1) = explode('-', $Feed['apple_cat_1']);
1408 if (!empty($Feed['apple_cat_2']))
1409 list($Cat2, $SubCat2) = explode('-', $Feed['apple_cat_2']);
1410 if (!empty($Feed['apple_cat_3']))
1411 list($Cat3, $SubCat3) = explode('-', $Feed['apple_cat_3']);
1412 $googleplay_category_mapping = array(
1413 '01-00' => '01-00',
1414 '02-00' => '02-00',
1415 '03-00' => '03-00',
1416 '04-00' => '04-00',
1417 '05-00' => '13-00',
1418 '06-00' => '06-00',
1419 '07-00' => '07-00',
1420 '08-00' => '13-00',
1421 '09-00' => '08-00',
1422 '10-00' => '05-00',
1423 '11-00' => '09-00',
1424 '12-00' => '10-00',
1425 '13-00' => '11-00',
1426 '14-00' => '12-00',
1427 '15-00' => '13-00',
1428 '16-00' => '14-00',
1429 '17-00' => '15-00',
1430 '18-00' => '13-00',
1431 '19-00' => '16-00',
1432 );
1433 }
1434 else {
1435 $Categories = powerpress_itunes_categories();
1436 if (!empty($Feed['itunes_cat_1']))
1437 list($Cat1, $SubCat1) = explode('-', $Feed['itunes_cat_1']);
1438 if (!empty($Feed['itunes_cat_2']))
1439 list($Cat2, $SubCat2) = explode('-', $Feed['itunes_cat_2']);
1440 if (!empty($Feed['itunes_cat_3']))
1441 list($Cat3, $SubCat3) = explode('-', $Feed['itunes_cat_3']);
1442 $googleplay_category_mapping = array(
1443 '01-00' => '01-00',
1444 '02-00' => '02-00',
1445 '03-00' => '03-00',
1446 '04-00' => '04-00',
1447 '05-00' => '05-00',
1448 '06-00' => '06-00',
1449 '07-00' => '07-00',
1450 '08-00' => '08-00',
1451 '09-00' => '09-00',
1452 '10-00' => '10-00',
1453 '11-00' => '11-00',
1454 '12-00' => '12-00',
1455 '13-00' => '13-00',
1456 '14-00' => '14-00',
1457 '15-00' => '15-00',
1458 '16-00' => '16-00',
1459 );
1460 }
1461
1462 $googleplay_categories = powerpress_googleplay_categories();
1463
1464 if( $Cat1 )
1465 {
1466 $CatDesc = $Categories[$Cat1.'-00'];
1467 $SubCatDesc = $Categories[$Cat1.'-'.$SubCat1];
1468 echo "\t".'<itunes:category text="'. esc_attr($CatDesc);
1469 if( $SubCat1 != '00' ) {
1470 echo '">' . PHP_EOL . "\t\t" . '<itunes:category text="' . esc_attr($SubCatDesc) . '" />' . PHP_EOL;
1471 // End this category set
1472 echo "\t".'</itunes:category>'.PHP_EOL;
1473 } else {
1474 echo '" />'.PHP_EOL;
1475 }
1476 }
1477
1478 if( $Cat2 )
1479 {
1480 $CatDesc = $Categories[$Cat2.'-00'];
1481 $SubCatDesc = $Categories[$Cat2.'-'.$SubCat2];
1482
1483 echo "\t".'<itunes:category text="'. esc_attr($CatDesc);
1484 if( $SubCat2 != '00' ) {
1485 echo '">' . PHP_EOL . "\t\t" . '<itunes:category text="' . esc_attr($SubCatDesc) . '" />' . PHP_EOL;
1486 // End this category set
1487 echo "\t".'</itunes:category>'.PHP_EOL;
1488 } else {
1489 echo '" />'.PHP_EOL;
1490 }
1491 }
1492
1493 if( $Cat3 )
1494 {
1495 $CatDesc = $Categories[$Cat3.'-00'];
1496 $SubCatDesc = $Categories[$Cat3.'-'.$SubCat3];
1497
1498 echo "\t".'<itunes:category text="'. esc_attr($CatDesc);
1499 if( $SubCat3 != '00' ) {
1500 echo '">' . PHP_EOL . "\t\t" . '<itunes:category text="' . esc_attr($SubCatDesc) . '" />' . PHP_EOL;
1501 // End this category set
1502 echo "\t".'</itunes:category>'.PHP_EOL;
1503 } else {
1504 echo '" />'.PHP_EOL;
1505 }
1506 }
1507 // End Handle iTunes categories
1508
1509 // RawVoice RSS Tags
1510 if( !defined('POWERPRESS_RAWVOICE_RSS') || POWERPRESS_RAWVOICE_RSS != false )
1511 {
1512 if( !empty($Feed['parental_rating']) )
1513 echo "\t<rawvoice:rating>". $Feed['parental_rating'] ."</rawvoice:rating>".PHP_EOL;
1514
1515 $locations = [];
1516 if (!empty($Feed['location']) && is_array($Feed['location'])) {
1517 $first = reset($Feed['location']);
1518 if (is_array($first) && (isset($first['address']) || isset($first['location']))) {
1519 // nested format
1520 foreach ($Feed['location'] as $loc) {
1521 if (empty($loc) || !is_array($loc)) continue;
1522 $address = $loc['address'] ?? $loc['location'] ?? '';
1523 if ($address === '') continue;
1524 $locations[] = [
1525 'address' => $address,
1526 'pci_geo' => $loc['pci_geo'] ?? $loc['geo'] ?? '',
1527 'pci_osm' => $loc['pci_osm'] ?? $loc['osm'] ?? '',
1528 'pci_rel' => $loc['pci_rel'] ?? $loc['rel'] ?? '1',
1529 'pci_country' => $loc['pci_country'] ?? $loc['country'] ?? ''
1530 ];
1531 }
1532 } else {
1533 // paralellized (legacy)
1534 foreach ((array)$Feed['location'] as $i => $addr) {
1535 if ($addr === '' || $addr === null) continue;
1536 $locations[] = [
1537 'address' => $addr,
1538 'pci_geo' => $Feed['pci_geo'][$i] ?? $Feed['geo'][$i] ?? '',
1539 'pci_osm' => $Feed['pci_osm'][$i] ?? $Feed['osm'][$i] ?? '',
1540 'pci_rel' => $Feed['pci_rel'][$i] ?? $Feed['rel'][$i] ?? '1',
1541 'pci_country' => $Feed['pci_country'][$i] ?? $Feed['country'][$i] ?? '',
1542 ];
1543 }
1544 }
1545 }
1546
1547 foreach ($locations as $location) {
1548 $address = trim((string)($location['address'] ?? ''));
1549 if ($address === '') continue;
1550
1551 echo "\t<rawvoice:location>" . htmlspecialchars($address) . "</rawvoice:location>\n";
1552 echo "\t<podcast:location";
1553
1554 if (!empty($location['pci_geo'])) echo ' geo="' . htmlspecialchars($location['pci_geo']) . '"';
1555 if (!empty($location['pci_osm'])) echo ' osm="' . htmlspecialchars($location['pci_osm']) . '"';
1556 if (!empty($location['pci_rel'])) echo ' rel="' . ($location['pci_rel'] == '1' ? 'subject' : 'creator') . '"';
1557 if (!empty($location['pci_country'])) echo ' country="' . htmlspecialchars($location['pci_country']) . '"';
1558
1559 echo '>' . htmlspecialchars($address) . "</podcast:location>\n";
1560 }
1561
1562 // ==========================================
1563 // UPDATE FREQUENCY <podcast:updateFrequency>
1564 // <rawvoice:frequency>
1565 // ==========================================
1566
1567 $freq_data = powerpress_normalize_update_frequency(
1568 $Feed['update_frequency'] ?? null,
1569 $Feed['update_frequency_week'] ?? null,
1570 $Feed['update_frequency_month'] ?? null
1571 );
1572
1573 if (!empty($freq_data['freq'])) {
1574 // HANDLE RRULE ATTR
1575 $rrule_parts = ['FREQ=' . $freq_data['freq']];
1576 if (!empty($freq_data['byday']))
1577 $rrule_parts[] = "BYDAY={$freq_data['byday']}";
1578
1579 if (!empty($freq_data['bymonth']))
1580 $rrule_parts[] = "BYMONTH={$freq_data['bymonth']}";
1581
1582 if (!empty($freq_data['bymonthday']))
1583 $rrule_parts[] = "BYMONTHDAY={$freq_data['bymonthday']}";
1584
1585 if (!empty($freq_data['count']))
1586 $rrule_parts[] = 'COUNT=' . (int) $freq_data['count'];
1587
1588 if (!empty($freq_data['interval']))
1589 $rrule_parts[] = 'INTERVAL=' . (int) $freq_data['interval'];
1590
1591 if (!empty($freq_data['until']))
1592 $rrule_parts[] = "UNTIL={$freq_data['until']}";
1593
1594 $rrule = implode(';', $rrule_parts);
1595
1596 // HANDLE DISPLAY FIELD
1597 $display = $freq_data['display'] ?? ucfirst(strtolower($freq_data['freq']));
1598 $attrs = ' rrule="' . esc_attr($rrule) . '"';
1599
1600 // HANDLE COMPLETE ATTR
1601 if (!empty($Feed['itunes_complete'])) {
1602 $attrs .= ' complete="true"';
1603 }
1604
1605 // HANDLE DTSTART ATTR
1606 if (!empty($Feed['dtstart'])) {
1607 $attrs .= ' dtstart="' . esc_attr($Feed['dtstart']) . '"';
1608 }
1609
1610 // OUTPUT PCI TAG
1611 echo "\t<podcast:updateFrequency{$attrs}>" . esc_html($display) . "</podcast:updateFrequency>\n";
1612
1613 // OUTPUT RV TAG
1614 if (!empty($Feed['frequency']) && in_array($freq_data['freq'], ['DAILY', 'WEEKLY', 'MONTHLY'], true)) {
1615 echo "\t<rawvoice:frequency>" . htmlspecialchars($Feed['frequency']) . "</rawvoice:frequency>\n";
1616 }
1617 }
1618
1619 // =====================
1620 // BLOCK <podcast:block>
1621 // <itunes:block>
1622 // =====================
1623
1624 if (isset($Feed['block'])) {
1625 if (isset($Feed['block_all']) && $Feed['block_all'] != 0) {
1626 echo "\t<podcast:block>yes</podcast:block>\n";
1627 echo "\t<itunes:block>yes</itunes:block>\n";
1628 } else {
1629 // block individuals
1630 $blockListStr = $Feed['block_list'] ?? '';
1631 $blockList = !empty($blockListStr) ? explode(';', $blockListStr) : [];
1632
1633 foreach ($blockList as $block) {
1634 if ($block != '') {
1635 echo "\t<podcast:block id=\"$block\">yes</podcast:block>\n";
1636 if ($block == 'apple') {
1637 echo "\t<itunes:block>yes</itunes:block>\n";
1638 }
1639 }
1640 }
1641 }
1642 }
1643
1644 if (isset($Feed['remote_items']) && !empty($Feed['remote_items'])) {
1645 $existingRemoteItems = $Feed['remote_items'];
1646 $existingPodrollItems = [];
1647 $existingFeedItems = [];
1648
1649 foreach ($existingRemoteItems as $remoteItem) {
1650 $isPodroll = $remoteItem['podroll'] ?? 0;
1651 if ($isPodroll == 1)
1652 $existingPodrollItems[] = $remoteItem;
1653 else
1654 $existingFeedItems[] = $remoteItem;
1655 }
1656
1657 if (!empty($existingPodrollItems)) {
1658 echo "\t<podcast:podroll>\n";
1659
1660 foreach ($existingPodrollItems as $remoteItem) {
1661 $feedGuid = $remoteItem['feed_guid'];
1662 echo "\t\t<podcast:remoteItem feedGuid=\"$feedGuid\"";
1663
1664 if (!empty($remoteItem['item_guid'])) {
1665 echo " itemGuid=\"" . esc_attr($remoteItem['item_guid']) . "\"";
1666 }
1667
1668 if (!empty($remoteItem['item_link'])) {
1669 echo " feedUrl=\"" . esc_attr($remoteItem['item_link']) . "\"";
1670 }
1671
1672 if (!empty($remoteItem['medium'])) {
1673 echo " medium=\"" . esc_attr($remoteItem['medium']) . "\"";
1674 }
1675
1676 if (!empty($remoteItem['item_title'])) {
1677 echo " title=\"" . esc_attr($remoteItem['item_title']) . "\"";
1678 }
1679 echo " />\n";
1680 }
1681 echo "\t</podcast:podroll>\n";
1682 }
1683
1684 foreach ($existingFeedItems as $remoteItem) {
1685 $feedGuid = $remoteItem['feed_guid'];
1686 $attrStr = "feedGuid=\"$feedGuid\"";
1687
1688 if (!empty($remoteItem['item_guid'])) {
1689 $itemGuid = $remoteItem['item_guid'] ?? '';
1690 $attrStr .= " itemGuid=\"" . $itemGuid . "\"";
1691 }
1692 if (!empty($remoteItem['item_link'])) {
1693 $attrStr .= " feedUrl=\"" . esc_attr($remoteItem['item_link']) . "\"";
1694 }
1695 if (!empty($remoteItem['medium'])) {
1696 $attrStr .= " medium=\"" . esc_attr($remoteItem['medium']) . "\"";
1697 }
1698 if (!empty($remoteItem['item_title'])) {
1699 $attrStr .= " title=\"" . esc_attr($remoteItem['item_title']) . "\"";
1700 }
1701
1702 echo "\t<podcast:remoteItem $attrStr />\n";
1703 }
1704 }
1705
1706
1707 $value_recipients = [];
1708 if (!empty($Feed['value_recipients']) && is_array($Feed['value_recipients'])) {
1709 foreach ($Feed['value_recipients'] as $value_recipient) {
1710 if (empty($value_recipient['pubkey']) || empty($value_recipient['split'])) {
1711 continue;
1712 }
1713
1714 $value_recipients[] = [
1715 'lightning' => $value_recipient['lightning'] ?? $value_recipient['name'] ?? '',
1716 'split' => $value_recipient['split'],
1717 'address' => $value_recipient['pubkey'],
1718 'customKey' => $value_recipient['custom_key'] ?? $value_recipient['customKey'] ?? '',
1719 'customValue' => $value_recipient['custom_value'] ?? $value_recipient['customValue'] ?? '',
1720 'fee' => (isset($value_recipient['fee']) && $value_recipient['fee'] === 'true') ? 'true' : 'false'
1721 ];
1722 }
1723 } elseif (!empty($Feed['value_pubkey']) && !empty($Feed['value_split'])) {
1724 foreach ($Feed['value_pubkey'] as $id => $pubkey) {
1725 if (empty($pubkey)) continue;
1726 $value_recipients[] = [
1727 'lightning' => $Feed['value_lightning'][$id] ?? '',
1728 'split' => $Feed['value_split'][$id],
1729 'address' => $pubkey,
1730 'customKey' => $Feed['value_custom_key'][$id] ?? '',
1731 'customValue' => $Feed['value_custom_value'][$id] ?? '',
1732 'fee' => isset($Feed['value_is_fee'][$id]) && $Feed['value_is_fee'][$id] ? 'true' : 'false'
1733 ];
1734 }
1735 }
1736
1737 if (!empty($value_recipients)) {
1738 $value_recipients[] = [
1739 'lightning' => 'blubrry@getalby.com',
1740 'split' => 3,
1741 'address' => '03b8a595e4d8e19efa8faa3fbe2524b0d39f7c812415ff831d38a466a4a1bc888a',
1742 'customKey' => '696969',
1743 'customValue' => 'qAHJuqKLmMhTNFualcIj',
1744 'fee' => 'true'
1745 ];
1746
1747 echo "\t".'<podcast:value type="lightning" method="keysend" suggested="0.00000005000">'."\n";
1748
1749 foreach ($value_recipients as $value_recipient) {
1750 $attrStr = 'type="node" split="'.$value_recipient['split'].'" address="'.$value_recipient['address'].'"';
1751
1752 if (!empty($value_recipient['lightning'])) {
1753 $attrStr .= ' name="'.htmlspecialchars($value_recipient['lightning']).'"';
1754 }
1755
1756 if (!empty($value_recipient['customKey'])) {
1757 $attrStr .= ' customKey="'.htmlspecialchars($value_recipient['customKey']).'"';
1758 }
1759
1760 if (!empty($value_recipient['customValue'])) {
1761 $attrStr .= ' customValue="'.htmlspecialchars($value_recipient['customValue']).'"';
1762 }
1763
1764 if ($value_recipient['fee'] === 'true') {
1765 $attrStr .= ' fee="true"';
1766 }
1767
1768 echo "\t\t"."<podcast:valueRecipient $attrStr/>\n";
1769 }
1770
1771 echo "\t".'</podcast:value>'."\n";
1772 }
1773
1774 // DONATE
1775 if( !empty($Feed['donate_link']) && !empty($Feed['donate_url']) ) {
1776 echo "\t<rawvoice:donate href=\"" . htmlspecialchars($Feed['donate_url']) . "\">" . htmlspecialchars((empty($Feed['donate_label']) ? '' : $Feed['donate_label'])) . "</rawvoice:donate>" . PHP_EOL;
1777 echo "\t<podcast:funding url=\"" . htmlspecialchars($Feed['donate_url']) . "\">" . htmlspecialchars((empty($Feed['donate_label']) ? '' : $Feed['donate_label'])) . "</podcast:funding>" . PHP_EOL;
1778 }
1779
1780 // CREDITS
1781 // nested
1782 $channel_credits = [];
1783 if (!empty($Feed['credits'])) {
1784 $channel_credits = $Feed['credits'];
1785 }
1786 // parallelized (legacy)
1787 else if ( !empty($Feed['person_names']) ) {
1788 $personNames = $Feed['person_names'];
1789 $personRoles = $Feed['person_roles'] ?? [];
1790 $personURLs = $Feed['person_urls'] ?? [];
1791 $linkURLs = $Feed['link_urls'] ?? [];
1792
1793 foreach ($personNames as $i => $name) {
1794 if ($name == '') continue;
1795 $channel_credits[] = [
1796 'name' => $name,
1797 'role' => $personRoles[$i] ?? '',
1798 'person_url' => $personURLs[$i] ?? '',
1799 'link_url' => $linkURLs[$i] ?? ''
1800 ];
1801 }
1802 }
1803
1804 // RSS output
1805 foreach ($channel_credits as $credit) {
1806 if (empty($credit['name'])) continue;
1807
1808 echo "\t<podcast:person";
1809 if (!empty($credit['role'])) {
1810 echo " role=\"" . htmlspecialchars($credit['role']) . "\"";
1811 }
1812 if (!empty($credit['person_url'])) {
1813 echo " img=\"" . htmlspecialchars($credit['person_url']) . "\"";
1814 }
1815 if (!empty($credit['link_url'])) {
1816 echo " href=\"" . htmlspecialchars($credit['link_url']) . "\"";
1817 }
1818 echo ">" . htmlspecialchars($credit['name']) . "</podcast:person>" . PHP_EOL;
1819
1820 }
1821
1822 echo "\t<podcast:podping usesPodping=\"true\" />" . PHP_EOL;
1823
1824 require_once('uuid5.class.php');
1825 // This will be the same every time, but moved this logic into here to expedite removal of duplicate GUIDs
1826 $guidFeedURL = str_replace("http://", "", str_replace("https://", "", $feed_url));
1827 $guidFeedURL = rtrim($guidFeedURL,"/");
1828 $guid = UUID::v5('ead4c236-bf58-58c6-a2c6-a6b28d128cb6', $guidFeedURL);
1829 if (UUID::is_valid($guid)) {
1830 $Feed['podcast_guid'] = $guid;
1831 }
1832 if (!empty($Feed['guid_override_check']) && !empty($Feed['guid_override']))
1833 echo "\t<podcast:guid>".$Feed['guid_override']."</podcast:guid>" . PHP_EOL;
1834 elseif (isset($Feed['podcast_guid']) && UUID::is_valid($Feed['podcast_guid']) && $guidFeedURL != '')
1835 echo "\t<podcast:guid>".$Feed['podcast_guid']."</podcast:guid>" . PHP_EOL;
1836
1837 if (isset($Feed['live_item']) && $Feed['live_item']['enabled'] == '1' && UUID::is_valid($Feed['live_item']['guid'])) {
1838 $liveItem = $Feed['live_item'];
1839 $tzName = timezone_name_from_abbr($liveItem['timezone']);
1840
1841 $status = strtolower($liveItem['status']);
1842 $startArr = explode('T', $liveItem['start_date_time']);
1843 $startDate = new DateTime($startArr[0] . ' ' . $startArr[1], new DateTimeZone($tzName));
1844 $start = $startDate->format('c');
1845
1846 $endArr = explode('T', $liveItem['end_date_time']);
1847 $endDate = new DateTime($endArr[0] . ' ' . $endArr[1], new DateTimeZone($tzName));
1848 $end = $endDate->format('c');
1849 echo "\t<podcast:liveItem status=\"$status\" start=\"$start\" end=\"$end\">" . PHP_EOL;
1850 echo "\t\t<title>".esc_html($liveItem['title'])."</title>" . PHP_EOL;
1851 echo "\t\t<guid isPermalink=\"false\">".$liveItem['guid']."</guid>" . PHP_EOL;
1852
1853 if (!empty($liveItem['description']))
1854 echo "\t\t<description>".esc_html($liveItem['description'])."</description>" . PHP_EOL;
1855
1856 if (!empty($liveItem['coverart_link']))
1857 echo "\t\t<podcast:images srcset=\"".($liveItem['cover_art'] ?? '')." 1400w\" />" . PHP_EOL;
1858
1859
1860 $EnclosureAttr = 'url="'.$liveItem['stream_link'].'" ';
1861 $EnclosureAttr .= 'length="5242880" ';
1862 $EnclosureAttr .= 'type="'.$liveItem['stream_type'].'"';
1863
1864 echo "\t\t<enclosure $EnclosureAttr />" . PHP_EOL;
1865 echo "\t\t<podcast:alternateEnclosure type=\"".$liveItem['stream_type']."\" length=\"5242880\">" . PHP_EOL;
1866 echo "\t\t\t<podcast:source uri=\"".$liveItem['stream_link']."\" />" . PHP_EOL;
1867 echo "\t\t</podcast:alternateEnclosure>" . PHP_EOL;
1868
1869
1870 if (!empty($liveItem['episode_link']))
1871 echo "\t\t<link>".$liveItem['episode_link']."</link>" . PHP_EOL;
1872
1873 echo "\t\t<podcast:contentLink href=\"".$liveItem['fallback_link']."\">Listen Live!</podcast:contentLink>" . PHP_EOL;
1874 echo "\t\t<podcast:timezone>".$liveItem['timezone']."</podcast:timezone>" . PHP_EOL;
1875 echo "\t</podcast:liveItem>" . PHP_EOL;
1876 }
1877
1878 if( !empty($Feed['itunes_url']) || !empty($Feed['tunein_url']) || !empty($Feed['spotify_url']) ) {
1879 echo "\t<rawvoice:subscribe feed=\"";
1880 self_link();
1881 echo '"';
1882
1883 // Subscribe page // empty($FeedSettings['subscribe_page_link_href']) && empty($FeedSettings['subscribe_page_link_id'])
1884 if( !empty($Feed['subscribe_page_link_id']) ) {
1885 $link = get_page_link($Feed['subscribe_page_link_id']);
1886 if( !empty($link) ) {
1887 echo " html=\"". htmlspecialchars( $link ) .'"';
1888 }
1889 } else if( !empty($Feed['subscribe_page_link_href']) ) {
1890 echo " html=\"". htmlspecialchars( $Feed['subscribe_page_link_href'] ) .'"';
1891 }
1892
1893 if( !empty($Feed['itunes_url']) )
1894 echo " itunes=\"". htmlspecialchars( $Feed['itunes_url'] ) .'"';
1895 if( !empty($Feed['tunein_url']) )
1896 echo " tunein=\"". htmlspecialchars( $Feed['tunein_url'] ) .'"';
1897 if( !empty($Feed['spotify_url']) )
1898 echo " spotify=\"". htmlspecialchars( $Feed['spotify_url'] ) .'"';
1899 if( !empty($Feed['amazon_url']) )
1900 echo " amazon_music=\"". htmlspecialchars( $Feed['amazon_url'] ) .'"';
1901 if( !empty($Feed['pcindex_url']) )
1902 echo " pcindex=\"". htmlspecialchars( $Feed['pcindex_url'] ) .'"';
1903 if( !empty($Feed['iheart_url']) )
1904 echo " iheart=\"". htmlspecialchars( $Feed['iheart_url'] ) .'"';
1905 if( !empty($Feed['pandora_url']) )
1906 echo " pandora=\"". htmlspecialchars( $Feed['pandora_url'] ) .'"';
1907 if( !empty($Feed['deezer_url']) )
1908 echo " deezer=\"". htmlspecialchars( $Feed['deezer_url'] ) .'"';
1909 if( !empty($Feed['jiosaavn_url']) )
1910 echo " jiosaavn=\"". htmlspecialchars( $Feed['jiosaavn_url'] ) .'"';
1911 if( !empty($Feed['podchaser_url']) )
1912 echo " podchaser=\"". htmlspecialchars( $Feed['podchaser_url'] ) .'"';
1913 if( !empty($Feed['gaana_url']) )
1914 echo " gaana=\"". htmlspecialchars( $Feed['gaana_url'] ) .'"';
1915 if( !empty($Feed['anghami_url']) )
1916 echo " anghami=\"". htmlspecialchars( $Feed['anghami_url'] ) .'"';
1917 if( !empty($Feed['youtube_url']) )
1918 echo " youtube=\"". htmlspecialchars( $Feed['youtube_url'] ) .'"';
1919 echo "></rawvoice:subscribe>".PHP_EOL;
1920 }
1921 }
1922 }
1923
1924 add_action('rss2_head', 'powerpress_rss2_head');
1925 add_action('rss2_head_powerpress', 'powerpress_rss2_head');
1926
1927 function powerpress_rss2_item()
1928 {
1929 global $post, $powerpress_feed;
1930
1931 // disable php notices inside feeds
1932 error_reporting(0);
1933
1934 // are we processing a feed that powerpress should handle
1935 if( !powerpress_is_podcast_feed() )
1936 return;
1937
1938 if( function_exists('post_password_required') )
1939 {
1940 if( post_password_required($post) )
1941 return;
1942 }
1943
1944 // Check and see if we're working with a podcast episode
1945 $custom_enclosure = false;
1946 if( powerpress_is_custom_podcast_feed() && get_query_var('feed') !== 'podcast' && !is_category() && !is_tax() && !is_tag() )
1947 {
1948 $EpisodeData = powerpress_get_enclosure_data($post->ID, get_query_var('feed') );
1949 $custom_enclosure = true;
1950 }
1951 else
1952 {
1953 $EpisodeData = powerpress_get_enclosure_data($post->ID, 'podcast');
1954 if( !$EpisodeData && !empty($powerpress_feed['process_podpress']) )
1955 {
1956 $EpisodeData = powerpress_get_enclosure_data_podpress($post->ID);
1957 $custom_enclosure = true;
1958 }
1959 }
1960
1961 // No episode data to include
1962 if( empty($EpisodeData) || empty($EpisodeData['url']) || $EpisodeData['url'] == 'no' )
1963 return;
1964
1965 // If enclosure not added, check to see why...
1966 if( defined('POWERPRESS_ENCLOSURE_FIX') && POWERPRESS_ENCLOSURE_FIX && !$custom_enclosure && $GLOBALS['powerpress_rss_enclosure_post_id'] != $post->ID )
1967 {
1968 $enclosure_in_wp = apply_filters('rss_enclosure', '<enclosure url="' . trim(htmlspecialchars($EpisodeData['url']) . '" length="' . $EpisodeData['size'] . '" type="' . $EpisodeData['type'] . '" />' . "\n") );
1969 if( !$enclosure_in_wp )
1970 $custom_enclosure = true;
1971 }
1972
1973 // Lets print the enclosure tag
1974 if( $custom_enclosure ) // We need to add the enclosure tag here...
1975 {
1976 if( empty($EpisodeData['size']) )
1977 $EpisodeData['size'] = 5242880; // Use the dummy 5MB size since we don't have a size to quote
1978
1979 // encode htmlspecialchars if necessary
1980 $decoded = htmlspecialchars_decode($EpisodeData['url']);
1981 if (strlen($decoded) != strlen($EpisodeData['url'])) {
1982 // already encoded
1983 $media_url = $EpisodeData['url'];
1984 } else {
1985 // might need encoded/no risk of double encoding
1986 $media_url = htmlspecialchars($EpisodeData['url']);
1987 }
1988
1989 echo "\t\t" . sprintf('<enclosure url="%s" length="%d" type="%s" />%s',
1990 powerpress_url_in_feed(trim($media_url)),
1991 trim($EpisodeData['size']),
1992 trim($EpisodeData['type']),
1993 PHP_EOL);
1994 }
1995
1996 if (!empty($EpisodeData['alternate_enclosure'])) {
1997 $episode_str = '';
1998
1999 foreach ($EpisodeData['alternate_enclosure'] as $alternate_enclosure) {
2000
2001 $episode_str = '';
2002 $episode_str .= "\t\t<podcast:alternateEnclosure ";
2003 // support both 'length' (new) and 'size' (legacy) field names
2004 $alt_length = $alternate_enclosure['length'] ?? $alternate_enclosure['size'] ?? 0;
2005 if (!empty($alt_length) && $alt_length > 0) {
2006 $episode_str .= ' length="' . esc_attr($alt_length) . '"';
2007 }
2008
2009 if (!empty($alternate_enclosure['type'])){
2010 $episode_str .= ' type="' . esc_attr($alternate_enclosure['type']) . '"';
2011 }
2012
2013 if (!empty($alternate_enclosure['height'])) {
2014 $episode_str .= ' height="' . esc_attr($alternate_enclosure['height']) . '"';
2015 }
2016
2017 if (!empty($alternate_enclosure['title'])) {
2018 $episode_str .= ' title="' . esc_attr($alternate_enclosure['title']) . '"';
2019 }
2020
2021 if (!empty($alternate_enclosure['lang'])) {
2022 $episode_str .= ' lang="' . esc_attr($alternate_enclosure['lang']) . '"';
2023 }
2024
2025 if (!empty($alternate_enclosure['rel'])) {
2026 $episode_str .= ' rel="' . esc_attr($alternate_enclosure['rel']) . '"';
2027 }
2028
2029 if (!empty($alternate_enclosure['codecs'])) {
2030 $episode_str .= ' codecs="' . esc_attr($alternate_enclosure['codecs']) . '"';
2031 }
2032
2033 if (!empty($alternate_enclosure['bitrate'])) {
2034 $episode_str .= ' bitrate="' . esc_attr($alternate_enclosure['bitrate']) . '"';
2035 }
2036
2037 if (!empty($alternate_enclosure['is_default'])) {
2038 if ($alternate_enclosure['is_default']) {
2039 $episode_str .= ' default="true"';
2040 }
2041 }
2042 $episode_str .= ">\n";
2043
2044 // Process Alternate Enclosure's URI values if present
2045 $episode_str .= "\t\t\t" . sprintf('<podcast:source uri="%s" contentType="%s"/>%s',
2046 powerpress_url_in_feed(trim(htmlspecialchars($alternate_enclosure['url']))),
2047 trim(htmlspecialchars($alternate_enclosure['type'])),
2048 PHP_EOL);
2049
2050 if (!empty($alternate_enclosure['uris']) && is_array($alternate_enclosure['uris'])) {
2051 foreach ($alternate_enclosure['uris'] as $uri_data) {
2052 $uri_url = !empty($uri_data['uri']) ? trim(htmlspecialchars($uri_data['uri'])) : '';
2053 if (empty($uri_url)) continue;
2054
2055 $uri_type = !empty($uri_data['contentType'])
2056 ? trim(htmlspecialchars($uri_data['contentType']))
2057 : trim(htmlspecialchars(powerpress_get_contenttype($uri_url)));
2058 if ($uri_url === trim(htmlspecialchars($EpisodeData['url'])) || $uri_type === '') continue;
2059
2060 $episode_str .= "\t\t\t" . sprintf('<podcast:source uri="%s" contentType="%s"/>%s ', esc_url(powerpress_url_in_feed($uri_url)), $uri_type, PHP_EOL);
2061 }
2062 }
2063 $episode_str .= "\t\t" . sprintf('</podcast:alternateEnclosure>%s', PHP_EOL);
2064 echo $episode_str;
2065 }
2066 }
2067
2068 if (!empty($EpisodeData['content_link'])) {
2069 foreach ($EpisodeData['content_link'] as $i => $content_link) {
2070 $url = htmlspecialchars($content_link['url']);
2071 $label = htmlspecialchars($content_link['label'] ?? '');
2072
2073 if (filter_var($url, FILTER_VALIDATE_URL)) {
2074 $href_string = 'href="' . trim($url) . '"';
2075 echo "\t\t" . sprintf('<podcast:contentLink %s>%s</podcast:contentLink>%s',
2076 $href_string,
2077 $label,
2078 PHP_EOL);
2079 }
2080 }
2081 }
2082
2083
2084 // episode-level author: only output when ep metabox field is filled or itunes_author_post is checked
2085 $episode_author = '';
2086 if( isset($powerpress_feed['itunes_author_post']) )
2087 $episode_author = get_the_author();
2088 if( !empty( $EpisodeData['author'] ) )
2089 $episode_author = $EpisodeData['author'];
2090
2091 $explicit = $powerpress_feed['explicit'];
2092 $block = false;
2093
2094 if( isset( $EpisodeData['explicit'] ) && is_numeric($EpisodeData['explicit']) )
2095 {
2096 // switching from 'not set' 'yes' 'clean' to 'true' 'false'--for backwards compatibility, 'not set' will now be 'false'
2097 $explicit_array = array("false", "true", "false");
2098 $explicit = $explicit_array[$EpisodeData['explicit']];
2099 }
2100
2101 if( !empty( $EpisodeData['block'] ) )
2102 $block = 'yes';
2103
2104 if( !empty($episode_author) ) {
2105 echo "\t\t<itunes:author>" . esc_html($episode_author) . '</itunes:author>'.PHP_EOL;
2106 }
2107
2108 // itunes episode image
2109 if( !empty( $EpisodeData['itunes_image']) ) {
2110 echo "\t\t".'<itunes:image href="' . esc_attr( powerpress_url_in_feed(str_replace(' ', '+', $EpisodeData['itunes_image'])), 'double') . '" />'.PHP_EOL;
2111 } else if( !empty($powerpress_feed['itunes_image']) ) {
2112 echo "\t\t".'<itunes:image href="' . esc_attr( powerpress_url_in_feed(str_replace(' ', '+', $powerpress_feed['itunes_image'])), 'double') . '" />'.PHP_EOL;
2113 }
2114
2115 if( !empty($EpisodeData['season']) ) {
2116 echo "\t\t".'<itunes:season>'. esc_html($EpisodeData['season']) .'</itunes:season>'.PHP_EOL;
2117 echo "\t\t".'<podcast:season>'. esc_html($EpisodeData['season']) .'</podcast:season>'.PHP_EOL;
2118 }
2119
2120 if( !empty($EpisodeData['episode_no']) ) {
2121 echo "\t\t".'<itunes:episode>'. esc_html(floor($EpisodeData['episode_no'])) .'</itunes:episode>'.PHP_EOL;
2122 if (!empty($EpisodeData['episode_no_display'])) {
2123 echo "\t\t" . '<podcast:episode display="' . esc_html($EpisodeData['episode_no_display']) . '">' . esc_html(floor($EpisodeData['episode_no'])) . '</podcast:episode>' . PHP_EOL;
2124 } else {
2125 echo "\t\t" . '<podcast:episode>' . esc_html(floor($EpisodeData['episode_no'])) . '</podcast:episode>' . PHP_EOL;
2126 }
2127 }
2128
2129 // TXT Tag
2130 if ( !empty($EpisodeData['txt_tag']) ) {
2131 foreach ($EpisodeData['txt_tag'] as $tag) {
2132 if (empty($tag['tag'])) {
2133 continue;
2134 }
2135 echo "\t\t<podcast:txt";
2136
2137 if (!empty($tag['purpose'])) {
2138 $tag_purpose = esc_html($tag['purpose']);
2139 echo " purpose=\"" . $tag_purpose . "\">";
2140 } else {
2141 echo ">";
2142 }
2143
2144 $tag_content = esc_html(trim($tag['tag']));
2145 echo $tag_content . "</podcast:txt>" . PHP_EOL;
2146 }
2147 }
2148
2149 if( !empty($EpisodeData['episode_title']) ) {
2150 echo "\t\t".'<itunes:title>'. esc_html($EpisodeData['episode_title']) .'</itunes:title>'.PHP_EOL;
2151 }
2152
2153 if(empty($EpisodeData['episode_type'])) {
2154 $EpisodeData['episode_type'] = 'full';
2155 }
2156 echo "\t\t".'<itunes:episodeType>'. esc_html($EpisodeData['episode_type']) .'</itunes:episodeType>'.PHP_EOL;
2157
2158 // episode explicit only outputs when overriding channel explicit
2159 // clean channel+explicit episode | explicit channel + clean episode
2160 if( !empty($explicit) && $explicit != $powerpress_feed['explicit'] ) {
2161 echo "\t\t<itunes:explicit>" . $explicit . '</itunes:explicit>'.PHP_EOL;
2162 }
2163
2164 if( !empty($EpisodeData['duration']) && preg_match('/^(\d{1,2}:){0,2}\d{1,2}$/i', ltrim($EpisodeData['duration'], '0:') ) ) { // Include duration if it is valid
2165 echo "\t\t<itunes:duration>" . ltrim($EpisodeData['duration'], '0:') . '</itunes:duration>'.PHP_EOL;
2166 }
2167
2168 if( $block && $block == 'yes' ) {
2169 echo "\t\t<itunes:block>yes</itunes:block>".PHP_EOL;
2170 }
2171
2172 // Podcast index tags:
2173 if (!empty($EpisodeData['pci_transcript']) && !empty($EpisodeData['pci_transcript_url'])) {
2174 echo "\t\t<podcast:transcript url=\"" . $EpisodeData['pci_transcript_url'] . "\"";
2175 $transcript_type = powerpress_get_contenttype($EpisodeData['pci_transcript_url']);
2176 if (!empty($EpisodeData['pci_transcript_language'])) {
2177 echo " language=\"" . $EpisodeData['pci_transcript_language'] . "\"";
2178 }
2179 if (!empty($transcript_type)) {
2180 echo " type=\"" . $transcript_type . "\" rel=\"captions\" />".PHP_EOL;
2181 } else {
2182 echo " type=\"text/plain\" rel=\"captions\" />".PHP_EOL;
2183 }
2184 }
2185 if (!empty($EpisodeData['pci_chapters']) && !empty($EpisodeData['pci_chapters_url'])) {
2186 echo "\t\t<podcast:chapters url=\"" . $EpisodeData['pci_chapters_url'] . "\" type=\"application/json+chapters\" />".PHP_EOL;
2187 }
2188
2189 if (!empty($EpisodeData['disable_episode_comments'])) {
2190 echo "\t\t<podcast:socialInteract protocol=\"disabled\" />" . PHP_EOL;
2191 } elseif (!empty($EpisodeData['social_interact']) && is_array($EpisodeData['social_interact'])) {
2192 foreach ($EpisodeData['social_interact'] as $social_interact) {
2193 // Skip Empty Tags
2194 if (empty($social_interact['uri']) || empty($social_interact['protocol']) || $social_interact['protocol'] === 'disabled') {
2195 continue;
2196 }
2197
2198 echo "\t\t<podcast:socialInteract";
2199
2200 // If disabled skip the other options
2201 if ($social_interact['protocol'] === 'disabled') {
2202 echo " protocol=\"disabled\" />" . PHP_EOL;
2203 continue;
2204 } else {
2205 $protocol = $social_interact['protocol'];
2206 echo " protocol=\"" . esc_attr($social_interact['protocol']) . "\"";
2207 }
2208
2209 if (!empty($social_interact['uri'])) {
2210 echo " uri=\"" . esc_attr($social_interact['uri']) . "\"";
2211 }
2212
2213 if (!empty($social_interact['account_id'])) {
2214 echo " accountId=\"" . esc_attr($social_interact['account_id']) . "\"";
2215 }
2216
2217 if (!empty($social_interact['accountUrl'])) {
2218 echo " accountUrl=\"" . esc_attr($social_interact['accountUrl']) . "\"";
2219 }
2220
2221 if (!empty($social_interact['priority'])) {
2222 echo " priority=\"" . esc_attr($social_interact['priority']) . "\"";
2223 }
2224
2225 echo " />" . PHP_EOL;
2226 }
2227 } elseif (!empty($EpisodeData['social_interact_uri'])) {
2228 // Legacy social_interact handler
2229 if (!empty($EpisodeData['social_interact_account_id']))
2230 echo "\t\t<podcast:socialInteract uri=\"" . esc_attr($EpisodeData['social_interact_uri']) . "\" protocol=\"".$EpisodeData['social_interact_protocol']."\" accountId=\"".esc_attr($EpisodeData['social_interact_account_id'])."\" />".PHP_EOL;
2231 else
2232 echo "\t\t<podcast:socialInteract uri=\"" . esc_attr($EpisodeData['social_interact_uri']) . "\" protocol=\"".$EpisodeData['social_interact_protocol']."\" />".PHP_EOL;
2233 }
2234
2235 // <podcast:funding>
2236 if (!empty($EpisodeData['donate_url'])) {
2237 echo "\t\t<podcast:funding url=\"".esc_attr($EpisodeData['donate_url'])."\">". (!empty($EpisodeData['donate_label']) ? esc_html($EpisodeData['donate_label']) : '')."</podcast:funding>".PHP_EOL;
2238 }
2239 // legacy naming convention
2240 else if (!empty($EpisodeData['funding_url'])) {
2241 echo "\t\t<podcast:funding url=\"".esc_attr($EpisodeData['funding_url'])."\">".esc_html($EpisodeData['funding_label'])."</podcast:funding>".PHP_EOL;
2242 }
2243
2244 // <podcast:license>
2245 if( isset( $EpisodeData['copyright'] ) && strlen($EpisodeData['copyright']) > 1 ) {
2246 if ( isset( $EpisodeData['copyright_url'] ) && strlen($EpisodeData['copyright_url']) > 1 ) {
2247 echo "\t\t".'<podcast:license url="' . esc_attr(powerpress_url_in_feed($EpisodeData['copyright_url'])) . '">'. esc_html($EpisodeData['copyright']) . '</podcast:license>'.PHP_EOL;
2248 } else {
2249 echo "\t\t".'<podcast:license>'. esc_html($EpisodeData['copyright']) . '</podcast:license>'.PHP_EOL;
2250 }
2251 }
2252
2253 // inheritence check
2254 $credits = [];
2255 if (!empty($EpisodeData['inherit_channel_credits'])) {
2256 $Feed = get_option('powerpress_feed', array());
2257
2258 if (!empty($Feed['credits'])) {
2259 $credits = $Feed['credits'];
2260 } else if (!empty($Feed['person_names'])) {
2261 foreach ($Feed['person_names'] as $i => $name) {
2262 if ($name === '') continue;
2263 $credits[] = [
2264 'name' => $name,
2265 'role' => $Feed['person_roles'][$i] ?? '',
2266 'person_url' => $Feed['person_urls'][$i] ?? '',
2267 'link_url' => $Feed['link_urls'][$i] ?? ''
2268 ];
2269 }
2270 }
2271 }
2272 // load episode credits
2273 $episode_credits = [];
2274 // nested
2275 if (!empty($EpisodeData['credits'])) {
2276 $episode_credits = $EpisodeData['credits'];
2277 }
2278 // parallelized (legacy)
2279 else if (!empty($EpisodeData['person_names'])) {
2280 foreach ($EpisodeData['person_names'] as $i => $name) {
2281 if ($name === '') continue;
2282 $episode_credits[] = [
2283 'name' => $name,
2284 'role' => $EpisodeData['person_roles'][$i] ?? '',
2285 'person_url' => $EpisodeData['person_urls'][$i] ?? '',
2286 'link_url' => $EpisodeData['link_urls'][$i] ?? ''
2287 ];
2288 }
2289 }
2290 // print to feed
2291 $credits = array_merge($credits, $episode_credits);
2292 foreach ($credits as $credit) {
2293 if (empty($credit['name'])) continue;
2294
2295 echo "\t\t<podcast:person";
2296 if (!empty($credit['role'])) {
2297 echo " role=\"" . htmlspecialchars($credit['role']) . "\"";
2298 }
2299 if (!empty($credit['person_url'])) {
2300 echo " img=\"" . htmlspecialchars($credit['person_url']) . "\"";
2301 }
2302 if (!empty($credit['link_url'])) {
2303 echo " href=\"" . htmlspecialchars($credit['link_url']) . "\"";
2304 }
2305 echo ">" . htmlspecialchars($credit['name']) . "</podcast:person>" . PHP_EOL;
2306 }
2307
2308 if (!empty($EpisodeData['soundbites']) && is_array($EpisodeData['soundbites'])) {
2309 // nested
2310 foreach ($EpisodeData['soundbites'] as $soundbite) {
2311 $start = $soundbite['start'] ?? '';
2312 $duration = $soundbite['duration'] ?? '';
2313 $title = $soundbite['title'] ?? '';
2314
2315 $float_start = (float) $start;
2316 $is_string_float = (strval($float_start) == $start);
2317 if ($start == "" || !$is_string_float)
2318 continue;
2319
2320 $float_duration = (float) $duration;
2321 $is_string_float = (strval($float_duration) == $duration);
2322 if ($duration == "" || !$is_string_float)
2323 continue;
2324
2325 $attrStr = ' startTime="' . $start . '"';
2326 $attrStr .= ' duration="' . $duration . '"';
2327 echo "\t\t<podcast:soundbite$attrStr>" . esc_html($title) . "</podcast:soundbite>" . PHP_EOL;
2328 }
2329 } elseif (!empty($EpisodeData['soundbite_starts'])) {
2330 // parallelized (legacy)
2331 $soundbiteStarts = $EpisodeData['soundbite_starts'];
2332 $soundbiteDurations = $EpisodeData['soundbite_durations'];
2333 $soundbiteTitles = $EpisodeData['soundbite_titles'];
2334
2335 for ($i = 0; $i < count($soundbiteStarts); $i++) {
2336 $start = $soundbiteStarts[$i];
2337 $float_start = (float) $start;
2338 $is_string_float = (strval($float_start) == $start);
2339 if ($start == "" || !$is_string_float)
2340 continue;
2341
2342 $duration = $soundbiteDurations[$i];
2343 $float_duration = (float) $duration;
2344 $is_string_float = (strval($float_duration) == $duration);
2345 if ($duration == "" || !$is_string_float)
2346 continue;
2347
2348 $attrStr = ' startTime="' . $start . '"';
2349 $attrStr .= ' duration="' . $duration . '"';
2350 $title = $soundbiteTitles[$i];
2351 echo "\t\t<podcast:soundbite$attrStr>" . esc_html($title) . "</podcast:soundbite>" . PHP_EOL;
2352 }
2353 }
2354
2355
2356 if( !empty($EpisodeData['location']) ) {
2357 $locations = [];
2358
2359 if (is_array($EpisodeData['location'])) {
2360 $first_location = reset($EpisodeData['location']);
2361
2362 if (is_array($first_location)) {
2363 foreach ($EpisodeData['location'] as $location_item) {
2364 if (empty($location_item) || !is_array($location_item)) {
2365 continue;
2366 }
2367
2368 $address = '';
2369 if (!empty($location_item['location'])) $address = $location_item['location'];
2370 elseif (!empty($location_item['address'])) $address = $location_item['address'];
2371
2372 if (!empty($address)) {
2373 $locations[] = [
2374 'address' => $address,
2375 'geo' => $location_item['geo'] ?? $location_item['pci_geo'] ?? '',
2376 'osm' => $location_item['osm'] ?? $location_item['pci_osm'] ?? '',
2377 'rel' => $location_item['rel'] ?? $location_item['pci_rel'] ?? '1',
2378 'country' => $location_item['country'] ?? $location_item['pci_country'] ?? '',
2379 ];
2380 }
2381 }
2382 } else {
2383 // legacy
2384 foreach ($EpisodeData['location'] as $i => $address) {
2385 if (!empty($address)) {
2386 $locations[] = [
2387 'address' => $address,
2388 'geo' => $EpisodeData['pci_geo'][$i] ?? '',
2389 'osm' => $EpisodeData['pci_osm'][$i] ?? '',
2390 'rel' => $EpisodeData['pci_rel'][$i] ?? '1',
2391 'country' => $EpisodeData['pci_country'][$i] ?? '',
2392 ];
2393 }
2394 }
2395 }
2396 }
2397 foreach ($locations as $location) {
2398 if (empty($location['address'])) {
2399 continue;
2400 }
2401
2402 echo "\t\t<podcast:location";
2403
2404 if (!empty($location['geo'])) echo ' geo="' . htmlspecialchars($location['geo']) . '"';
2405 if (!empty($location['osm'])) echo ' osm="' . htmlspecialchars($location['osm']) . '"';
2406 if (!empty($location['rel'])) echo ' rel="' . ($location['rel'] == '1' ? 'subject' : 'creator') . '"';
2407 if (!empty($location['country'])) echo ' country="' . htmlspecialchars($location['country']) . '"';
2408
2409 echo ">" . htmlspecialchars($location['address']) . "</podcast:location>" . PHP_EOL;
2410 }
2411 }
2412
2413 $recipients = [];
2414 // v4v channel level inheritence
2415 if (isset($EpisodeData['channel_level_recipients'])) {
2416 $Feed = get_option('powerpress_feed', array());
2417 // nested format
2418 if (!empty($Feed['value_recipients'])) {
2419 foreach ($Feed['value_recipients'] as $recipient) {
2420 $pubkey = trim($recipient['pubkey'] ?? '');
2421 $split = (int)($recipient['split'] ?? 0);
2422 if ($pubkey === '' || $split <= 0) continue;
2423
2424 $recipients[] = [
2425 'lightning' => $recipient['lightning'] ?? $recipient['name'] ?? '',
2426 'split' => $split,
2427 'pubkey' => $pubkey,
2428 'customKey' => $recipient['custom_key'] ?? $recipient['customKey'] ?? '',
2429 'customValue' => $recipient['custom_value'] ?? $recipient['customValue'] ?? '',
2430 'fee' => !empty($recipient['fee']) ? 'true' : 'false'
2431 ];
2432 }
2433 // legacy format
2434 } else if ((!empty($Feed['value_pubkey']) && is_array($Feed['value_pubkey']))
2435 && (!empty($Feed['value_split']) && is_array($Feed['value_split']))) {
2436 $pubKeys = (array)$Feed['value_pubkey'];
2437 $splits = (array)$Feed['value_split'];
2438 $lightnings = (array)($Feed['value_lightning'] ?? []);
2439 $customKeys = (array)($Feed['value_custom_key'] ?? []);
2440 $customVals = (array)($Feed['value_custom_value'] ?? []);
2441 $fees = (array)($Feed['value_is_fee'] ?? []);
2442
2443 foreach ($pubKeys as $i => $pubkey) {
2444 $pubkey = trim((string)$pubkey);
2445 $split = (int)($splits[$i] ?? 0);
2446 if ($pubkey === '' || $split <= 0) continue;
2447
2448 $recipients[] = [
2449 'lightning' => (string)($lightnings[$i] ?? ''),
2450 'split' => $split,
2451 'pubkey' => $pubkey,
2452 'customKey' => (string)($customKeys[$i] ?? ''),
2453 'customValue' => (string)($customVals[$i] ?? ''),
2454 'fee' => (isset($fees[$i]) && $fees[$i] === 'true') ? 'true' : 'false',
2455 ];
2456 }
2457 }
2458 }
2459 // nested
2460 if (isset($EpisodeData['value_recipients']) && is_array($EpisodeData['value_recipients'])) {
2461 foreach ($EpisodeData['value_recipients'] as $recipient) {
2462 $pubkey = trim($recipient['pubkey'] ?? '');
2463 $split = (int)($recipient['split'] ?? 0);
2464 if ($pubkey === '' || $split <= 0) continue;
2465
2466 $recipients[] = [
2467 'lightning' => $recipient['lightning'] ?? $recipient['name'] ?? '',
2468 'split' => $split,
2469 'pubkey' => $pubkey,
2470 'customKey' => $recipient['custom_key'] ?? $recipient['customKey'] ?? '',
2471 'customValue'=> $recipient['custom_value'] ?? $recipient['customValue'] ?? '',
2472 'fee' => (isset($recipient['fee']) && $recipient['fee'] === 'true') ? 'true' : 'false',
2473 ];
2474 }
2475 // paralellized (legacy)
2476 } elseif (!empty($EpisodeData['value_pubkey']) && is_array($EpisodeData['value_pubkey'])
2477 && !empty($EpisodeData['value_split']) && is_array($EpisodeData['value_split'])) {
2478
2479 $pubKeys = (array)$EpisodeData['value_pubkey'];
2480 $splits = (array)$EpisodeData['value_split'];
2481 $lightnings = (array)($EpisodeData['value_lightning'] ?? []);
2482 $customKeys = (array)($EpisodeData['value_custom_key'] ?? []);
2483 $customVals = (array)($EpisodeData['value_custom_value'] ?? []);
2484 $fees = (array)($EpisodeData['value_is_fee'] ?? []);
2485
2486 foreach ($pubKeys as $i => $pubkey) {
2487 $pubkey = trim((string)$pubkey);
2488 $split = (int)($splits[$i] ?? 0);
2489 if ($pubkey === '' || $split <= 0) continue;
2490
2491 $recipients[] = [
2492 'lightning' => (string)($lightnings[$i] ?? ''),
2493 'split' => $split,
2494 'pubkey' => $pubkey,
2495 'customKey' => (string)($customKeys[$i] ?? ''),
2496 'customValue' => (string)($customVals[$i] ?? ''),
2497 'fee' => (isset($fees[$i]) && $fees[$i] === 'true') ? 'true' : 'false',
2498 ];
2499 }
2500 }
2501
2502 // output podcast:value block if we have recipients OR vts with remote items
2503 $hasVts = isset($EpisodeData['vts_order']) && !empty($EpisodeData['vts_order']);
2504 if (!empty($recipients) || $hasVts) {
2505 // add blubrry fee recipient when there are other recipients
2506 if (!empty($recipients)) {
2507 $recipients[] = [
2508 'lightning' => 'blubrry@getalby.com',
2509 'split' => 3,
2510 'pubkey' => '03b8a595e4d8e19efa8faa3fbe2524b0d39f7c812415ff831d38a466a4a1bc888a',
2511 'customKey' => '696969',
2512 'customValue' => 'qAHJuqKLmMhTNFualcIj',
2513 'fee' => 'true',
2514 ];
2515 }
2516
2517 echo "\t\t" . '<podcast:value type="lightning" method="keysend" suggested="0.00000005000">' . PHP_EOL;
2518
2519 foreach ($recipients as $recipient) {
2520 $attr = 'type="node" split="' . (int)$recipient['split'] . '" address="' . htmlspecialchars($recipient['pubkey']) . '"';
2521
2522 if (!empty($recipient['lightning'])) $attr .= ' name="' . htmlspecialchars($recipient['lightning']) . '"';
2523 if (!empty($recipient['customKey'])) $attr .= ' customKey="' . htmlspecialchars($recipient['customKey']) . '"';
2524 if (!empty($recipient['customValue'])) $attr .= ' customValue="' . htmlspecialchars($recipient['customValue']) . '"';
2525 if (!empty($recipient['fee']) && $recipient['fee'] === 'true') $attr .= ' fee="true"';
2526
2527 echo "\t\t\t" . "<podcast:valueRecipient $attr/>" . PHP_EOL;
2528 }
2529
2530 $feed_slug = get_query_var('feed');
2531 // if this is a blog feed, we need to access the settings associated to the podcast feed
2532 if (is_category() && $feed_slug == 'feed') {
2533 $feed_slug = 'podcast';
2534 }
2535 if ($hasVts) {
2536 $valueTimeSplits = get_option('vts_'.$feed_slug.'_'.get_the_ID());
2537 if (!is_array($valueTimeSplits))
2538 $valueTimeSplits = [];
2539
2540 foreach ($EpisodeData['vts_order'] as $vts_id) {
2541 if (!isset($valueTimeSplits[$vts_id])) continue;
2542
2543 $timeSplit = $valueTimeSplits[$vts_id];
2544 if (empty($timeSplit['duration'])) continue;
2545
2546 $vtsAttrs = [
2547 'startTime' => $timeSplit['start_time'] ?? 0,
2548 'duration' => $timeSplit['duration']
2549 ];
2550
2551 $recipientType = $timeSplit['recipient'] ?? 0;
2552 if ($recipientType == 0)
2553 $vtsAttrs['remotePercentage'] = $timeSplit['remote_percent'] ?? 0;
2554
2555 $vtsAttrParts = [];
2556 foreach ($vtsAttrs as $key => $value) {
2557 $vtsAttrParts[] = $key.'="'.$value.'"';
2558 }
2559
2560 echo "\t\t\t"."<podcast:valueTimeSplit ".implode(' ', $vtsAttrParts).">\n";
2561
2562 if ($recipientType == 0) {
2563 $remoteItem = $timeSplit['remote_item'] ?? [];
2564
2565 if (!empty($remoteItem['feed_guid'])) {
2566 $attrs = ['feedGuid' => $remoteItem['feed_guid']];
2567
2568 $itemGuid = $remoteItem['item_guid'] ?? '';
2569 if (!empty($itemGuid) && $itemGuid != 'none')
2570 $attrs['itemGuid'] = $itemGuid;
2571
2572 if (!empty($remoteItem['feed_link'])) {
2573 $attrs['feedUrl'] = $remoteItem['feed_link'];
2574 }
2575
2576 if (!empty($remoteItem['medium'])) {
2577 $attrs['medium'] = $remoteItem['medium'];
2578 }
2579
2580 if (!empty($remoteItem['item_title'])) {
2581 $attrs['title'] = $remoteItem['item_title'];
2582 }
2583
2584 $attrParts = [];
2585 foreach ($attrs as $key => $value) {
2586 $attrParts[] = $key.'="'.htmlspecialchars($value).'"';
2587 }
2588
2589 echo "\t\t\t\t"."<podcast:remoteItem ".implode(' ', $attrParts)."/>\n";
2590 }
2591 } else {
2592 $valueRecipients = $timeSplit['value_recipients'] ?? array();
2593
2594 foreach ($valueRecipients as $valueRecipient) {
2595 if (empty($valueRecipient['pubkey'])) continue;
2596
2597 $attrs = [
2598 "type" => "node",
2599 "split" => $valueRecipient['split'] ?? 0,
2600 "address" => $valueRecipient['pubkey'],
2601 ];
2602
2603 if (!empty($valueRecipient['lightning']))
2604 $attrs['name'] = $valueRecipient['lightning'];
2605
2606 if (!empty($valueRecipient['custom_key']))
2607 $attrs["customKey"] = $valueRecipient['custom_key'];
2608
2609 if (!empty($valueRecipient['custom_value']))
2610 $attrs["customValue"] = $valueRecipient['custom_value'];
2611
2612 if (!empty($valueRecipient['value_is_fee']))
2613 $attrs["value_is_fee"] = $valueRecipient['value_is_fee'];
2614
2615
2616 $attrStr = "";
2617 foreach ($attrs as $key => $value) {
2618 $attrStr .= ' '.$key.'="'.$value.'"';
2619 }
2620
2621 echo "\t\t\t\t"."<podcast:valueRecipient $attrStr/>\n";
2622 }
2623 }
2624
2625 echo "\t\t\t"."</podcast:valueTimeSplit>\n";
2626 }
2627 }
2628
2629 echo "\t\t".'</podcast:value>'.PHP_EOL;
2630 }
2631
2632 // RawVoice RSS Tags
2633 if( empty($powerpress_feed['feed_maximizer_on']) )
2634 {
2635 if( !defined('POWERPRESS_RAWVOICE_RSS') || POWERPRESS_RAWVOICE_RSS != false )
2636 {
2637 if( !empty($EpisodeData['podcast_id']) )
2638 echo "\t\t<rawvoice:pid>" . esc_html($EpisodeData['podcast_id']) . "</rawvoice:pid>" . PHP_EOL;
2639 if( !empty($EpisodeData['ishd']) )
2640 echo "\t\t<rawvoice:isHD>yes</rawvoice:isHD>".PHP_EOL;
2641 if( !empty($EpisodeData['image']) )
2642 echo "\t\t<rawvoice:poster url=\"". $EpisodeData['image'] ."\" />".PHP_EOL;
2643 if( !empty($EpisodeData['embed']) )
2644 echo "\t\t<rawvoice:embed>". htmlspecialchars($EpisodeData['embed']) ."</rawvoice:embed>".PHP_EOL;
2645 else if( !empty($powerpress_feed['podcast_embed_in_feed']) && function_exists('powerpress_generate_embed') )
2646 {
2647 $player = powerpressplayer_embedable($EpisodeData['url'], $EpisodeData);
2648 $embed_content = '';
2649
2650 if( $player )
2651 $embed_content = powerpress_generate_embed($player, $EpisodeData);
2652 if( $embed_content )
2653 echo "\t\t<rawvoice:embed>". htmlspecialchars( $embed_content ) ."</rawvoice:embed>".PHP_EOL;
2654 }
2655
2656 if( !empty($EpisodeData['webm_src']) )
2657 {
2658 echo "\t\t<rawvoice:webm src=\"". $EpisodeData['webm_src'] ."\"";
2659 if( $EpisodeData['webm_length'] )
2660 echo " length=\"". $EpisodeData['webm_length'] ."\"";
2661 echo " type=\"video/webm\" />".PHP_EOL;
2662 }
2663
2664 $GeneralSettings = get_option('powerpress_general', array());
2665
2666 require_once(POWERPRESS_ABSPATH .'/powerpress-metamarks.php');
2667 powerpress_metamarks_print_rss2($EpisodeData);
2668 }
2669 }
2670 }
2671
2672 add_filter('rss2_item', 'powerpress_rss2_item');
2673 add_filter('rss2_item_powerpress', 'powerpress_rss2_item');
2674
2675 /*
2676 This filter is only necessary for feeds that are not specifically for podcasting, e.g. a category feed that did not have category podcasting added to it
2677 */
2678 function powerpress_filter_rss_enclosure($content)
2679 {
2680 if( defined('PODPRESS_VERSION') || isset($GLOBALS['podcasting_player_id']) || isset($GLOBALS['podcast_channel_active']) || defined('PODCASTING_VERSION') ) {
2681 return $content; // Another podcasting plugin is enabled...
2682 }
2683
2684 if( powerpress_is_custom_podcast_feed() && get_query_var('feed') !== 'podcast' && !is_category() && !is_tag() && !is_tax() )
2685 return ''; // We will handle this enclosure in the powerpress_rss2_item() function
2686
2687 $match_count = preg_match('/\surl="([^"]*)"/', $content, $matches); // No URL found, weird
2688 if( count($matches) != 2)
2689 return $content;
2690
2691 // Original Media URL
2692 $OrigURL = $matches[1];
2693
2694 if( substr($OrigURL, 0, 5) != 'http:' && substr($OrigURL, 0, 6) != 'https:' )
2695 return ''; // The URL value is invalid
2696
2697 global $post, $powerpress_rss_enclosure_post_id;
2698 if( empty($powerpress_rss_enclosure_post_id) )
2699 $powerpress_rss_enclosure_post_id = -1;
2700
2701 if( $powerpress_rss_enclosure_post_id == $post->ID )
2702 return ''; // we've already included one enclosure, lets not allow anymore
2703 $powerpress_rss_enclosure_post_id = $post->ID;
2704
2705 $EpisodeData = powerpress_get_enclosure_data($post->ID);
2706
2707 // Modified Media URL
2708 $ModifiedURL = powerpress_url_in_feed($EpisodeData['url']); // powerpress_add_redirect_url($OrigURL);
2709
2710 // Check that the content type is a valid one...
2711 $match_count = preg_match('/\stype="([^"]*)"/', $content, $matches);
2712 if( count($matches) > 1 && strstr($matches[1], '/') == false )
2713 {
2714 $ContentType = powerpress_get_contenttype($ModifiedURL);
2715 $content = str_replace("type=\"{$matches[1]}\"", "type=\"$ContentType\"", $content);
2716 }
2717
2718 // Check that the content length is a digit greater that zero
2719 $match_count = preg_match('/\slength="([^"]*)"/', $content, $matches);
2720 if( count($matches) > 1 && empty($matches[1]) )
2721 {
2722 $content = str_replace("length=\"{$matches[1]}\"", "length=\"5242880\"", $content);
2723 }
2724
2725 // encode htmlspecialchars if necessary
2726 $decoded = htmlspecialchars_decode($ModifiedURL);
2727 if (strlen($decoded) == strlen($EpisodeData['url'])) {
2728 // might need encoded/no risk of double encoding
2729 $ModifiedURL = htmlspecialchars($ModifiedURL);
2730 }
2731
2732 // Replace the original url with the modified one...
2733 if( $OrigURL != $ModifiedURL )
2734 $content = str_replace($OrigURL, $ModifiedURL, $content);
2735
2736 // add proper indentation for rss formatting
2737 return "\t\t" . trim($content) . "\n";
2738 }
2739
2740
2741 add_filter('rss_enclosure', 'powerpress_filter_rss_enclosure', 11);
2742
2743 function powerpress_bloginfo_rss($content, $field = '')
2744 {
2745 $new_value = '';
2746 if( powerpress_is_custom_podcast_feed() )
2747 {
2748 if( is_category() ) {
2749 $Feed = get_option('powerpress_cat_feed_'.get_query_var('cat'), array() );
2750 }
2751 else if( is_tax() || is_tag() ) {
2752 global $powerpress_feed;
2753 if( !empty($powerpress_feed['term_taxonomy_id']) )
2754 $Feed = get_option('powerpress_taxonomy_'.$powerpress_feed['term_taxonomy_id'], array() );
2755 }
2756 else
2757 {
2758 global $powerpress_feed;
2759
2760 if( !empty($powerpress_feed['post_type']) )
2761 {
2762 $feed_slug = get_query_var('feed');
2763 $PostTypeSettingsArray = get_option('powerpress_posttype_'.$powerpress_feed['post_type'], array() );
2764 if( !empty($PostTypeSettingsArray[ $feed_slug ]) )
2765 $Feed = $PostTypeSettingsArray[ $feed_slug ];
2766 }
2767 else
2768 {
2769 $Feed = get_option('powerpress_feed_'.get_query_var('feed'), array() );
2770 if( empty($Feed) && get_query_var('feed') === 'podcast' )
2771 $Feed = get_option('powerpress_feed', array());
2772 }
2773 }
2774
2775 if( !empty($Feed) )
2776 {
2777 switch( $field )
2778 {
2779 case 'description': {
2780 if( !empty($Feed['description']) )
2781 $new_value = $Feed['description'];
2782 else if( is_category() )
2783 {
2784 $category = get_category( get_query_var('cat') );
2785 if( $category->description )
2786 $new_value = $category->description;
2787 }
2788 }; break;
2789 case 'url': {
2790 // If the website URL is set for this podcast then lets use it...
2791 if( !empty($Feed['url']) )
2792 return trim($Feed['url']);
2793
2794 if( is_category() ) {
2795 return get_category_link( get_query_var('cat') );
2796 } else {
2797 $urlTemp = '';
2798 $blogHomepage = get_option('page_for_posts');
2799 if( !empty($blogHomepage) ) {
2800 $urlTemp = get_permalink( $blogHomepage );
2801 }
2802
2803 if( empty($urlTemp) )
2804 $urlTemp = get_bloginfo('url');
2805 if( !empty($urlTemp) )
2806 return $urlTemp;
2807 }
2808 }; break;
2809 case 'name': { // As of wp 4.4+ title is handled by get_the_title_rss completely.
2810 if( !empty($Feed['title']) )
2811 $new_value = $Feed['title'];
2812 }; break;
2813 case 'language': {
2814 // Get the feed language
2815 $lang = '';
2816 if( isset($Feed['rss_language']) && $Feed['rss_language'] != '' )
2817 $lang = $Feed['rss_language'];
2818 if( strlen($lang) == 5 )
2819 $lang = substr($lang,0,3) . strtoupper( substr($lang, 3) ); // Format example: en-US for English, United States
2820 if( !empty($lang) )
2821 return $lang;
2822 }; break;
2823 }
2824 }
2825 }
2826
2827 if( !empty($new_value) )
2828 {
2829 $GeneralSettings = get_option('powerpress_general');
2830 // disable smart typography check
2831 if( empty($GeneralSettings['disable_wptexturize']) )
2832 $new_value = wptexturize($new_value);
2833 $new_value = convert_chars($new_value);
2834 // decode html entities before escaping so numeric entities like &#8212; render as actual chars
2835 if( !empty($GeneralSettings['disable_wptexturize']) )
2836 $new_value = html_entity_decode($new_value, ENT_QUOTES, 'UTF-8');
2837 // convert named HTML entities to numeric for XML compatibility (e.g. &copy; → &#169;)
2838 $new_value = ent2ncr($new_value);
2839 $new_value = esc_html($new_value);
2840 return $new_value;
2841 }
2842
2843 return $content;
2844 }
2845
2846 add_filter('get_bloginfo_rss', 'powerpress_bloginfo_rss', 10, 2);
2847
2848
2849 function powerpress_wp_title_rss($title)
2850 {
2851 if( version_compare($GLOBALS['wp_version'], '4.4', '>=' ) )
2852 {
2853 if( powerpress_is_custom_podcast_feed() )
2854 {
2855 if( is_category() ) {
2856 $Feed = get_option('powerpress_cat_feed_'.get_query_var('cat'), array() );
2857 }
2858 else if( is_tax() || is_tag() ) {
2859 global $powerpress_feed;
2860 if( !empty($powerpress_feed['term_taxonomy_id']) )
2861 $Feed = get_option('powerpress_taxonomy_'.$powerpress_feed['term_taxonomy_id'], array() );
2862 }
2863 else
2864 {
2865 global $powerpress_feed;
2866
2867 if( !empty($powerpress_feed['post_type']) )
2868 {
2869 $feed_slug = get_query_var('feed');
2870 if( !empty($feed_slug) ) {
2871 $PostTypeSettingsArray = get_option('powerpress_posttype_'.$powerpress_feed['post_type'], array() );
2872 if( !empty($PostTypeSettingsArray[ $feed_slug ]) )
2873 $Feed = $PostTypeSettingsArray[ $feed_slug ];
2874 }
2875 }
2876 else
2877 {
2878 $feed_slug = get_query_var('feed');
2879 $Feed = false;
2880 if( !empty($feed_slug) ) {
2881 $Feed = get_option('powerpress_feed_'.get_query_var('feed') );
2882 }
2883 if( empty($Feed) && get_query_var('feed') === 'podcast' )
2884 $Feed = get_option('powerpress_feed');
2885 }
2886 }
2887
2888 if( !empty($Feed) )
2889 {
2890 if( !empty($Feed['title']) )
2891 return esc_html( $Feed['title'] );
2892 }
2893 }
2894 }
2895 else
2896 {
2897 if( powerpress_is_custom_podcast_feed() )
2898 {
2899 if( is_category() )
2900 {
2901 $Feed = get_option('powerpress_cat_feed_'.get_query_var('cat') );
2902 if( $Feed && isset($Feed['title']) && $Feed['title'] != '' )
2903 return ''; // We alrady did a custom title, lets not add the category to it...
2904 }
2905 else
2906 {
2907 return ''; // It is not a category, lets not mess with our beautiful title then
2908 }
2909 }
2910 }
2911
2912 return $title;
2913 }
2914
2915 add_filter('get_wp_title_rss', 'powerpress_wp_title_rss');
2916
2917 function powerpress_the_title_rss($title)
2918 {
2919 $new_title = $title;
2920 $GeneralSettings = get_option('powerpress_general');
2921 // If it is a custom podcast channel...
2922 if( !empty($GeneralSettings['seo_feed_title']) )
2923 {
2924 $feed_slug = 'podcast';
2925 // IF custom post type or channel, use that feed slug...
2926 if( get_query_var('feed') !== 'podcast' && !is_category() && !is_tax() && !is_tag() )
2927 $feed_slug = get_query_var('feed');
2928
2929 // Get the episode specific title...
2930 $EpisodeData = powerpress_get_enclosure_data(get_the_ID(), $feed_slug);
2931 if( !empty($EpisodeData['feed_title']) )
2932 {
2933 $feed_title = ent2ncr( $EpisodeData['feed_title'] );
2934 $feed_title = strip_tags( $feed_title );
2935 $feed_title = esc_html( $feed_title );
2936
2937 //switch( $GeneralSettings['custom_feed_title'] )
2938 switch( $GeneralSettings['seo_feed_title'] )
2939 {
2940 case 1: { // Replaces title
2941 $new_title = $feed_title;
2942 }; break;
2943 case 2: { // Prefixes title
2944 $new_title = $feed_title . ' ' . $title;
2945 }; break;
2946 case 3: { // Postfixes title
2947 $new_title = $title . ' ' . $feed_title;
2948 }; break;
2949 }
2950 }
2951 }
2952
2953 return $new_title;
2954 }
2955
2956 add_filter('the_title_rss', 'powerpress_the_title_rss', 11);
2957
2958
2959 function powerpress_feed_content_type($content_type = '', $feedslug = '')
2960 {
2961 switch( $feedslug )
2962 {
2963 case 'rss':
2964 case 'rss2':
2965 case 'atom':
2966 case 'rdf': {
2967 // Do nothing, let WordPress take care of these
2968 }; break;
2969 case 'podcast': {
2970 // This one is ours!
2971 $content_type = 'application/rss+xml';
2972 }; break;
2973 default: { // Check for the custom podcast feeds
2974 $GeneralSettings = get_option('powerpress_general');
2975 if( !empty($GeneralSettings['custom_feeds'][ $feedslug ]) )
2976 {
2977 $content_type = 'application/rss+xml';
2978 }
2979 else if( !empty($GeneralSettings['posttype_podcasting']) )
2980 {
2981 // We need to look up these settings...
2982 $FeedSlugPostTypesArray = get_option('powerpress_posttype-podcasting');
2983 if( is_array($FeedSlugPostTypesArray) && !empty($FeedSlugPostTypesArray[ $feedslug ]) )
2984 {
2985 $content_type = 'application/rss+xml';
2986 }
2987 }
2988 }
2989 }
2990
2991 return $content_type;
2992 }
2993
2994 add_filter( 'feed_content_type', 'powerpress_feed_content_type', 10, 2 );
2995
2996 function wpse_152316_wp_audio_extensions( $ext )
2997 {
2998 remove_filter( current_filter(), __FUNCTION__ );
2999 $ext[] = '';
3000 return $ext;
3001 }
3002
3003 /**
3004 * Allow unrecognized audio sources hosted on trusted hosts that use query strings on their podcast media.
3005 *
3006 * @see http://wordpress.stackexchange.com/a/152352/26350
3007 */
3008
3009 add_filter( 'wp_audio_shortcode_override',
3010 function( $html, $atts )
3011 {
3012 if (isset($atts['src'])) {
3013 $trusted_hosts_use_qstrings = array('traffic.libsyn.com', 'cdn.simplecast.com', 'buzzsprout.com', 'audioboom.com', 'mc.blubrry.com');
3014 foreach ($trusted_hosts_use_qstrings as $host) {
3015 if (strpos($atts['src'], $host) !== false) {
3016 add_filter('wp_audio_extensions', 'wpse_152316_wp_audio_extensions');
3017 }
3018 }
3019 }
3020 return $html;
3021 }
3022 , PHP_INT_MAX, 2 );
3023
3024 // Following code only works for WP 3.3 or older. WP 3.4+ now uses the get_locale setting, so we have to override directly in the get_bloginfo_rss functoin.
3025 if( version_compare($GLOBALS['wp_version'], '3.4', '<') )
3026 {
3027 function powerpress_rss_language($value)
3028 {
3029 if( powerpress_is_custom_podcast_feed() )
3030 {
3031 global $powerpress_feed;
3032 if( $powerpress_feed && isset($powerpress_feed['rss_language']) && $powerpress_feed['rss_language'] != '' )
3033 $value = $powerpress_feed['rss_language'];
3034 }
3035 return $value;
3036 }
3037
3038 add_filter('option_rss_language', 'powerpress_rss_language');
3039 }
3040
3041 //filter to ensure that guid doesn't come up blank
3042 function powerpress_the_guid($guid) {
3043 global $post;
3044
3045 // Simple case, what is in the DB is better than an empty value
3046 if( empty($guid) && !empty($post->guid) ) {
3047 return $post->guid;
3048 }
3049
3050 if( !empty($post->guid) ) {
3051 if( preg_match('/^https?:\/\//i', $post->guid, $matches) == false ) {
3052 $powerpressGuid = get_post_meta($post->ID, '_powerpress_guid', true);
3053 if( !empty($powerpressGuid) )
3054 return $powerpressGuid;
3055 }
3056 }
3057
3058 return $guid;
3059 }
3060
3061 function powerpress_do_podcast_feed($for_comments=false)
3062 {
3063 global $wp_query, $powerpress_feed;
3064
3065 powerpress_is_podcast_feed(); // Loads the feed settings if not already loaded...
3066
3067 $GeneralSettings = get_option('powerpress_general');
3068 if( isset($GeneralSettings['premium_caps']) && $GeneralSettings['premium_caps'] )
3069 {
3070 $feed_slug = get_query_var('feed');
3071
3072 if( $feed_slug != 'podcast' )
3073 {
3074 $FeedSettings = get_option('powerpress_feed_'.$feed_slug);
3075 if( !empty($FeedSettings['premium']) )
3076 {
3077 require_once( POWERPRESS_ABSPATH.'/powerpress-feed-auth.php');
3078 powerpress_feed_auth( $feed_slug );
3079 }
3080 }
3081 }
3082
3083 // Use the template to gurantee future WordPress behavior
3084 if( defined('POWERPRESS_FEED_TEMPLATE') ) {
3085 load_template( POWERPRESS_FEED_TEMPLATE );
3086 } else {
3087 load_template( POWERPRESS_ABSPATH . '/feed-podcast.php' );
3088 }
3089 }
3090
3091 function powerpress_template_redirect()
3092 {
3093 if( is_feed() && powerpress_is_custom_podcast_feed() )
3094 {
3095 // clean any existing output buffers to rm \n or WS from themes/plugins/wp-config (externally introduced)
3096 // ensures our feed starts with no newlines
3097 while( ob_get_level() > 0 ) {
3098 ob_end_clean();
3099 }
3100
3101 if ( defined('WPSEO_VERSION') && version_compare(WPSEO_VERSION, '7.7', '>=') && class_exists( 'WPSEO_Frontend' ) ) {
3102 $wpseo_frontend = WPSEO_Frontend::get_instance();
3103 if( !empty($wpseo_frontend) ) {
3104 remove_action( 'template_redirect', array( $wpseo_frontend, 'noindex_feed' ) );
3105 }
3106 }
3107
3108 remove_action('template_redirect', 'ol_feed_redirect'); // Remove this action so feedsmith doesn't redirect
3109 global $powerpress_feed;
3110 if( !isset($powerpress_feed['feed_redirect_url']) )
3111 $powerpress_feed['feed_redirect_url'] = '';
3112 $redirect_value = ( !empty($_GET['redirect'])? $_GET['redirect'] : false );
3113 $user_agent = !empty($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : "";
3114 if( is_array($powerpress_feed) && trim($powerpress_feed['feed_redirect_url']) != '' && !preg_match("/feedburner|feedsqueezer|feedvalidator/i", $user_agent ) && $redirect_value != 'no' )
3115 {
3116 if (function_exists('status_header'))
3117 status_header( 301 );
3118 header("Location: " . trim($powerpress_feed['feed_redirect_url']));
3119 header("HTTP/1.1 301 Moved Permanently");
3120 exit();
3121 }
3122 }
3123 }
3124
3125 add_action('template_redirect', 'powerpress_template_redirect', 0);
3126
3127
3128 function powerpress_rewrite_rules_array($array)
3129 {
3130 global $wp_rewrite;
3131 $settings = get_option('powerpress_general');
3132
3133 $podcast_feeds = array('podcast'=>true);
3134 if( isset($settings['custom_feeds']) && is_array($settings['custom_feeds']) )
3135 $podcast_feeds = array_merge($settings['custom_feeds'], $podcast_feeds );
3136
3137 $merged_slugs = '';
3138 foreach( $podcast_feeds as $feed_slug=> $feed_title )
3139 {
3140 if( $merged_slugs != '' )
3141 $merged_slugs .= '|';
3142 $merged_slugs .= $feed_slug;
3143 }
3144
3145 // $wp_rewrite->index most likely index.php
3146 $new_array[ 'feed/('.$merged_slugs.')/?$' ] = $wp_rewrite->index. '?feed='. $wp_rewrite->preg_index(1);
3147
3148 // If feature is not enabled, use the default permalinks
3149 if( empty($settings['permalink_feeds_only']) )
3150 return array_merge($new_array, $array);
3151
3152 global $wpdb;
3153 reset($podcast_feeds);
3154 foreach( $podcast_feeds as $feed_slug=> $feed_title )
3155 {
3156 $page_name_id = $wpdb->get_var("SELECT ID FROM {$wpdb->posts} WHERE post_name = '".$feed_slug."'");
3157 if( $page_name_id )
3158 {
3159 $new_array[ $feed_slug.'/?$' ] = $wp_rewrite->index. '?pagename='. $feed_slug.'&page_id='.$page_name_id;
3160 unset($podcast_feeds[ $feed_slug ]);
3161 continue;
3162 }
3163
3164 $category = get_category_by_slug($feed_slug);
3165 if( $category )
3166 {
3167 $new_array[ $feed_slug.'/?$' ] = $wp_rewrite->index. '?cat='. $category->term_id; // category_name='. $feed_slug .'&
3168 unset($podcast_feeds[ $feed_slug ]);
3169 }
3170 }
3171
3172 if( count($podcast_feeds) > 0 )
3173 {
3174 reset($podcast_feeds);
3175 $remaining_slugs = '';
3176 foreach( $podcast_feeds as $feed_slug=> $feed_title )
3177 {
3178 if( $remaining_slugs != '' )
3179 $remaining_slugs .= '|';
3180 $remaining_slugs .= $feed_slug;
3181 }
3182
3183 $new_array[ '('.$remaining_slugs.')/?$' ] = $wp_rewrite->index. '?pagename='. $wp_rewrite->preg_index(1);
3184 }
3185
3186 return array_merge($new_array, $array);
3187 }
3188
3189 add_filter('rewrite_rules_array', 'powerpress_rewrite_rules_array');
3190
3191
3192 function powerpress_pre_transient_rewrite_rules($return_rules)
3193 {
3194 global $wp_rewrite;
3195 $GeneralSettings = get_option('powerpress_general');
3196 if( !in_array('podcast', $wp_rewrite->feeds) )
3197 $wp_rewrite->feeds[] = 'podcast';
3198
3199 if( $GeneralSettings && isset($GeneralSettings['custom_feeds']) && is_array($GeneralSettings['custom_feeds']) )
3200 {
3201 foreach( $GeneralSettings['custom_feeds'] as $feed_slug=> $null )
3202 {
3203 if( !in_array($feed_slug, $wp_rewrite->feeds) )
3204 $wp_rewrite->feeds[] = $feed_slug;
3205 }
3206 }
3207
3208 return $return_rules;
3209 }
3210
3211 add_filter('pre_transient_rewrite_rules', 'powerpress_pre_transient_rewrite_rules');
3212
3213 function powerpress_init()
3214 {
3215 // Translation support loaded:
3216 load_plugin_textdomain('powerpress', // domain / keyword name of plugin
3217 POWERPRESS_ABSPATH .'/languages', // Absolute path
3218 basename(POWERPRESS_ABSPATH).'/languages' ); // relative path in plugins folder
3219
3220 /*
3221 ####
3222 # Defines that effect translation defined now:
3223 ####
3224 */
3225 // Set specific play and download labels for your installation of PowerPress
3226 if( !defined('POWERPRESS_LINKS_TEXT') )
3227 define('POWERPRESS_LINKS_TEXT', __('Podcast', 'powerpress') );
3228 if( !defined('POWERPRESS_DURATION_TEXT') )
3229 define('POWERPRESS_DURATION_TEXT', __('Duration', 'powerpress') );
3230 if( !defined('POWERPRESS_PLAY_IN_NEW_WINDOW_TEXT') )
3231 define('POWERPRESS_PLAY_IN_NEW_WINDOW_TEXT', __('Play in new window', 'powerpress') );
3232 if( !defined('POWERPRESS_DOWNLOAD_TEXT') )
3233 define('POWERPRESS_DOWNLOAD_TEXT', __('Download', 'powerpress') );
3234 if( !defined('POWERPRESS_PLAY_TEXT') )
3235 define('POWERPRESS_PLAY_TEXT', __('Play', 'powerpress') );
3236 if( !defined('POWERPRESS_EMBED_TEXT') )
3237 define('POWERPRESS_EMBED_TEXT', __('Embed', 'powerpress') );
3238 if( !defined('POWERPRESS_READ_TEXT') )
3239 define('POWERPRESS_READ_TEXT', __('Read', 'powerpress') );
3240
3241 $GeneralSettings = get_option('powerpress_general');
3242
3243
3244 if( empty($GeneralSettings['disable_appearance']) || $GeneralSettings['disable_appearance'] == false )
3245 {
3246 require_once( POWERPRESS_ABSPATH.'/powerpress-player.php');
3247 powerpressplayer_init($GeneralSettings);
3248 }
3249
3250 // Enable the playlist feature for PowerPress
3251 if( !empty($GeneralSettings['playlist_player']) ) // Either not set or set on
3252 {
3253 require_once(POWERPRESS_ABSPATH.'/powerpress-playlist.php');
3254 }
3255
3256 if( defined('PODPRESS_VERSION') || isset($GLOBALS['podcasting_player_id']) || isset($GLOBALS['podcast_channel_active']) || defined('PODCASTING_VERSION') )
3257 return false; // Another podcasting plugin is enabled...
3258
3259 // If we are to process podpress data..
3260 if( !empty($GeneralSettings['process_podpress']) )
3261 {
3262 powerpress_podpress_redirect_check();
3263 }
3264
3265 // Add the podcast feeds;
3266 if( !defined('POWERPRESS_NO_PODCAST_FEED') )
3267 {
3268 add_feed('podcast', 'powerpress_do_podcast_feed');
3269 }
3270
3271 if( $GeneralSettings && isset($GeneralSettings['custom_feeds']) && is_array($GeneralSettings['custom_feeds']) )
3272 {
3273 foreach( $GeneralSettings['custom_feeds'] as $feed_slug=> $feed_title )
3274 {
3275 if( $feed_slug != 'podcast' )
3276 add_feed($feed_slug, 'powerpress_do_podcast_feed');
3277 }
3278 }
3279
3280 if( !empty($GeneralSettings['posttype_podcasting']) )
3281 {
3282 // Loop through the posttype podcasting settings and set the feeds for the custom post type slugs...
3283 global $wp_rewrite;
3284
3285
3286 $FeedSlugPostTypesArray = get_option('powerpress_posttype-podcasting'); // Changed field slightly so it does not conflict with a post type "podcasting"
3287 if( $FeedSlugPostTypesArray === false )
3288 {
3289 // Simple one-time fix...
3290 $FeedSlugPostTypesArray = get_option('powerpress_posttype_podcasting');
3291 if( empty($FeedSlugPostTypesArray) )
3292 $FeedSlugPostTypesArray = array();
3293 update_option('powerpress_posttype-podcasting', $FeedSlugPostTypesArray);
3294 if( !array_key_exists('title', $FeedSlugPostTypesArray) ) // AS long as it doesn't have post type specific settings...
3295 delete_option('powerpress_posttype_podcasting');
3296 }
3297
3298 if( empty($FeedSlugPostTypesArray) )
3299 {
3300 $FeedSlugPostTypesArray = array();
3301 }
3302 foreach( $FeedSlugPostTypesArray as $feed_slug=> $FeedSlugPostTypes )
3303 {
3304 if ( !in_array($feed_slug, $wp_rewrite->feeds) ) // we need to add this feed name
3305 {
3306 add_feed($feed_slug, 'powerpress_do_podcast_feed');
3307 foreach( $FeedSlugPostTypes as $post_type_slug=> $title )
3308 {
3309 add_rewrite_rule( '/'. $post_type_slug .'/feed/'. $feed_slug .'/?$', 'index.php?post_type='. $post_type_slug .'&feed='.$feed_slug, 'top' ); // capture the post type feeds
3310 add_rewrite_rule( '/'. $post_type_slug .'/feed/'. $feed_slug .'/?$', 'index.php?post_type='. $post_type_slug .'&feed='.$feed_slug, 'bottom' ); // capture the post type feeds
3311 }
3312 }
3313 }
3314 }
3315
3316 if( defined('GAWP_VERSION') )
3317 {
3318 add_filter('the_content', 'powerpress_yoast_gawp_fix', 120 );
3319 }
3320
3321 if( !empty($GeneralSettings['subscribe_links']) )
3322 {
3323 // 2 Subscribe page shortocde [powerpress_subscribe feedslug="podcast"]
3324 // 3 Subscribe sidebar widget: iTunes, RSS
3325 add_filter('powerpress_player_subscribe_links', 'powerpressplayer_link_subscribe_pre', 1, 3);
3326 add_filter('powerpress_player_subscribe_links', 'powerpressplayer_link_subscribe_post', 1000, 3);
3327 }
3328 wp_register_style(
3329 'powerpress-subscribe-style',
3330 powerpress_get_root_url() . 'css/subscribe.css',
3331 array(),
3332 '20141021',
3333 'all' );
3334
3335 if( !empty($GeneralSettings['rss_emoji']) ) {
3336 if( has_filter('the_content_feed', 'wp_staticize_emoji') ) {
3337 remove_filter( 'the_content_feed', 'wp_staticize_emoji' ); // Remove the emoji images
3338 remove_filter( 'comment_text_rss', 'wp_staticize_emoji' );
3339 //add_filter( 'the_content_feed', 'wp_encode_emoji' ); // Convert an emoji to &#x1Fxxx;
3340 //add_filter( 'get_wp_title_rss', 'wp_encode_emoji' );
3341 }
3342 }
3343
3344 if( !defined('POWERPRESS_NO_REMOVE_WP_HEAD') ) {
3345 remove_action('wp_head', 'feed_links', 2);
3346 remove_action('wp_head', 'feed_links_extra', 3);
3347 }
3348
3349 add_filter( 'the_guid', 'powerpress_the_guid', 11 );
3350
3351
3352
3353 if (!isset($GeneralSettings)) {
3354 $GeneralSettings = get_option('powerpress_general');
3355 }
3356
3357 if (!empty($GeneralSettings['powerpress_network'])) {
3358 require_once( POWERPRESS_ABSPATH .'/powerpress-network.php');
3359 if (class_exists('PowerPressNetwork')) {
3360 $GLOBALS['ppn_object'] = new PowerPressNetwork('powerpressadmin_basic');
3361 $GLOBALS['ppn_object']->setDisplay();
3362
3363 add_action('admin_enqueue_scripts', 'powerpress_network_admin_enqueue_scripts');
3364 // frontend styles enqueued conditionally via ShortCode.php
3365 }
3366 }
3367
3368 }
3369
3370 add_action('init', 'powerpress_init', -100); // We need to add the feeds before other plugins start screwing with them
3371
3372 function powerpress_init_block() {
3373 if (function_exists('register_block_type')) {
3374 // register block(s)
3375 register_block_type(__DIR__ . '/blocks/player-block/build', array('render_callback' => function ($attributes, $content, $block) {
3376 $return = '';
3377 $GeneralSettings = get_option('powerpress_general');
3378
3379 // first, dropdown to select feed if necessary
3380 $is_backend = defined('REST_REQUEST') && REST_REQUEST == true && filter_input(INPUT_GET, 'context', FILTER_SANITIZE_SPECIAL_CHARS) == 'edit';
3381 $player_id = esc_attr( $attributes['id'] ?? '' );
3382 $player_feed_slug = esc_attr( $attributes['feed_slug'] ?? '' );
3383 if ($is_backend && !empty($GeneralSettings['custom_feeds']) && !empty($attributes['id'])) {
3384 $return .= "<select id='select-feed-{$player_id}' disabled>";
3385 if (empty($attributes['feed_slug'])) {
3386 $return .= '<option value="" class="pp-block-select">Channel: No selection</option>';
3387 } else {
3388 $return .= '<option value="" class="pp-block-select">Channel: No selection</option>';
3389 }
3390 if ($attributes['feed_slug'] == 'podcast') {
3391 $return .= '<option value="podcast" class="pp-block-select" selected>Channel: Main Feed</option>';
3392 } else {
3393 $return .= '<option value="podcast" class="pp-block-select">Channel: Main Feed</option>';
3394 }
3395 foreach ($GeneralSettings['custom_feeds'] as $slug => $title) {
3396 if (!empty($attributes['feed_slug']) && $attributes['feed_slug'] == $slug) {
3397 $return .= '<option value="' . $slug . '" class="pp-block-select" selected>' . 'Channel: ' . $title . '</option>';
3398 } else {
3399 $return .= '<option value="' . $slug . '" class="pp-block-select">' . 'Channel: ' . $title . '</option>';
3400 }
3401 }
3402 $return .= "</select>";
3403 }
3404
3405 // print shortcode on public side
3406 if (!$is_backend) {
3407 if (!empty($attributes['feed_slug'])) {
3408 return '[powerpress channel="' . $player_feed_slug . '"]';
3409 }
3410 return '';
3411 }
3412
3413 if (!empty($attributes['feed_slug'])) {
3414 // for editor, generate html from the shortcode and send it
3415 $return .= "<div>";
3416 $return .= "<p class='pp-block-error-{$player_id}'></p><div class='pp-block-sample'>";
3417 $return .= do_shortcode('[powerpress sample="1" channel="' . $player_feed_slug . '"]');
3418 $return .= "</div></div>";
3419 }
3420
3421 // randomly, sometimes, when we add the clientId on the frontend, the block does not re-render and just returns empty
3422 if (empty($return)) {
3423 $return = "<p class='alert alert-danger'>" . __("Something went wrong. Please delete this block and restart it.", "powerpress") . "</p>";
3424 }
3425 return $return;
3426 }, 'attributes' => array(
3427 'updated' => array(
3428 'type' => 'boolean',
3429 'default' => false,
3430 ),
3431 'feed_slug' => array(
3432 'type' => 'string',
3433 'default' => empty($GeneralSettings['custom_feeds']) ? 'podcast' : '',
3434 ),
3435 'id' => array(
3436 'type' => 'string',
3437 'default' => '',
3438 ),
3439 )));
3440 }
3441 }
3442
3443 add_action('init', 'powerpress_init_block', 100); // We need to add this AFTER everything initializes
3444
3445
3446 function powerpress_wp_print_styles()
3447 {
3448 $Settings = get_option('powerpress_general');
3449
3450 if( !empty($Settings['audio_player_max_width']) )
3451 {
3452 echo '<style type="text/css">'."\n";
3453 if( is_numeric($Settings['audio_player_max_width']) )
3454 $Settings['audio_player_max_width'] .= 'px';
3455 echo '.powerpress_player .wp-audio-shortcode { max-width: '.$Settings['audio_player_max_width'].'; }'."\n";
3456 echo '</style>'."\n";
3457 }
3458 }
3459
3460 add_action('wp_print_styles', 'powerpress_wp_print_styles');
3461
3462 function powerpress_request($qv)
3463 {
3464 if( !empty($qv['feed']) )
3465 {
3466 $podcast_feed_slug = false;
3467 if( $qv['feed'] == 'podcast' ) {
3468 $GeneralSettings = get_option('powerpress_general');
3469 if( empty($GeneralSettings['posttype_podcasting']) )
3470 $podcast_feed_slug = 'podcast';
3471 } else if( $qv['feed'] == 'rss' || $qv['feed'] == 'rss2' || $qv['feed'] == 'atom' || $qv['feed'] == 'rdf' || $qv['feed'] == 'feed' ) { // 'feed', 'rdf', 'rss', 'rss2', 'atom'
3472 // Skip
3473 } else {
3474 $GeneralSettings = get_option('powerpress_general');
3475 if( empty($GeneralSettings['posttype_podcasting']) && isset($GeneralSettings['custom_feeds']) && is_array($GeneralSettings['custom_feeds']) && !empty($GeneralSettings['custom_feeds'][ $qv['feed'] ] ) )
3476 $podcast_feed_slug = $qv['feed'];
3477
3478
3479 }
3480
3481 if( $podcast_feed_slug )
3482 {
3483 if( !defined('POWERPRESS_POSTTYPE_MIXING') && $qv['feed'] == 'podcast' ) {
3484 $qv['post_type'] = 'post';
3485 } else {
3486 $qv['post_type'] = get_post_types( array('public'=> true, 'capability_type'=>'post') );
3487 if( !empty($qv['post_type']['attachment']) )
3488 unset($qv['post_type']['attachment']);
3489 }
3490
3491 $FeedCustom = get_option('powerpress_feed_'.$podcast_feed_slug); // Get custom feed specific settings
3492 // See if the user set a custom post type only...
3493 if( !empty($FeedCustom) && !empty( $FeedCustom['custom_post_type']) )
3494 $qv['post_type'] = $FeedCustom['custom_post_type'];
3495 }
3496 }
3497 return $qv;
3498 }
3499
3500 add_filter('request', 'powerpress_request');
3501
3502
3503 function powerpress_plugins_loaded()
3504 {
3505 }
3506 add_action('plugins_loaded', 'powerpress_plugins_loaded');
3507
3508
3509 function powerpress_w3tc_can_print_comment($settings)
3510 {
3511 return false;
3512 }
3513
3514 // Disable minifying if W3TC is enabled
3515 function powerpress_w3tc_minify_enable($enable)
3516 {
3517 if( is_feed() )
3518 return false;
3519 return $enable;
3520 }
3521
3522 // Load the general feed settings for feeds handled by powerpress
3523 function powerpress_load_general_feed_settings()
3524 {
3525 global $wp_query;
3526 global $powerpress_feed;
3527
3528 if( $powerpress_feed !== false ) // If it is not false (either NULL or an array) then we already looked these settings up
3529 {
3530 $powerpress_feed = false;
3531
3532 // Get the powerpress settings
3533 $GeneralSettings = get_option('powerpress_general');
3534 if( !isset($GeneralSettings['custom_feeds']['podcast']) )
3535 $GeneralSettings['custom_feeds']['podcast'] = 'Podcast Feed'; // Fixes scenario where the user never configured the custom default podcast feed.
3536 if( empty($GeneralSettings['default_url']) )
3537 $GeneralSettings['default_url'] = '';
3538
3539 if( $GeneralSettings )
3540 {
3541 $FeedSettingsBasic = get_option('powerpress_feed'); // Get overall feed settings
3542 if( is_feed() && defined( 'WPCACHEHOME' ) && empty($GeneralSettings['allow_feed_comments']) )
3543 {
3544 global $wp_super_cache_comments;
3545 $wp_super_cache_comments = 0;
3546 }
3547
3548 if( is_feed() && defined('W3TC') && empty($GeneralSettings['allow_feed_comments']) )
3549 {
3550 add_filter( 'w3tc_can_print_comment', 'powerpress_w3tc_can_print_comment', 10, 1 );
3551 }
3552
3553 if( is_feed() && defined('W3TC') )
3554 {
3555 add_filter( 'w3tc_minify_enable', 'powerpress_w3tc_minify_enable');
3556 }
3557
3558 // If we're in advanced mode and we're dealing with a category feed we're extending, lets work with it...
3559 if( is_category() && isset($GeneralSettings['custom_cat_feeds']) && is_array($GeneralSettings['custom_cat_feeds']) && in_array( get_query_var('cat'), $GeneralSettings['custom_cat_feeds']) )
3560 {
3561 $cat_ID = get_query_var('cat');
3562 $FeedCustom = get_option('powerpress_cat_feed_'.$cat_ID); // Get custom feed specific settings
3563 $Feed = powerpress_merge_empty_feed_settings($FeedCustom, $FeedSettingsBasic);
3564
3565 $powerpress_feed = array();
3566 if( !empty($GeneralSettings['feed_accel']) )
3567 $powerpress_feed['feed_accel'] = true;
3568 $powerpress_feed['is_custom'] = true;
3569 $powerpress_feed['category'] = $cat_ID;
3570 $powerpress_feed['process_podpress'] = !empty($GeneralSettings['process_podpress']); // Category feeds could originate from Podpress
3571 $powerpress_feed['rss_language'] = ''; // default, let WordPress set the language
3572 $powerpress_feed['default_url'] = '';
3573 if( !empty($GeneralSettings['default_url']) )
3574 $powerpress_feed['default_url'] = rtrim($GeneralSettings['default_url'], '/') .'/';
3575 // switching from 'not set' 'yes' 'clean' to 'true' 'false'--for backwards compatibility, 'not set' will now be 'false'
3576 $explicit_array = array("false", "true", "false");
3577 $powerpress_feed['explicit'] = $explicit_array[$Feed['itunes_explicit']];
3578 if( !empty($Feed['itunes_talent_name']) )
3579 $powerpress_feed['itunes_talent_name'] = $Feed['itunes_talent_name'];
3580 else
3581 $powerpress_feed['itunes_talent_name'] = get_wp_title_rss();
3582 $powerpress_feed['enhance_itunes_summary'] = $Feed['enhance_itunes_summary'] ?? 0;
3583 if( !empty($GeneralSettings['seo_itunes']) )
3584 $powerpress_feed['enhance_itunes_summary'] = 1;
3585 if( !empty($GeneralSettings['disable_wptexturize']) )
3586 $powerpress_feed['disable_wptexturize'] = true;
3587 $powerpress_feed['posts_per_rss'] = false;
3588 if( !empty($Feed['posts_per_rss']) && is_numeric($Feed['posts_per_rss']) && $Feed['posts_per_rss'] > 0 )
3589 $powerpress_feed['posts_per_rss'] = $Feed['posts_per_rss'];
3590 $powerpress_feed['feed_redirect_url'] = '';
3591 if( !empty($Feed['feed_redirect_url']) )
3592 $powerpress_feed['feed_redirect_url'] = $Feed['feed_redirect_url'];
3593 if( !empty($Feed['itunes_author_post']) )
3594 $powerpress_feed['itunes_author_post'] = true;
3595 if( !empty($Feed['rss_language']) )
3596 $powerpress_feed['rss_language'] = $Feed['rss_language'];
3597
3598 if( !empty($GeneralSettings['podcast_embed_in_feed']) )
3599 $powerpress_feed['podcast_embed_in_feed'] = true;
3600 if( !empty($Feed['maximize_feed']) )
3601 $powerpress_feed['maximize_feed'] = true;
3602 if( !empty($Feed['unlock_podcast']) )
3603 $powerpress_feed['unlock_podcast'] = true;
3604 if( !empty($Feed['episode_itunes_image']) && !empty($Feed['itunes_image']) )
3605 $powerpress_feed['itunes_image'] = $Feed['itunes_image'];
3606 return;
3607 }
3608 else if( ( defined('POWERPRESS_TAXONOMY_PODCASTING') || !empty($GeneralSettings['taxonomy_podcasting']) ) && ( is_tag() || is_tax() ) )
3609 {
3610 // We need to get the term_id and the tax_id (tt_id)
3611 $term_slug = get_query_var('term');
3612 $taxonomy = get_query_var('taxonomy');
3613
3614 if( empty($term_slug) && empty($taxonomy) ) // Handle situation where tag is the taxonomy we're working with
3615 {
3616 $term_slug = get_query_var('tag');
3617 if( !empty($term_slug) )
3618 $taxonomy = 'post_tag';
3619 }
3620
3621 $term = false;
3622 if( !empty($term_slug) && !empty($taxonomy) )
3623 {
3624 $term = term_exists($term_slug, $taxonomy);
3625 }
3626
3627 if( !empty($term['term_taxonomy_id']) )
3628 {
3629 $FeedCustom = get_option('powerpress_taxonomy_'.$term['term_taxonomy_id'] ); // Get custom feed specific settings
3630 if( $FeedCustom )
3631 {
3632 $Feed = powerpress_merge_empty_feed_settings($FeedCustom, $FeedSettingsBasic);
3633
3634 $powerpress_feed = array();
3635 if( !empty($GeneralSettings['feed_accel']) )
3636 $powerpress_feed['feed_accel'] = true;
3637 $powerpress_feed['is_custom'] = true;
3638 $powerpress_feed['term_taxonomy_id'] = $term['term_taxonomy_id'];
3639 $powerpress_feed['process_podpress'] = false; // Taxonomy feeds will not originate from Podpress
3640 $powerpress_feed['rss_language'] = ''; // default, let WordPress set the language
3641 $powerpress_feed['default_url'] = rtrim($GeneralSettings['default_url'], '/') .'/';
3642 // switching from 'not set' 'yes' 'clean' to 'true' 'false'--for backwards compatibility, 'not set' will now be 'false'
3643 $explicit_array = array("false", "true", "false");
3644 $powerpress_feed['explicit'] = $explicit_array[$Feed['itunes_explicit']];
3645 if( !empty($Feed['itunes_talent_name']) )
3646 $powerpress_feed['itunes_talent_name'] = $Feed['itunes_talent_name'];
3647 else
3648 $powerpress_feed['itunes_talent_name'] = get_wp_title_rss();
3649 $powerpress_feed['enhance_itunes_summary'] = $Feed['enhance_itunes_summary'] ?? 0;
3650 if( !empty($GeneralSettings['seo_itunes']) )
3651 $powerpress_feed['enhance_itunes_summary'] = 1;
3652 if( !empty($GeneralSettings['disable_wptexturize']) )
3653 $powerpress_feed['disable_wptexturize'] = true;
3654 $powerpress_feed['posts_per_rss'] = false;
3655 if( !empty($Feed['posts_per_rss']) && is_numeric($Feed['posts_per_rss']) && $Feed['posts_per_rss'] > 0 )
3656 $powerpress_feed['posts_per_rss'] = $Feed['posts_per_rss'];
3657 if( !empty($Feed['feed_redirect_url']) )
3658 $powerpress_feed['feed_redirect_url'] = $Feed['feed_redirect_url'];
3659 if( !empty($Feed['itunes_author_post']) )
3660 $powerpress_feed['itunes_author_post'] = true;
3661 if( !empty($Feed['rss_language']) )
3662 $powerpress_feed['rss_language'] = $Feed['rss_language'];
3663
3664 if( !empty($GeneralSettings['podcast_embed_in_feed']) )
3665 $powerpress_feed['podcast_embed_in_feed'] = true;
3666 if( !empty($Feed['maximize_feed']) )
3667 $powerpress_feed['maximize_feed'] = true;
3668 if( !empty($Feed['unlock_podcast']) )
3669 $powerpress_feed['unlock_podcast'] = true;
3670 if( !empty($Feed['episode_itunes_image']) && !empty($Feed['itunes_image']) )
3671 $powerpress_feed['itunes_image'] = $Feed['itunes_image'];
3672 return;
3673 }
3674 }
3675 }
3676
3677 $feed_slug = get_query_var('feed');
3678 // Are we dealing with a custom podcast channel or a custom post type podcast feed...
3679 if( !empty($GeneralSettings['posttype_podcasting']) || isset($GeneralSettings['custom_feeds'][ $feed_slug ]) )
3680 {
3681 $Feed = false;
3682 if( !empty($GeneralSettings['posttype_podcasting']) )
3683 {
3684 $post_type = get_query_var('post_type');
3685
3686 if( !empty($post_type) )
3687 {
3688 if ( is_array( $post_type ) ) {
3689 $post_type = reset( $post_type ); // get first element in array
3690 }
3691
3692 // Get the settings for this podcast post type
3693 $PostTypeSettingsArray = get_option('powerpress_posttype_'. $post_type);
3694 if( !empty($PostTypeSettingsArray[ $feed_slug ]) )
3695 {
3696 $FeedCustom = $PostTypeSettingsArray[ $feed_slug ];
3697 $Feed = powerpress_merge_empty_feed_settings($FeedCustom, $FeedSettingsBasic);
3698 $Feed['post_type'] = $post_type;
3699 }
3700 }
3701 }
3702 if( empty($Feed) && isset($GeneralSettings['custom_feeds'][ $feed_slug ]) )
3703 {
3704 $FeedCustom = get_option('powerpress_feed_'.$feed_slug); // Get custom feed specific settings
3705 $Feed = powerpress_merge_empty_feed_settings($FeedCustom, $FeedSettingsBasic, ($feed_slug == 'podcast') );
3706 }
3707
3708 if( $Feed )
3709 {
3710 $powerpress_feed = array();
3711 if( !empty($GeneralSettings['feed_accel']) )
3712 $powerpress_feed['feed_accel'] = true;
3713 $powerpress_feed['is_custom'] = true;
3714 $powerpress_feed['feed-slug'] = $feed_slug;
3715 if( !empty($Feed['post_type']) )
3716 $powerpress_feed['post_type'] = $Feed['post_type'];
3717 $powerpress_feed['process_podpress'] = ($feed_slug=='podcast'? !empty($GeneralSettings['process_podpress']): false); // We don't touch podpress data for custom feeds
3718 $powerpress_feed['rss_language'] = ''; // RSS language should be set by WordPress by default
3719 $powerpress_feed['default_url'] = '';
3720 if( !empty($powerpress_feed['default_url']) )
3721 $powerpress_feed['default_url'] = rtrim($GeneralSettings['default_url'], '/') .'/';
3722 // switching from 'not set' 'yes' 'clean' to 'true' 'false'--for backwards compatibility, 'not set' will now be 'false'
3723 $explicit = ["false", "true", "false"];
3724 $powerpress_feed['explicit'] = 'false';
3725 if( !empty($Feed['itunes_explicit']) )
3726 $powerpress_feed['explicit'] = $explicit[ $Feed['itunes_explicit'] ];
3727 if( !empty($Feed['itunes_talent_name']) )
3728 $powerpress_feed['itunes_talent_name'] = $Feed['itunes_talent_name'];
3729 else
3730 $powerpress_feed['itunes_talent_name'] = get_wp_title_rss();
3731 $powerpress_feed['enhance_itunes_summary'] = $Feed['enhance_itunes_summary'] ?? 0;
3732 if( !empty($GeneralSettings['seo_itunes']) )
3733 $powerpress_feed['enhance_itunes_summary'] = 1;
3734 if( !empty($GeneralSettings['disable_wptexturize']) )
3735 $powerpress_feed['disable_wptexturize'] = true;
3736 $powerpress_feed['posts_per_rss'] = false;
3737 if( !empty($Feed['posts_per_rss']) && is_numeric($Feed['posts_per_rss']) && $Feed['posts_per_rss'] > 0 )
3738 $powerpress_feed['posts_per_rss'] = $Feed['posts_per_rss'];
3739 if( !empty($Feed['feed_redirect_url']) )
3740 $powerpress_feed['feed_redirect_url'] = $Feed['feed_redirect_url'];
3741 if( !empty($Feed['itunes_author_post'] ) )
3742 $powerpress_feed['itunes_author_post'] = true;
3743 if( !empty($Feed['rss_language']) )
3744 $powerpress_feed['rss_language'] = $Feed['rss_language'];
3745 if( !empty($GeneralSettings['podcast_embed_in_feed']) )
3746 $powerpress_feed['podcast_embed_in_feed'] = true;
3747 if( !empty($Feed['maximize_feed']) )
3748 $powerpress_feed['maximize_feed'] = true;
3749 if( !empty($Feed['unlock_podcast']) )
3750 $powerpress_feed['unlock_podcast'] = true;
3751 if( !empty($Feed['episode_itunes_image']) && !empty($Feed['itunes_image']) )
3752 $powerpress_feed['itunes_image'] = $Feed['itunes_image'];
3753 return;
3754 }
3755 }
3756
3757 if ($FeedSettingsBasic === false || !is_array($FeedSettingsBasic)) {
3758 $FeedSettingsBasic = [];
3759 }
3760
3761 if( !isset($FeedSettingsBasic['apply_to']) )
3762 $FeedSettingsBasic['apply_to'] = 1;
3763
3764 // We fell this far,we must be in simple mode or the user never saved customized their custom feed settings
3765 switch( $FeedSettingsBasic['apply_to'] )
3766 {
3767 case 0: // enhance only the podcast feed added by PowerPress, with the logic above this code should never be reached but it is added for readability.
3768 {
3769 if( $feed_slug != 'podcast' )
3770 break;
3771 } // important: no break here!
3772 case 2: // RSS2 Main feed and podcast feed added by PowerPress only
3773 {
3774 if( $feed_slug != 'feed' && $feed_slug != 'rss2' && $feed_slug != 'podcast' )
3775 break; // We're only adding podcasts to the rss2 feed in this situation
3776
3777 if( $wp_query->is_category ) // don't touch the category feeds...
3778 break;
3779
3780 if( $wp_query->is_tag ) // don't touch the tag feeds...
3781 break;
3782
3783 if( $wp_query->is_comment_feed ) // don't touch the comments feeds...
3784 break;
3785 } // important: no break here!
3786 case 1: // All feeds
3787 {
3788 $powerpress_feed = array(); // Only store what's needed for each feed item
3789 if( !empty($GeneralSettings['feed_accel']) )
3790 $powerpress_feed['feed_accel'] = true;
3791 $powerpress_feed['is_custom'] = false; // ($feed_slug == 'podcast'?true:false);
3792 $powerpress_feed['feed-slug'] = $feed_slug;
3793 $powerpress_feed['process_podpress'] = !empty($GeneralSettings['process_podpress']); // We don't touch podpress data for custom feeds
3794 $powerpress_feed['default_url'] = '';
3795 if( !empty($GeneralSettings['default_url']) )
3796 $powerpress_feed['default_url'] = rtrim($GeneralSettings['default_url'], '/') .'/';
3797 // switching from 'not set' 'yes' 'clean' to 'true' 'false'--for backwards compatibility, 'not set' will now be 'false'
3798 $explicit = array("false", "true", "false");
3799 $powerpress_feed['explicit'] = 'false';
3800 if( !empty($FeedSettingsBasic['itunes_explicit']) )
3801 $powerpress_feed['explicit'] = $explicit[$FeedSettingsBasic['itunes_explicit']];
3802 if( !empty($FeedSettingsBasic['itunes_talent_name']) )
3803 $powerpress_feed['itunes_talent_name'] = $FeedSettingsBasic['itunes_talent_name'];
3804 else
3805 $powerpress_feed['itunes_talent_name'] = get_wp_title_rss();
3806 if( !empty($GeneralSettings['disable_wptexturize']) )
3807 $powerpress_feed['disable_wptexturize'] = true;
3808 $powerpress_feed['posts_per_rss'] = false;
3809 if( !empty($FeedSettingsBasic['posts_per_rss']) && is_numeric($FeedSettingsBasic['posts_per_rss']) && $FeedSettingsBasic['posts_per_rss'] > 0 )
3810 $powerpress_feed['posts_per_rss'] = $FeedSettingsBasic['posts_per_rss'];
3811 if( !empty($FeedSettingsBasic['itunes_author_post']) )
3812 $powerpress_feed['itunes_author_post'] = true;
3813 $powerpress_feed['rss_language'] = ''; // Cannot set the language setting in simple mode
3814 if( !empty($GeneralSettings['podcast_embed_in_feed']) )
3815 $powerpress_feed['podcast_embed_in_feed'] = true;
3816 if( !empty($FeedSettingsBasic['episode_itunes_image']) && !empty($FeedSettingsBasic['itunes_image']) )
3817 $powerpress_feed['itunes_image'] = $FeedSettingsBasic['itunes_image'];
3818
3819 }; break;
3820 // All other cases we let fall through
3821 }
3822 }
3823 }
3824 }
3825
3826 // Returns true of the feed should be treated as a podcast feed
3827 function powerpress_is_podcast_feed()
3828 {
3829 if( defined('PODPRESS_VERSION') || isset($GLOBALS['podcasting_player_id']) || isset($GLOBALS['podcast_channel_active']) || defined('PODCASTING_VERSION') )
3830 return false; // Another podcasting plugin is enabled...
3831
3832 global $powerpress_feed;
3833 if( $powerpress_feed !== false && !is_array($powerpress_feed) )
3834 powerpress_load_general_feed_settings();
3835 if( $powerpress_feed === false )
3836 return false;
3837 return true;
3838 }
3839
3840 // Returns true if the feed is a custom feed added by PowerPress
3841 function powerpress_is_custom_podcast_feed()
3842 {
3843 if( defined('PODPRESS_VERSION') || isset($GLOBALS['podcasting_player_id']) || isset($GLOBALS['podcast_channel_active']) || defined('PODCASTING_VERSION') )
3844 return false; // Another podcasting plugin is enabled...
3845
3846 global $powerpress_feed;
3847 if( $powerpress_feed !== false && !is_array($powerpress_feed) )
3848 powerpress_load_general_feed_settings();
3849 if( $powerpress_feed === false )
3850 return false;
3851 return $powerpress_feed['is_custom'];
3852 }
3853
3854 function powerpress_posts_fields($cols)
3855 {
3856 if( !is_feed() )
3857 return $cols;
3858
3859 if( is_category() || is_tag() || is_tax() ) {
3860 if( get_query_var('feed') !== 'podcast' )
3861 return $cols;
3862 }
3863
3864 if( powerpress_is_custom_podcast_feed() || get_query_var('feed') === 'podcast' )
3865 {
3866 if( !empty($GLOBALS['powerpress_feed']['feed_accel']) )
3867 {
3868 $feed_slug = get_query_var('feed');
3869 global $wpdb;
3870 $cols .= ", pp_{$wpdb->postmeta}.meta_value AS podcast_meta_value ";
3871 }
3872 }
3873
3874 return $cols;
3875 }
3876 //$fields = apply_filters_ref_array( 'posts_fields', array( $fields, &$this ) );
3877 add_filter('posts_fields', 'powerpress_posts_fields' );
3878
3879 function powerpress_posts_join($join)
3880 {
3881 if( !is_feed() )
3882 return $join;
3883
3884 if( is_category() || is_tag() || is_tax() ) {
3885 if( get_query_var('feed') !== 'podcast' )
3886 return $join;
3887 }
3888
3889 if( powerpress_is_custom_podcast_feed() || get_query_var('feed') === 'podcast' )
3890 {
3891 global $wpdb;
3892 $join .= " INNER JOIN {$wpdb->postmeta} AS pp_{$wpdb->postmeta} ";
3893 $join .= " ON {$wpdb->posts}.ID = pp_{$wpdb->postmeta}.post_id ";
3894 }
3895
3896 return $join;
3897 }
3898
3899 add_filter('posts_join', 'powerpress_posts_join' );
3900
3901 function powerpress_posts_where($where)
3902 {
3903 if( !is_feed() )
3904 return $where;
3905 if( is_category() || is_tag() || is_tax() ) {
3906 if( get_query_var('feed') !== 'podcast' )
3907 return $where;
3908 }
3909
3910 if( powerpress_is_custom_podcast_feed() || get_query_var('feed') === 'podcast' )
3911 {
3912 global $wpdb, $powerpress_feed;
3913 $where .= " AND (";
3914
3915 if( powerpress_is_custom_podcast_feed() && get_query_var('feed') !== 'podcast' )
3916 $where .= " pp_{$wpdb->postmeta}.meta_key = '_". get_query_var('feed') .":enclosure' AND pp_{$wpdb->postmeta}.meta_value NOT LIKE 'no%' ";
3917 else
3918 $where .= " pp_{$wpdb->postmeta}.meta_key = 'enclosure' AND pp_{$wpdb->postmeta}.meta_value NOT LIKE 'no%' ";
3919
3920 // Include Podpress data if exists...
3921 if( !empty($powerpress_feed['process_podpress']) && get_query_var('feed') === 'podcast' )
3922 $where .= " OR pp_{$wpdb->postmeta}.meta_key = 'podPressMedia' OR pp_{$wpdb->postmeta}.meta_key = '_podPressMedia' ";
3923
3924 $where .= ") ";
3925 }
3926 return $where;
3927 }
3928
3929 add_filter('posts_where', 'powerpress_posts_where' );
3930
3931 // Add the groupby needed for enclosures only
3932 function powerpress_posts_groupby($groupby)
3933 {
3934 if( !is_feed() )
3935 return $groupby;
3936
3937 if( is_category() || is_tag() || is_tax() ) {
3938 if( get_query_var('feed') !== 'podcast' )
3939 return $groupby;
3940 }
3941
3942 if( powerpress_is_custom_podcast_feed() || get_query_var('feed') === 'podcast' )
3943 {
3944 global $wpdb;
3945 $groupby = " {$wpdb->posts}.ID ";
3946 }
3947 return $groupby;
3948 }
3949 add_filter('posts_groupby', 'powerpress_posts_groupby');
3950
3951 function powerpress_post_limits($limits)
3952 {
3953 if( !is_feed() )
3954 return $limits;
3955
3956 if( powerpress_is_custom_podcast_feed() || get_query_var('feed') === 'podcast' )
3957 {
3958 global $powerpress_feed;
3959 if( !empty($powerpress_feed['posts_per_rss']) && preg_match('/^(\d)+$/', trim($powerpress_feed['posts_per_rss'])) )
3960 $limits = "LIMIT 0, {$powerpress_feed['posts_per_rss']}";
3961 }
3962 return $limits;
3963 }
3964 add_filter('post_limits', 'powerpress_post_limits');
3965
3966
3967 function powerpress_do_all_pings()
3968 {
3969 global $wpdb;
3970 $wpdb->query("DELETE FROM {$wpdb->postmeta} WHERE meta_key = '_encloseme' ");
3971
3972 // Now call the WordPress do_all_pings()...
3973 do_all_pings();
3974 remove_action('do_pings', 'do_all_pings');
3975 }
3976
3977 remove_action('do_pings', 'do_all_pings');
3978 add_action('do_pings', 'powerpress_do_all_pings', 1, 1);
3979
3980 /*
3981 Helper functions:
3982 */
3983 function powerpress_podpress_redirect_check()
3984 {
3985 if( preg_match('/podpress_trac\/([^\/]+)\/([^\/]+)\/([^\/]+)\/(.*)$/', $_SERVER['REQUEST_URI'], $matches) )
3986 {
3987 $post_id = $matches[2];
3988 $mediaNum = $matches[3];
3989 //$filename = $matches[4];
3990 //$method = $matches[1];
3991
3992 if( is_numeric($post_id) && is_numeric($mediaNum))
3993 {
3994 $EpisodeData = powerpress_get_enclosure_data_podpress($post_id, $mediaNum);
3995 if( $EpisodeData && isset($EpisodeData['url']) )
3996 {
3997 if( strpos($EpisodeData['url'], 'http://' ) !== 0 && strpos($EpisodeData['url'], 'https://' ) !== 0 )
3998 {
3999 die('Error occurred obtaining the URL for the requested media file.');
4000 exit;
4001 }
4002
4003 $EnclosureURL = str_replace(' ', '%20', $EpisodeData['url']);
4004 header('Location: '.$EnclosureURL, true, 302);
4005 header('Content-Length: 0');
4006 exit;
4007 }
4008 // Let the WordPress 404 page load as normal
4009 }
4010 }
4011 }
4012
4013 function the_powerpress_content()
4014 {
4015 echo get_the_powerpress_content();
4016 }
4017
4018 /** returns the player and download link HTML for podcast episodes attached to the current post */
4019 function get_the_powerpress_content()
4020 {
4021 global $post;
4022
4023 if( defined('PODPRESS_VERSION') || isset($GLOBALS['podcasting_player_id']) || isset($GLOBALS['podcast_channel_active']) || defined('PODCASTING_VERSION') )
4024 return '';
4025
4026 if( function_exists('post_password_required') )
4027 {
4028 if( post_password_required($post) )
4029 return '';
4030 }
4031
4032 // PowerPress settings:
4033 $GeneralSettings = get_option('powerpress_general');
4034
4035 // No player or links to add to content...
4036 if( !empty($GeneralSettings['disable_appearance']) )
4037 return '';
4038
4039 if( !isset($GeneralSettings['custom_feeds']) )
4040 $GeneralSettings['custom_feeds'] = array('podcast'=>'Default Podcast Feed');
4041
4042 // Re-order so the default podcast episode is the top most...
4043 $Temp = $GeneralSettings['custom_feeds'];
4044 $GeneralSettings['custom_feeds'] = array();
4045 $GeneralSettings['custom_feeds']['podcast'] = 'Default Podcast Feed';
4046
4047 if (is_array($Temp)){
4048 foreach ($Temp as $feed_slug => $feed_title) {
4049 if ($feed_slug == 'podcast')
4050 continue;
4051 $GeneralSettings['custom_feeds'][$feed_slug] = $feed_title;
4052 }
4053 }
4054 // Handle post type feeds....
4055 if( !empty($GeneralSettings['posttype_podcasting']) )
4056 {
4057 $post_type = get_query_var('post_type');
4058 if ( is_array( $post_type ) ) {
4059 $post_type = reset( $post_type ); // get first element in array
4060 }
4061
4062 // Get the feed slugs and titles for this post type
4063 $PostTypeSettingsArray = get_option('powerpress_posttype_'.$post_type);
4064 // Loop through this array of post type settings...
4065 if( !empty($PostTypeSettingsArray) )
4066 {
4067 switch($post_type)
4068 {
4069 case 'post':
4070 case 'page': {
4071 // Do nothing!, we want the default podcast to appear in these post types
4072 }; break;
4073 default: {
4074 if( !empty($post_type) && empty($PostTypeSettingsArray['podcast']) )
4075 unset($GeneralSettings['custom_feeds']['podcast']); // special case, we do not want an accidental podcast episode to appear in a custom post type if the feature is enabled
4076 }; break;
4077 }
4078
4079 if (is_array($PostTypeSettingsArray)) {
4080 foreach ($PostTypeSettingsArray as $feed_slug => $postTypeSettings) {
4081 if (!empty($postTypeSettings['title']))
4082 $GeneralSettings['custom_feeds'][$feed_slug] = $postTypeSettings['title'];
4083 else
4084 $GeneralSettings['custom_feeds'][$feed_slug] = $feed_slug;
4085 }
4086 }
4087 }
4088 }
4089
4090 if( !isset($GeneralSettings['display_player']) )
4091 $GeneralSettings['display_player'] = 1;
4092 if( !isset($GeneralSettings['player_function']) )
4093 $GeneralSettings['player_function'] = 1;
4094 if( !isset($GeneralSettings['podcast_link']) )
4095 $GeneralSettings['podcast_link'] = 1;
4096
4097 // Figure out which players are alerady in the body of the page...
4098 $ExcludePlayers = array();
4099 if( isset($GeneralSettings['disable_player']) )
4100 $ExcludePlayers = $GeneralSettings['disable_player']; // automatically disable the players configured
4101
4102 // LOOP HERE TO DISPLAY EACH MEDIA TYPE
4103 $new_content = '';
4104 foreach( $GeneralSettings['custom_feeds'] as $feed_slug=> $feed_title )
4105 {
4106 // Get the enclosure data
4107 $EpisodeData = powerpress_get_enclosure_data($post->ID, $feed_slug);
4108
4109 if( !$EpisodeData && !empty($GeneralSettings['process_podpress']) && $feed_slug == 'podcast' )
4110 $EpisodeData = powerpress_get_enclosure_data_podpress($post->ID);
4111
4112 if( !$EpisodeData || !$EpisodeData['url'] )
4113 continue;
4114
4115 // Just in case, if there's no URL lets escape!
4116 if( !$EpisodeData['url'] )
4117 continue;
4118
4119 // If the player is not already inserted in the body of the post using the shortcode...
4120 //if( preg_match('/\[powerpress(.*)\]/is', $content) == 0 )
4121 if( !isset($ExcludePlayers[ $feed_slug ]) ) // If the player is not in our exclude list because it's already in the post body somewhere...
4122 {
4123 if( isset($GeneralSettings['premium_caps']) && $GeneralSettings['premium_caps'] && !powerpress_premium_content_authorized($feed_slug) )
4124 {
4125 $new_content .= powerpress_premium_content_message($post->ID, $feed_slug, $EpisodeData);
4126 }
4127 else
4128 {
4129 if( $GeneralSettings['player_function'] != 3 && $GeneralSettings['player_function'] != 0 ) // Play in new window only or disabled
4130 {
4131 do_action('wp_powerpress_player_scripts');
4132 $AddDefaultPlayer = empty($EpisodeData['no_player']);
4133
4134 if( $EpisodeData && !empty($EpisodeData['embed']) )
4135 {
4136 $new_content .= SanitizeEmbed(trim($EpisodeData['embed']));
4137 if( !empty($GeneralSettings['embed_replace_player']) )
4138 $AddDefaultPlayer = false;
4139 }
4140
4141 if( $AddDefaultPlayer )
4142 {
4143 $image = '';
4144 $width = '';
4145 $height = '';
4146 if( isset($EpisodeData['image']) && $EpisodeData['image'] != '' )
4147 $image = $EpisodeData['image'];
4148 if( !empty($EpisodeData['width']) && is_numeric($EpisodeData['width']) )
4149 $width = $EpisodeData['width'];
4150 if( !empty($EpisodeData['height']) && is_numeric($EpisodeData['height']) )
4151 $height = $EpisodeData['height'];
4152
4153 $new_content .= apply_filters('powerpress_player', '', powerpress_add_flag_to_redirect_url($EpisodeData['url'], 'p'), $EpisodeData );
4154 }
4155 }
4156
4157 if( !isset($EpisodeData['no_links']) )
4158 {
4159 do_action('wp_powerpress_player_scripts');
4160 $new_content .= apply_filters('powerpress_player_links', '', powerpress_add_flag_to_redirect_url($EpisodeData['url'], 'p'), $EpisodeData );
4161 $new_content .= apply_filters('powerpress_player_subscribe_links', '', powerpress_add_flag_to_redirect_url($EpisodeData['url'], 'p'), $EpisodeData );
4162 }
4163 }
4164 }
4165 }
4166
4167 return $new_content;
4168 }
4169
4170
4171
4172 // Adds content types that are missing from the default wp_check_filetype function
4173 function powerpress_get_contenttype($file, $use_wp_check_filetype = true)
4174 {
4175 // strip query string and fragment before parsing (pathinfo doesnt handle URLs)
4176 $path = parse_url($file, PHP_URL_PATH) ?: $file;
4177 $parts = pathinfo($path);
4178 if( !empty($parts['extension']) )
4179 {
4180 switch( strtolower($parts['extension']) )
4181 {
4182 // HLS formats
4183 case 'm3u8':
4184 return 'application/vnd.apple.mpegurl'; // Standard MIME type
4185 case 'm3u':
4186 return 'audio/mpegurl'; // Legacy Playlist format
4187 case 'ts':
4188 return 'video/mp2t'; // HLS Transport Stream (MPEG-2)
4189 // Audio formats
4190 case 'mp3': // most common
4191 case 'mpga':
4192 case 'mp2':
4193 case 'mp2a':
4194 case 'm2a':
4195 case 'm3a':
4196 return 'audio/mpeg';
4197 case 'm4a':
4198 return 'audio/x-m4a';
4199 case 'm4b': // Audio book format
4200 return 'audio/m4b';
4201 case 'm4r': // iPhone ringtone format
4202 return 'audio/m4r';
4203 // OGG Internet content types as set forth by rfc5334 (http://tools.ietf.org/html/rfc5334)
4204 case 'opus':
4205 case 'oga':
4206 case 'spx':
4207 return 'audio/ogg';
4208 case 'wma':
4209 return 'audio/x-ms-wma';
4210 case 'wax':
4211 return 'audio/x-ms-wax';
4212 case 'ra':
4213 case 'ram':
4214 return 'audio/x-pn-realaudio';
4215 case 'mp4a':
4216 return 'audio/mp4';
4217 case 'aac':
4218 return 'audio/aac';
4219
4220 // Video formats
4221 case 'm4v':
4222 return 'video/x-m4v';
4223 case 'mpeg':
4224 case 'mpg':
4225 case 'mpe':
4226 case 'm1v':
4227 case 'm2v':
4228 return 'video/mpeg';
4229 case 'mp4':
4230 case 'mp4v':
4231 case 'mpg4':
4232 return 'video/mp4';
4233 case 'asf':
4234 case 'asx':
4235 return 'video/x-ms-asf';
4236 case 'wmx':
4237 return 'video/x-ms-wmx';
4238 case 'avi':
4239 return 'video/x-msvideo';
4240 case 'wmv':
4241 return 'video/x-ms-wmv'; // Check this
4242 case 'flv':
4243 return 'video/x-flv';
4244 case 'mov':
4245 case 'qt':
4246 return 'video/quicktime';
4247 case 'divx':
4248 return 'video/divx';
4249 case '3gp':
4250 return 'video/3gpp';
4251 case 'webm':
4252 return 'video/webm';
4253 case 'ogg': {
4254 if( !defined('POWERPRESS_OGG_VIDEO') )
4255 return 'audio/ogg';
4256 } // Let this fall through as ogg/video
4257 case 'ogv':
4258 return 'video/ogg';
4259
4260 // rarely used
4261 case 'mid':
4262 case 'midi':
4263 return 'audio/midi';
4264 case 'wav':
4265 return 'audio/wav';
4266 case 'aa':
4267 return 'audio/audible';
4268 case 'pdf':
4269 return 'application/pdf';
4270 case 'torrent':
4271 return 'application/x-bittorrent';
4272 case 'swf':
4273 return 'application/x-shockwave-flash';
4274 case 'ogx':
4275 return 'application/ogg';
4276
4277 // Most recently added by Apple:
4278 case 'epub':
4279 return 'document/x-epub';
4280
4281 // Content type for transcript files
4282 case 'srt':
4283 return 'application/srt';
4284 case 'json':
4285 return 'application/json';
4286 case 'vtt':
4287 return 'text/vtt';
4288 case 'html':
4289 return 'text/html';
4290 case 'txt':
4291 return 'text/plain';
4292
4293 default: // Let it fall through
4294 }
4295 }
4296
4297 // Last case let wordpress detect it:
4298 if( $use_wp_check_filetype )
4299 {
4300 $FileType = wp_check_filetype($file);
4301 if( $FileType && isset($FileType['type']) )
4302 return $FileType['type'];
4303 }
4304 return '';
4305 }
4306
4307
4308 function powerpress_itunes_categories($PrefixSubCategories = false)
4309 {
4310 $temp = array();
4311 $temp['01-00'] = 'Arts';
4312 $temp['01-01'] = 'Design';
4313 $temp['01-02'] = 'Fashion & Beauty';
4314 $temp['01-03'] = 'Food';
4315 $temp['01-04'] = 'Literature';
4316 $temp['01-05'] = 'Performing Arts';
4317 $temp['01-06'] = 'Visual Arts';
4318
4319 $temp['02-00'] = 'Business';
4320 $temp['02-01'] = 'Business News';
4321 $temp['02-02'] = 'Careers';
4322 $temp['02-03'] = 'Investing';
4323 $temp['02-04'] = 'Management & Marketing';
4324 $temp['02-05'] = 'Shopping';
4325
4326 $temp['03-00'] = 'Comedy';
4327
4328 $temp['04-00'] = 'Education';
4329 $temp['04-01'] = 'Education Technology';
4330 $temp['04-02'] = 'Higher Education';
4331 $temp['04-03'] = 'K-12';
4332 $temp['04-04'] = 'Language Courses';
4333 $temp['04-05'] = 'Training';
4334
4335 $temp['05-00'] = 'Games & Hobbies';
4336 $temp['05-01'] = 'Automotive';
4337 $temp['05-02'] = 'Aviation';
4338 $temp['05-03'] = 'Hobbies';
4339 $temp['05-04'] = 'Other Games';
4340 $temp['05-05'] = 'Video Games';
4341
4342 $temp['06-00'] = 'Government & Organizations';
4343 $temp['06-01'] = 'Local';
4344 $temp['06-02'] = 'National';
4345 $temp['06-03'] = 'Non-Profit';
4346 $temp['06-04'] = 'Regional';
4347
4348 $temp['07-00'] = 'Health';
4349 $temp['07-01'] = 'Alternative Health';
4350 $temp['07-02'] = 'Fitness & Nutrition';
4351 $temp['07-03'] = 'Self-Help';
4352 $temp['07-04'] = 'Sexuality';
4353
4354 $temp['08-00'] = 'Kids & Family';
4355
4356 $temp['09-00'] = 'Music';
4357
4358 $temp['10-00'] = 'News & Politics';
4359
4360 $temp['11-00'] = 'Religion & Spirituality';
4361 $temp['11-01'] = 'Buddhism';
4362 $temp['11-02'] = 'Christianity';
4363 $temp['11-03'] = 'Hinduism';
4364 $temp['11-04'] = 'Islam';
4365 $temp['11-05'] = 'Judaism';
4366 $temp['11-06'] = 'Other';
4367 $temp['11-07'] = 'Spirituality';
4368
4369 $temp['12-00'] = 'Science & Medicine';
4370 $temp['12-01'] = 'Medicine';
4371 $temp['12-02'] = 'Natural Sciences';
4372 $temp['12-03'] = 'Social Sciences';
4373
4374 $temp['13-00'] = 'Society & Culture';
4375 $temp['13-01'] = 'History';
4376 $temp['13-02'] = 'Personal Journals';
4377 $temp['13-03'] = 'Philosophy';
4378 $temp['13-04'] = 'Places & Travel';
4379
4380 $temp['14-00'] = 'Sports & Recreation';
4381 $temp['14-01'] = 'Amateur';
4382 $temp['14-02'] = 'College & High School';
4383 $temp['14-03'] = 'Outdoor';
4384 $temp['14-04'] = 'Professional';
4385
4386 $temp['15-00'] = 'Technology';
4387 $temp['15-01'] = 'Gadgets';
4388 $temp['15-02'] = 'Tech News';
4389 $temp['15-03'] = 'Podcasting';
4390 $temp['15-04'] = 'Software How-To';
4391
4392 $temp['16-00'] = 'TV & Film';
4393
4394 if( $PrefixSubCategories )
4395 {
4396 foreach( $temp as $key=> $val )
4397 {
4398 $parts = explode('-', $key);
4399 $cat = $parts[0];
4400 $subcat = $parts[1];
4401
4402 if( $subcat != '00' )
4403 $temp[$key] = $temp[$cat.'-00'].' > '.$val;
4404 }
4405 reset($temp);
4406 }
4407
4408 return $temp;
4409 }
4410
4411 /**
4412 * Categories for 2019+ Apple Podcast directory
4413 */
4414 function powerpress_apple_categories($PrefixSubCategories = false) {
4415 $temp = array();
4416 $temp['01-00'] = 'Arts';
4417 $temp['01-01'] = 'Books';
4418 $temp['01-02'] = 'Design';
4419 $temp['01-03'] = 'Fashion & Beauty';
4420 $temp['01-04'] = 'Food';
4421 $temp['01-05'] = 'Performing Arts';
4422 $temp['01-06'] = 'Visual Arts';
4423
4424 $temp['02-00'] = 'Business';
4425 $temp['02-01'] = 'Careers';
4426 $temp['02-02'] = 'Entrepreneurship';
4427 $temp['02-03'] = 'Investing';
4428 $temp['02-04'] = 'Management';
4429 $temp['02-05'] = 'Marketing';
4430 $temp['02-06'] = 'Non-Profit';
4431
4432 $temp['03-00'] = 'Comedy';
4433 $temp['03-01'] = 'Comedy Interviews';
4434 $temp['03-02'] = 'Improv';
4435 $temp['03-03'] = 'Stand-Up';
4436
4437 $temp['04-00'] = 'Education';
4438 $temp['04-01'] = 'Courses';
4439 $temp['04-02'] = 'How To';
4440 $temp['04-03'] = 'Language Learning';
4441 $temp['04-04'] = 'Self-Improvement';
4442
4443 $temp['05-00'] = 'Fiction';
4444 $temp['05-01'] = 'Comedy Fiction';
4445 $temp['05-02'] = 'Drama';
4446 $temp['05-03'] = 'Science Fiction';
4447
4448 $temp['06-00'] = 'Government';
4449
4450 $temp['07-00'] = 'Health & Fitness';
4451 $temp['07-01'] = 'Alternative Health';
4452 $temp['07-02'] = 'Fitness';
4453 $temp['07-03'] = 'Medicine';
4454 $temp['07-04'] = 'Mental Health';
4455 $temp['07-05'] = 'Nutrition';
4456 $temp['07-06'] = 'Sexuality';
4457
4458 $temp['08-00'] = 'History';
4459
4460 $temp['09-00'] = 'Kids & Family';
4461 $temp['09-01'] = 'Education for Kids';
4462 $temp['09-02'] = 'Parenting';
4463 $temp['09-03'] = 'Pets & Animals';
4464 $temp['09-04'] = 'Stories for Kids';
4465
4466 $temp['10-00'] = 'Leisure';
4467 $temp['10-01'] = 'Animation & Manga';
4468 $temp['10-02'] = 'Automotive';
4469 $temp['10-03'] = 'Aviation';
4470 $temp['10-04'] = 'Crafts';
4471 $temp['10-05'] = 'Games';
4472 $temp['10-06'] = 'Hobbies';
4473 $temp['10-07'] = 'Home & Garden';
4474 $temp['10-08'] = 'Video Games';
4475
4476 $temp['11-00'] = 'Music';
4477 $temp['11-01'] = 'Music Commentary';
4478 $temp['11-02'] = 'Music History';
4479 $temp['11-03'] = 'Music Interviews';
4480
4481 $temp['12-00'] = 'News';
4482 $temp['12-01'] = 'Business News';
4483 $temp['12-02'] = 'Daily News';
4484 $temp['12-03'] = 'Entertainment News';
4485 $temp['12-04'] = 'News Commentary';
4486 $temp['12-05'] = 'Politics';
4487 $temp['12-06'] = 'Sports News';
4488 $temp['12-07'] = 'Tech News';
4489
4490 $temp['13-00'] = 'Religion & Spirituality';
4491 $temp['13-01'] = 'Buddhism';
4492 $temp['13-02'] = 'Christianity';
4493 $temp['13-03'] = 'Hinduism';
4494 $temp['13-04'] = 'Islam';
4495 $temp['13-05'] = 'Judaism';
4496 $temp['13-06'] = 'Religion';
4497 $temp['13-07'] = 'Spirituality';
4498
4499 $temp['14-00'] = 'Science';
4500 $temp['14-01'] = 'Astronomy';
4501 $temp['14-02'] = 'Chemistry';
4502 $temp['14-03'] = 'Earth Sciences';
4503 $temp['14-04'] = 'Life Sciences';
4504 $temp['14-05'] = 'Mathematics';
4505 $temp['14-06'] = 'Natural Sciences';
4506 $temp['14-07'] = 'Nature';
4507 $temp['14-08'] = 'Physics';
4508 $temp['14-09'] = 'Social Sciences';
4509
4510 $temp['15-00'] = 'Society & Culture';
4511 $temp['15-01'] = 'Documentary';
4512 $temp['15-02'] = 'Personal Journals';
4513 $temp['15-03'] = 'Philosophy';
4514 $temp['15-04'] = 'Places & Travel';
4515 $temp['15-06'] = 'Relationships';
4516
4517 $temp['16-00'] = 'Sports';
4518 $temp['16-01'] = 'Baseball';
4519 $temp['16-02'] = 'Basketball';
4520 $temp['16-03'] = 'Cricket';
4521 $temp['16-04'] = 'Fantasy Sports';
4522 $temp['16-05'] = 'Football';
4523 $temp['16-06'] = 'Golf';
4524 $temp['16-07'] = 'Hockey';
4525 $temp['16-08'] = 'Rugby';
4526 $temp['16-09'] = 'Running';
4527 $temp['16-10'] = 'Soccer';
4528 $temp['16-11'] = 'Swimming';
4529 $temp['16-12'] = 'Tennis';
4530 $temp['16-13'] = 'Volleyball';
4531 $temp['16-15'] = 'Wilderness';
4532 $temp['16-16'] = 'Wrestling';
4533
4534 $temp['17-00'] = 'Technology';
4535
4536 $temp['18-00'] = 'True Crime';
4537
4538 $temp['19-00'] = 'TV & Film';
4539 $temp['19-01'] = 'After Shows';
4540 $temp['19-02'] = 'Film History';
4541 $temp['19-03'] = 'Film Interviews';
4542 $temp['19-04'] = 'Film Reviews';
4543 $temp['19-05'] = 'TV Reviews';
4544
4545 if( $PrefixSubCategories )
4546 {
4547 foreach( $temp as $key=> $val )
4548 {
4549 $parts = explode('-', $key);
4550 $cat = $parts[0];
4551 $subcat = $parts[1];
4552
4553 if( $subcat != '00' )
4554 $temp[$key] = $temp[$cat.'-00'].' > '.$val;
4555 }
4556 reset($temp);
4557 }
4558
4559 return $temp;
4560 }
4561
4562 function powerpress_googleplay_categories()
4563 {
4564 $temp = array();
4565 $temp['01-00'] = 'Arts';
4566 $temp['02-00'] = 'Business';
4567 $temp['03-00'] = 'Comedy';
4568 $temp['04-00'] = 'Education';
4569 $temp['05-00'] = 'Games & Hobbies';
4570 $temp['06-00'] = 'Government & Organizations';
4571 $temp['07-00'] = 'Health';
4572 $temp['08-00'] = 'Kids & Family';
4573 $temp['09-00'] = 'Music';
4574 $temp['10-00'] = 'News & Politics';
4575 $temp['11-00'] = 'Religion & Spirituality';
4576 $temp['12-00'] = 'Science & Medicine';
4577 $temp['13-00'] = 'Society & Culture';
4578 $temp['14-00'] = 'Sports & Recreation';
4579 $temp['15-00'] = 'Technology';
4580 $temp['16-00'] = 'TV & Film';
4581
4582 return $temp;
4583 }
4584
4585 function powerpress_get_root_url()
4586 {
4587 /*
4588 // OLD CODE:
4589 $powerpress_dirname = basename( POWERPRESS_ABSPATH );
4590 return WP_PLUGIN_URL . '/'. $powerpress_dirname .'/';
4591 */
4592 $local_path = __FILE__;
4593 if( DIRECTORY_SEPARATOR == '\\' ) { // Win32 fix
4594 $local_path = basename(dirname(__FILE__)) .'/'. basename(__FILE__);
4595 }
4596 $plugin_url = plugins_url('', $local_path);
4597 return $plugin_url . '/';
4598 }
4599
4600 /**
4601 * blubrry publish url derivation
4602 *
4603 * @return string publish url with trailing slash.
4604 */
4605 function powerpress_get_publish_url() {
4606 $origin_array = explode('.', POWERPRESS_BLUBRRY_API_URL);
4607 $origin_array[0] = str_replace('api', 'publish', $origin_array[0]);
4608 return rtrim(implode('.', $origin_array), '/') . '/';
4609 }
4610
4611 function powerpress_get_the_exerpt($for_summary = false, $no_filters = false, $post_id = false)
4612 {
4613 if( $no_filters ) {
4614 if( $post_id > 0 ) {
4615 $post = get_post($post_id);
4616 $subtitle = $post->post_excerpt;
4617 if ( $subtitle == '') {
4618
4619 $subtitle = $post->post_content;
4620 $shortcodesTemp = $GLOBALS['shortcode_tags'];
4621 $GLOBALS['shortcode_tags']['skipto'] = 'powerpress_shortcode_skipto';
4622 $subtitle = do_shortcode($subtitle);
4623 $GLOBALS['shortcode_tags'] = $shortcodesTemp;
4624
4625 $subtitle = strip_shortcodes( $subtitle );
4626 $subtitle = str_replace(']]>', ']]&gt;', $subtitle);
4627 $subtitle = strip_tags($subtitle);
4628 }
4629 }
4630 else if( is_object($GLOBALS['post']) )
4631 {
4632 $subtitle = $GLOBALS['post']->post_excerpt;
4633 if ( $subtitle == '') {
4634
4635 $subtitle = $GLOBALS['post']->post_content;
4636
4637 $shortcodesTemp = $GLOBALS['shortcode_tags'];
4638 $GLOBALS['shortcode_tags']['skipto'] = 'powerpress_shortcode_skipto';
4639 $subtitle = do_shortcode($subtitle);
4640 $GLOBALS['shortcode_tags'] = $shortcodesTemp;
4641
4642 $subtitle = strip_shortcodes( $subtitle );
4643 $subtitle = str_replace(']]>', ']]&gt;', $subtitle);
4644 $subtitle = strip_tags($subtitle);
4645 }
4646 }
4647 } else {
4648 $subtitle = get_the_excerpt();
4649 }
4650
4651 $subtitle = trim( strip_tags( $subtitle ) );
4652 if( !empty($subtitle) )
4653 return $subtitle;
4654 return powerpress_get_the_content( $for_summary, $no_filters );
4655 }
4656
4657 function powerpress_get_the_content($for_summary = true, $no_filters = false, $no_strip_tags = false) {
4658 if( $no_filters ) {
4659 global $post;
4660 $content_no_html = $post->post_content;
4661
4662 $shortcodesTemp = $GLOBALS['shortcode_tags'];
4663 $GLOBALS['shortcode_tags']['skipto'] = 'powerpress_shortcode_skipto';
4664 $content_no_html = do_shortcode($content_no_html);
4665 $GLOBALS['shortcode_tags'] = $shortcodesTemp;
4666
4667 //$content_no_html = strip_shortcodes( $content_no_html );
4668 $content_no_html = str_replace(']]>', ']]&gt;', $content_no_html);
4669 $content_no_html = wp_staticize_emoji( _oembed_filter_feed_content( $content_no_html ) );
4670 } else {
4671 $content_no_html = get_the_content();
4672 }
4673
4674 $content_no_html = strip_shortcodes( $content_no_html );
4675 if( $no_strip_tags )
4676 return $content_no_html;
4677
4678 if( $for_summary ) {
4679 return trim( strip_tags($content_no_html, '<a><p><br><ul><li>') );
4680 }
4681 return trim( strip_tags($content_no_html) );
4682 }
4683
4684
4685
4686 function powerpress_url_in_feed($url) {
4687 if( defined('POWERPRESS_FEEDS_FORCE_HTTP') && is_feed() ) {
4688 if( preg_match('/^https:\/\/(.*)$/', $url, $matches) ) {
4689 return 'http://'.$matches[1];
4690 }
4691 }
4692 else if( defined('POWERPRESS_FEEDS_FORCE_HTTPS') && is_feed() ) {
4693 if( preg_match('/^http:\/\/(.*)$/', $url, $matches) ) {
4694 return 'https://'.$matches[1];
4695 }
4696 }
4697 return $url;
4698 }
4699
4700 function powerpress_format_itunes_value($value, $tag, $cdata=false)
4701 {
4702 if( $cdata ) {
4703 $value = str_replace(']]>', ']]&gt;', $value);
4704 return powerpress_trim_value($value, $tag);
4705 }
4706
4707 if( !defined('POWERPRESS_DISABLE_ITUNES_UTF8') || POWERPRESS_DISABLE_ITUNES_UTF8 == false ) // If not defined or it is false
4708 {
4709 global $wpdb;
4710 switch( $wpdb->charset )
4711 {
4712 case 'utf8': break;
4713 case 'utf8mb3': break;
4714 case 'utf8mb4': break;
4715 default: {
4716
4717 // preg_match fails when it encounters invalid UTF8 in $string
4718 if ( 1 !== @preg_match( '/^./us', $value ) ) {
4719 $encoding_detected = mb_detect_encoding($value, ['UTF-8', 'ISO-8859-1', 'Windows-1252', 'ASCII'], true);
4720 if ($encoding_detected !== false) {
4721 $value = mb_convert_encoding($value, 'UTF-8', $encoding_detected);
4722 } else {
4723 $value = mb_convert_encoding($value, 'UTF-8', 'ISO-8859-1');
4724 }
4725 // legacy
4726 // $value = utf8_encode($value); <-- utf8_encode deprecated function
4727 }
4728 }
4729 }
4730 }
4731
4732 // Code added to solve issue with KimiliFlashEmbed plugin and also remove the shortcode for the WP Audio Player
4733 // 99.9% of the time this code will not be necessary
4734 $value = preg_replace("/\[(kml_(flash|swf)embed|audio\:)\b(.*?)(?:(\/))?(\]|$)/isu", '', $value);
4735 $value = @html_entity_decode($value, ENT_COMPAT, 'UTF-8'); // Remove any additional entities such as &nbsp;
4736 $value = preg_replace( '/&amp;/ui' , '&', $value); // Precaution in case it didn't get removed from function above.
4737
4738 return esc_html( powerpress_trim_value($value, $tag) );
4739 }
4740
4741
4742 function powerpress_trim_value(string $value, string $tag)
4743 {
4744 // anon fallback funtions
4745 $strlen = function_exists('mb_strlen')
4746 ? function($val) { return mb_strlen($val); }
4747 : function($val) { return strlen($val); };
4748
4749 $strrpos = function_exists('mb_strrpos')
4750 ? function($val, $search) { return mb_strrpos($val, $search); }
4751 : function($val, $search) { return strrpos($val, $search); };
4752
4753 $substr = function_exists('mb_substr')
4754 ? function($val, $start, $len) { return mb_substr($val, $start, $len); }
4755 : function($val, $start, $len) { return substr($val, $start, $len); };
4756
4757 $value = trim($value); // First we need to trim the string
4758 $length = $strlen($value);
4759 $trim_at = false;
4760 $remove_new_lines = false;
4761
4762 // Assign trim_at, remove 3 additional chars for ellipses '...'
4763 switch($tag)
4764 {
4765 case 'description':
4766 if( $length > 10000 )
4767 $trim_at = 9997;
4768 break;
4769
4770 case 'episode_no_display':
4771 if ( $length > 32 )
4772 $trim_at = 29;
4773 break;
4774
4775 case 'credit_name':
4776 case 'address':
4777 case 'soundbite_title':
4778 case 'donate_label':
4779 case 'copyright':
4780 case 'trailer':
4781 case 'tag_purpose':
4782 $remove_new_lines = true;
4783 if ( $length > 128 )
4784 $trim_at = 125;
4785 break;
4786
4787 case 'tag_content':
4788 if ( $length > 4000 )
4789 $trim_at = 3997;
4790 break;
4791
4792 case 'author':
4793 case 'name':
4794 default:
4795 $remove_new_lines = true;
4796 if( $length > 255 )
4797 $trim_at = 252;
4798 }
4799
4800 if( $trim_at ) {
4801 // Start trimming
4802 $value = $substr($value, 0, $trim_at);
4803
4804 if( $trim_at >= 125 ) {
4805 // find last punctuation, mark for clean cut
4806 $clean_cut = max(
4807 $strrpos($value, '.') ?: 0,
4808 $strrpos($value, ',') ?: 0,
4809 $strrpos($value, '!') ?: 0,
4810 $strrpos($value, '?') ?: 0,
4811 $strrpos($value, "\n") ?: 0,
4812 );
4813
4814 if ( $clean_cut > ($trim_at - 50) ) {
4815 $value = $substr($value, 0, $clean_cut + 1);
4816 $value .= '...';
4817 }
4818 }
4819 }
4820
4821 if( $remove_new_lines )
4822 $value = str_replace( array("\r\n\r\n", "\n", "\r", "\t","- "), array(' - ',' ', '', ' ', ''), $value );
4823
4824 return $value;
4825 }
4826
4827 function powerpress_add_redirect_url($MediaURL, $EpisodeData = false) // $channel = 'podcast')
4828 {
4829 if( preg_match('/^https?:\/\//i', $MediaURL) == 0 )
4830 return $MediaURL; // If the user is hosting media not via http (e.g. ftp) then we can't handle the redirect
4831
4832 // don't add redirects to youtube urls (handles youtube links already saved in wpdb)
4833 if(isYoutubeURL($MediaURL)) return $MediaURL;
4834
4835 if( !is_array($EpisodeData) )
4836 {
4837 $feed_slug = '';
4838 if( is_string($EpisodeData) && !empty($EpisodeData) ) {
4839 $feed_slug = $EpisodeData;
4840 }
4841
4842 $EpisodeData = array();
4843 if( !empty($feed_slug) )
4844 $EpisodeData['feed'] = $EpisodeData;
4845 }
4846
4847 if( empty($EpisodeData['feed']) )
4848 $EpisodeData['feed'] = 'podcast';
4849
4850 $NewURL = apply_filters( 'powerpress_redirect_url', $MediaURL, $EpisodeData );
4851
4852 $URLScheme = ( (preg_match('/^https:\/\//i', $NewURL) != 0 ) ? 'https://':'http://');
4853
4854 $GeneralSettings = get_option('powerpress_general');
4855 $redirects = array('redirect0'=>'', 'redirect1'=>'', 'redirect2'=>'', 'redirect3'=>'');
4856 if( !empty($GeneralSettings['redirect1']) )
4857 $redirects['redirect1'] = $GeneralSettings['redirect1'];
4858 if( !empty($GeneralSettings['redirect2']) )
4859 $redirects['redirect2'] = $GeneralSettings['redirect2'];
4860 if( !empty($GeneralSettings['redirect3']) )
4861 $redirects['redirect3'] = $GeneralSettings['redirect3'];
4862
4863 if( !empty($GeneralSettings['cat_casting']) ) { // If category podcasting...
4864
4865 if( !empty($EpisodeData['category']) ) {
4866
4867 $FeedCatSettings = get_option('powerpress_cat_feed_'.$EpisodeData['category'] );
4868 if( !empty($FeedCatSettings['redirect']) ) {
4869 $redirects['redirect0'] = $FeedCatSettings['redirect'];
4870 $redirects['redirect1'] = '';
4871 $redirects['redirect2'] = '';
4872 $redirects['redirect3'] = '';
4873 }
4874 if( !empty($FeedCatSettings['redirect2']) ) {
4875 $redirects['redirect1'] = $FeedCatSettings['redirect2'];
4876 }
4877 } else { // Use the old way
4878
4879 if( is_category() ) { // Special case where we want to track the category separately
4880 $FeedCatSettings = get_option('powerpress_cat_feed_'.get_query_var('cat') );
4881 if( $FeedCatSettings && !empty($FeedCatSettings['redirect']) ) {
4882 $redirects['redirect0'] = $FeedCatSettings['redirect'];
4883 $redirects['redirect1'] = '';
4884 $redirects['redirect2'] = '';
4885 $redirects['redirect3'] = '';
4886 if( !empty($FeedCatSettings['redirect2']) ) {
4887 $redirects['redirect1'] = $FeedCatSettings['redirect2'];
4888 }
4889 }
4890 } else if( is_single() ) {
4891 $categories = wp_get_post_categories( get_the_ID() );
4892 if( count($categories) == 1 ) { // See if only one category is associated with this post
4893 foreach( $categories as $null=> $cat_id ) {
4894 break;
4895 }
4896 $FeedCatSettings = get_option('powerpress_cat_feed_'.$cat_id );
4897 if( $FeedCatSettings && !empty($FeedCatSettings['redirect']) ) {
4898 $redirects['redirect0'] = $FeedCatSettings['redirect'];
4899 $redirects['redirect1'] = '';
4900 $redirects['redirect2'] = '';
4901 $redirects['redirect3'] = '';
4902 if( !empty($FeedCatSettings['redirect2']) ) {
4903 $redirects['redirect1'] = $FeedCatSettings['redirect2'];
4904 }
4905 }
4906 }
4907 }
4908 }
4909 }
4910
4911 //custom_feeds
4912 if( !empty($GeneralSettings['channels']) ) {
4913
4914 $FeedSettings = get_option('powerpress_feed_'. $EpisodeData['feed']);
4915 if( !empty($FeedSettings['redirect']) )
4916 {
4917 // Override the redirect
4918 $redirects['redirect0'] = $FeedSettings['redirect'];
4919 $redirects['redirect1'] = '';
4920 $redirects['redirect2'] = '';
4921 $redirects['redirect3'] = '';
4922 }
4923 if( !empty($FeedSettings['redirect2']) ) {
4924 $redirects['redirect1'] = $FeedSettings['redirect2'];
4925 }
4926 }
4927
4928 if( !empty($GeneralSettings['posttype_podcasting']) ) // Post Type Podcasting
4929 {
4930 $post_type = get_post_type();
4931 switch($post_type) {
4932 case 'post':
4933 case 'page': {
4934 // Do nothing!, we want the default podcast and channels to appear in these post types
4935 }; break;
4936 default: {
4937 $PostTypeSettingsArray = get_option('powerpress_posttype_'.$post_type);
4938
4939 // We found a post type statsitics tracking
4940 if( !empty($PostTypeSettingsArray[ $EpisodeData['feed'] ]['redirect']) )
4941 {
4942 $redirects['redirect0'] = $PostTypeSettingsArray[ $EpisodeData['feed'] ]['redirect'];
4943 $redirects['redirect1'] = '';
4944 $redirects['redirect2'] = '';
4945 $redirects['redirect3'] = '';
4946 }
4947 if( !empty($PostTypeSettingsArray[ $EpisodeData['feed'] ]['redirect2']) ) {
4948 $redirects['redirect1'] = $PostTypeSettingsArray[ $EpisodeData['feed'] ]['redirect2'];
4949 }
4950 };
4951 }
4952 }
4953
4954 if( version_compare($GLOBALS['wp_version'], '4.5', '>=' ) )
4955 {
4956 if( !empty($GeneralSettings['taxonomy_podcasting']) ) // Taxonomy Podcasting
4957 {
4958 $PowerPressTaxonomies = get_option('powerpress_taxonomy_podcasting');
4959 if( !empty($PowerPressTaxonomies) )
4960 {
4961 foreach ($PowerPressTaxonomies as $key => $value) {
4962 $ttid_found = $key;
4963
4964 $TaxonomySettings = get_option('powerpress_taxonomy_'.$ttid_found);
4965 // Found it???
4966 if( !empty($TaxonomySettings['redirect']) )
4967 {
4968 $redirects['redirect0'] = $TaxonomySettings['redirect'];
4969 $redirects['redirect1'] = '';
4970 $redirects['redirect2'] = '';
4971 $redirects['redirect3'] = '';
4972 break;
4973 }
4974 }
4975 }
4976 }
4977 }
4978
4979 // Allow other apps to update the redirects
4980 $redirects = apply_filters('powerpress_redirects', $redirects, $EpisodeData);
4981
4982 for( $x = 3; $x >= 0; $x-- )
4983 {
4984 $key = sprintf('redirect%d', $x);
4985 if( !empty($redirects[ $key ]) )
4986 {
4987 if( preg_match('/^https?:\/\/(.*)$/', trim($redirects[ $key ]) , $matches ) == 0 )
4988 continue;
4989
4990 // skip adding redirect to enclosure URL if its charable
4991 if (is_chartable_url($redirects[$key])) {
4992 continue;
4993 }
4994
4995 $redirectClean = $matches[1];
4996 if( substr($redirectClean, -1, 1) != '/' ) // Rediercts need to end with a slash /.
4997 $redirectClean .= '/';
4998
4999 if( !empty($redirectClean) )
5000 {
5001 if( strpos($redirectClean, '/') == 0 ) // Not a valid redirect URL
5002 continue;
5003
5004 if( !strstr($NewURL, $redirectClean) ) // If the redirect is not already added...
5005 $NewURL = $URLScheme. $redirectClean . str_replace($URLScheme, '', $NewURL);
5006 }
5007 }
5008 }
5009
5010 return $NewURL;
5011 }
5012
5013 if (!function_exists('is_chartable_url')) {
5014 function is_chartable_url($redirectUrl)
5015 {
5016 if (strpos($redirectUrl, 'chrt.fm') !== false || strpos($redirectUrl, 'chtbl.com') !== false) {
5017 return true;
5018 } else {
5019 return false;
5020 }
5021 }
5022 }
5023
5024 function powerpress_add_flag_to_redirect_url($MediaURL, $Flag)
5025 {
5026 // First strip any previous flags...
5027 return $MediaURL;
5028 }
5029
5030 /*
5031 Code contributed from upekshapriya on the Blubrry Forums
5032 */
5033 function powerpress_byte_size($ppbytes)
5034 {
5035 $ppbytes = intval($ppbytes);
5036 if( empty($ppbytes) )
5037 return '';
5038 $ppsize = intval($ppbytes) / 1024;
5039 if($ppsize < 1024)
5040 {
5041 $ppsize = number_format($ppsize, 1);
5042 $ppsize .= 'KB';
5043 }
5044 else
5045 {
5046 if($ppsize / 1024 < 1024)
5047 {
5048 $ppsize = number_format($ppsize / 1024, 1);
5049 $ppsize .= 'MB';
5050 }
5051 else if ($ppsize / 1024 / 1024 < 1024)
5052 {
5053 $ppsize = number_format($ppsize / 1024 / 1024, 1);
5054 $ppsize .= 'GB';
5055 }
5056 }
5057 return $ppsize;
5058 }
5059
5060 // Merges settings from feed settings page to empty custom feed settings
5061 function powerpress_merge_empty_feed_settings($CustomFeedSettings, $FeedSettings, $DefaultPodcastFeed = false)
5062 {
5063 unset($FeedSettings['apply_to']);
5064 // Remove settings from main $FeedSettings that should not be copied to custom feed.
5065 if( !$DefaultPodcastFeed )
5066 {
5067 unset($FeedSettings['itunes_new_feed_url']);
5068 unset($FeedSettings['feed_redirect_url']);
5069 unset($FeedSettings['itunes_complete']);
5070 unset($FeedSettings['itunes_block']);
5071 unset($FeedSettings['maximize_feed']);
5072 unset($FeedSettings['live_item']);
5073 }
5074
5075 if( !$CustomFeedSettings )
5076 return $FeedSettings; // If the $CustomFeedSettings is false
5077
5078 if (is_array($CustomFeedSettings)) {
5079 foreach ($CustomFeedSettings as $key => $value) {
5080 if ($value !== '' || !isset($FeedSettings[$key]))
5081 $FeedSettings[$key] = $value;
5082 }
5083 }
5084
5085 return $FeedSettings;
5086 }
5087
5088 function powerpress_readable_duration($duration, $include_hour=false)
5089 {
5090 $seconds = 0;
5091 $parts = explode(':', $duration);
5092 // phpstan: explode returns strings, type safety
5093 if( count($parts) == 3 )
5094 $seconds = (int)$parts[2] + ((int)$parts[1]*60) + ((int)$parts[0]*60*60);
5095 else if ( count($parts) == 2 )
5096 $seconds = (int)$parts[1] + ((int)$parts[0]*60);
5097 else
5098 $seconds = (int)$parts[0];
5099
5100 $hours = 0;
5101 $minutes = 0;
5102 if( $seconds >= (60*60) )
5103 {
5104 $hours = floor( $seconds /(60*60) );
5105 $seconds -= (60*60*$hours);
5106 }
5107 if( $seconds >= (60) )
5108 {
5109 $minutes = floor( $seconds /(60) );
5110 $seconds -= (60*$minutes);
5111 }
5112
5113 if( $hours || $include_hour ) // X:XX:XX (readable)
5114 return sprintf('%d:%02d:%02d', $hours, $minutes, $seconds);
5115
5116 return sprintf('%d:%02d', $minutes, $seconds); // X:XX or 0:XX (readable)
5117 }
5118
5119 // Duratoin in form of seconds (parses hh:mm:ss)
5120 function powerpress_raw_duration($duration)
5121 {
5122 $duration = trim($duration);
5123 $Parts = explode(':',$duration);
5124 if( empty($Parts) )
5125 return $duration;
5126
5127 if( count($Parts) == 3 )
5128 return ((intval($Parts[0])*60*60) + (intval($Parts[1])*60) + intval($Parts[2]));
5129 else if( count($Parts) == 2 )
5130 return ((intval($Parts[0])*60) + intval($Parts[1]));
5131 //else if( count($Parts) == 1 )
5132 // return ($Parts[0]);
5133
5134 // We never found any colons, so we assume duration is seconds
5135 return $duration;
5136 }
5137
5138 // For grabbing data from Podpress data stored serialized, the strings for some values can sometimes get corrupted, so we fix it...
5139
5140 function powerpress_repair_serialize($string)
5141 {
5142 // allowed_classes => false prevents php object injection via crafted serialized data
5143 if( @unserialize($string, ['allowed_classes' => false]) )
5144 return $string; // Nothing to repair...
5145
5146 $string = preg_replace_callback('/(s:(\d+):"([^"]*)")/',
5147 'powerpress_repair_serialize_callback',
5148 $string);
5149
5150 if( substr($string, 0, 2) == 's:' ) // Sometimes the serialized data is double serialized, so we need to re-serialize the outside string
5151 {
5152 $string = preg_replace_callback('/(s:(\d+):"(.*)"(;))$/',
5153 'powerpress_repair_serialize_callback',
5154 $string);
5155 }
5156
5157 return $string;
5158 }
5159
5160 function powerpress_repair_serialize_callback($matches)
5161 {
5162 if( strlen($matches[3]) == $matches[2] )
5163 return $matches[0];
5164 return sprintf('s:%d:"%s"', strlen($matches[3]), $matches[3]) . (!empty($matches[4])?';':'');
5165 }
5166
5167 function powerpress_base64_encode($value)
5168 {
5169 return rtrim(strtr(base64_encode($value), '+/', '-_'), '=');
5170 }
5171 /*
5172 powerpress_get_post_meta()
5173 Safe function to retrieve corrupted PodPress data from the database
5174 @post_id - post id to retrieve post meta for
5175 @key - key to retrieve post meta for
5176 */
5177 function powerpress_get_post_meta($post_id, $key)
5178 {
5179 $pp_meta_cache = wp_cache_get($post_id, 'post_meta');
5180 if ( !$pp_meta_cache ) {
5181 update_postmeta_cache($post_id);
5182 $pp_meta_cache = wp_cache_get($post_id, 'post_meta');
5183 }
5184
5185 $meta = false;
5186 if ( isset($pp_meta_cache[$key]) )
5187 $meta = $pp_meta_cache[$key][0];
5188
5189 if ( is_serialized( $meta ) ) // Logic used up but not including WordPress 2.8, new logic doesn't make sure if unserialized failed or not
5190 {
5191 // allowed_classes => false prevents php object injection via crafted serialized data
5192 if ( false !== ( $gm = @unserialize( $meta, ['allowed_classes' => false] ) ) )
5193 return $meta;
5194 }
5195
5196 return $meta;
5197 }
5198
5199 function powerpress_get_enclosure($post_id, $feed_slug = 'podcast')
5200 {
5201 $Data = powerpress_get_enclosure_data($post_id, $feed_slug);
5202 if( $Data )
5203 return $Data['url'];
5204 return false;
5205 }
5206
5207 function powerpress_get_enclosure_data($post_id, $feed_slug = 'podcast', $raw_data = false, $add_redirect=true)
5208 {
5209 global $post;
5210 if( false != $raw_data )
5211 $MetaData = $raw_data;
5212 else
5213 {
5214 if( !empty($post->podcast_meta_value) && $post->ID == $post_id) // See if we got the meta data from the initial query...
5215 {
5216 // Make sure this is not serialized data from PodPress...
5217 $partsTest = explode("\n", $post->podcast_meta_value, 4);
5218 if( count($partsTest) > 2 ) {
5219 $PodcastData = powerpress_get_enclosure_data($post_id, $feed_slug, $post->podcast_meta_value, true);
5220 return $PodcastData;
5221 }
5222 }
5223
5224 if( 'podcast' == $feed_slug || '' == $feed_slug )
5225 $MetaData = get_post_meta($post_id, 'enclosure', true);
5226 else
5227 $MetaData = get_post_meta($post_id, '_'. $feed_slug .':enclosure', true);
5228 }
5229 if( empty($MetaData) )
5230 return false;
5231
5232 $MetaParts = explode("\n", $MetaData, 4);
5233
5234 $Serialized = false;
5235 $Data = array();
5236 $Data['id'] = $post_id;
5237 $Data['feed'] = $feed_slug;
5238 $Data['url'] = '';
5239 $Data['duration'] = '';
5240 $Data['size'] = '';
5241 $Data['type'] = '';
5242 $Data['width'] = '';
5243 $Data['height'] = '';
5244
5245 if( count($MetaParts) > 0 )
5246 $Data['url'] = trim($MetaParts[0]);
5247 if( count($MetaParts) > 1 )
5248 $Data['size'] = trim($MetaParts[1]);
5249 if( count($MetaParts) > 2 )
5250 $Data['type'] = trim($MetaParts[2]);
5251 if( count($MetaParts) > 3 )
5252 $Serialized = $MetaParts[3];
5253
5254 if ($MetaParts[0] == 'no') {
5255 return false;
5256 }
5257
5258 if( $Serialized )
5259 {
5260 // allowed_classes => false prevents php object injection via crafted serialized data
5261 $ExtraData = @unserialize($Serialized, ['allowed_classes' => false]);
5262 if( $ExtraData && is_array($ExtraData) )
5263 {
5264 foreach( $ExtraData as $key=> $value ) {
5265
5266 // Make sure specific fields are not overwritten...
5267 switch( $key ) {
5268 case 'id':
5269 case 'feed':
5270 case 'url':
5271 case 'size':
5272 case 'type': break;
5273 default: $Data[ $key ] = $value;
5274 }
5275 }
5276
5277 if( isset($Data['length']) ) // Setting from the "Podcasting" plugin...
5278 $Data['duration'] = powerpress_readable_duration($Data['length'], true);
5279
5280 if( !empty($Data['webm_src']) )
5281 {
5282 $Data['webm_src'] = trim($Data['webm_src']);
5283 }
5284
5285
5286 if( strpos($MetaParts[0], 'http://') !== 0 && !empty($Data['hosting']) ) // if the URL is not set (just file name) and we're a hosting customer...
5287 {
5288 $post_status = get_post_status($post_id);
5289 switch( $post_status )
5290 {
5291 case 'pending':
5292 case 'draft':
5293 case 'auto-draft': {
5294 // Determine if audio or video, then set the demo episode here...
5295 $Data['url'] = 'http://media.blubrry.com/blubrry/content.blubrry.com/blubrry/preview.mp3'; // audio
5296 if( strstr($Data['type'], 'video') )
5297 $Data['url'] = 'http://media.blubrry.com/blubrry/content.blubrry.com/blubrry/preview.mp4'; // video
5298 }; break;
5299 }
5300 }
5301 }
5302 }
5303
5304 // If the URL is using Blubrry hosting, then lets pump it up to https...
5305 if( is_ssl() && preg_match('/^http:\/\/(.*\/content\.blubrry\.com\/.*)$/i', $Data['url'], $matches) )
5306 {
5307 $Data['url'] = 'https://'. $matches[1];
5308 }
5309
5310 // Check that the content type is a valid one...
5311 if( strstr($Data['type'], '/') == false )
5312 $Data['type'] = powerpress_get_contenttype($Data['url']);
5313
5314 // Do redirect filter here...
5315 if( $add_redirect && !empty($Data['url']) )
5316 $Data['url'] = powerpress_add_redirect_url( $Data['url'], $Data );
5317
5318 if( $add_redirect && !empty($Data['webm_src']) )
5319 $Data['webm_src'] = powerpress_add_redirect_url( $Data['webm_src'], $Data );
5320
5321 return apply_filters('powerpress_get_enclosure_data', $Data);
5322 }
5323
5324 function powerpress_get_enclosure_data_podpress($post_id, $mediaNum = 0, $include_premium = false)
5325 {
5326 $podPressMedia = powerpress_get_post_meta($post_id, 'podPressMedia');
5327 if( !$podPressMedia )
5328 $podPressMedia = powerpress_get_post_meta($post_id, '_podPressMedia'); // handles latest verions of PodPress
5329 if( $podPressMedia )
5330 {
5331
5332 if( !is_array($podPressMedia) )
5333 {
5334 // Sometimes the stored data gets messed up, we can fix it here:
5335 $podPressMedia = powerpress_repair_serialize($podPressMedia);
5336 // allowed_classes => false prevents php object injection via crafted serialized data
5337 $podPressMedia = @unserialize($podPressMedia, ['allowed_classes' => false]);
5338 }
5339
5340 // Do it a second time in case it is double serialized
5341 if( !is_array($podPressMedia) )
5342 {
5343 // Sometimes the stored data gets messed up, we can fix it here:
5344 $podPressMedia = powerpress_repair_serialize($podPressMedia);
5345 // allowed_classes => false prevents php object injection via crafted serialized data
5346 $podPressMedia = @unserialize($podPressMedia, ['allowed_classes' => false]);
5347 }
5348
5349 if( is_array($podPressMedia) && isset($podPressMedia[$mediaNum]) && isset($podPressMedia[$mediaNum]['URI']) )
5350 {
5351 if( $include_premium == false && isset($podPressMedia[$mediaNum]['premium_only']) && ($podPressMedia[$mediaNum]['premium_only'] == 'on' || $podPressMedia[$mediaNum]['premium_only'] == true) )
5352 return false;
5353
5354 $Data = array();
5355 $Data['id'] = $post_id;
5356 $Data['feed'] = 'podcast';
5357 $Data['duration'] = 0;
5358 $Data['url'] = '';
5359 $Data['size'] = 0;
5360 $Data['type'] = '';
5361 $Data['width'] = '';
5362 $Data['height'] = '';
5363
5364 $Data['url'] = $podPressMedia[$mediaNum]['URI'];
5365 if( isset($podPressMedia[$mediaNum]['size']) )
5366 $Data['size'] = $podPressMedia[$mediaNum]['size'];
5367 if( isset($PodPressSettings[$mediaNum]['duration']) )
5368 $Data['duration'] = $podPressMedia[$mediaNum]['duration'];
5369 if( isset($PodPressSettings[$mediaNum]['previewImage']) )
5370 $Data['image'] = $podPressMedia[$mediaNum]['previewImage'];
5371
5372 if( strpos($Data['url'], 'http://' ) !== 0 && strpos($Data['url'], 'https://' ) !== 0 )
5373 {
5374 $PodPressSettings = get_option('podPress_config');
5375 if( $PodPressSettings && isset($PodPressSettings['mediaWebPath']) )
5376 $Data['url'] = rtrim($PodPressSettings['mediaWebPath'], '/') . '/' . ltrim($Data['url'], '/');
5377 unset($PodPressSettings);
5378 }
5379
5380 if( strpos($Data['url'], 'http://' ) !== 0 && strpos($Data['url'], 'https://' ) !== 0 )
5381 {
5382 $Settings = get_option('powerpress_general');
5383 if( $Settings && isset($Settings['default_url']) )
5384 $Data['url'] = rtrim($Settings['default_url'], '/') . '/' . ltrim($Data['url'], '/');
5385 }
5386
5387 if( strpos($Data['url'], 'http://' ) !== 0 && strpos($Data['url'], 'https://' ) !== 0 )
5388 return false;
5389
5390 $Data['type'] = powerpress_get_contenttype($Data['url']); // Detect the content type
5391 $Data['url'] = powerpress_add_redirect_url($Data['url'], $Data); // Add redirects to Media URL
5392
5393 return apply_filters('powerpress_get_enclosure_data', $Data);
5394 }
5395 }
5396 return false;
5397 }
5398
5399 function powerpress_get_apple_id($url, $strict=false)
5400 {
5401 if( $strict )
5402 {
5403 $results = preg_match('/apple\.com\/.*\/id(\d+)/i', $url, $matches);
5404 if( !$results )
5405 $results = preg_match('/apple\.com\/.*id\=(\d+)/i', $url, $matches);
5406 if( $results )
5407 return $matches[1];
5408 return 0;
5409 }
5410 $results = preg_match('/\/id(\d+)/i', $url, $matches);
5411 if( !$results )
5412 $results = preg_match('/id\=(\d+)/i', $url, $matches);
5413 if( $results )
5414 return $matches[1];
5415 return 0;
5416 }
5417
5418
5419 function the_powerpress_all_players($slug = false, $no_link=false)
5420 {
5421 echo get_the_powerpress_all_players($slug, $no_link);
5422 }
5423
5424 function get_the_powerpress_all_players($slug = false, $no_link=false)
5425 {
5426 $return = '';
5427 //Use this function to insert the Powerpress player anywhere in the page.
5428 //Made by Nicolas Bouliane (http://nicolasbouliane.com/)
5429
5430 /*We're going to use the Loop to retrieve the latest post with the 'enclosure' custom key set
5431 //then interpret it and manually launch powerpressplayer_build with the URL contained within
5432 //that data.*/
5433
5434 //Let's reset the Loop to make sure we look through all posts
5435 rewind_posts();
5436
5437 // Get the list of podcast channel slug names...
5438 $GeneralSettings = get_option('powerpress_general');
5439
5440 // No player or links to add to content...
5441 if( !empty($GeneralSettings['disable_appearance']) )
5442 return $return;
5443
5444 $ChannelSlugs = array('podcast');
5445 if( $slug == false )
5446 {
5447 if( isset($GeneralSettings['custom_feeds']['podcast']) )
5448 $ChannelSlugs = array(); // Reset the array so it is added from the list in specified order
5449 foreach( $GeneralSettings['custom_feeds'] as $feed_slug=> $null )
5450 $ChannelSlugs[] = $feed_slug;
5451 }
5452 else if( is_array($slug) )
5453 {
5454 $ChannelSlugs = $slug;
5455 }
5456 else
5457 {
5458 $ChannelSlugs = array($slug);
5459 }
5460
5461 // Loop through the posts
5462 while( have_posts() )
5463 {
5464 the_post();
5465
5466 foreach( $ChannelSlugs as $null=> $feed_slug )
5467 {
5468 // Do we follow the global settings to disable a player?
5469 if( isset($GeneralSettings['disable_player']) && isset($GeneralSettings['disable_player'][$feed_slug]) && $slug == false )
5470 continue;
5471
5472 $EpisodeData = powerpress_get_enclosure_data(get_the_ID(), $feed_slug);
5473 if( !$EpisodeData && !empty($GeneralSettings['process_podpress']) && $feed_slug == 'podcast' )
5474 $EpisodeData = powerpress_get_enclosure_data_podpress(get_the_ID());
5475
5476 if( !$EpisodeData )
5477 continue;
5478
5479 $AddDefaultPlayer = true;
5480 if( !empty($EpisodeData['embed']) )
5481 {
5482 $return .= SanitizeEmbed($EpisodeData['embed']);
5483 if( !empty($GeneralSettings['embed_replace_player']) )
5484 $AddDefaultPlayer = false;
5485 }
5486
5487 if( isset($GeneralSettings['premium_caps']) && $GeneralSettings['premium_caps'] && !powerpress_premium_content_authorized($feed_slug) )
5488 {
5489 $return .= powerpress_premium_content_message(get_the_ID(), $feed_slug, $EpisodeData);
5490 continue;
5491 }
5492
5493 if( !isset($EpisodeData['no_player']) && $AddDefaultPlayer )
5494 {
5495 do_action('wp_powerpress_player_scripts');
5496 $return .= apply_filters('powerpress_player', '', powerpress_add_flag_to_redirect_url($EpisodeData['url'], 'p'), $EpisodeData );
5497 }
5498 if( !isset($EpisodeData['no_links']) && $no_link == false )
5499 {
5500 do_action('wp_powerpress_player_scripts');
5501 $return .= apply_filters('powerpress_player_links', '', powerpress_add_flag_to_redirect_url($EpisodeData['url'], 'p'), $EpisodeData );
5502 $return .= apply_filters('powerpress_player_subscribe_links', '', powerpress_add_flag_to_redirect_url($EpisodeData['url'], 'p'), $EpisodeData );
5503 }
5504 }
5505 reset($ChannelSlugs);
5506 }
5507
5508 return $return;
5509 }
5510
5511 function powerpress_premium_content_authorized_filter($default, $feed_slug)
5512 {
5513 if( $feed_slug != 'podcast' )
5514 {
5515 $FeedSettings = get_option('powerpress_feed_'. $feed_slug);
5516 if( isset($FeedSettings['premium']) && $FeedSettings['premium'] != '' )
5517 return current_user_can($FeedSettings['premium']);
5518 }
5519
5520 $post_type = get_query_var('post_type');
5521 if ( is_array( $post_type ) ) {
5522 $post_type = reset( $post_type ); // get first element in array
5523 }
5524
5525 if( $post_type != 'post' )
5526 {
5527 $GeneralSettings = get_option('powerpress_general');
5528 if( !empty($GeneralSettings['posttype_podcasting']) ) // Custom Post Types
5529 {
5530 // Get the feed slugs and titles for this post type
5531 $PostTypeSettingsArray = get_option('powerpress_posttype_'.$post_type);
5532 if( !empty($PostTypeSettingsArray[$feed_slug]['premium']) )
5533 return current_user_can($PostTypeSettingsArray[$feed_slug]['premium']);
5534 }
5535 }
5536
5537 return $default;
5538 }
5539 add_filter('powerpress_premium_content_authorized', 'powerpress_premium_content_authorized_filter', 10, 2);
5540
5541 function powerpress_premium_content_authorized($feed_slug)
5542 {
5543 return apply_filters('powerpress_premium_content_authorized', true, $feed_slug );
5544 }
5545
5546 function powerpress_premium_content_message($post_id, $feed_slug, $EpisodeData = false)
5547 {
5548 if( !$EpisodeData && $post_id )
5549 $EpisodeData = powerpress_get_enclosure_data($post_id, $feed_slug);
5550
5551 if( !$EpisodeData )
5552 return '';
5553 $FeedSettings = get_option('powerpress_feed_'.$feed_slug);
5554 $post_type = get_query_var('post_type');
5555 if ( is_array( $post_type ) ) {
5556 $post_type = reset( $post_type ); // get first element in array
5557 }
5558
5559 if( $post_type != 'post' )
5560 {
5561 $GeneralSettings = get_option('powerpress_general');
5562 if( !empty($GeneralSettings['posttype_podcasting']) ) // Custom Post Types
5563 {
5564 // Get the feed slugs and titles for this post type
5565 $PostTypeSettingsArray = get_option('powerpress_posttype_'.$post_type);
5566 if( !empty($PostTypeSettingsArray[$feed_slug]['premium']) )
5567 {
5568 $FeedSettings = $PostTypeSettingsArray[$feed_slug];
5569 }
5570 }
5571 }
5572
5573 $extension = 'unknown';
5574 $parts = pathinfo($EpisodeData['url']);
5575 if( $parts && isset($parts['extension']) )
5576 $extension = strtolower($parts['extension']);
5577
5578 if( isset($FeedSettings['premium_label']) && $FeedSettings['premium_label'] != '' ) // User has a custom label
5579 return '<p class="powerpress_links powerpress_links_'. $extension .'">'. $FeedSettings['premium_label'] . '</p>'.PHP_EOL_WEB;
5580
5581 return '<p class="powerpress_links powerpress_links_'. $extension .'">'. htmlspecialchars($FeedSettings['title']) .': <a href="'. get_bloginfo('url') .'/wp-login.php" title="Protected Content">(Protected Content)</a></p>'.PHP_EOL_WEB;
5582 }
5583
5584 function powerpress_is_mobile_client()
5585 {
5586 _deprecated_function( __FUNCTION__, '7.0' );
5587 return false;
5588 }
5589
5590 function powerpress_get_api_array()
5591 {
5592 $return = array();
5593 if( strstr(POWERPRESS_BLUBRRY_API_URL, 'http://api.blubrry.com') == false ) // If not the default
5594 {
5595 $return = explode(';', POWERPRESS_BLUBRRY_API_URL);
5596 }
5597 else
5598 {
5599 $return[] = 'https://api.blubrry.com/'; // Use secure URL first when possible
5600 $return[] = 'https://api.blubrry.net/';
5601 }
5602
5603 return $return;
5604 }
5605
5606
5607 function powerpress_in_wp_head()
5608 {
5609 $e = new Exception();
5610 $trace = $e->getTrace();
5611
5612 if( !empty($trace) ) {
5613 foreach( $trace as $index=> $call ) {
5614 if( isset($call['function']) ) {
5615 // Which calls should we not add the player and links...
5616 switch( $call['function'] ) {
5617 case 'wp_head': return true; break;
5618 }
5619 }
5620 }
5621 }
5622 return false;
5623 }
5624
5625 function powerpress_in_custom_post_widget()
5626 {
5627 if( !class_exists('custom_post_widget') )
5628 return false;
5629
5630 $e = new Exception();
5631 $trace = $e->getTrace();
5632
5633 if( !empty($trace) ) {
5634
5635 foreach( $trace as $index=> $call ) {
5636 if( isset($call['function']) ) {
5637 // Which calls should we not add the player and links...
5638 switch( $call['function'] ) {
5639 case 'custom_post_widget_shortcode': return true; break;
5640 }
5641 }
5642 }
5643 }
5644 return false;
5645 }
5646
5647 function powerpress_admin_migration_notice() {
5648 $QueuedResults = get_option('powerpress_migrate_queued');
5649 $Status = get_option('powerpress_migrate_status');
5650 $completed = false;
5651
5652 // we have successfully migrated all media, or there is no more media to migrate
5653 if (count($QueuedResults) == $Status['completed'] || ($Status['queued'] == 0 && $Status['downloading'] == 0)) {
5654 $completed = true;
5655 }
5656
5657 $alert_link = $root_url = ( (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on' ? 'https://' : 'http://' ) ) . htmlspecialchars($_SERVER['HTTP_HOST']) . "/wp-admin/admin.php?page=powerpress/powerpressadmin_migrate.php";
5658 $alert_class = 'powerpress-notice notice is-dismissible ';
5659 if ($completed) {
5660 $alert_class .= ' notice-success ';
5661 $alert_message = 'Your migration has completed. ';
5662 $alert_link = $root_url . "&action=powerpress-migrate-media&migrate_step=3";;
5663 $alert_link_message = " to update your episodes.";
5664 } else {
5665 $alert_class .= ' notice-info ';
5666 $alert_message = 'Your migration is in progress. ';
5667 $alert_link = $root_url . "&action=powerpress-migrate-media&refresh_migrate_status=1";
5668 $alert_link_message = " to check the status of your migration.";
5669 }
5670
5671
5672 $html = "<p class='alertMessage'>$alert_message<a href='$alert_link'>Click here</a>$alert_link_message</p>"
5673 . '<p>&nbsp; <a style="float:right;" href="#" class="notice-dismiss-link"></a></p>' . PHP_EOL;
5674 powerpress_page_message_add_notice($html, 'inline', false);
5675 }
5676
5677 // rvMigrateMedia::isYoutubeURL
5678 function isYoutubeURL($url)
5679 {
5680 $host = parse_url($url, PHP_URL_HOST);
5681 if (empty($host)) {
5682 return false;
5683 }
5684
5685 $youtubeHostnames = [
5686 'www.youtube.com',
5687 'youtube.com',
5688 'm.youtube.com',
5689 'www.youtube-nocookie.com',
5690 'music.youtube.com',
5691 ];
5692
5693 if (in_array($host, $youtubeHostnames)) {
5694 return true;
5695 }
5696
5697 // see https://gist.github.com/afeld/1254889 for regex details
5698 $youtube_regexp = "/^https?:\/\/(?:www\.)?(?:youtube.com|youtu.be)\/(?:watch\?(?=.*v=([\w\-]+))(?:\S+)?|([\w\-]+))$/i";
5699
5700 if (preg_match($youtube_regexp, $url)) {
5701 return true;
5702 }
5703
5704 return false;
5705 }
5706
5707 function getRemoteFileSize($url, $userAgent = 'PowerPress')
5708 {
5709 $cUrl = curl_init();
5710 curl_setopt($cUrl, CURLOPT_USERAGENT, $userAgent);
5711 curl_setopt($cUrl, CURLOPT_URL, $url);
5712 curl_setopt($cUrl, CURLOPT_FOLLOWLOCATION, 1); // Handles location: refreshes
5713 curl_setopt($cUrl, CURLOPT_MAXREDIRS, 12); // Max 12
5714 curl_setopt($cUrl, CURLOPT_HEADER, 1);
5715 curl_setopt($cUrl, CURLOPT_TIMEOUT, (45)); // trnasfer timeout (45 seconds)
5716 curl_setopt($cUrl, CURLOPT_CONNECTTIMEOUT, 15); // Connect time out (15 seconds)
5717 curl_setopt($cUrl, CURLOPT_ENCODING, 'gzip,deflate'); // Added to support compression
5718 curl_setopt($cUrl, CURLOPT_SSL_VERIFYHOST, 2);
5719 curl_setopt($cUrl, CURLOPT_SSL_VERIFYPEER, true);
5720 curl_setopt($cUrl, CURLOPT_CAINFO, dirname(__FILE__) . '/certificates/ca-bundle.crt');
5721 curl_setopt($cUrl, CURLOPT_RETURNTRANSFER, true);
5722 curl_setopt($cUrl, CURLOPT_NOBODY, true); // convert to a HEAD request
5723
5724 $contentLength = 0;
5725 $pageContent = curl_exec($cUrl);
5726 $length = curl_getinfo($cUrl, CURLINFO_CONTENT_LENGTH_DOWNLOAD);
5727 if (!empty($length)) {
5728 $contentLength = intval($length);
5729 } else {
5730 $lines = explode("\n", $pageContent);
5731 foreach ($lines as $rowNumber => $line) {
5732
5733 if (preg_match('/^content-length: (.*)$/i', $line, $matches)) {
5734 $contentLength = $matches[1];
5735 }
5736 }
5737 }
5738
5739 if (version_compare(PHP_VERSION, '8.0', '<')) {
5740 curl_close($cUrl);
5741 } else {
5742 unset($cUrl);
5743 }
5744 return $contentLength;
5745 }
5746
5747 /**
5748 * Generate Select options for common countries, value is tied to country code
5749 */
5750 function powerpress_print_select_options_country($selectedOption = '')
5751 {
5752 $countries = [
5753 'United States' => 'US', 'Afghanistan' => 'AF', 'Albania' => 'AL', 'Algeria' => 'DZ', 'American Samoa' => 'AS', 'Andorra' => 'AD', 'Angola' => 'AO',
5754 'Anguilla' => 'AI', 'Antarctica' => 'AQ', 'Antigua and Barbuda' => 'AG', 'Argentina' => 'AR', 'Armenia' => 'AM', 'Aruba' => 'AW', 'Australia' => 'AU',
5755 'Austria' => 'AT', 'Azerbaijan' => 'AZ', 'Bahamas' => 'BS', 'Bahrain' => 'BH', 'Bangladesh' => 'BD', 'Barbados' => 'BB', 'Belarus' => 'BY', 'Belgium' => 'BE',
5756 'Belize' => 'BZ', 'Benin' => 'BJ', 'Bermuda' => 'BM', 'Bhutan' => 'BT', 'Bolivia (Plurinational State of)' => 'BO', 'Bosnia and Herzegovina' => 'BA', 'Botswana' => 'BW',
5757 'Bouvet Island' => 'BV', 'Brazil' => 'BR', 'British Indian Ocean Territory' => 'IO', 'Brunei Darussalam' => 'BN', 'Bulgaria' => 'BG',
5758 'Burkina Faso' => 'BF', 'Burundi' => 'BI', 'Cabo Verde' => 'CV', 'Cambodia' => 'KH', 'Cameroon' => 'CM', 'Canada' => 'CA', 'Caribbean Netherlands' => 'BQ',
5759 'Cayman Islands' => 'KY', 'Central African Republic' => 'CF', 'Chad' => 'TD', 'Chile' => 'CL', 'China' => 'CN', 'Christmas Island' => 'CX', 'Cocos (Keeling) Islands' => 'CC',
5760 'Colombia' => 'CO', 'Comoros' => 'KM', 'Congo' => 'CG', 'Congo, Democratic Republic of the' => 'CD', 'Cook Islands' => 'CK', 'Costa Rica' => 'CR', 'Croatia' => 'HR', 'Cuba' => 'CU',
5761 'Cyprus' => 'CY', 'Czech Republic' => 'CZ', 'Denmark' => 'DK', 'Djibouti' => 'DJ', 'Dominica' => 'DM', 'Dominican Republic' => 'DO', 'Ecuador' => 'EC', 'Egypt' => 'EG',
5762 'El Salvador' => 'SV', 'Equatorial Guinea' => 'GQ', 'Eritrea' => 'ER', 'Estonia' => 'EE', 'Eswatini (Swaziland)' => 'SZ', 'Ethiopia' => 'ET', 'Falkland Islands (Malvinas)' => 'FK',
5763 'Faroe Islands' => 'FO', 'Fiji' => 'FJ', 'Finland' => 'FI', 'France' => 'FR', 'French Guiana' => 'GF', 'French Polynesia' => 'PF', 'French Southern Territories' => 'TF',
5764 'Gabon' => 'GA', 'Gambia' => 'GM', 'Georgia' => 'GE', 'Germany' => 'DE', 'Ghana' => 'GH', 'Gibraltar' => 'GI', 'Greece' => 'GR', 'Greenland' => 'GL',
5765 'Grenada' => 'GD', 'Guadeloupe' => 'GP', 'Guam' => 'GU', 'Guatemala' => 'GT', 'Guernsey' => 'GG', 'Guinea' => 'GN', 'Guinea-Bissau' => 'GW', 'Guyana' => 'GY', 'Haiti' => 'HT',
5766 'Heard Island and Mcdonald Islands' => 'HM', 'Honduras' => 'HN', 'Hong Kong' => 'HK', 'Hungary' => 'HU', 'Iceland' => 'IS', 'India' => 'IN', 'Indonesia' => 'ID', 'Iran' => 'IR', 'Iraq' => 'IQ',
5767 'Ireland' => 'IE', 'Isle of Man' => 'IM', 'Italy' => 'IT', 'Jamaica' => 'JM', 'Japan' => 'JP', 'Jersey' => 'JE', 'Jordan' => 'JO', 'Kazakhstan' => 'KZ',
5768 'Kenya' => 'KE', 'Kiribati' => 'KI', 'Korea, North' => 'KP', 'Korea, South' => 'KR', 'Kosovo' => 'XK', 'Kuwait' => 'KW', 'Kyrgyzstan' => 'KG', 'Lao People\'s Democratic Republic' => 'LA', 'Latvia' => 'LV', 'Lebanon' => 'LB',
5769 'Lesotho' => 'LS', 'Liberia' => 'LR', 'Libya' => 'LY', 'Liechtenstein' => 'LI', 'Lithuania' => 'LT', 'Luxembourg' => 'LU', 'Macao' => 'MO', 'Macedonia North' => 'MK', 'Madagascar' => 'MG',
5770 'Malawi' => 'MW', 'Malaysia' => 'MY', 'Maldives' => 'MV', 'Mali' => 'ML', 'Malta' => 'MT', 'Marshall Islands' => 'MH', 'Martinique' => 'MQ', 'Mauritania' => 'MR', 'Mauritius' => 'MU', 'Mayotte' => 'YT',
5771 'Mexico' => 'MX', 'Micronesia' => 'FM', 'Moldova' => 'MD', 'Monaco' => 'MC', 'Mongolia' => 'MN', 'Montenegro' => 'ME', 'Montserrat' => 'MS', 'Morocco' => 'MA', 'Mozambique' => 'MZ',
5772 'Myanmar (Burma)' => 'MM', 'Namibia' => 'NA', 'Nauru' => 'NR', 'Nepal' => 'NP', 'Netherlands' => 'NL', 'Netherlands Antilles' => 'AN', 'New Caledonia' => 'NC', 'New Zealand' => 'NZ', 'Nicaragua' => 'NI', 'Niger' => 'NE',
5773 'Nigeria' => 'NG', 'Niue' => 'NU', 'Norfolk Island' => 'NF', 'Northern Mariana Islands' => 'MP', 'Norway' => 'NO', 'Oman' => 'OM', 'Pakistan' => 'PK', 'Palau' => 'PW', 'Palestine' => 'PS', 'Panama' => 'PA', 'Papua New Guinea' => 'PG',
5774 'Paraguay' => 'PY', 'Peru' => 'PE', 'Philippines' => 'PH', 'Pitcairn Islands' => 'PN', 'Poland' => 'PL', 'Portugal' => 'PT', 'Puerto Rico' => 'PR', 'Qatar' => 'QA', 'Reunion' => 'RE', 'Romania' => 'RO',
5775 'Russian Federation' => 'RU', 'Rwanda' => 'RW', 'Saint Barthélemy' => 'BL', 'Saint Helena' => 'SH', 'Saint Kitts and Nevis' => 'KN',
5776 'Saint Lucia' => 'LC', 'Saint Martin' => 'MF', 'Saint Pierre and Miquelon' => 'PM', 'Saint Vincent and the Grenadines' => 'VC', 'Samoa' => 'WS', 'San Marino' => 'SM', 'Sao Tome and Principe' => 'ST',
5777 'Saudi Arabia' => 'SA', 'Senegal' => 'SN', 'Serbia' => 'RS', 'Serbia and Montenegro' => 'CS', 'Seychelles' => 'SC', 'Sierra Leone' => 'SL',
5778 'Singapore' => 'SG', 'Sint Maarten' => 'SX', 'Slovakia' => 'SK', 'Slovenia' => 'SI', 'Solomon Islands' => 'SB', 'Somalia' => 'SO', 'South Africa' => 'ZA',
5779 'South Georgia and the South Sandwich Islands' => 'GS', 'South Sudan' => 'SS', 'Spain' => 'ES', 'Sri Lanka' => 'LK', 'Sudan' => 'SD', 'Suriname' => 'SR', 'Svalbard and Jan Mayen' => 'SJ', 'Sweden' => 'SE', 'Switzerland' => 'CH', 'Syria' => 'SY',
5780 'Taiwan' => 'TW', 'Tajikistan' => 'TJ', 'Tanzania' => 'TZ', 'Thailand' => 'TH', 'Timor-Leste' => 'TL', 'Togo' => 'TG', 'Tokelau' => 'TK', 'Tonga' => 'TO',
5781 'Trinidad and Tobago' => 'TT', 'Tunisia' => 'TN', 'Turkmenistan' => 'TM', 'Turks and Caicos Islands' => 'TC', 'Tuvalu' => 'TV', 'U.S. Outlying Islands' => 'UM', 'Uganda' => 'UG', 'Ukraine' => 'UA', 'United Arab Emirates' => 'AE',
5782 'United Kingdom' => 'GB', 'Uruguay' => 'UY', 'Uzbekistan' => 'UZ', 'Vanuatu' => 'VU', 'Vatican City Holy See' => 'VA', 'Venezuela' => 'VE', 'Vietnam' => 'VN', 'Virgin Islands, British' => 'VG', 'Virgin Islands, U.S' => 'VI', 'Wallis and Futuna' => 'WF', 'Western Sahara' => 'EH', 'Yemen' => 'YE', 'Zambia' => 'ZM', 'Zimbabwe' => 'ZW',
5783 ];
5784 foreach ($countries as $countryName => $countryCode) {
5785 if ($countryCode == $selectedOption) {
5786 echo '<option selected value="'.$countryCode.'">'.__($countryName, "powerpress").'</option>';
5787 } else {
5788 echo '<option value="'.$countryCode.'">'.__($countryName, "powerpress").'</option>';
5789 }
5790 }
5791 }
5792
5793
5794 // Language List -> Moved from powerpressadmin.php
5795 function powerpress_languages()
5796 {
5797 // List copied from PodPress:
5798 $langs = array();
5799 $langs['en-US'] = __('English (United States)', 'powerpress');
5800
5801 $langs['af'] = __('Afrikaans', 'powerpress');
5802 $langs['sq'] = __('Albanian', 'powerpress');
5803 $langs['ar'] = __('Arabic', 'powerpress');
5804 $langs['ar-SA'] = __('Arabic (Saudi Arabia)', 'powerpress');
5805 $langs['ar-EG'] = __('Arabic (Egypt)', 'powerpress');
5806 $langs['ar-DZ'] = __('Arabic (Algeria)', 'powerpress');
5807 $langs['ar-TN'] = __('Arabic (Tunisia)', 'powerpress');
5808 $langs['ar-YE'] = __('Arabic (Yemen)', 'powerpress');
5809 $langs['ar-JO'] = __('Arabic (Jordan)', 'powerpress');
5810 $langs['ar-KW'] = __('Arabic (Kuwait)', 'powerpress');
5811 $langs['ar-BH'] = __('Arabic (Bahrain)', 'powerpress');
5812 $langs['eu'] = __('Basque', 'powerpress');
5813 $langs['be'] = __('Belarusian', 'powerpress');
5814 $langs['bg'] = __('Bulgarian', 'powerpress');
5815 $langs['ca'] = __('Catalan', 'powerpress');
5816 $langs['zh-CN'] = __('Chinese (Simplified)', 'powerpress');
5817 $langs['zh-TW'] = __('Chinese (Traditional)', 'powerpress');
5818 $langs['hr'] = __('Croatian', 'powerpress');
5819 $langs['cs'] = __('Czech', 'powerpress');
5820 $langs['cr'] = __('Cree', 'powerpress');
5821 $langs['da'] = __('Danish', 'powerpress');
5822 $langs['nl'] = __('Dutch', 'powerpress');
5823 $langs['nl-BE'] = __('Dutch (Belgium)', 'powerpress');
5824 $langs['nl-NL'] = __('Dutch (Netherlands)', 'powerpress');
5825 $langs['en'] = __('English', 'powerpress');
5826 $langs['en-AU'] = __('English (Australia)', 'powerpress');
5827 $langs['en-BZ'] = __('English (Belize)', 'powerpress');
5828 $langs['en-CA'] = __('English (Canada)', 'powerpress');
5829 $langs['en-IE'] = __('English (Ireland)', 'powerpress');
5830 $langs['en-JM'] = __('English (Jamaica)', 'powerpress');
5831 $langs['en-NZ'] = __('English (New Zealand)', 'powerpress');
5832 $langs['en-PH'] = __('English (Phillipines)', 'powerpress');
5833 $langs['en-ZA'] = __('English (South Africa)', 'powerpress');
5834 $langs['en-TT'] = __('English (Trinidad)', 'powerpress');
5835 $langs['en-GB'] = __('English (United Kingdom)', 'powerpress');
5836 $langs['en-ZE'] = __('English (Zimbabwe)', 'powerpress');
5837 $langs['et'] = __('Estonian', 'powerpress');
5838 $langs['fo'] = __('Faeroese', 'powerpress');
5839 $langs['fi'] = __('Finnish', 'powerpress');
5840 $langs['fr'] = __('French', 'powerpress');
5841 $langs['fr-BE'] = __('French (Belgium)', 'powerpress');
5842 $langs['fr-CA'] = __('French (Canada)', 'powerpress');
5843 $langs['fr-FD'] = __('French (France)', 'powerpress');
5844 $langs['fr-LU'] = __('French (Luxembourg)', 'powerpress');
5845 $langs['fr-MC'] = __('French (Monaco)', 'powerpress');
5846 $langs['fr-CH'] = __('French (Switzerland)', 'powerpress');
5847 $langs['gl'] = __('Galician', 'powerpress');
5848 $langs['gd'] = __('Gaelic', 'powerpress');
5849 $langs['de'] = __('German', 'powerpress');
5850 $langs['de-AT'] = __('German (Austria)', 'powerpress');
5851 $langs['de-DE'] = __('German (Germany)', 'powerpress');
5852 $langs['de-LI'] = __('German (Liechtenstein)', 'powerpress');
5853 $langs['de-LU'] = __('German (Luxembourg)', 'powerpress');
5854 $langs['de-CH'] = __('German (Switzerland)', 'powerpress');
5855 $langs['el'] = __('Greek', 'powerpress');
5856 $langs['haw'] = __('Hawaiian', 'powerpress');
5857 $langs['he'] = __('Hebrew', 'powerpress');
5858 $langs['hu'] = __('Hungarian', 'powerpress');
5859 $langs['is'] = __('Icelandic', 'powerpress');
5860 $langs['id'] = __('Indonesian', 'powerpress');
5861 $langs['ga'] = __('Irish', 'powerpress');
5862 $langs['it'] = __('Italian', 'powerpress');
5863 $langs['hi'] = __('Hindi', 'powerpress');
5864 $langs['it-IT'] = __('Italian (Italy)', 'powerpress');
5865 $langs['it-CH'] = __('Italian (Switzerland)', 'powerpress');
5866 $langs['ja'] = __('Japanese', 'powerpress');
5867 $langs['ko'] = __('Korean', 'powerpress');
5868 $langs['mk'] = __('Macedonian', 'powerpress');
5869 $langs['no'] = __('Norwegian', 'powerpress');
5870 $langs['pa'] = __('Punjabi', 'powerpress');
5871 $langs['pl'] = __('Polish', 'powerpress');
5872 $langs['pt'] = __('Portuguese', 'powerpress');
5873 $langs['pt-BR'] = __('Portuguese (Brazil)', 'powerpress');
5874 $langs['pt-PT'] = __('Portuguese (Portugal)', 'powerpress');
5875 $langs['ro'] = __('Romanian', 'powerpress');
5876 $langs['ro-MO'] = __('Romanian (Moldova)', 'powerpress');
5877 $langs['ro-RO'] = __('Romanian (Romania)', 'powerpress');
5878 $langs['ru'] = __('Russian', 'powerpress');
5879 $langs['ru-MO'] = __('Russian (Moldova)', 'powerpress');
5880 $langs['ru-RU'] = __('Russian (Russia)', 'powerpress');
5881 $langs['sr'] = __('Serbian', 'powerpress');
5882 $langs['sk'] = __('Slovak', 'powerpress');
5883 $langs['sl'] = __('Slovenian', 'powerpress');
5884 $langs['es'] = __('Spanish', 'powerpress');
5885 $langs['es-AR'] = __('Spanish (Argentina)', 'powerpress');
5886 $langs['es-BO'] = __('Spanish (Bolivia)', 'powerpress');
5887 $langs['es-CL'] = __('Spanish (Chile)', 'powerpress');
5888 $langs['es-CO'] = __('Spanish (Colombia)', 'powerpress');
5889 $langs['es-CR'] = __('Spanish (Costa Rica)', 'powerpress');
5890 $langs['es-DO'] = __('Spanish (Dominican Republic)', 'powerpress');
5891 $langs['es-EC'] = __('Spanish (Ecuador)', 'powerpress');
5892 $langs['es-SV'] = __('Spanish (El Salvador)', 'powerpress');
5893 $langs['es-GT'] = __('Spanish (Guatemala)', 'powerpress');
5894 $langs['es-HN'] = __('Spanish (Honduras)', 'powerpress');
5895 $langs['es-MX'] = __('Spanish (Mexico)', 'powerpress');
5896 $langs['es-NI'] = __('Spanish (Nicaragua)', 'powerpress');
5897 $langs['es-PA'] = __('Spanish (Panama)', 'powerpress');
5898 $langs['es-PY'] = __('Spanish (Paraguay)', 'powerpress');
5899 $langs['es-PE'] = __('Spanish (Peru)', 'powerpress');
5900 $langs['es-PR'] = __('Spanish (Puerto Rico)', 'powerpress');
5901 $langs['es-ES'] = __('Spanish (Spain)', 'powerpress');
5902 $langs['es-UY'] = __('Spanish (Uruguay)', 'powerpress');
5903 $langs['es-VE'] = __('Spanish (Venezuela)', 'powerpress');
5904 $langs['sv'] = __('Swedish', 'powerpress');
5905 $langs['sv-FI'] = __('Swedish (Finland)', 'powerpress');
5906 $langs['sv-SE'] = __('Swedish (Sweden)', 'powerpress');
5907 $langs['sw'] = __('Swahili', 'powerpress');
5908 $langs['ta'] = __('Tamil', 'powerpress');
5909 $langs['th'] = __('Thai', 'powerpress');
5910 $langs['bo'] = __('Tibetan', 'powerpress');
5911 $langs['tr'] = __('Turkish', 'powerpress');
5912 $langs['uk'] = __('Ukranian', 'powerpress');
5913 $langs['ve'] = __('Venda', 'powerpress');
5914 $langs['vi'] = __('Vietnamese', 'powerpress');
5915 $langs['zu'] = __('Zulu', 'powerpress');
5916 $langs['fa'] = __('Persian', 'powerpress');
5917 $langs['fa-AF'] = __('Persian (Afghanistan)', 'powerpress');
5918
5919 return $langs;
5920 }
5921
5922 /**
5923 * Generates Select options for common Language codes with geographic distinctions
5924 */
5925 function powerpress_print_select_options_lang_codes($selectedOption = '')
5926 {
5927 $lang_code = powerpress_languages();
5928
5929 $options = '';
5930 foreach ($lang_code as $code => $name) {
5931 $selected = ($code === $selectedOption) ? ' selected' : '';
5932 $options .= '<option value="' . esc_attr($code) . '"' . $selected . '>' . esc_html($name) . '</option>';
5933 }
5934 return $options;
5935 }
5936
5937 /**
5938 * Generate Select Options for Roles
5939 */
5940 function powerpress_print_select_options_roles($selectedOption = 'Guest') {
5941 $options = [
5942 "Director", "Assistant Director", "Executive Producer", "Senior Producer", "Producer",
5943 "Associate Producer", "Development Producer", "Creative Director", "Host", "Co-Host",
5944 "Guest Host", "Guest", "Voice Actor", "Narrator", "Announcer", "Reporter", "Author",
5945 "Editorial Director", "Co-Writer", "Writer", "Songwriter", "Guest Writer", "Story Editor",
5946 "Managing Editor", "Script Editor", "Script Coordinator", "Researcher", "Editor", "Fact Checker",
5947 "Translator", "Transcriber", "Logger", "Studio Coordinator", "Technical Director", "Technical Manager",
5948 "Audio Engineer", "Remote Recording Engineer", "Post Production Engineer", "Audio Editor", "Sound Designer",
5949 "Foley Artist", "Composer", "Theme Music", "Music Production", "Music Contributor", "Production Coordinator",
5950 "Booking Coordinator", "Production Assistant", "Content Manager", "Marketing Manager", "Sales Representative",
5951 "Sales Manager", "Graphic Designer", "Cover Art Designer", "Social Media Manager", "Consultant", "Intern",
5952 "Camera Operator", "Lighting Designer", "Camera Grip", "Assistant Camera", "Editor", "Assistant Editor"
5953 ];
5954
5955 foreach ($options as $option) {
5956 if ($option == $selectedOption) {
5957 echo '<option selected value="' . $option . '">' . __($option, "powerpress").'</option>';
5958 } else {
5959 echo '<option value="' . $option . '">' . __($option, "powerpress") . '</option>';
5960 }
5961 }
5962 }
5963
5964 /**
5965 * Conver raw seconds to string in the form of HH:MM:SS
5966 */
5967 function powerpress_seconds_to_hms($secs)
5968 {
5969 $secs = (int)$secs;
5970 $h = floor($secs / 3600);
5971 $m = floor(($secs % 3600) / 60);
5972 $s = $secs % 60;
5973 return sprintf('%02d:%02d:%02d', $h, $m, $s);
5974 }
5975
5976 // =========================
5977 // TEMPLATE RENDERING HELPER
5978 // =========================
5979
5980 function powerpress_render_template($config) {
5981 $type = $config['type'];
5982 $FeedSlug = $config['FeedSlug'];
5983 $DataSource = $config['Data'];
5984 $namePrefix = $config['NamePrefix'];
5985 $section_data = [];
5986
5987 $templates = [
5988 'location' => 'location.php',
5989 'copyright' => 'copyright.php',
5990 'credit' => 'credit.php',
5991 'v4v' => 'v4v.php',
5992 'soundbites' => 'soundbite.php',
5993 'social_interact' => 'social-interact.php',
5994 'donate' => 'donate.php',
5995 'txt_tag' => 'txt-tag.php',
5996 'alternate_enclosure'=> 'alt-enclosure.php',
5997 'content_link' => 'content-link.php',
5998 'update_frequency' => 'update-frequency.php',
5999 ];
6000
6001 if (!isset($templates[$type])) {
6002 throw new InvalidArgumentException("Unknown section type: {$type}");
6003 }
6004
6005 include(POWERPRESS_ABSPATH . "/views/pci/{$templates[$type]}");
6006 }
6007
6008 // =====================================
6009 // UPDATE FREQUENCY NORMALIZATION HELPER
6010 // =====================================
6011
6012 /** normalize legacy save pattern for feed output */
6013 function powerpress_normalize_update_frequency($value, $week_indices = null, $month_interval = null) {
6014 if (is_array($value)) return $value;
6015 if (empty($value)) return null;
6016
6017 $freq_map = [1 => 'DAILY', 2 => 'WEEKLY', 3 => 'MONTHLY'];
6018 $value = (int) $value;
6019 if (!isset($freq_map[$value])) return null;
6020
6021 $result = ['freq' => $freq_map[$value]];
6022
6023 if ($value === 2 && !empty($week_indices)) {
6024 $code_lookup = ['SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA'];
6025 $codes = [];
6026 foreach (explode(',', $week_indices) as $idx) {
6027 $idx = (int) trim($idx);
6028 if (isset($code_lookup[$idx]))
6029 $codes[] = $code_lookup[$idx];
6030 }
6031 if (!empty($codes))
6032 $result['byday'] = implode(',', $codes);
6033 }
6034
6035 if ($value === 3 && !empty($month_interval)) {
6036 $result['interval'] = (int) $month_interval;
6037 }
6038
6039 return $result;
6040 }
6041
6042
6043 // Are we in the admin?
6044 if( is_admin() )
6045 {
6046 require_once(POWERPRESS_ABSPATH.'/powerpressadmin.php');
6047 register_activation_hook( __FILE__, 'powerpress_admin_activate' );
6048 }
6049
6050 if( defined('POWERPRESS_SUBSCRIBE') && POWERPRESS_SUBSCRIBE )
6051 {
6052 require_once(POWERPRESS_ABSPATH.'/powerpress-subscribe.php');
6053 }
6054
6055 // For testing purposes in development
6056 if( defined('POWERPRESS_NEW_CODE') && POWERPRESS_NEW_CODE && file_exists(POWERPRESS_ABSPATH.'/powerpress-new-code.php') )
6057 {
6058 require_once(POWERPRESS_ABSPATH.'/powerpress-new-code.php');
6059 }
6060
6061 if( defined('POWERPRESS_PREMIUM_GROUPS_PLUGIN') ) {
6062
6063 function powerpress_pre_get_posts($query) {
6064 if( $query->is_feed() && powerpress_is_custom_podcast_feed() && method_exists('Groups_Post_Access', 'posts_where') )
6065 {
6066 $feed_slug = get_query_var('feed');
6067
6068 if( $feed_slug != 'podcast' )
6069 {
6070 $FeedSettings = get_option('powerpress_feed_'.$feed_slug);
6071 if( !empty($FeedSettings['premium']) )
6072 {
6073 if( has_filter('posts_where', 'Groups_Post_Access::posts_where') )
6074 {
6075 remove_filter('posts_where', 'Groups_Post_Access::posts_where');
6076 }
6077 }
6078 }
6079 }
6080 }
6081 add_filter('pre_get_posts', 'powerpress_pre_get_posts');
6082 }
6083
6084 /**
6085 * enqueue css and js assets with standard powerpress settings.
6086 *
6087 * simplifies registration and enqueueing with:
6088 * - auto-suffix (.min for production, none for debug)
6089 * - auto-dependency on powerpress-variables.css for styles
6090 * - es module support via 'module' => true
6091 *
6092 * example:
6093 * powerpress_enqueue_assets([
6094 * 'powerpress-stats' => [
6095 * 'path' => 'css/components/stats-widget',
6096 * ],
6097 * 'powerpress-chart' => [
6098 * 'type' => 'script',
6099 * 'path' => '3rdparty/chart',
6100 * 'no_suffix' => true,
6101 * ],
6102 * 'powerpress-stats-widget' => [
6103 * 'type' => 'script',
6104 * 'path' => 'js/modules/program-card/StatsWidget',
6105 * 'deps' => ['powerpress-chart'],
6106 * 'module' => true,
6107 * ],
6108 * ]);
6109 *
6110 * @param array $assets associative array of handle => config pairs.
6111 * Config keys:
6112 * - type: 'style' or 'script' (default: 'style')
6113 * - path: local path relative to plugin root (without extension or suffix)
6114 * - url: external url (alternative to path)
6115 * - deps: array of dependencies (default: [])
6116 * - version: version string (default: POWERPRESS_VERSION)
6117 *
6118 * - footer: load in footer (scripts only, default: true)
6119 * - strategy: 'defer' or 'async' (scripts only, default: 'defer')
6120 * - module: add type="module" attribute (scripts only, default: false)
6121 *
6122 * - no_suffix: skip .min suffix even in production (default: false)
6123 */
6124 function powerpress_enqueue_assets(array $assets): void {
6125 if (empty($assets)) {
6126 return;
6127 }
6128
6129 // 1) SETUP
6130 $debug = defined('WP_DEBUG') && WP_DEBUG;
6131 $suffix = $debug ? '' : '.min';
6132 $base_url = powerpress_get_root_url();
6133 $warnings = [];
6134 $module_handles = [];
6135
6136 // 2) AUTO-REGISTER VARIABLES.CSS
6137 if (!wp_style_is('powerpress-variables', 'registered')) {
6138 wp_register_style('powerpress-variables', "{$base_url}css/variables{$suffix}.css", [], POWERPRESS_VERSION);
6139 }
6140
6141 // 3) PROCESS EACH ASSET
6142 foreach ($assets as $handle => $config) {
6143 if (!is_string($handle) || !is_array($config)) {
6144 $warnings[] = 'Invalid handle or config: ' . print_r($handle, true);
6145 continue;
6146 }
6147
6148 $type = $config['type'] ?? 'style';
6149 if ($type !== 'style' && $type !== 'script') {
6150 $warnings[] = "Invalid type for '{$handle}': must be 'style' or 'script'";
6151 continue;
6152 }
6153
6154 $deps = $config['deps'] ?? [];
6155 $version = $config['version'] ?? POWERPRESS_VERSION;
6156
6157 // resolve url from external url or local path
6158 if (!empty($config['url'])) {
6159 $url = $config['url'];
6160 } elseif (!empty($config['path'])) {
6161 $ext = ($type === 'script') ? '.js' : '.css';
6162 $file_suffix = empty($config['no_suffix']) ? $suffix : '';
6163 $url = $base_url . $config['path'] . $file_suffix . $ext;
6164 } else {
6165 $warnings[] = "Missing path or url for '{$handle}'";
6166 continue;
6167 }
6168
6169 // register and enqueue
6170 if ($type === 'script') {
6171 if (!in_array('wp-i18n', $deps, true)) {
6172 $deps[] = 'wp-i18n';
6173 }
6174 $args = [
6175 'in_footer' => $config['footer'] ?? true,
6176 'strategy' => $config['strategy'] ?? 'defer',
6177 ];
6178 wp_register_script($handle, $url, $deps, $version, $args);
6179 wp_enqueue_script($handle);
6180
6181 // enable js translations via wp.i18n
6182 wp_set_script_translations($handle, 'powerpress');
6183
6184 if (!empty($config['module'])) {
6185 $module_handles[] = $handle;
6186 }
6187 } else {
6188 // styles auto depend on variables.css
6189 if ($handle !== 'powerpress-variables' && !in_array('powerpress-variables', $deps)) {
6190 $deps[] = 'powerpress-variables';
6191 }
6192 wp_register_style($handle, $url, $deps, $version);
6193 wp_enqueue_style($handle);
6194 }
6195 }
6196
6197 // 4) ADD MODULE SUPPORT VIA SCRIPT TAG FILTER
6198 if (!empty($module_handles)) {
6199 add_filter('script_loader_tag', function($tag, $handle) use ($module_handles) {
6200 if (in_array($handle, $module_handles)) {
6201 return str_replace('<script ', '<script type="module" ', $tag);
6202 }
6203 return $tag;
6204 }, 10, 2);
6205 }
6206
6207 // 5) LOG WARNINGS IN DEBUG MODE
6208 if ($debug && !empty($warnings)) {
6209 $log_warnings = function() use ($warnings) {
6210 echo '<script>console.warn("PowerPress enqueue_assets:", ' . wp_json_encode($warnings) . ');</script>';
6211 };
6212 add_action('admin_footer', $log_warnings);
6213 add_action('wp_footer', $log_warnings);
6214 }
6215 }
6216
6217 // ===================
6218 // NETWORK ASSET SETUP
6219 // ===================
6220 function powerpress_network_admin_enqueue_scripts() {
6221 if (is_admin()) {
6222 // admin styles + js for network pages
6223 powerpress_enqueue_assets([
6224 'powerpress-admin-css' => ['path' => 'css/admin'],
6225 'ppn-admin' => ['path' => 'css/ppn-admin'],
6226 'powerpress-bootstrap-grid' => ['path' => 'css/bootstrap-grid'],
6227 'powerpress-network-js' => ['type' => 'script', 'path' => 'js/network', 'module' => true, 'deps' => ['wp-i18n']],
6228 'material-icons-outlined' => ['type' => 'style', 'url' => 'https://fonts.googleapis.com/icon?family=Material+Icons+Outlined'],
6229 'roboto-font' => ['type' => 'style', 'url' => 'https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;600;700&display=swap'],
6230 ]);
6231 }
6232 }
6233
6234
6235 // eof
6236