PluginProbe
PowerPress Podcasting plugin by Blubrry / trunk
PowerPress Podcasting plugin by Blubrry vtrunk
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 / powerpressadmin-rss-import.php

powerpressadmin-rss-import.php in PowerPress Podcasting plugin by Blubrry trunk, at powerpressadmin-rss-import.php

1,996 lines 77.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 // Load Importer API
4 require_once( ABSPATH . 'wp-admin/includes/import.php');
5
6 if ( !class_exists( 'WP_Importer' ) ) {
7 if ( file_exists( ABSPATH . 'wp-admin/includes/class-wp-importer.php' ) )
8 require_once( ABSPATH . 'wp-admin/includes/class-wp-importer.php' );
9 }
10
11 require_once ( POWERPRESS_ABSPATH . '/powerpress-feed-parser.class.php');
12
13
14 /**
15 * PowerPress RSS Podcast Importer
16 *
17 * Will process a Podcast RSS feed for importing posts into WordPress.
18 *
19 */
20 if ( class_exists( 'WP_Importer' ) ) {
21 class PowerPress_RSS_Podcast_Import extends WP_Importer {
22
23 var $m_content = '';
24 var $m_item_pos = 0;
25 var $m_item_inserted_count = 0;
26 var $m_item_skipped_count = 0;
27 var $m_item_migrate_count = 0;
28 var $m_step = 0;
29 var $m_errors = array();
30 private $isHostedOnBlubrry = false; //used to show Blubrry signin during onboarding process
31
32 private $parser = null;
33
34 function migrateCount() {
35 return $this->m_item_migrate_count;
36 }
37
38 function importCount() {
39 return $this->m_item_inserted_count;
40 }
41
42 function skippedCount() {
43 return $this->m_item_skipped_count;
44 }
45
46 function errorsExist() {
47 return ( count($this->m_errors) > 0 );
48 }
49
50 function getErrors() {
51 return $this->m_errors;
52 }
53
54 function addError($msg) {
55 $this->m_errors[] = $msg;
56 }
57
58
59 function header() {
60 powerpress_enqueue_assets([
61 'powerpress_onboarding_styles' => ['path' => 'css/onboarding'],
62 ]);
63 echo '<div class="wrap" style="min-height: 100vh">';
64 echo '<div class="pp_container" style="max-width: 100rem;">';
65 }
66
67
68 function greet() {
69 $General = powerpress_get_settings('powerpress_general');
70 if (isset($_GET['from']) && ($_GET['from'] == 'gs' || $_GET['from'] == 'onboarding')) {
71 $from_onboarding = true;
72 } else {
73 $from_onboarding = false;
74 }
75 if( !empty($_GET['import']) )
76 {
77 switch($_GET['import'] )
78 {
79 case 'powerpress-soundcloud-rss-podcast': echo '<h2 class="pp_align-center">'.__('Import Podcast from SoundCloud', 'powerpress').'</h2>'; break;
80 case 'powerpress-libsyn-rss-podcast': echo '<h2 class="pp_align-center">'.__('Import Podcast from LibSyn', 'powerpress').'</h2>'; break;
81 case 'powerpress-podbean-rss-podcast': echo '<h2 class="pp_align-center">'.__('Import Podcast from PodBean', 'powerpress').'</h2>'; break;
82 case 'powerpress-squarespace-rss-podcast': echo '<h2 class="pp_align-center">'.__('Import Podcast from Squarespace', 'powerpress').'</h2>'; break;
83 case 'powerpress-anchor-rss-podcast': echo '<h2 class="pp_align-center">'.__('Import Podcast from Anchor.fm', 'powerpress').'</h2>'; break;
84 case 'powerpress-buzzsprout-rss-podcast': echo '<h2 class="pp_align-center">'.__('Import Podcast from Buzzsprout', 'powerpress').'</h2>'; break;
85
86 case 'powerpress-rss-podcast':
87 default: echo '<h2 style="margin-bottom: 0;">'.__('Import Podcast RSS Feed', 'powerpress').'</h2>'; break;
88 }
89 }
90 else
91 {
92 echo '<h2 style="margin-bottom: 0;">'.__('Import Podcast RSS Feed', 'powerpress').'</h2>';
93 }
94 ?>
95 <p class="pp_align-center"><b><?php echo __('The following tool will import your podcast episodes to this website.', 'powerpress'); ?></b></p>
96 <hr />
97 <section id="one" class="pp_wrapper">
98 <div class="pp_inner">
99 <form enctype="multipart/form-data" action="" method="post" name="import-podcast-feed">
100 <?php wp_nonce_field('import-powerpress-rss') ?>
101 <input type="hidden" name="step" value="1" />
102 <input type="hidden" name="import" value="<?php echo( !empty($_REQUEST['import']) ? htmlspecialchars($_REQUEST['import']) : ''); ?>" />
103 <input type="hidden" name="MAX_FILE_SIZE" value="<?php echo wp_max_upload_size(); ?>" />
104 <div class="pp_flex-grid">
105 <div class="pp_form-group" style="width: 100%;">
106 <p class="label" style="font-size: 12px;"><?php echo __('Podcast Feed URL', 'powerpress'); ?></p>
107 <?php
108 $placeholder = 'https://example.com/feed.xml';
109 switch($_GET['import']) {
110 case 'powerpress-soundcloud-rss-podcast': $placeholder = 'http://feeds.soundcloud.com/users/soundcloud:users:00000000/sounds.rss'; break;
111 case 'powerpress-libsyn-rss-podcast': $placeholder = 'http://yourshow.libsyn.com/rss'; break;
112 case 'powerpress-podbean-rss-podcast': $placeholder = 'http://yourshow.podbean.com/feed/'; break;
113 case 'powerpress-squarespace-rss-podcast': $placeholder = 'http://example.com/podcast/?format=rss'; break;
114 case 'powerpress-anchor-rss-podcast': $placeholder = 'https://anchor.fm/s/xxxxxx/podcast/rss'; break;
115 }
116 ?>
117 <input type="text" name="podcast_feed_url" id="podcast_feed_url" class="pp_outlined" style="width: 100%; font-size: 12px;" placeholder="<?php echo esc_attr($placeholder); ?>" />
118 </div>
119
120 </div>
121 <div class="pp_col">
122 <link rel="stylesheet" href="<?php echo powerpress_get_root_url(); ?>css/admin.css" type="text/css" media="screen" />
123 <script language="javascript">
124
125 jQuery(document).ready( function() {
126
127 jQuery('.pp-expand-section').click( function(e) {
128 e.preventDefault();
129
130 if( jQuery(this).hasClass('pp-expand-section-expanded') ) {
131 jQuery(this).removeClass('pp-expand-section-expanded');
132 jQuery(this).parent().next('div').hide(400);
133 //jQuery('#import_from_local_disk').hide(400);
134 jQuery(this).blur();
135 } else {
136 jQuery(this).addClass('pp-expand-section-expanded');
137 jQuery(this).parent().next('div').show(400);
138 //jQuery('#import_from_local_disk').show(400);
139 jQuery(this).blur();
140 }
141 });
142
143 jQuery('#podcast_feed_file').change(function(e) {
144 let filepath_parts;
145 if (e.currentTarget.value.includes('/')) {
146 filepath_parts = e.currentTarget.value.split('/');
147 } else {
148 filepath_parts = e.currentTarget.value.split('\\');
149 }
150 jQuery('#importFilePath').val(filepath_parts[filepath_parts.length - 1]);
151 });
152
153 <?php
154 if(empty($_GET['import']) || $_GET['import'] != 'powerpress-libsyn-rss-podcast'){
155 ?>
156 jQuery('#podcast_feed_url').on('input', function () {
157 if(jQuery(this).val().toUpperCase().includes('LIBSYN')){
158 jQuery('#remove_query_string_input').prop('disabled', true);
159 jQuery('#remove_query_string_input').prop('checked', true);
160 } else {
161 jQuery('#remove_query_string_input').prop('disabled', false);
162 jQuery('#remove_query_string_input').prop('checked', false);
163 }
164 });
165 <?php } ?>
166 });
167
168 </script>
169 <style>
170 .ppi-option {
171 margin: 4px 0;
172 font-size: 12px;
173 }
174 .ppi-option p,
175 .ppi-option label,
176 .ppi-option select {
177 font-size: 12px;
178 }
179 .pp-expand-section:before, .pp-expand-section-expanded:before {
180 height: 16px;
181 width: 16px;
182 margin-right: 8px;
183 font-size: 12px;
184 line-height: 12px;
185 content: '+';
186 }
187 .pp-expand-section {
188 font-size: 12px;
189 }
190
191 </style>
192 <h6><a href="#" class="pp-expand-section"><?php echo __('Advanced Options', 'powerpress'); ?></a></h6>
193
194 <div style="display: none;">
195 <div id="import_from_local_disk" style="margin-top: 2em;">
196 <p class="label" style="font-size: 12px;margin-bottom: 0;"><?php echo __('Choose from your local disk:', 'powerpress'); ?></p>
197 <div id="upload-import-button" onclick="document.getElementById('podcast_feed_file').click();">
198 <img style="color: #3c434a; vertical-align: middle;" src="<?php echo powerpress_get_root_url(); ?>images/onboarding/upload.svg" />
199 <span style="vertical-align: middle; line-height: 24px;"><?php echo __('Choose RSS/XML File', 'powerpress'); ?></span>
200 <input type="file" id="podcast_feed_file" name="podcast_feed_file" class="pp_file_upload" style="display: none;" />
201 </div>
202 <input type="text" id="importFilePath" readonly class="pp_outlined" style="margin: 0 0 1ch 0; display: inline-block;" placeholder="No File Chosen">
203 </div>
204 <div class="pp-import-advanced-columns">
205 <div class="pp-import-column-container left">
206 <div class="ppi-option">
207 <h4><?php echo __('Blubrry Podcast Media Hosting', 'powerpress'); ?></h4>
208 </div>
209 <?php
210 if( empty($General['blubrry_hosting']) || $General['blubrry_hosting'] === 'false' ) {
211 ?>
212 <div class="ppi-option">
213 <label><input type="checkbox" name="NULL" value="1" disabled> <?php echo __('Migrate media to your Blubrry hosting account', 'powerpress'); ?></label>
214 </div>
215 <?php
216 } else { ?>
217 <div class="ppi-option">
218 <label><input type="checkbox" name="migrate_to_blubrry" value="1" checked> <?php echo __('Migrate media to your Blubrry hosting account', 'powerpress'); ?></label>
219 </div>
220 <?php
221 }
222 ?>
223 <!--
224 <p><?php echo sprintf(__('Importing your feed does not migrate your media files. Please use the %s tool to migrate your media once your feed is imported.', 'powerpress'), '<strong><a href="'.admin_url('admin.php?page=powerpress/powerpressadmin_migrate.php') .'">'. __('Migrate Media', 'powerpress') .'</a></strong>'); ?></p>
225 -->
226 <div class="ppi-option">
227 <h4 style="margin: 1em 0 0 0;"><?php echo __('Import Podcast To', 'powerpress'); ?></h4>
228 </div>
229
230 <div class="ppi-option">
231 <label><input type="radio" name="import_to" id="import_to_default" value="default" checked /> <?php echo __('Default podcast feed', 'powerpress'); ?></label><br />
232 <div class="import-to" id="import-to-default" style="display: none;">
233 <div style="margin: 4px 0 4px 24px;">
234 <label><input type="checkbox" name="import_overwrite_program_info" value="1" <?php echo isset($_GET['from']) ? 'checked': '' ?> > <?php echo __('Import program information', 'powerpress'); ?></label>
235 </div>
236 <div style="margin: 4px 0 4px 24px;">
237 <label><input type="checkbox" name="import_itunes_image" value="1" <?php echo isset($_GET['from']) ? 'checked': '' ?>> <?php echo __('Import Program artwork', 'powerpress'); ?></label>
238 </div>
239 </div>
240 </div>
241
242 <div class="ppi-option">
243 <label><input type="radio" name="import_to" id="import_to_category" value="category" /> <?php echo __('Podcast Category feed', 'powerpress'); ?></label>
244 <div class="import-to" id="import-to-category" style="display: none;">
245 <div style="margin: 10px 0 10px 24px;">
246 <label for="category"><?php echo __('Category', 'powerpress'); ?></label> &nbsp; <?php
247 wp_dropdown_categories(array('show_option_none' => __( '&mdash; Select &mdash;' ), 'option_none_value' => '', 'hide_empty' => 0, 'id'=>'category', 'name' => 'category', 'orderby' => 'name', 'selected' => '', 'hierarchical' => true));
248 ?>
249 </div>
250 <div style="margin: 10px 0 10px 24px;">
251 <label><input type="checkbox" name="import_overwrite_program_info_category" value="1"> <?php echo __('Import program information', 'powerpress'); ?></label>
252 </div>
253 <div style="margin: 10px 0 10px 24px;">
254 <label><input type="checkbox" name="import_itunes_image_category" value="1"> <?php echo __('Import Program artwork', 'powerpress'); ?></label>
255 </div>
256 </div>
257 </div>
258 <?php
259
260 if( !empty($General['channels']) )
261 {
262 // List rall of teh podcast channel feeds
263 $Feeds = array();
264 if( isset($General['custom_feeds']) )
265 $Feeds = $General['custom_feeds'];
266 if( isset($General['custom_feeds']['podcast']) )
267 unset($General['custom_feeds']['podcast']);
268 if( !empty($Feeds) )
269 {
270 ?>
271 <div class="ppi-option">
272 <label><input type="radio" name="import_to" id="import_to_channel" value="channel" /> <?php echo __('Podcast Channel feed', 'powerpress'); ?></label><br />
273 <div class="import-to" id="import-to-channel" style="display: none;">
274 <div style="margin: 10px 0 10px 24px;">
275 <select id="feed_slug" name="feed_slug" class="large-input">
276 <option value=""><?php echo __('Select Channel feed', 'powerpress'); ?></option>
277 <?php
278
279 asort($Feeds, SORT_STRING); // Sort feeds
280 foreach( $Feeds as $feed_slug => $feed_title ) {
281
282 echo "\t<option value=\"$feed_slug\">$feed_title ($feed_slug)</option>\n";
283 }
284 ?>
285 </select>
286 </div>
287 <div style="margin: 10px 0 10px 24px;">
288 <label><input type="checkbox" name="import_overwrite_program_info_channel" value="1"> <?php echo __('Import program information', 'powerpress'); ?></label>
289 </div>
290 <div style="margin: 10px 0 10px 24px;">
291 <label><input type="checkbox" name="import_itunes_image_channel" value="1"> <?php echo __('Import Program artwork', 'powerpress'); ?></label>
292 </div>
293 </div>
294 </div>
295 <?php
296 }
297 } // end podcast channel
298
299 if( !empty($General['posttype_podcasting']) )
300 {
301 ?>
302 <div class="ppi-option">
303 <label><input type="radio" name="import_to" id="import_to_post_type" value="post_type" /> <?php echo __('Podcast Post Type feed', 'powerpress'); ?></label>
304 <div class="import-to" id="import-to-post_type" style="display: none;">
305 <div style="margin: 10px 0 10px 24px;">
306 <label for="post_type"><?php echo __('Post type', 'powerpress'); ?></label> &nbsp;
307 <input type="text" name="post_type" id="post_type" class="medium-text" value="" />
308 </div>
309 <div style="margin: 10px 0 10px 24px;">
310 <label for="post_type_feed_slug"><?php echo __('Feed slug', 'powerpress'); ?></label> &nbsp;
311 <input type="text" name="post_type_feed_slug" id="post_type_feed_slug" class="medium-text" value="" />
312 </div>
313 <div style="margin: 10px 0 10px 24px;">
314 <label><input type="checkbox" name="import_overwrite_program_info_post_type" value="1"> <?php echo __('Import program information', 'powerpress'); ?></label>
315 </div>
316 <div style="margin: 10px 0 10px 24px;">
317 <label><input type="checkbox" name="import_itunes_image_post_type" value="1"> <?php echo __('Import Program artwork', 'powerpress'); ?></label>
318 </div>
319 </div>
320 </div>
321 <?php
322 } // end post type
323
324 if( !empty($General['taxonomy_podcasting']) )
325 {
326 $PowerPressTaxonomies = get_option('powerpress_taxonomy_podcasting', array());
327
328 ?>
329 <div class="ppi-option">
330 <label><input type="radio" name="import_to" id="import_to_taxonomy" value="taxonomy" /> <?php echo __('Podcast Taxonomy feed', 'powerpress'); ?></label>
331 <div class="import-to" id="import-to-taxonomy" style="display: none;">
332 <div style="margin: 10px 0 10px 24px;">
333 <?php
334
335 if( !empty($PowerPressTaxonomies) ) { // If taxonomy podcasting feeds exist..
336
337 global $wpdb;
338 $tt_ids = '';
339
340 $SelectOptions = array();
341 foreach( $PowerPressTaxonomies as $tt_id => $null ) {
342 if( !empty($tt_ids) )
343 $tt_ids .= ',';
344 $tt_ids .= $tt_id;
345
346 $term = get_term_by('term_taxonomy_id', $tt_id);
347 if( is_wp_error($term) )
348 continue;
349 $SelectOptions[ $tt_id ] = sprintf('%s (%s)', $term->name, $term->slug);
350 }
351
352 ?>
353 <select id="podcast_ttid" name="podcast_ttid" style="min-width: 240px;" class="postform">
354 <option value=""><?php echo __('Select Taxonomy Podcast', ''); ?></option>
355 <?php
356
357 foreach( $SelectOptions as $tt_id => $label )
358 {
359 echo "\t<option value=\"$tt_id\">". htmlspecialchars($label). "</option>\n";
360 }
361
362 ?>
363 </select>
364 </div>
365 <div style="margin: 10px 0 10px 24px;">
366 <label><input type="checkbox" name="import_overwrite_program_info_taxonomy" value="1"> <?php echo __('Import program information', 'powerpress'); ?></label>
367 </div>
368 <div style="margin: 10px 0 10px 24px;">
369 <label><input type="checkbox" name="import_itunes_image_taxonomy" value="1"> <?php echo __('Import Program artwork', 'powerpress'); ?></label>
370 </div>
371 <?php } else { // else no taxonomy feeds have been created yet ?>
372 <div style="margin: 10px 0 10px 24px;">
373 <label><?php echo __('Please create a taxonomy podcast to continue.', 'powerpress'); ?></label>
374 </div>
375 <?php } ?>
376 </div>
377 </div>
378 <?php
379 } // End if taxonomy podcasting enabled
380 ?>
381 </div>
382 <div class="pp-import-column-container">
383 <div class="ppi-option">
384 <h4><?php echo __('Import Options', 'powerpress'); ?></h4>
385 </div>
386 <div class="ppi-option">
387 <label><input type="checkbox" name="NULL" value="1" checked disabled> <?php echo __('Match episode by GUID (required)', 'powerpress'); ?></label>
388 </div>
389 <div class="ppi-option">
390 <label><input type="checkbox" name="match_filename" value="1" checked> <?php echo __('Match episode by filename (recommended)', 'powerpress'); ?></label>
391 </div>
392 <div class="ppi-option">
393 <label><input type="checkbox" name="match_title" value="1"> <?php echo __('Match episode by post title', 'powerpress'); ?></label>
394 </div>
395 <div class="ppi-option">
396 <label><input type="checkbox" name="match_date" value="1"> <?php echo __('Match episode by exact post date and time', 'powerpress'); ?></label>
397 </div>
398 <div class="ppi-option">
399 <label><input type="checkbox" name="import_blog_posts" value="1" > <?php echo __('Include blog posts', 'powerpress'); ?></label>
400 </div>
401 <div class="ppi-option">
402 <label><input type="checkbox" name="match_existing_posts" value="1" > <?php echo __('Add podcast episodes to existing posts that match', 'powerpress'); ?></label>
403 </div>
404 <div class="ppi-option">
405 <input type="hidden" name="remove_query_string" value="0" />
406 <label><input id="remove_query_string_input" type="checkbox" name="remove_query_string" value="1" <?php if( !empty($_REQUEST['import']) && $_REQUEST['import'] == 'powerpress-libsyn-rss-podcast' ) {
407 echo 'checked disabled'; } ?> > <?php echo __('Remove query strings from media URLs', 'powerpress'); ?></label>
408 </div>
409 </div>
410 <div class="pp-import-column-container">
411 <div class="ppi-option" style="margin-top: 3em;">
412 <label for="import_post_status"><?php echo __('Post Status', 'powerpress'); ?></label> &nbsp;
413 <select id="import_post_status" name="import_post_status" class="medium-text">
414 <?php
415 $post_statuses = get_post_statuses();
416 foreach( $post_statuses as $post_status_slug => $post_status_label ) {
417
418 echo "\t<option value=\"$post_status_slug\"". ($post_status_slug=='publish'?' selected':'') .">". htmlspecialchars("$post_status_label ($post_status_slug)") . "</option>\n";
419 }
420 ?>
421 </select>
422 </div>
423 <div class="ppi-option" style="margin-top: 2em;">
424 <label for="import_item_limit"><?php echo __('Episode Limit', 'powerpress'); ?></label> &nbsp;
425 <input type="text" name="import_item_limit" id="import_item_limit" style="width: 100%;font-size: 12px;" value="" />
426 </div>
427 </div>
428
429 </div>
430 </div>
431 <div class="pp_col" style="padding: 20px 0px;">
432 <hr class="pp_align-center">
433 <div class="pp_button-container" style="float: right;">
434 <button name="submit" type="submit" class="pp_button" value="Import Podcast"><span><?php echo __('Import Podcast', 'powerpress'); ?></span></button>
435 </div>
436 </form>
437 </div>
438 </div>
439 </div>
440 </div>
441 <script>
442 jQuery(document).ready( function() {
443
444 var import_type = jQuery("input[name='import_to']:checked").val()
445 jQuery('#import-to-'+import_type).show();
446 jQuery("input[name='import_to']").change( function(e) {
447 jQuery('.import-to').hide(400);
448 jQuery('#import-to-'+jQuery(this).val() ).show(400);
449 });
450 });
451 </script>
452 <?php
453 return;
454 echo '<div class="narrow">';
455
456 echo '<h2>'.__('Import saved Feed', 'powerpress') .'</h2>';
457 wp_import_upload_form("admin.php?import=rss-podcast&amp;step=1");
458 echo '</div>';
459 }
460
461 function _normalize_tag( $matches ) {
462 return '<' . strtolower( $matches[1] );
463 }
464
465 function import_program_info($overwrite=false, $download_itunes_image=false, $category_id = '', $feed_slug ='', $post_type = '', $ttid = '') {
466 $Feed = get_option('powerpress_feed_podcast', array() );
467 if( empty($Feed) )
468 $Feed = get_option('powerpress_feed', array());
469
470 if( !empty($category_id) ) {
471 $Feed = get_option('powerpress_cat_feed_'.$category_id, array());
472 } else if( !empty($feed_slug) ) {
473 $Feed = get_option('powerpress_feed_'.$feed_slug, array());
474 } else if( !empty($ttid) ) {
475 $Feed = get_option('powerpress_taxonomy_'.$ttid, array());
476 }
477
478 $NewSettings = array();
479
480 // ==================
481 // BASIC CHANNEL TAGS
482 // ==================
483
484 // <title>
485 if (($v = $this->parser->get_channel_title()) !== null && ($overwrite || empty($Feed['title']))) {
486 $NewSettings['title'] = $v;
487 }
488
489 // <language>
490 if (($v = $this->parser->get_channel_language()) !== null && ($overwrite || empty($Feed['rss_language']))) {
491 $NewSettings['rss_language'] = $v;
492 }
493
494 // <copyright>
495 if (($v = $this->parser->get_channel_copyright()) !== null && ($overwrite || empty($Feed['copyright']))) {
496 $NewSettings['copyright'] = $v;
497 }
498
499 // <description>
500 if (($v = $this->parser->get_channel_description()) !== null && ($overwrite || empty($Feed['description']))) {
501 $NewSettings['description'] = $v;
502 }
503
504 // ===================
505 // ITUNES CHANNEL TAGS
506 // ===================
507
508 // <itunes:author>
509 if (($v = $this->parser->get_channel_author()) !== null && ($overwrite || empty($Feed['itunes_talent_name']))) {
510 $NewSettings['itunes_talent_name'] = $v;
511 }
512
513 // <itunes:owner> -> <itunes:name>
514 if (empty($NewSettings['itunes_talent_name'])
515 && ($v = $this->parser->get_channel_owner_name()) !== null
516 && ($overwrite || empty($Feed['itunes_talent_name']))) {
517 $NewSettings['itunes_talent_name'] = $v;
518 }
519
520 // <itunes:owner> -> <itunes:email>
521 if (($v = $this->parser->get_channel_owner_email()) !== null && ($overwrite || empty($Feed['email']))) {
522 $NewSettings['email'] = $v;
523 }
524
525 // <itunes:explicit>
526 if (($v = $this->parser->get_channel_explicit()) !== null && ($overwrite || empty($Feed['itunes_explicit']))) {
527 $NewSettings['itunes_explicit'] = $v;
528 }
529
530 // <itunes:type>
531 if (($v = $this->parser->get_channel_type()) !== null && ($overwrite || empty($Feed['itunes_type']))) {
532 $NewSettings['itunes_type'] = $v;
533 }
534
535 // <itunes:image>
536 $itunes_image = $this->parser->get_channel_artwork();
537 if ($itunes_image !== null) {
538 // download the image then save it locally...
539 if( $download_itunes_image ) {
540
541 echo '<div id="pp-imported-artwork">';
542 echo '<p style="margin: 0 0 1ch 0;"><strong>'. __('Program image', 'powerpress') .'</strong></p>';
543
544 $upload_path = false;
545 $upload_url = false;
546 $UploadArray = wp_upload_dir();
547 if( false === $UploadArray['error'] )
548 {
549 $upload_path = $UploadArray['basedir'].'/powerpress/';
550 $upload_url = $UploadArray['baseurl'].'/powerpress/';
551 $filename = str_replace(" ", "_", basename($itunes_image) );
552
553 if( file_exists($upload_path . $filename ) )
554 {
555 $filenameParts = pathinfo($filename);
556 if( !empty($filenameParts['extension']) ) {
557 do {
558 $filename_no_ext = substr($filenameParts['basename'], 0, (strlen($filenameParts['extension'])+1) * -1 );
559 $filename = sprintf('%s-%03d.%s', $filename_no_ext, md5( rand(0, 999) . time() ), $filenameParts['extension'] );
560 } while( file_exists($upload_path . $filename ) );
561 }
562 }
563
564 $options = array();
565 $options['user-agent'] = 'Blubrry PowerPress/'.POWERPRESS_VERSION;
566 if( !empty($_GET['import']) && $_GET['import'] == 'powerpress-squarespace-rss-podcast' )
567 $options['user-agent'] = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.111 Safari/537.36';
568 $options['timeout'] = 10;
569
570 $image_data = '';
571 $response = wp_safe_remote_get($itunes_image, $options);
572 if ( !is_wp_error( $response ) ) {
573 $image_data = wp_remote_retrieve_body( $response );
574 } else {
575 $this->addError( __('Error downloading program image.', 'powerpress') );
576 }
577
578 if( !empty($image_data) ) {
579 file_put_contents($upload_path.$filename, $image_data);
580 $NewSettings['itunes_image'] = $upload_url . $filename;
581 echo "<img id='pp-onboarding-artwork-preview' src='{$NewSettings['itunes_image']}' alt='{$NewSettings['itunes_image']}' />";
582 echo '<ul class="ul-disc" id="pp-onboarding-artwork-link">';
583 echo sprintf('Program image saved to:<br /> <a href="%s" style="margin-top: 1em;">%s</a>.', ($upload_url . $filename), ($upload_url . $filename) );
584 echo '</ul>';
585 } else {
586 $this->addError( __('No program image downloaded.', 'powerpress') );
587 echo 'Error occurred downloading program image.';
588 }
589 } else {
590 echo 'Unable to save image to local folder.';
591 }
592
593 echo "</div>";
594 } else if( $overwrite || empty($Feed['itunes_image']) ) {
595 $NewSettings['itunes_image'] = $itunes_image;
596 }
597 }
598
599 // <itunes:category>
600 foreach ($this->parser->get_channel_categories() as $i => $code) {
601 $field = sprintf('apple_cat_%d', $i + 1);
602 if ($overwrite || empty($Feed[$field])) {
603 $NewSettings[$field] = $code;
604 }
605 }
606
607 // <itunes:complete>
608 if (($v = $this->parser->get_channel_complete()) !== null
609 && empty($NewSettings['itunes_complete'])
610 && ($overwrite || empty($Feed['itunes_complete']))) {
611 $NewSettings['itunes_complete'] = $v;
612 }
613
614 // <itunes:block> + <podcast:block>
615 if (($block = $this->parser->get_channel_block()) !== null) {
616 // EXTRACT ITUNES BLOCK
617 if ($block['itunes_block'] !== null && ($overwrite || empty($Feed['itunes_block']))) {
618 $NewSettings['itunes_block'] = $block['itunes_block'];
619 }
620
621 // EXTRACT PCI BLOCK
622 if ($block['block_all'] !== null && ($overwrite || empty($Feed['block_all']))) {
623 $NewSettings['block_all'] = $block['block_all'];
624 }
625 }
626
627 // ====================
628 // PODCAST CHANNEL TAGS
629 // ====================
630
631 // <podcast:locked>
632 // PRESERVE LOCK ON IMPORT, USER REQUIRED TO UNLOCK AT ORIGINAL FEED SOURCE
633 if ($this->parser->get_channel_locked() && ($overwrite || empty($Feed['pp_enable_feed_lock']))) {
634 $NewSettings['pp_enable_feed_lock'] = 1;
635 }
636
637 // <podcast:medium>
638 if (($v = $this->parser->get_channel_medium()) !== null && ($overwrite || empty($Feed['medium']))) {
639 $NewSettings['medium'] = $v;
640 }
641
642 // <podcast:guid>
643 if (($v = $this->parser->get_channel_guid()) !== null && ($overwrite || empty($Feed['podcast_guid']))) {
644 $NewSettings['podcast_guid'] = $v;
645 }
646
647 // <podcast:license>
648 if (($license = $this->parser->get_channel_license()) !== null) {
649 // EXTRACT COPYRIGHT TITLE
650 if ($license['copyright'] !== null
651 && empty($NewSettings['copyright'])
652 && ($overwrite || empty($Feed['copyright']))) {
653 $NewSettings['copyright'] = $license['copyright'];
654 }
655
656 // EXTRACT COPYRIGHT URL
657 if ($license['url'] !== null && ($overwrite || empty($Feed['copyright_url']))) {
658 $NewSettings['copyright_url'] = $license['url'];
659 }
660 }
661
662 // <podcast:funding>
663 if (($funding = $this->parser->get_channel_funding()) !== null) {
664 // EXTRACT FUNDING URL
665 if ($funding['url'] !== null && ($overwrite || empty($Feed['donate_url']))) {
666 $NewSettings['donate_url'] = $funding['url'];
667 }
668
669 // EXTRACT FUNDING LABEL
670 if ($funding['label'] !== null && ($overwrite || empty($Feed['donate_label']))) {
671 $NewSettings['donate_label'] = $funding['label'];
672 }
673 }
674
675 // <podcast:person>
676 $persons = $this->parser->get_channel_persons();
677 if (!empty($persons) && ($overwrite || empty($Feed['credits']))) {
678 $NewSettings['credits'] = $persons;
679 }
680
681 // <podcast:location>
682 $locations = $this->parser->get_channel_locations();
683 if (!empty($locations) && ($overwrite || empty($Feed['location']))) {
684 $NewSettings['location'] = $locations;
685 }
686
687 // <podcast:podroll> + <podcast:remoteItem>
688 $podroll_items = $this->parser->get_channel_podroll();
689 $standalone_items = $this->parser->get_channel_remote_items();
690 $remote_items = array_merge($podroll_items, $standalone_items);
691 if (!empty($remote_items) && ($overwrite || empty($Feed['remote_items']))) {
692 $NewSettings['remote_items'] = $remote_items;
693 }
694
695 // <podcast:value> -> <podcast:valueRecipients>
696 $value_recipients = $this->parser->get_channel_value_recipients();
697 if (!empty($value_recipients) && ($overwrite || empty($Feed['value_recipients']))) {
698 $NewSettings['value_recipients'] = $value_recipients;
699 }
700
701 // <podcast:updateFrequency>
702 if (($frequency = $this->parser->get_channel_update_frequency()) !== null) {
703 // EXTRACT COMPLETE
704 if (isset($frequency['complete'])) {
705 if ($frequency['complete'] === true && ($overwrite || empty($Feed['itunes_complete']))) {
706 $NewSettings['itunes_complete'] = 1;
707 }
708 unset($frequency['complete']);
709 }
710
711 // EXTRACT DTSTART
712 if (isset($frequency['dtstart'])) {
713 if ($overwrite || empty($Feed['dtstart'])) {
714 $NewSettings['dtstart'] = $frequency['dtstart'];
715 }
716 unset($frequency['dtstart']);
717 }
718
719 // EXTRACT FREQUENCY
720 if (!empty($frequency) && ($overwrite || empty($Feed['update_frequency']))) {
721 $NewSettings['update_frequency'] = $frequency;
722 }
723 }
724
725 // <podcast:txt>
726 $txt_tags = array_values(array_filter(
727 $this->parser->get_channel_txt_tags(),
728 function ($entry) {
729 return ($entry['purpose'] ?? null) !== 'applepodcastsverify';
730 }
731 ));
732 if (!empty($txt_tags) && ($overwrite || empty($Feed['txt_tag']))) {
733 $NewSettings['txt_tag'] = $txt_tags;
734 }
735
736 // <podcast:liveItem>
737 $live_item = $this->parser->get_channel_live_item();
738 if ($live_item !== null && ($overwrite || empty($Feed['live_item']))) {
739 $NewSettings['live_item'] = $live_item;
740 }
741
742 // =====================
743 // RAWVOICE CHANNEL TAGS
744 // =====================
745
746 // <rawvoice:rating>
747 if (($v = $this->parser->get_channel_rating()) !== null && ($overwrite || empty($Feed['parental_rating']))) {
748 $NewSettings['parental_rating'] = $v;
749 }
750
751 // <rawvoice:frequency>
752 if (($v = $this->parser->get_channel_frequency()) !== null
753 && empty($NewSettings['update_frequency'])
754 && ($overwrite || empty($Feed['update_frequency']))) {
755 $NewSettings['frequency'] = $v;
756 }
757
758 // <rawvoice:donate href>
759 if (($donate = $this->parser->get_channel_donate()) !== null) {
760 // EXTRACT URL
761 if ($donate['url'] !== null
762 && empty($NewSettings['donate_url'])
763 && ($overwrite || empty($Feed['donate_url']))) {
764 $NewSettings['donate_url'] = $donate['url'];
765 }
766
767 // EXTRACT LABEL
768 if ($donate['label'] !== null
769 && empty($NewSettings['donate_label'])
770 && ($overwrite || empty($Feed['donate_label']))) {
771 $NewSettings['donate_label'] = $donate['label'];
772 }
773 }
774
775 // <rawvoice:subscribe>
776 foreach ($this->parser->get_channel_subscribe_urls() as $key => $value) {
777 if ($overwrite || empty($Feed[$key])) {
778 $NewSettings[$key] = esc_url_raw($value);
779 }
780 }
781
782 // ========
783 // SANITIZE
784 // ========
785
786 $nss_url_keys = ['itunes_image', 'copyright_url', 'donate_url'];
787 foreach ($nss_url_keys as $nss_key) {
788 if (isset($NewSettings[$nss_key]))
789 $NewSettings[$nss_key] = esc_url_raw($NewSettings[$nss_key]);
790 }
791 if (isset($NewSettings['email']))
792 $NewSettings['email'] = sanitize_email($NewSettings['email']);
793
794 // ============
795 // SAVE HANDLER
796 // ============
797
798 if( !empty($NewSettings) )
799 {
800 if( empty($category_id) && empty($feed_slug) && empty($post_type) && empty($ttid) ) {
801 // Save here..
802 if( get_option('powerpress_feed_podcast') ) { // If the settings were moved to the podcast channels feature...
803 powerpress_save_settings($NewSettings, 'powerpress_feed_podcast' ); // save a copy here if that is the case.
804 } else {
805 powerpress_save_settings($NewSettings, 'powerpress_feed' );
806 }
807 } else if( !empty($category_id) ) {
808
809 // First save the new settings into the specified options row...
810 powerpress_save_settings($NewSettings, 'powerpress_cat_feed_'.$category_id ); // save a copy here if that is the case.
811
812 // Then add the category id to the global array...
813 $CurrentSettings = powerpress_get_settings('powerpress_general');
814 if( !in_array($category_id, $CurrentSettings['custom_cat_feeds']) )
815 {
816 $NewSettings = array();
817 if( !empty($CurrentSettings['custom_cat_feeds']) )
818 $NewSettings['custom_cat_feeds'] = $CurrentSettings['custom_cat_feeds'];
819 $NewSettings['custom_cat_feeds'][] = $category_id;
820 if( empty($CurrentSettings['cat_casting']) ) {
821 $NewSettings['cat_casting'] = 1; // Turn on category podcasting if not enabled
822 $NewSettings['cat_casting_podcast_feeds'] = 1;
823 $NewSettings['cat_casting_strict'] = 1;
824 }
825
826 powerpress_save_settings($NewSettings);
827 }
828 } else if ( !empty($post_type) ) {
829 // TODO
830 } else if ( !empty($feed_slug) ) {
831 powerpress_save_settings($NewSettings, 'powerpress_feed_'.$feed_slug );
832 } else if ( !empty($ttid) ) {
833 powerpress_save_settings($NewSettings, 'powerpress_taxonomy_'. $ttid );
834 }
835
836
837
838 $field_labels = [
839 'title' => __('Feed Title (Show Title)', 'powerpress'),
840 'rss_language' => __('Feed Language', 'powerpress'),
841 'description' => __('Feed Description', 'powerpress'),
842 'copyright' => __('Copyright', 'powerpress'),
843 'copyright_url' => __('Copyright URL', 'powerpress'),
844 'itunes_talent_name' => __('Author Name', 'powerpress'),
845 'itunes_image' => __('Program Image', 'powerpress'),
846 'itunes_explicit' => __('Explicit', 'powerpress'),
847 'itunes_type' => __('Show Type', 'powerpress'),
848 'email' => __('Email', 'powerpress'),
849 'itunes_cat_1' => __('Category', 'powerpress'),
850 'itunes_cat_2' => __('Category 2', 'powerpress'),
851 'itunes_cat_3' => __('Category 3', 'powerpress'),
852 'apple_cat_1' => __('Apple Podcasts Category', 'powerpress'),
853 'apple_cat_2' => __('Apple Podcasts Category 2', 'powerpress'),
854 'apple_cat_3' => __('Apple Podcasts Category 3', 'powerpress'),
855 'medium' => __('Medium', 'powerpress'),
856 'podcast_guid' => __('Podcast GUID', 'powerpress'),
857 'donate_url' => __('Donate URL', 'powerpress'),
858 'donate_label' => __('Donate Label', 'powerpress'),
859 'credits' => __('Channel Credits', 'powerpress'),
860 'location' => __('Channel Location', 'powerpress'),
861 'value_recipients' => __('Value Recipients', 'powerpress'),
862 'txt_tag' => __('Txt Tags', 'powerpress'),
863 'parental_rating' => __('Parental Rating', 'powerpress'),
864 'frequency' => __('Frequency (Legacy)', 'powerpress'),
865 'update_frequency' => __('Update Frequency', 'powerpress'),
866 'dtstart' => __('Start Date', 'powerpress'),
867 'remote_items' => __('Related Shows / Podroll', 'powerpress'),
868 ];
869
870 echo '<p><strong>'. __('Program information imported', 'powerpress') .'</strong></p>';
871 echo '<ul class="ul-disc">';
872 foreach( $NewSettings as $field => $value )
873 {
874 if( $field === 'rss2_image' ) continue;
875 $label = $field_labels[$field] ?? $field;
876 echo '<li>' . esc_html($label) . '</li>';
877 }
878 echo '</ul>';
879 }
880 }
881
882 function import_item($feed_item, $MatchFilter, $import_blog_posts=false, $category_strict='', $feed_slug='', $post_type = '', $taxonomy = '', $term = '', $remove_query_string = false, $post_status = 'publish', $match_existing_posts = false) {
883 global $wpdb;
884 $this->m_item_pos++;
885
886 $matches = array();
887
888 // <title>
889 $raw_title = $this->parser->get_item_post_title($feed_item);
890 if ($raw_title === null) {
891 echo sprintf(__('Empty episode title for item %d', 'powerpress'), $this->m_item_pos);
892 $this->m_item_skipped_count++;
893 return false;
894 }
895 $post_title = $this->_sanatize_tag_value($raw_title);
896
897 // Look for an enclosure, if not found skip it...
898 // <enclosure>
899 $enclosure = $this->_parse_enclosure($feed_item, $category_strict);
900 if (empty($enclosure['url'])) {
901 echo sprintf(__('No Media found for item %d', 'powerpress'), $this->m_item_pos);
902 //echo '<pre>'.htmlspecialchars($post).'</pre>'; // Uncomment for debugging
903 if( empty($import_blog_posts) ) {
904 $this->m_item_skipped_count++;
905 return false;
906 }
907
908 echo ' - ';
909 }
910
911 // GUID has to be last, as we will use the media URL as the guid as a last resort
912 // <guid>
913 $guid = $this->parser->get_item_guid($feed_item);
914 if ($guid !== null) {
915 $guid = $this->_sanatize_tag_value($guid);
916 }
917 else if (!empty($enclosure['url'])) {
918 $guid = $enclosure['url'];
919 }
920
921
922 $media_url = '';
923 if( !empty($enclosure['url']) ) {
924 if( !empty($remove_query_string) && !empty($enclosure['url']) && strstr($enclosure['url'], '?') ) {
925 $enclosure['url'] = strtok($enclosure['url'],'?'); //Tund3r: added for libsyn
926 }
927 $media_url = $enclosure['url'];
928 }
929 if(preg_match('/https?:\/\/(www\.)?media\.blubrry\.com\//m', $media_url)) {
930 $this->isHostedOnBlubrry = true;
931 }
932
933 // <pubDate>
934 $ts = $this->parser->get_item_pubdate($feed_item);
935 $post_date_gmt = gmdate('Y-m-d H:i:s', $ts ?? 0);
936 $post_date = get_date_from_gmt( $post_date_gmt );
937
938 // Before we go any further, lets see if we have imported this one already...
939 $exists = $this->_find_post(
940 (empty($MatchFilter['match_guid'])?'':$guid),
941 (empty($MatchFilter['match_title'])?'':$post_title),
942 (empty($MatchFilter['match_date'])?'':$post_date),
943 (empty($MatchFilter['match_filename'])?'':$media_url),
944 $feed_slug
945 );
946
947 if( !empty($exists) )
948 {
949 $existing_enclosure_data = true;
950 if ($match_existing_posts) {
951 // check for enclosure in the existing post
952 if ('podcast' == $feed_slug || '' == $feed_slug)
953 $existing_enclosure_data = get_post_meta($exists, 'enclosure', true);
954 else
955 $existing_enclosure_data = get_post_meta($exists, '_' . $feed_slug . ':enclosure', true);
956 }
957
958 if (!$existing_enclosure_data) {
959 // if there's no enclosure yet, we can add the one from the feed
960 $post_to_save = compact('post_date', 'post_date_gmt', 'post_title', 'guid', 'enclosure');
961
962 if( !empty($post_type) ) // If the post should go into a custom post type...
963 {
964 $post_to_save['post_type'] = $post_type;
965 }
966 $this->m_item_inserted_count++;
967
968 $post_id = $this->_import_post_to_db($post_to_save, $feed_slug, $exists);
969
970 ?>
971 <td><?php echo htmlspecialchars($post_title) ?></td>
972 <td>&#x2714;&#xFE0F;</td>
973 <td><?php echo htmlspecialchars(__('Episode Added to Existing Post', 'powerpress')); ?></td>
974 <?php
975 return true;
976 } else {
977 ?>
978 <td><?php echo htmlspecialchars($post_title) ?></td>
979 <td>&#x274c;</td>
980 <td><?php echo htmlspecialchars(__('Episode Already Imported', 'powerpress')); ?></td>
981 <?php
982 $this->m_item_skipped_count++;
983 return false;
984 }
985 }
986
987 // Okay awesome, lets dig through the rest...
988 // <category>
989 $categories = $this->parser->get_item_categories($feed_item);
990
991
992 // <content:encoded>
993 $post_content = $this->parser->get_item_content($feed_item);
994 $post_content = $post_content !== null ? $this->_sanatize_tag_value($post_content) : '';
995
996 if (empty($post_content) && !empty($enclosure['summary'])) {
997 $post_content = $enclosure['summary'];
998 }
999
1000 // Clean up content
1001 $post_content = preg_replace_callback('|<(/?[A-Z]+)|', array( &$this, '_normalize_tag' ), $post_content);
1002 $post_content = str_replace('<br>', '<br />', $post_content);
1003 $post_content = str_replace('<hr>', '<hr />', $post_content);
1004
1005 $post_author = get_current_user_id();
1006
1007 // Save this episode to the database...
1008 $post_to_save = compact('post_author', 'post_date', 'post_date_gmt', 'post_content', 'post_title', 'post_status', 'guid', 'categories', 'enclosure');
1009
1010 if( !empty($post_type) ) // If the post should go into a custom post type...
1011 {
1012 $post_to_save['post_type'] = $post_type;
1013 }
1014 $this->m_item_inserted_count++;
1015
1016 $post_id = $this->_import_post_to_db($post_to_save, $feed_slug);
1017 if( empty($post_id) || is_wp_error($post_id) ) {
1018 ?>
1019 <td><?php echo htmlspecialchars($post_title) ?></td>
1020 <td><?php echo htmlspecialchars(__('Import Failed', 'powerpress')); ?></td>
1021 <td>&#x274c;</td>
1022 <?php
1023 return false;
1024 }
1025 $permalink = get_permalink($post_id);
1026 ?>
1027 <td><?php echo "<a href=\"". esc_attr($permalink) ."\" target='_blank'>" . esc_html($post_title) . "</a>" ?></td>
1028 <td><?php echo htmlspecialchars(__('Episode Imported', 'powerpress')); ?></td>
1029 <td>&#x2714;&#xFE0F;</td>
1030 <?php
1031
1032 // Display a link to the blog post
1033 //echo ' <a href="'. get_permalink($post_id) .'" target="_blank"><i class="wp-menu-image dashicons-before dashicons-admin-links"></i></a>';
1034
1035 // Category strict
1036 if( !empty($category_strict) )
1037 {
1038 wp_set_post_categories( $post_id, array($category_strict), true );
1039 }
1040
1041 // Set specific taxonomy term to this post
1042 if( !empty($taxonomy) && !empty($term) )
1043 {
1044 wp_set_post_terms( $post_id, array($term), $taxonomy, true );
1045 }
1046
1047 return ( $post_id > 0 );
1048 }
1049
1050 function _sanatize_tag_value($value)
1051 {
1052 if( !is_string($value) )
1053 return '';
1054
1055 $value = trim($value);
1056 if( preg_match('/^<!\[CDATA\[(.*)\]\]>$/is', $value, $matches) ) {
1057 $value = $matches[1];
1058 } else {
1059 $value = html_entity_decode($value);
1060 }
1061
1062 return $value;
1063 }
1064
1065 function import_episodes($MatchFilter, $import_blog_posts=false, $import_item_limit=0, $category='', $feed_slug='', $post_type = '', $ttid = '', $remove_query_string = false, $post_status='publish', $match_existing_posts = false) {
1066 global $wpdb;
1067 @set_time_limit(60*15); // Give it 15 minutes
1068 $this->m_item_pos = 0;
1069 $taxonomy = '';
1070 $term = '';
1071 if( $ttid )
1072 {
1073 $TaxTermObj = get_term_by('term_taxonomy_id', $ttid);
1074 if( $TaxTermObj )
1075 {
1076 $term = $TaxTermObj->name;
1077 $taxonomy = $TaxTermObj->taxonomy;
1078 // Now get the post type if the taxonomy, which may not be "post"...
1079 $TaxonomyObj = get_taxonomy($taxonomy);
1080 // Set the post type to import into
1081 if( !empty($TaxonomyObj->object_type[0]) && $TaxonomyObj->object_type[0] != 'post' ) {
1082 $post_type = $TaxonomyObj->object_type[0];
1083 }
1084 // We should use the term's ID rather than it's name
1085 if( !empty($TaxonomyObj->hierarchical) ) {
1086 $term = intval($TaxTermObj->term_id);
1087 }
1088 }
1089 else
1090 {
1091 // Do not go any further, there is an error here!
1092 echo '<p><strong>';
1093 echo __('Error, unable to locate term taxonomy.', 'powerpress');
1094 echo '</strong></p>';
1095 return;
1096 }
1097 }
1098
1099 $feed_items = $this->parser ? $this->parser->get_items() : [];
1100 $item_count = is_array($feed_items) ? count($feed_items) : 0;
1101 echo '<div class="pp_flex-grid">';
1102 ?>
1103 <style>
1104 #table_header {
1105 box-sizing: border-box;
1106 width: 100%;
1107 padding-bottom: 20px;
1108 margin-top: 3em;
1109 }
1110 table tbody td {
1111 padding: 10px 5px 12px 5px;
1112 }
1113 table {
1114 width: 100%;
1115 table-layout: fixed;
1116 border-collapse: separate;
1117 border: 1px solid rgba(144, 144, 144, 0.40);
1118 border-radius: 4px;
1119 }
1120 .left {
1121 float: left;
1122 }
1123 .right {
1124 float: right;
1125 }
1126 /*thead th {
1127 padding: 20px;
1128 border-bottom: 1px solid rgba(144, 144, 144, 0.40);
1129 }*/
1130 thead th:nth-child(1) {
1131 width: 3%
1132 }
1133 thead th:nth-child(2) {
1134 width: 58%;
1135 }
1136 thead th:nth-child(3) {
1137 width: 24%;
1138 }
1139 tbody td:nth-child(3) {
1140 text-align: right;
1141 }
1142 tbody td {
1143 padding: 15px 20px;
1144 border-bottom: 1px solid rgba(144, 144, 144, 0.40);
1145 }
1146 tbody td:nth-child(2) {
1147 font-weight: bold;
1148 text-align: left;
1149 }
1150 tbody td:nth-child(3) {
1151 text-align: right;
1152 }
1153 tbody td:nth-child(4) {
1154 text-align: right;
1155 }
1156 tbody tr:last-child td:first-child {
1157 border-bottom-left-radius: 10px;
1158 }
1159 tbody tr:last-child td{
1160 border: unset;
1161 }
1162 tbody tr:last-child td:last-child {
1163 border-bottom-right-radius: 10px;
1164 }
1165 .green-text {
1166 color: green;
1167 }
1168 .warning-text {
1169 color: orange;
1170 }
1171 .subtle-text {
1172
1173 }
1174 </style>
1175 <div class="pp_col" style="flex: 5; margin: 0;">
1176 <div id="table_header">
1177 <strong class="left">Imported Episodes</strong>
1178 <span class="right"><?php echo sprintf( __('%d Episodes Found', 'powerpress'), intval($item_count)) ?></span>
1179 </div>
1180 <table>
1181 <thead>
1182 <tr>
1183 <th></th>
1184 <th></th>
1185 <th></th>
1186 <th></th>
1187 </tr>
1188 </thead>
1189 <tbody>
1190 <?php
1191 @flush();
1192
1193 $count = 0;
1194 $wpdb->query('START TRANSACTION');
1195 foreach( $feed_items as $feed_item )
1196 {
1197 $count++;
1198
1199 if( $import_item_limit > 0 && $this->m_item_pos >= $import_item_limit ) {
1200 break;
1201 }
1202
1203 echo "<tr><td>{$count}</td>";
1204 $this->import_item($feed_item, $MatchFilter, $import_blog_posts, $category, $feed_slug, $post_type, $taxonomy, $term, $remove_query_string, $post_status, $match_existing_posts);
1205 echo '</tr>';
1206
1207 if( $count % 25 == 0 ) {
1208 $wpdb->query('COMMIT');
1209 $wpdb->query('START TRANSACTION');
1210 @flush();
1211 }
1212 }
1213 $wpdb->query('COMMIT');
1214 }
1215
1216 function import() {
1217 ?>
1218 <h3><?php _e('PowerPress', 'powerpress') ?></h3>
1219 <h5><?php _e('Importing Podcast', 'powerpress') ?>
1220 <?php
1221
1222 $result = false;
1223 if ( empty($_POST['podcast_feed_url']) ) {
1224 ?><?php _e(' from uploaded file...', 'powerpress'); ?></h5><hr /><?php
1225 $result = $this->_import_handle_upload();
1226 }
1227 else
1228 {
1229 ?><?php _e(' from URL: ', 'powerpress'); echo esc_html($_POST['podcast_feed_url']) ?></h5><hr /><?php
1230 $result = $this->_import_handle_url();
1231 }
1232
1233 if( $result == false ) {
1234 $this->addError( __('Error occurred importing podcast.', 'powerpress') );
1235 return;
1236 }
1237
1238 $this->parser = PowerPress_FeedParser::from_raw($this->m_content);
1239 if (is_wp_error($this->parser)) {
1240 $this->addError(__('Failed to parse podcast feed: ', 'powerpress') . $this->parser->get_error_message());
1241 $this->parser = null;
1242 return;
1243 }
1244
1245 // Match posts by:
1246 $MatchFilter = array('match_guid'=>true);
1247 $MatchFilter['match_date'] = (!empty($_POST['match_date'])?true:false);
1248 $MatchFilter['match_title'] = (!empty($_POST['match_title'])?true:false);
1249 $MatchFilter['match_filename'] = (!empty($_POST['match_filename'])?true:false);
1250
1251 $match_existing_posts = (!empty($_POST['match_existing_posts'])?true:false);
1252 $import_blog_posts = (!empty($_POST['import_blog_posts'])?true:false);
1253 $import_item_limit = (!empty($_POST['import_item_limit'])?intval($_POST['import_item_limit']):0);
1254 $remove_query_string = (!empty($_POST['remove_query_string'])?true:false);
1255 $post_status = ( !empty($_POST['import_post_status']) ? $_POST['import_post_status']: 'publish' );
1256 $category = (!empty($_POST['category'])?intval($_POST['category']):'');
1257 $feed_slug = (!empty($_POST['feed_slug'])?($_POST['feed_slug']):'');
1258 $post_type = (!empty($_POST['post_type'])?($_POST['post_type']):'');
1259 $post_type_feed_slug = (!empty($_POST['post_type_feed_slug'])?($_POST['post_type_feed_slug']):'');
1260 $ttid = (!empty($_POST['podcast_ttid'])?intval($_POST['podcast_ttid']):'');
1261 //$import_ = (!empty($_POST['import_item_limit'])?intval($_POST['import_item_limit']):0);
1262 $import_to = 'default';
1263 if( !empty($_POST['import_to']) && $_POST['import_to'] != 'default' )
1264 $import_to = $_POST['import_to'];
1265 if( !empty($_REQUEST['import']) && $_REQUEST['import'] == 'powerpress-libsyn-rss-podcast' )
1266 $remove_query_string = true;
1267
1268 // Libsyn feeds must always have this option enabled.
1269 if(!$remove_query_string && !empty($_POST['podcast_feed_url']) && strpos($_POST['podcast_feed_url'], 'libsyn') !== false){
1270 $remove_query_string = true;
1271 }
1272
1273 // Set the correct parameters going in...
1274 switch( $import_to )
1275 {
1276 case 'category': {
1277 $feed_slug = '';
1278 $post_type = '';
1279 $ttid = '';
1280 if( empty($category) ) {
1281 echo '<p>No category selected.</p>';
1282 return;
1283 }
1284 }; break;
1285 case 'channel': {
1286 $category = '';
1287 $post_type = '';
1288 $ttid = '';
1289 if( empty($feed_slug) ) {
1290 echo '<p>No podcast channel selected.</p>';
1291 return;
1292 }
1293 }; break;
1294 case 'post_type': {
1295 $category = '';
1296 $feed_slug = $post_type_feed_slug;
1297 $ttid = '';
1298
1299 if( empty($feed_slug) ) {
1300 echo '<p>No feed slug specified.</p>';
1301 return;
1302 }
1303 if( empty($post_type) ) {
1304 echo '<p>No post type specified.</p>';
1305 return;
1306 }
1307 }; break;
1308 case 'taxonomy': {
1309 $category = '';
1310 $feed_slug = '';
1311 $post_type = '';
1312
1313 if( empty($ttid) ) {
1314 echo '<p>No taxonomy podcast selected.</p>';
1315 return;
1316 }
1317
1318 }; break;
1319 case 'default':
1320 default: {
1321 $category = '';
1322 $feed_slug = '';
1323 $post_type = '';
1324 $ttid = '';
1325 }; break;
1326 }
1327
1328 // Need to check for podcast:locked tag before importing anything
1329 if (preg_match_all('/<podcast:locked\s*owner=["\'](.*)["\']\s*>([\s\S]*)<\/podcast:locked>/', $this->m_content, $matches)) {
1330 if (strpos($matches[2][0], 'yes') !== false) {
1331 echo '<p>Failed to import: podcast feed is locked.</p>';
1332 return;
1333 }
1334 }
1335
1336 // First import program info...
1337 if( preg_match('/^(.*)<item>/is', $this->m_content, $matches) )
1338 {
1339 if( $import_to == 'default' ) {
1340 $overwrite_program_info = (!empty($_POST['import_overwrite_program_info'])?true:false);
1341 $import_itunes_image = (!empty($_POST['import_itunes_image'])?true:false);
1342 if( $overwrite_program_info || $import_itunes_image )
1343 $this->import_program_info($overwrite_program_info, $import_itunes_image);
1344 } else if( $import_to == 'category' ) {
1345 $overwrite_program_info = (!empty($_POST['import_overwrite_program_info_category'])?true:false);
1346 $import_itunes_image = (!empty($_POST['import_itunes_image_category'])?true:false);
1347 if( $overwrite_program_info || $import_itunes_image )
1348 $this->import_program_info($overwrite_program_info, $import_itunes_image, $category);
1349 } else if( $import_to == 'channel' ) {
1350 $overwrite_program_info = (!empty($_POST['import_overwrite_program_info_channel'])?true:false);
1351 $import_itunes_image = (!empty($_POST['import_itunes_image_channel'])?true:false);
1352 if( $overwrite_program_info || $import_itunes_image )
1353 $this->import_program_info($overwrite_program_info, $import_itunes_image, false, $feed_slug);
1354 } else if( $import_to == 'post_type' ) {
1355 $overwrite_program_info = (!empty($_POST['import_overwrite_program_info_post_type'])?true:false);
1356 $import_itunes_image = (!empty($_POST['import_itunes_image_post_type'])?true:false);
1357 if( $overwrite_program_info || $import_itunes_image )
1358 $this->import_program_info($overwrite_program_info, $import_itunes_image, false, $feed_slug, $post_type);
1359 } else if( $import_to == 'taxonomy' ) {
1360 $overwrite_program_info = (!empty($_POST['import_overwrite_program_info_taxonomy'])?true:false);
1361 $import_itunes_image = (!empty($_POST['import_itunes_image_taxonomy'])?true:false);
1362 if( $overwrite_program_info || $import_itunes_image )
1363 $this->import_program_info($overwrite_program_info, $import_itunes_image, false, false, false, $ttid);
1364 }
1365 }
1366
1367 $this->import_episodes($MatchFilter, $import_blog_posts, $import_item_limit, $category, $feed_slug, $post_type, $ttid, $remove_query_string, $post_status, $match_existing_posts);
1368
1369 ?>
1370 <tr><td colspan="4" style="text-align: right">
1371 <?php
1372 if ($this->m_item_inserted_count != 0) {
1373 echo $this->m_item_inserted_count . " Episodes Imported";
1374 }
1375 if ($this->m_item_skipped_count != 0) {
1376 if($this->m_item_inserted_count != 0) {
1377 echo ' / ';
1378 }
1379 echo $this->m_item_skipped_count . " Episodes Skipped";
1380 }
1381 ?>
1382 </td></tr>
1383 <?php
1384 echo '</tbody></table></div></div>';
1385 $migrated_to_blubrry = false;
1386 if( !empty($_POST['migrate_to_blubrry']) && !empty($GLOBALS['pp_migrate_media_urls']) ) {
1387 require_once( POWERPRESS_ABSPATH .'/powerpressadmin-migrate.php');
1388 $migrated_to_blubrry = true;
1389
1390 $update_option = true;
1391 $QueuedFiles = get_option('powerpress_migrate_queued');
1392 if( !is_array($QueuedFiles) ) {
1393 $QueuedFiles = array();
1394 $update_option = false;
1395 }
1396
1397 $add_urls = '';
1398 foreach( $GLOBALS['pp_migrate_media_urls'] as $meta_id => $url )
1399 {
1400 if( empty($QueuedFiles[ $meta_id ]) ) { // Add to the array if not already added
1401 $QueuedFiles[ $meta_id ] = $url;
1402 if( !empty($add_urls) ) {
1403 $add_urls .= "\n";
1404 }
1405 $this->m_item_migrate_count++;
1406 $add_urls .= $url;
1407 }
1408 }
1409 if (!isset($_GET['from']) || ($_GET['from'] != 'gs' || $_GET['from'] != 'onboarding')) {
1410 echo '<h3>';
1411 echo __('Migration request...', 'powerpress');
1412 echo '</h3>';
1413 echo '<pre style="border: 1px solid #333; background-color: #FFFFFF; padding: 4px 8px; white-space: pre-wrap; word-break: break-all;">';
1414 echo $add_urls;
1415 echo '</pre>';
1416 }
1417 $UpdateResults = powepress_admin_migrate_add_urls($add_urls);
1418 if( !empty($UpdateResults) )
1419 {
1420 echo '<p>Migration queued successfully.</p>';
1421 // Queued ok...
1422 if( $update_option )
1423 update_option('powerpress_migrate_queued', $QueuedFiles);
1424 else
1425 add_option('powerpress_migrate_queued', $QueuedFiles, '', 'no');
1426 }
1427 else
1428 {
1429 echo '<p>Failed to request migration.</p>';
1430 }
1431 }
1432 powerpress_page_message_print();
1433 if( !empty( $this->m_item_migrate_count ) )
1434 echo '<p>'. sprintf(__('Media files queued for migration: %d', 'powerpress'), $this->m_item_migrate_count).'</p>';
1435
1436 echo '';
1437 if( $migrated_to_blubrry ) {
1438 echo '<p>'. sprintf(__('Visit %s to monitor the migration process.','powerpress'), '<strong><a href="'.admin_url('admin.php?page=powerpress/powerpressadmin_migrate.php') .'">'. __('Migrate Media', 'powerpress') .'</a></strong>' ). '</p>';
1439 }
1440 $nextUrl = '';
1441 $GeneralSettings = powerpress_get_settings('powerpress_general');
1442 if(!empty($_GET['from']) && $_GET['from'] == 'onboarding') {
1443 if (isset($GeneralSettings['blubrry_hosting']) && $GeneralSettings['blubrry_hosting'] != null) {
1444 $nextUrl = admin_url("admin.php?page=powerpressadmin_basic&import=true&migrate=true");
1445 } else {
1446 if ($this->isHostedOnBlubrry) {
1447 $pp_nonce = powerpress_login_create_nonce();
1448 $nextUrl = add_query_arg( '_wpnonce', $pp_nonce, admin_url("admin.php?page=powerpressadmin_basic&step=blubrrySignin&import=true"));
1449 } else {
1450 $nextUrl = admin_url("admin.php?page=powerpressadmin_basic&step=nohost&import=true&from=import");
1451 }
1452 }
1453 }
1454 else if (!empty($_GET['from']) && $_GET['from'] == 'gs') {
1455 if (isset($GeneralSettings['blubrry_hosting']) && $GeneralSettings['blubrry_hosting'] != null) {
1456 $nextUrl = admin_url("admin.php?page=powerpressadmin_basic&import=true&migrate=true");
1457 } else {
1458 if ($this->isHostedOnBlubrry) {
1459 $pp_nonce = powerpress_login_create_nonce();
1460 $nextUrl = add_query_arg( '_wpnonce', $pp_nonce, admin_url("admin.php?page=powerpressadmin_onboarding.php&step=blubrrySignin&import=true"));
1461 } else {
1462 $nextUrl = admin_url("admin.php?page=powerpressadmin_onboarding.php&step=nohost&import=true&from=import");
1463 }
1464 }
1465 }
1466 if(!empty($_GET['from'])) {
1467 ?>
1468
1469 <div class="pp_col" style="padding: 20px 0px;margin-top: 2em;">
1470 <div class="pp_button-container" style="float: right;">
1471 <a href="<?php echo htmlspecialchars($nextUrl) ?>"><button name="submit" type="button" class="pp_button" value="Import Podcast"><span>Continue</span></button></a>
1472 </div>
1473
1474 </div>
1475 <?php
1476 }
1477 }
1478
1479 function dispatch() {
1480
1481 $this->m_step = 0;
1482 if( !empty($_POST['step']) )
1483 $this->m_step = intval($_POST['step']);
1484 else if( !empty($_GET['step']) )
1485 $this->m_step = intval($_GET['step']);
1486
1487 // Drop back down a step if not setup for hosting...
1488 if( !empty($_POST['migrate_to_blubrry']) ) {
1489 $Settings = get_option('powerpress_general', array());
1490 $creds = get_option('powerpress_creds');
1491 if( empty($Settings['blubrry_auth']) && !$creds ) {
1492 echo '<div class="notice is-dismissible updated"><p>'. sprintf(__('You must have a blubrry Podcast Hosting account to continue.', 'powerpress')) .' '. '<a href="https://blubrry.com/services/podcast-hosting/" target="_blank">'. __('Learn More', 'powerpress') .'</a>'. '</p></div>';
1493 $this->m_step = 0; // Drop back a step
1494 }
1495 }
1496
1497 $this->header();
1498
1499 switch ($this->m_step) {
1500 case 0 :
1501 $this->greet();
1502 break;
1503 case 1 :
1504 check_admin_referer('import-powerpress-rss');
1505 $result = $this->import();
1506 if ( is_wp_error( $result ) )
1507 echo htmlspecialchars($result->get_error_message());
1508 break;
1509 }
1510
1511 }
1512
1513 function get_step() {
1514
1515 return $this->m_step;
1516 }
1517
1518 function _find_post_by_guid($guid)
1519 {
1520 global $wpdb;
1521
1522 $post_guid = wp_unslash( sanitize_post_field( 'guid', $guid, 0, 'db' ) );
1523 if (empty($post_guid)) return 0;
1524
1525 $query = $wpdb->prepare("SELECT ID FROM $wpdb->posts WHERE guid = %s", $post_guid);
1526 return intval($wpdb->get_var($query));
1527 }
1528
1529 function _find_post_by_title($title)
1530 {
1531 global $wpdb;
1532
1533 $post_guid = wp_unslash( sanitize_post_field( 'post_title', $title, 0, 'db' ) );
1534
1535 $query = "SELECT ID FROM $wpdb->posts WHERE 1=1 ";
1536 $args = array();
1537
1538 if ( !empty ( $post_guid ) ) {
1539 $query .= 'AND post_title = %s';
1540 $args[] = $title;
1541 }
1542
1543 if ( !empty ( $args ) ) {
1544 $found = intval( $wpdb->get_var( $wpdb->prepare($query, $args) ) );
1545 if( $found > 0 )
1546 return $found;
1547 }
1548
1549 return 0;
1550 }
1551
1552 function _find_post_by_date($date)
1553 {
1554 global $wpdb;
1555
1556 $post_guid = wp_unslash( sanitize_post_field( 'post_date', $date, 0, 'db' ) );
1557
1558 $query = "SELECT ID FROM $wpdb->posts WHERE 1=1 ";
1559 $args = array();
1560
1561 if ( !empty ( $post_guid ) ) {
1562 $query .= 'AND post_date = %s';
1563 $args[] = $date;
1564 }
1565
1566 if ( !empty ( $args ) ) {
1567 $found = intval( $wpdb->get_var( $wpdb->prepare($query, $args) ) );
1568 if( $found > 0 )
1569 return $found;
1570 }
1571
1572 return 0;
1573 }
1574
1575 function _find_post_by_enclosure_filename($filename, $feed_slug = '')
1576 {
1577 global $wpdb;
1578
1579 $meta_key = 'enclosure';
1580 if( !empty($feed_slug) && $feed_slug != 'podcast' )
1581 $meta_key = '_'. $feed_slug .':enclosure';
1582
1583 $like = '%/' . $wpdb->esc_like($filename) . '%';
1584
1585 $query = "SELECT p.ID ";
1586 $query .= "FROM {$wpdb->posts} AS p ";
1587 $query .= "INNER JOIN {$wpdb->postmeta} AS pm ON p.ID = pm.post_id ";
1588 $query .= "WHERE pm.meta_key = %s ";
1589 $query .= "AND pm.meta_value LIKE %s ";
1590 $query .= "AND p.post_type != 'revision' ";
1591 $query .= "GROUP BY p.ID ";
1592 $query .= "ORDER BY p.post_date ASC LIMIT 1 "; // Make sure we use the oldest date
1593 $query = $wpdb->prepare($query, $meta_key, $like);
1594
1595 $results = $wpdb->get_results($query, ARRAY_A);
1596 if( !empty($results) )
1597 {
1598 foreach( $results as $null => $row ) {
1599 return (int) $row['ID'];
1600 }
1601 }
1602
1603 return 0;
1604 }
1605
1606 function _find_post($guid = '', $title = '', $date = '', $media_url = '', $feed_slug='') {
1607 global $wpdb;
1608
1609 if( !empty($guid) )
1610 {
1611 $found = $this->_find_post_by_guid($guid);
1612 if( $found )
1613 return $found;
1614 }
1615
1616 if( !empty($media_url) )
1617 {
1618 $filename = basename(strtok($media_url, '?'));
1619 if( !empty($filename) ) {
1620 $found = $this->_find_post_by_enclosure_filename($filename, $feed_slug);
1621 if( $found )
1622 return $found;
1623 }
1624 }
1625
1626 if( !empty($title) )
1627 {
1628 $found = $this->_find_post_by_title($title);
1629 if( $found )
1630 return $found;
1631 }
1632
1633 if( !empty($date) )
1634 {
1635 $found = $this->_find_post_by_date($date);
1636 return $found;
1637 }
1638
1639 return 0;
1640 }
1641
1642 function _import_post_to_db($post, $feed_slug = '', $post_id = false)
1643 {
1644 global $wpdb;
1645 $categories = $post['categories'] ?? [];
1646 $enclosure = $post['enclosure'] ?? [];
1647 if ($post_id === false) {
1648 if (isset($post['post_content']))
1649 $post['post_content'] = wp_kses_post($post['post_content']);
1650 if (isset($post['post_title']))
1651 $post['post_title'] = sanitize_text_field($post['post_title']);
1652 $post_id = wp_insert_post($post);
1653 if (0 != count($categories))
1654 wp_create_categories($categories, $post_id);
1655 }
1656
1657 if ( is_wp_error( $post_id ) )
1658 return $post_id;
1659 if (!$post_id) {
1660 _e('Couldn&#8217;t get post ID', 'powerpress');
1661 return false;
1662 }
1663
1664 //Update the post to overwrite wordpress's guid (or the old guid)
1665 $query = $wpdb->prepare("UPDATE {$wpdb->posts} SET guid=%s WHERE ID=%d", $post['guid'], $post_id);
1666 $return = $wpdb->query($query);
1667
1668 // If the GUID does not start with a http or https protocol, lets also save it to this custom field so it gets picked up as it was from the original source.
1669 if( preg_match('/^https?:\/\//i', $post['guid']) == false ) {
1670 add_post_meta($post_id, '_powerpress_guid', $post['guid'], true);
1671 }
1672
1673
1674 if( !empty($enclosure['url']) )
1675 {
1676 // vts stored in wp_options instead of serialized metadata, early extract -> unset
1677 if (!empty($enclosure['_pending_vts'])) {
1678 $vts_feed_slug = empty($feed_slug) ? 'podcast' : $feed_slug;
1679 $vts_feed_slug = sanitize_key($vts_feed_slug ?: 'podcast');
1680 update_option('vts_' . $vts_feed_slug . '_' . $post_id, $enclosure['_pending_vts']);
1681 unset($enclosure['_pending_vts']);
1682 }
1683
1684 $encstring = $enclosure['url'] . "\n" . $enclosure['length'] . "\n" . $enclosure['type'];
1685 $reserved = ['url', 'length', 'type', 'category'];
1686 $serialize = [];
1687
1688 foreach ($enclosure as $key => $value) {
1689 if (in_array($key, $reserved, true)) continue;
1690
1691 if ($value === null || $value === '' || $value === []) continue;
1692
1693 if ($key === 'duration' && function_exists('powerpress_raw_duration')) {
1694 $value = powerpress_raw_duration($value);
1695 }
1696
1697 $serialize[$key] = $value;
1698 }
1699
1700
1701 if( !empty($serialize) )
1702 $encstring .= "\n". serialize( $serialize );
1703
1704 if( empty($feed_slug) || $feed_slug == 'podcast' ) // 'podcast' == $feed_slug || '' == $feed_slug
1705 $meta_id = add_post_meta($post_id, 'enclosure', $encstring, true);
1706 else
1707 $meta_id = add_post_meta($post_id, '_'. $feed_slug .':enclosure', $encstring, true);
1708
1709 if( $meta_id ) {
1710 if( empty($GLOBALS['pp_migrate_media_urls']) )
1711 $GLOBALS['pp_migrate_media_urls'] = array();
1712 $GLOBALS['pp_migrate_media_urls'][ $meta_id ] = $enclosure['url'];
1713 }
1714 }
1715 return $post_id;
1716 }
1717
1718 function _parse_enclosure($feed_item, $category_strict='') {
1719 if (!$this->parser || !$feed_item) return [];
1720
1721 $enc = $this->parser->get_item_enclosure($feed_item);
1722 $url = $enc ? esc_url_raw($this->parser->get_item_enclosure_url($enc)) : '';
1723
1724 if (!empty($url)) {
1725 $enclosure = [
1726 'url' => $url,
1727 'length' => $this->parser->get_item_enclosure_length($enc) ?? 1,
1728 'type' => $this->parser->get_item_enclosure_type($enc) ?? '',
1729 ];
1730 } else {
1731 $enclosure = $this->_enclosure_from_alternate($feed_item);
1732 }
1733
1734 if (empty($enclosure['url'])) return [];
1735
1736 if (empty($enclosure['type'])) {
1737 $enclosure['type'] = powerpress_get_contenttype($enclosure['url']);
1738 }
1739
1740 return array_merge($enclosure, $this->_parse_episode_metadata($feed_item, $category_strict));
1741 }
1742
1743 function _enclosure_from_alternate($feed_item) {
1744 $alts = $this->parser->get_item_alternate_enclosures($feed_item);
1745 if (empty($alts)) return [];
1746
1747 $chosen = $alts[0];
1748 foreach ($alts as $alt) {
1749 if (!empty($alt['is_default'])) {
1750 $chosen = $alt;
1751 break;
1752 }
1753 }
1754
1755 return [
1756 'url' => $chosen['url'],
1757 'length' => $chosen['length'] ?? 1,
1758 'type' => $chosen['type'] ?? '',
1759 ];
1760 }
1761
1762
1763 function _parse_episode_metadata($feed_item, $category_strict='')
1764 {
1765 if (!$this->parser || !$feed_item) return [];
1766
1767 $meta = [];
1768
1769 // ================
1770 // ITUNES NAMESPACE
1771 // ================
1772
1773 // <itunes:title>
1774 if (($v = $this->parser->get_item_title($feed_item)) !== null)
1775 $meta['episode_title'] = $v;
1776
1777 // <itunes:episodeType>
1778 if (($v = $this->parser->get_item_episode_type($feed_item)) !== null)
1779 $meta['episode_type'] = $v;
1780
1781 // <itunes:duration>
1782 if (($v = $this->parser->get_item_duration($feed_item)) !== null)
1783 $meta['duration'] = $v;
1784
1785 // <itunes:summary>
1786 if (($v = $this->parser->get_item_summary($feed_item)) !== null)
1787 $meta['show_notes'] = $v;
1788
1789 // <itunes:author>
1790 if (($v = $this->parser->get_item_author($feed_item)) !== null)
1791 $meta['author'] = $v;
1792
1793 // <itunes:block>
1794 if (($v = $this->parser->get_item_block($feed_item)) !== null)
1795 $meta['block'] = $v;
1796
1797 // <itunes:image>
1798 if (($v = $this->parser->get_item_artwork($feed_item)) !== null)
1799 $meta['itunes_image'] = $v;
1800
1801 // <itunes:explicit>
1802 if (($v = $this->parser->get_item_explicit($feed_item)) !== null)
1803 $meta['explicit'] = $v;
1804
1805 // =======================
1806 // PODCAST INDEX NAMESPACE
1807 // =======================
1808
1809 // <podcast:season> | <itunes:season>
1810 if (($v = $this->parser->get_item_pci_season($feed_item)) !== null) {
1811 $meta['season'] = $v;
1812 } elseif (($v = $this->parser->get_item_itunes_season($feed_item)) !== null) {
1813 $meta['season'] = $v;
1814 }
1815
1816 // <podcast:episode display> | <itunes:episode>
1817 if (($ep = $this->parser->get_item_pci_episode($feed_item)) !== null) {
1818 $meta['episode_no'] = $ep['number'];
1819 if (!empty($ep['display']))
1820 $meta['episode_no_display'] = $ep['display'];
1821 } else if (($v = $this->parser->get_item_itunes_episode($feed_item)) !== null) {
1822 $meta['episode_no'] = $v;
1823 }
1824
1825 // <podcast:funding>
1826 if (($v = $this->parser->get_item_funding($feed_item)) !== null) {
1827 if ($v['url'] !== null) $meta['donate_url'] = $v['url'];
1828 if ($v['label'] !== null) $meta['donate_label'] = $v['label'];
1829 }
1830
1831 // <podcast:license>
1832 if (($v = $this->parser->get_item_license($feed_item)) !== null) {
1833 if ($v['copyright'] !== null) $meta['copyright'] = $v['copyright'];
1834 if ($v['url'] !== null) $meta['copyright_url'] = $v['url'];
1835 }
1836
1837 // <podcast:chapters>
1838 if (($v = $this->parser->get_item_chapters($feed_item)) !== null) {
1839 $meta['pci_chapters'] = '1';
1840 $meta['pci_chapters_url'] = $v;
1841 }
1842
1843 // <podcast:transcript>
1844 if (($v = $this->parser->get_item_transcript($feed_item)) !== null) {
1845 $meta['pci_transcript'] = '1';
1846 $meta['pci_transcript_url'] = $v['url'];
1847 if ($v['language'] !== null) $meta['pci_transcript_language'] = $v['language'];
1848 }
1849
1850 // <podcast:person>
1851 $persons = $this->parser->get_item_persons($feed_item);
1852 if (!empty($persons))
1853 $meta['credits'] = $persons;
1854
1855 // <podcast:soundbite>
1856 $soundbites = $this->parser->get_item_soundbites($feed_item);
1857 if (!empty($soundbites))
1858 $meta['soundbites'] = $soundbites;
1859
1860 // <podcast:location>
1861 $locations = $this->parser->get_item_locations($feed_item);
1862 if (!empty($locations))
1863 $meta['location'] = $locations;
1864
1865 // <podcast:contentLink>
1866 $content_links = $this->parser->get_item_content_links($feed_item);
1867 if (!empty($content_links))
1868 $meta['content_link'] = $content_links;
1869
1870 // <podcast:txt>
1871 $txt_tags = $this->parser->get_item_txt_tags($feed_item);
1872 if (!empty($txt_tags))
1873 $meta['txt_tag'] = $txt_tags;
1874
1875 // <podcast:alternateEnclosure>
1876 $alt_enclosures = $this->parser->get_item_alternate_enclosures($feed_item);
1877 if (!empty($alt_enclosures))
1878 $meta['alternate_enclosure'] = $alt_enclosures;
1879
1880 // <podcast:value> -> <podcast:valueRecipient>
1881 $value_recipients = $this->parser->get_item_value_recipients($feed_item);
1882 if (!empty($value_recipients))
1883 $meta['value_recipients'] = $value_recipients;
1884
1885 // <podcast:valueTimeSplit>
1886 $value_time_splits = $this->parser->get_item_value_time_splits($feed_item);
1887 if (!empty($value_time_splits)) {
1888 $vts_dict = [];
1889 $vts_order = [];
1890 foreach ($value_time_splits as $vts) {
1891 $vts_id = wp_generate_uuid4();
1892 $vts['vts_id'] = $vts_id;
1893 $vts_dict[$vts_id] = $vts;
1894 $vts_order[] = $vts_id;
1895 }
1896
1897 $meta['_pending_vts'] = $vts_dict;
1898 $meta['vts_order'] = $vts_order;
1899 }
1900
1901 // <podcast:socialInteract>
1902 $social_interacts = $this->parser->get_item_social_interacts($feed_item);
1903 if (!empty($social_interacts))
1904 $meta['social_interact'] = $social_interacts;
1905
1906 // ==================
1907 // RAWVOICE NAMESPACE
1908 // ==================
1909
1910 // <rawvoice:pid>
1911 if (($v = $this->parser->get_item_pid($feed_item)) !== null)
1912 $meta['podcast_id'] = $v;
1913
1914 // CATEGORY
1915 if (!empty($category_strict))
1916 $meta['category'] = $category_strict;
1917
1918 // ====================
1919 // SANITIZE META FIELDS
1920 // ====================
1921
1922 // URLS
1923 $url_keys = ['itunes_image', 'donate_url', 'copyright_url', 'pci_chapters_url', 'pci_transcript_url'];
1924 foreach ($url_keys as $url_key) {
1925 if (isset($meta[$url_key]))
1926 $meta[$url_key] = esc_url_raw($meta[$url_key]);
1927 }
1928
1929 // FREE TEXT FIELDS
1930 $text_keys = ['episode_title', 'author', 'donate_label', 'copyright'];
1931 foreach ($text_keys as $text_key) {
1932 if (isset($meta[$text_key]))
1933 $meta[$text_key] = sanitize_text_field($meta[$text_key]);
1934 }
1935 if (isset($meta['show_notes']))
1936 $meta['show_notes'] = wp_kses_post($meta['show_notes']);
1937
1938 return $meta;
1939 }
1940
1941 function _import_handle_url() {
1942
1943 if( empty($_POST['podcast_feed_url']) ) {
1944 echo '<p>'. __( 'URL is empty.', 'powerpress' ) .'<p>';
1945 return false;
1946 }
1947
1948 // DEFAULT UA + CONFIG
1949 $options = [
1950 'user-agent' => 'Blubrry PowerPress/' . POWERPRESS_VERSION,
1951 'timeout' => 10,
1952 ];
1953
1954 // SQUARESPACE
1955 if( !empty($_GET['import']) && $_GET['import'] == 'powerpress-squarespace-rss-podcast' )
1956 $options['user-agent'] = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.111 Safari/537.36';
1957 // PODBEAN
1958 else if( !empty($_GET['import']) && $_GET['import'] == 'powerpress-podbean-rss-podcast' )
1959 $options['user-agent'] = 'iTunes/12.2.2 (Macintosh; OS X 10.10.5) AppleWebKit/600.8.9'; // Common user agent
1960 // 'gPodder/3.8.4 (+http://gpodder.org/)';
1961
1962 $response = wp_safe_remote_get($_POST['podcast_feed_url'], $options);
1963 if ( is_wp_error( $response ) ) {
1964 echo '<p>'. htmlspecialchars($response->get_error_message()) .'<p>';
1965 return false;
1966 }
1967
1968 $this->m_content = wp_remote_retrieve_body( $response );
1969 return true;
1970 }
1971
1972 function _import_handle_upload() {
1973 if ( ! isset( $_FILES['podcast_feed_file'] ) || empty($_FILES['podcast_feed_file']['tmp_name']) ) {
1974 echo '<p>'. __( 'Upload failed.', 'powerpress' ).'<p>';
1975 return false;
1976 }
1977
1978 $this->m_content = file_get_contents($_FILES['podcast_feed_file']['tmp_name']);
1979 return true;
1980 }
1981 } // end PowerPress_RSS_Podcast_Import class
1982
1983 $powerpress_rss_podcast_import = new PowerPress_RSS_Podcast_Import();
1984
1985 register_importer('powerpress-soundcloud-rss-podcast', __('Podcast from SoundCloud', 'powerpress'), __('Import episodes from a SoundCloud podcast feed.', 'powerpress'), array ($powerpress_rss_podcast_import, 'dispatch'));
1986 register_importer('powerpress-libsyn-rss-podcast', __('Podcast from LibSyn', 'powerpress'), __('Import episodes from a LibSyn podcast feed.', 'powerpress'), array ($powerpress_rss_podcast_import, 'dispatch'));
1987 register_importer('powerpress-podbean-rss-podcast', __('Podcast from PodBean ', 'powerpress'), __('Import episodes from a PodBean podcast feed.', 'powerpress'), array ($powerpress_rss_podcast_import, 'dispatch'));
1988 register_importer('powerpress-squarespace-rss-podcast', __('Podcast from Squarespace', 'powerpress'), __('Import episodes from a Squarespace podcast feed.', 'powerpress'), array ($powerpress_rss_podcast_import, 'dispatch'));
1989 register_importer('powerpress-anchor-rss-podcast', __('Podcast from Anchor.fm', 'powerpress'), __('Import episodes from an Anchor.fm podcast feed.', 'powerpress'), array ($powerpress_rss_podcast_import, 'dispatch'));
1990 register_importer('powerpress-buzzsprout-rss-podcast', __('Podcast from Buzzsprout', 'powerpress'), __('Import episodes from a Buzzsprout podcast feed.', 'powerpress'), array ($powerpress_rss_podcast_import, 'dispatch'));
1991 register_importer('powerpress-rss-podcast', __('Podcast RSS Feed', 'powerpress'), __('Import episodes from a RSS podcast feed.', 'powerpress'), array ($powerpress_rss_podcast_import, 'dispatch'));
1992
1993 }; // end if WP_Importer exists
1994
1995 // eof
1996