PluginProbe
FV Player 8 / 8.0.21
FV Player 8 v8.0.21
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 8.0.21, at models/conversion/shortcode2DB.class.php

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