PluginProbe
PowerPress Podcasting plugin by Blubrry / 11.17.1
PowerPress Podcasting plugin by Blubrry v11.17.1
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.1, at powerpress.php

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