PluginProbe
FV Player 8 / trunk
FV Player 8 vtrunk
trunk 8.0.18 8.0.19 8.0.20 8.0.21 8.0.25 8.0.27 8.1 8.1.3
fv-player / models / conversion / shortcode2DB.class.php

shortcode2DB.class.php in FV Player 8 trunk, at models/conversion/shortcode2DB.class.php

546 lines 18.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 if ( ! defined( 'ABSPATH' ) ) {
4 exit;
5 }
6
7 class FV_Player_Shortcode2Database_Conversion extends FV_Player_Conversion_Base {
8
9 var $supported_atts;
10
11 var $supported_player_atts;
12
13 var $supported_video_atts;
14
15 function __construct() {
16
17 if ( ! defined( 'ABSPATH' ) ) {
18 exit;
19 }
20
21 parent::__construct( array(
22 'title' => 'FV Player Shortcode2Database Conversion',
23 'slug' => 'shortcode2db',
24 ) );
25
26 $this->conversion_limit = 1;
27
28 // atts for video that are supported
29 $this->supported_video_atts = array(
30 'src',
31 'src1',
32 'src2',
33 'splash',
34 );
35
36 // atts for player that are supported
37 $this->supported_player_atts = array(
38 'width',
39 'height',
40 'autoplay',
41 'lightbox',
42 'playlist',
43 'caption',
44 'subtitles',
45 'transcript',
46 'original_formatting',
47 'ab',
48 'chapters',
49 'controlbar',
50 'speed'
51 );
52
53 $this->supported_atts = array_merge( $this->supported_video_atts, $this->supported_player_atts );
54
55 $this->screen_fields = array(
56 'ID',
57 'Title',
58 'Post Type',
59 'Shortcode',
60 'Result',
61 'Error'
62 );
63
64 if( isset($_GET['fv-conversion-export']) && !empty($_GET['page']) && sanitize_key( $_GET['page'] ) === $this->screen ) {
65 add_action('admin_init', array( $this, 'csv_export' ) );
66 }
67 }
68
69 public function get_text( $type ) {
70 if ( 'help' === $type ) {
71 return __( "This converts the <code>[fvplayer src=...]</code> and <code>[flowplayer src=...]</code> shortcodes into database <code>[fvplayer id=...]</code> shortcodes.", 'fv-player' );
72
73 } else if ( 'start_warning' === $type ) {
74 return __( 'Please make sure you backup your database before continuing. You can use post revisions to get back to previous version of your posts as well.', 'fv-player' );
75 }
76
77 return parent::get_text( $type );
78 }
79
80 /**
81 * Get posts with [fvplayer/flowplayer src...] shortcodes
82 *
83 * @return object|null $result
84 */
85 function get_items($offset, $limit) {
86 global $wpdb;
87
88 // Each row is the matching wp_posts row or wp_posts row with matching meta_value
89 $results = $wpdb->get_results(
90 $wpdb->prepare(
91 "SELECT SQL_CALC_FOUND_ROWS ID, post_author, post_date_gmt, post_status, post_title, post_type, post_content FROM {$wpdb->posts} AS p JOIN {$wpdb->postmeta} AS m ON p.ID = m.post_id WHERE post_status NOT IN ('inherit','trash') AND (post_content LIKE %s OR post_content LIKE %s) AND post_type NOT IN ('topic','reply') OR (meta_value LIKE %s OR meta_value LIKE %s) AND meta_key NOT LIKE %s AND meta_key NOT LIKE %s GROUP BY ID ORDER BY post_date_gmt DESC LIMIT %d, %d",
92 '%' . $wpdb->esc_like( "[fvplayer src=" ) . '%',
93 '%' . $wpdb->esc_like( "[flowplayer src=" ) . '%',
94 '%' . $wpdb->esc_like( "[fvplayer src=" ) . '%',
95 '%' . $wpdb->esc_like( "[flowplayer src=" ) . '%',
96 '%' . $wpdb->esc_like( "_fv_player_%_backup_" ) . '%',
97 '%' . $wpdb->esc_like( "_fv_player_%_failed_" ) . '%',
98 $offset,
99 $limit
100 )
101 );
102
103 return $results;
104 }
105
106 /**
107 * Converts all shortcodes to DB
108 *
109 * @param WP_Post $post
110 *
111 * @return arrray
112 */
113 function convert_one( $post ) {
114 $content_updated = false; // track if content was updated
115 $new_content = $post->post_content; // copy of content for update
116 $output_data = array(); // output for html
117 $errors = array(); // all errors for export
118
119 if( !empty( $post->post_content) ) {
120
121 // match shortcodes in post_content, ignore shotcodes in double brackets like [[fvplayer src="https://your-website.com/videos/video.mp4"]]
122 preg_match_all( '~(?<!\[)\[(?:flowplayer|fvplayer) .*?\](?!\[)~', $post->post_content, $matched_shortcodes );
123
124 if( !empty($matched_shortcodes) && !empty($matched_shortcodes[0]) ) {
125 foreach( $matched_shortcodes[0] as $shortcode ) {
126 $result = $this->worker( $shortcode, $post, $new_content );
127 if( $result ) {
128
129 $new_content = $result['new_content'];
130 if( $result['content_updated'] ) {
131 $content_updated = $result['content_updated'];
132 }
133 $errors = array_merge( $errors, $result['errors'] );
134
135 $output_data[] = $result['data'];
136 }
137 }
138 }
139 }
140
141 // match shortcodes also in post meta
142 $meta = get_post_custom( $post->ID );
143
144 if( is_array($meta) ) {
145 foreach( $meta AS $meta_key => $meta_values ) {
146 // Skip meta keys created by the conversion
147 if(
148 preg_match( '~^_fv_player_.*?_backup_~', $meta_key ) ||
149 preg_match( '~^_fv_player_.*?_failed$~', $meta_key )
150 ) {
151 continue;
152 }
153
154 foreach( $meta_values AS $meta_value ) {
155
156 // Skip serialized meta values, it would be tricky to update
157 if( is_serialized($meta_value) ) {
158 continue;
159 }
160
161 $original_meta_value = $meta_value;
162
163 $meta_updated = false;
164
165 preg_match_all( '~(?<!\[)\[(?:flowplayer|fvplayer) .*?\](?!\[)~', $meta_value, $matched_shortcodes );
166
167 if( !empty($matched_shortcodes) && !empty($matched_shortcodes[0]) ) {
168 foreach( $matched_shortcodes[0] as $shortcode ) {
169 $result = $this->worker( $shortcode, $post, $meta_value, $meta_key );
170 if( $result ) {
171 if( $result['content_updated'] ) {
172 $meta_updated = $result['content_updated'];
173 $meta_value = $result['new_content'];
174 }
175 $errors = array_merge( $errors, $result['errors'] );
176
177 $output_data[] = $result['data'];
178 }
179 }
180 }
181
182 if( $this->is_live() && $meta_updated ) {
183 update_post_meta( $post->ID, '_fv_player_'.$this->slug.'_backup_'.$meta_key, $original_meta_value );
184 update_post_meta( $post->ID, $meta_key, $meta_value, $original_meta_value );
185 }
186 }
187 }
188 }
189
190 return array(
191 'new_content' => $new_content,
192 'content_updated' => $content_updated,
193 'output_data' => $output_data,
194 'errors' => $errors
195 );
196 }
197
198 function conversion_button() {
199 ?>
200 <tr>
201 <td><label>Convert <code>[fvplayer src="..."]</code> shortocdes to database-driven <code>[fvplayer id="..."]</code> :</label></td>
202 <td>
203 <p class="description">
204 <input type="button" class="button" value="<?php esc_attr_e('Convert FV Player shortcodes to DB', 'fv-player-pro'); ?>" style="margin-top: 2ex;" onclick="location.href='<?php echo admin_url('admin.php?page=' . $this->screen ) ?>'; "/>
205 </p>
206 </td>
207 </tr>
208 <?php
209 }
210
211 function worker( $shortcode, $post, $new_content, $meta_key = false ) {
212 $content_updated = false;
213
214 $atts = shortcode_parse_atts( trim(rtrim($shortcode,']')) );
215 $import_video_atts = array();
216 $import_player_atts = array();
217 $import_atts = array();
218 $errors = array();
219
220 unset( $atts[0] ); // remove [fvplayer or [flowplayer
221
222 // ignore db players
223 if ( isset( $atts['id'] ) ) {
224 return false;
225 }
226
227 // check for unsupported args
228 $unsupported_atts_found = array();
229 foreach( $atts as $k => $v ) {
230 if( !in_array( $k, $this->supported_atts ) ) {
231 $unsupported_atts_found[] = $k;
232 } else {
233 $import_atts[$k] = $v;
234 }
235 }
236
237 $output_msg = "Conversion failed.";
238 $failed_msg = "";
239
240 // check if unsupported args found
241 if( !empty($unsupported_atts_found) ) {
242 $failed_msg = "Unsupported argument(s) " . implode(',', $unsupported_atts_found);
243
244 $errors[] = array(
245 'ID' => $post->ID,
246 'post_title' => $post->post_title,
247 'post_link' => get_permalink( $post->ID ),
248 'post_edit' => get_edit_post_link( $post->ID ),
249 'shortcode' => $shortcode,
250 'message' => $failed_msg
251 );
252 } else {
253 // single video set 0 index
254 $video_index = 0;
255 $import_video_atts[$video_index] = array();
256 // add video atts
257 foreach( $this->supported_video_atts as $video_att ) {
258 if( isset( $import_atts[$video_att] ) ) {
259 $import_video_atts[$video_index][$video_att] = $import_atts[$video_att];
260 }
261 }
262
263 // add player atts , parse lightbox, playlist items
264 foreach( $this->supported_player_atts as $player_att ) {
265 $video_index = 0; // reset video index to 0
266 if( isset( $import_atts[$player_att] ) ) {
267 if( strcmp( $player_att, 'lightbox' ) == 0 ) { // handle lightbox
268 $lightbox_atts = explode(';', $import_atts[$player_att] );
269
270 $lightbox_count = count( $lightbox_atts );
271
272 if( $lightbox_count == 2 ) { // lightbox_caption
273 $import_player_atts['lightbox_caption'] = $lightbox_atts[1];
274 } else if( $lightbox_count == 3 ) { // lightbox_width, lightbox_height
275 $import_player_atts['lightbox_width'] = $lightbox_atts[1];
276 $import_player_atts['lightbox_height'] = $lightbox_atts[2];
277 } else if( $lightbox_count == 4 ) { // lightbox_caption, lightbox_width, lightbox_height
278 $import_player_atts['lightbox_width'] = $lightbox_atts[1];
279 $import_player_atts['lightbox_height'] = $lightbox_atts[2];
280 $import_player_atts['lightbox_caption'] = $lightbox_atts[3];
281 }
282
283 $import_player_atts[$player_att] = $lightbox_atts[0]; // lightbox
284 } else if( strcmp( $player_att, 'playlist' ) == 0 ) { // handle playlist
285 $playlist_items = explode(';', $import_atts[$player_att]);
286 foreach($playlist_items as $item) {
287 $video_index++;
288 $import_video_atts[$video_index] = array();
289
290 $item_data = explode(',', $item );
291
292 // parse src, scr1, scr2 and splash
293 if( count( $item_data ) > 1 ) {
294 foreach( $item_data as $i => $data ) {
295 if( preg_match('~\.(png|gif|jpg|jpe|jpeg)($|\?)~', $data) || stripos($data, 'i.vimeocdn.com') !== false ) { // splash
296 $import_video_atts[$video_index]['splash'] = $data;
297 } else if( $i > 0 ) { // src1, src2
298 $import_video_atts[$video_index]['src'.$i] = $data;
299 }
300 }
301 }
302
303 $import_video_atts[$video_index]['src'] = $item_data[0]; // src
304 }
305 } else if(strcmp( $player_att, 'subtitles' ) == 0) { // subtitles
306 $subtitles = explode(';', $import_atts[$player_att]);
307 foreach( $subtitles as $subtile ) {
308 if( !empty( $subtile ) ) {
309 if( !isset( $import_video_atts[$video_index]['meta'] ) ) {
310 $import_video_atts[$video_index]['meta'] = array();
311 }
312 $import_video_atts[$video_index]['meta'][] = array( 'meta_key' => 'subtitles', 'meta_value' => esc_url_raw($subtile) );
313 }
314
315 $video_index++;
316 }
317
318 } else if(strcmp( $player_att, 'caption' ) == 0) { // caption
319 $replace_from = array('&amp;','\;', '\,'); // escaped characters
320 $replace_to = array('<!--amp-->','<!--semicolon-->','<!--comma-->'); // temp replacements
321 $unescaped = array( '&', ';', ',' );
322 $captions = str_replace( $replace_from, $replace_to, $import_atts[$player_att] );
323 $captions = explode(';', $captions);
324
325 foreach( $captions as $caption ) {
326 $caption = str_replace( $replace_to, $unescaped, $caption );
327 $import_video_atts[$video_index]['caption'] = $caption;
328
329 $video_index++;
330 }
331 } else if(strcmp( $player_att, 'chapters' ) == 0) { // subtitles
332 $chapters = explode(';', $import_atts[$player_att]);
333 foreach( $chapters as $chapters_vtt ) {
334 if( !empty( $chapters_vtt ) ) {
335 if( !isset( $import_video_atts[$video_index]['meta'] ) ) {
336 $import_video_atts[$video_index]['meta'] = array();
337 }
338 $import_video_atts[$video_index]['meta'][] = array( 'meta_key' => 'chapters', 'meta_value' => esc_url_raw($chapters_vtt) );
339 }
340
341 $video_index++;
342 }
343
344 } else if(strcmp( $player_att, 'transcript' ) == 0) { // transcript text
345 $transcript_text = $import_atts[$player_att];
346 if( !empty($transcript_text) ) {
347 $import_video_atts[$video_index]['meta'][] = array( 'meta_key' => 'transcript_text', 'meta_value' => $transcript_text );
348 }
349
350 } else if(strcmp( $player_att, 'original_formatting' ) == 0) { // transcript original formatting
351 $transcript_original_formatting = $import_atts[$player_att];
352
353 if( $transcript_original_formatting === 'true' ) {
354 $import_video_atts[$video_index]['meta'][] = array( 'meta_key' => 'transcript_original_formatting', 'meta_value' => $transcript_original_formatting );
355 }
356
357 } else if(strcmp( $player_att, 'ab' ) == 0) { // subtitles
358 if( $import_atts[$player_att] == 'true' ) {
359 $import_player_atts[$player_att] = 'on';
360 } else if( $import_atts[$player_att] == 'false' ) {
361 $import_player_atts[$player_att] = 'off';
362 } else {
363 $import_player_atts[$player_att] = $import_atts[$player_att];
364 }
365
366 } else if(strcmp( $player_att, 'speed' ) == 0) { // subtitles
367 if( $import_atts[$player_att] == 'buttons' ) {
368 $import_player_atts[$player_att] = 'yes';
369 } else {
370 $import_player_atts[$player_att] = $import_atts[$player_att];
371 }
372
373 } else { // other atts
374 $import_player_atts[$player_att] = $import_atts[$player_att];
375 }
376 }
377 }
378
379 // add metadata
380 $import_player_atts['meta'] = array(
381 array(
382 'meta_key' => 'post_id',
383 'meta_value' => $post->ID
384 ),
385 array(
386 'meta_key' => 'fv_player_conversion',
387 'meta_value' => get_class($this)
388 )
389 );
390
391 // add author
392 $import_player_atts['author'] = $post->post_author;
393
394 // add status
395 $import_player_atts['status'] = 'published';
396
397 // add date_created
398 $import_player_atts['date_created'] = strtotime($post->post_date_gmt) > 0 ? $post->post_date_gmt : current_time( 'mysql' );
399
400 // add player_name
401 // $import_player_atts['player_name'] = 'player_name';
402
403 // add videos
404 $import_player_atts['videos'] = $import_video_atts;
405
406 // echo '<pre>';
407 // var_export($import_player_atts);
408 // echo '</pre>';
409 // die();
410
411 if( $this->is_live() ) {
412 global $FV_Player_Db;
413 $player_id = $FV_Player_Db->import_player_data(false, false, $import_player_atts);
414
415 if( $player_id > 0 ) {
416 // echo "Inserted player #".$player_id."\n";
417 $new_content = str_replace( $shortcode , '[fvplayer id="'.$player_id.'"]', $new_content );
418 $content_updated = true;
419 $output_msg = "New FV Player #" . $player_id ;
420 } else {
421 $failed_msg = "Error saving FV Player instance";
422
423 $errors[] = array(
424 'ID' => $post->ID,
425 'post_title' => $post->post_title,
426 'post_link' => get_permalink( $post->ID ),
427 'post_edit' => get_edit_post_link( $post->ID ),
428 'shortcode' => $shortcode,
429 'message' => $failed_msg
430 );
431 }
432
433 } else {
434 $output_msg = "Would create new FV Player";
435 }
436 }
437
438 $type = $post->post_type;
439 if( $meta_key ) {
440 $type .= '<br />meta_key: <code>'.$meta_key.'</code>';
441 }
442
443 return array(
444 'errors' => $errors,
445 'data' => array(
446 'ID' => $post->ID,
447 'title' => $post->post_title,
448 'type' => $type,
449 'shortcode' => $shortcode,
450 'output' => $output_msg,
451 'error' => $failed_msg
452 ),
453 'new_content' => $new_content,
454 'content_updated' => $content_updated
455 );
456 }
457
458 function build_output_html($data, $percent_done) {
459 $html = array();
460
461 foreach( $data as $output_data ) {
462 $html[] = "<tr><td><a href='" . get_edit_post_link( $output_data['ID'] ) . "' target='_blank'> #". $output_data['ID'] . "</a></td><td><a href='" . get_permalink( $output_data['ID'] ) ."' target='_blank'>". $output_data['title'] . "</a></td><td>" . $output_data['type'] . "</td><td>". $output_data['shortcode'] . "</td><td>" . $output_data['output'] . "</td><td>" . $output_data['error'] . "</td></tr>";
463 }
464
465 if( empty($html) && $percent_done == 0 ) {
466 $html[] = "<tr><td colspan='6'>No matching players found.</td></tr>";
467 }
468
469 return $html;
470 }
471
472 function iterate_data($data) {
473 $conversions_output = array();
474 $convert_error = false;
475
476 foreach( $data AS $post ) {
477 $result = $this->convert_one($post);
478 // mark post if conversion failed
479 if( !empty( $result['errors'] ) ) {
480 update_post_meta( $post->ID, '_fv_player_' . $this->slug . '_failed', $result['errors'] );
481 $convert_error = true;
482 } else {
483 if( $result['content_updated'] ) {
484 // no problem, unmark
485 delete_post_meta( $post->ID, '_fv_player_' . $this->slug . '_failed' );
486 }
487 }
488
489 $conversions_output = array_merge( $conversions_output, $result['output_data'] );
490
491 if( $this->is_live() && $result['content_updated'] ) {
492 wp_update_post( array( 'ID' => $post->ID, 'post_content' => $result['new_content'] ) );
493 }
494 }
495
496 return array(
497 'convert_error' => $convert_error,
498 'conversions_output' => $conversions_output
499 );
500 }
501
502 function csv_export() {
503 if( !current_user_can('install_plugins') ) return;
504
505 global $wpdb;
506
507 $filename = $this->slug . '-export-' . gmdate('Y-m-d') . '.csv';
508
509 header('Content-type: text/csv');
510 header("Content-Disposition: attachment; filename=$filename");
511 header("Pragma: no-cache");
512 header("Expires: 0");
513
514 $meta_key = '_fv_player_' . $this->slug . '_failed';
515
516 $results = $wpdb->get_col( $wpdb->prepare( "SELECT {$wpdb->postmeta}.meta_value FROM {$wpdb->postmeta} JOIN {$wpdb->posts} ON {$wpdb->postmeta}.post_id = {$wpdb->posts}.ID WHERE {$wpdb->postmeta}.meta_key = %s ORDER BY {$wpdb->posts}.post_date_gmt DESC ", $meta_key ) );
517
518 if( !empty( $results ) ) {
519 $fp = fopen('php://output', 'wb');
520
521 $header = array('ID','Title','Post-Link','Edit-Link','Shortcode','Message');
522
523 fputcsv($fp, $header);
524
525 foreach( $results as $result ) {
526 $unserialized = unserialize( $result );
527
528 foreach( $unserialized as $row ) {
529 $row['post_link'] = htmlspecialchars_decode( $row['post_link'] );
530 $row['post_edit'] = htmlspecialchars_decode( $row['post_edit'] );
531 fputcsv($fp, $row);
532 }
533 }
534
535 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fclose
536 fclose($fp);
537 }
538
539 die();
540 }
541
542 }
543
544 global $FV_Player_Shortcode2Database_Conversion;
545 $FV_Player_Shortcode2Database_Conversion = new FV_Player_Shortcode2Database_Conversion;
546