PluginProbe
WebberZone Top 10 — Popular Posts / 4.4.0
WebberZone Top 10 — Popular Posts v4.4.0
4.5.1 4.5.0 4.4.3 4.4.2 4.4.1 4.4.0 4.3.4 4.3.3 4.3.2 4.3.1 4.3.0 trunk 1.0 1.0.1 1.1 1.2 1.3 1.4 1.4.1 1.5 1.5.1 1.5.2 1.5.3 1.6 1.6.1 All 117 releases
top-10 / includes / admin / class-import-export.php

class-import-export.php in WebberZone Top 10 — Popular Posts 4.4.0, at includes/admin/class-import-export.php

578 lines 18.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Import Export class.
4 *
5 * @package WebberZone\Top_Ten\Admin
6 */
7
8 namespace WebberZone\Top_Ten\Admin;
9
10 use WebberZone\Top_Ten\Database;
11 use WebberZone\Top_Ten\Util\Helpers;
12 use WebberZone\Top_Ten\Util\Hook_Registry;
13 use WebberZone\Top_Ten\Util\Csv_Helper;
14
15 if ( ! defined( 'WPINC' ) ) {
16 die;
17 }
18
19 /**
20 * Import Export functions.
21 *
22 * @since 3.3.0
23 */
24 class Import_Export {
25
26 /**
27 * Parent Menu ID.
28 *
29 * @since 3.3.0
30 *
31 * @var string Parent Menu ID.
32 */
33 public $parent_id;
34
35 /**
36 * Constructor class.
37 *
38 * @since 3.3.0
39 */
40 public function __construct() {
41 Hook_Registry::add_filter( 'admin_init', array( $this, 'process_settings_import' ), 9 );
42 Hook_Registry::add_filter( 'admin_init', array( $this, 'process_settings_export' ) );
43 Hook_Registry::add_filter( 'admin_init', array( $this, 'export_tables' ) );
44 Hook_Registry::add_filter( 'admin_init', array( $this, 'import_tables' ), 9 );
45 Hook_Registry::add_action( 'admin_menu', array( $this, 'admin_menu' ) );
46 Hook_Registry::add_action( 'network_admin_menu', array( $this, 'network_admin_menu' ), 11 );
47 Hook_Registry::add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) );
48
49 new WPP_Importer();
50 }
51
52 /**
53 * Enqueue scripts in admin area.
54 *
55 * @since 4.0.0
56 *
57 * @param string $hook The current admin page.
58 */
59 public function admin_enqueue_scripts( $hook ) {
60 if ( $hook === $this->parent_id ) {
61 wp_enqueue_script( 'top-ten-admin-js' );
62 wp_enqueue_style( 'top-ten-admin-css' );
63
64 }
65 }
66
67 /**
68 * Admin Menu.
69 *
70 * @since 3.3.0
71 */
72 public function admin_menu() {
73
74 $this->parent_id = add_submenu_page(
75 'tptn_dashboard',
76 esc_html__( 'Top 10 Import Export Tables', 'top-10' ),
77 esc_html__( 'Import/Export', 'top-10' ),
78 'manage_options',
79 'tptn_exim_page',
80 array( $this, 'render_page' )
81 );
82 }
83
84 /**
85 * Admin Menu.
86 *
87 * @since 3.3.0
88 */
89 public function network_admin_menu() {
90
91 $this->parent_id = add_submenu_page(
92 'tptn_dashboard',
93 esc_html__( 'Top 10 Import Export Tables', 'top-10' ),
94 esc_html__( 'Import/Export', 'top-10' ),
95 'manage_network_options',
96 'tptn_exim_page',
97 array( $this, 'render_page' )
98 );
99 }
100 /**
101 * Render the tools settings page.
102 *
103 * @since 2.7.0
104 *
105 * @return void
106 */
107 public function render_page() {
108
109 /* Message for successful file import */
110 if ( isset( $_GET['file_import'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
111 if ( 'success' === $_GET['file_import'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
112 add_settings_error( 'tptn-notices', '', esc_html__( 'Data has been imported into the table', 'top-10' ), 'success' );
113 } elseif ( 'fail' === $_GET['file_import'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
114 add_settings_error( 'tptn-notices', '', esc_html__( 'Data import failure. Check the number of columns for the file being imported, if you are uploading it in the right section below and that the data is correct', 'top-10' ), 'error' );
115 }
116 }
117
118 /* Message for successful file import */
119 if ( isset( $_GET['settings_import'] ) && 'success' === $_GET['settings_import'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
120 add_settings_error( 'tptn-notices', '', esc_html__( 'Settings have been imported successfully', 'top-10' ), 'success' );
121 }
122
123 ob_start();
124 ?>
125 <div class="wrap">
126 <h1><?php esc_html_e( 'Top 10 - Import/Export tables', 'top-10' ); ?></h1>
127 <?php do_action( 'tptn_settings_page_header' ); ?>
128
129 <?php settings_errors(); ?>
130
131 <div id="poststuff">
132 <div id="post-body" class="metabox-holder columns-2">
133 <div id="post-body-content">
134
135 <?php if ( ! is_network_admin() ) : ?>
136 <div class="postbox">
137 <h2><span><?php esc_html_e( 'Export/Import settings', 'top-10' ); ?></span></h2>
138 <div class="inside">
139 <form method="post">
140 <p class="description">
141 <?php esc_html_e( 'Export the plugin settings for this site as a .json file. This allows you to easily import the configuration into another site.', 'top-10' ); ?>
142 </p>
143 <p><input type="hidden" name="tptn_action" value="export_settings" /></p>
144 <p>
145 <?php submit_button( esc_html__( 'Export Settings', 'top-10' ), 'primary', 'tptn_export_settings', false ); ?>
146 </p>
147
148 <?php wp_nonce_field( 'tptn_export_settings_nonce', 'tptn_export_settings_nonce' ); ?>
149 </form>
150
151 <form method="post" enctype="multipart/form-data">
152 <p class="description">
153 <?php esc_html_e( 'Import the plugin settings from a .json file. This file can be obtained by exporting the settings on this/another site using the form above.', 'top-10' ); ?>
154 </p>
155 <p>
156 <input type="file" name="import_settings_file" />
157 </p>
158 <p>
159 <?php submit_button( esc_html__( 'Import Settings', 'top-10' ), 'primary', 'tptn_import_settings', false ); ?>
160 </p>
161
162 <input type="hidden" name="tptn_action" value="import_settings" />
163 <?php wp_nonce_field( 'tptn_import_settings_nonce', 'tptn_import_settings_nonce' ); ?>
164 </form>
165 </div>
166 </div>
167 <?php endif; ?>
168
169 <div class="postbox">
170 <h2><span><?php esc_html_e( 'Export tables', 'top-10' ); ?></span></h2>
171 <div class="inside">
172 <form method="post">
173 <p class="description">
174 <?php esc_html_e( 'Click the buttons below to export the overall and the daily tables. The file is downloaded as an CSV file which you should be able to edit in Excel or any other compatible software.', 'top-10' ); ?>
175 <?php esc_html_e( 'If you are using WordPress Multisite then this will include the counts across all sites as the plugin uses a single table to store counts.', 'top-10' ); ?>
176 </p>
177 <p>
178 <label><input type="checkbox" name="export_urls" id="export_urls" value="1" /> <?php esc_html_e( 'Include URLs in export', 'top-10' ); ?></label>
179 <input type="hidden" name="tptn_action" value="export_tables" />
180 <input type="hidden" name="network_wide" value="<?php echo ( is_network_admin() ? 1 : 0 ); ?>" />
181 </p>
182 <p>
183 <?php submit_button( esc_html__( 'Export overall tables', 'top-10' ), 'primary', 'tptn_export_total', false ); ?>
184 <?php submit_button( esc_html__( 'Export daily tables', 'top-10' ), 'primary', 'tptn_export_daily', false ); ?>
185 </p>
186
187 <?php wp_nonce_field( 'tptn_export_nonce', 'tptn_export_nonce' ); ?>
188 </form>
189 </div>
190 </div>
191
192 <div class="postbox">
193 <h2><span><?php esc_html_e( 'Import tables', 'top-10' ); ?></span></h2>
194 <div class="inside">
195 <form method="post" enctype="multipart/form-data">
196 <p class="description">
197 <?php esc_html_e( 'Importing a file will add or increment counts — it does not replace existing data. To start fresh, use the Maintenance tab to truncate the tables first. Best practice is to export before importing. It is important to maintain the export format of the data to avoid corruption.', 'top-10' ); ?>
198 <br />
199 <?php esc_html_e( 'Be careful when opening the file in Excel as it tends to change the date format. Recommended date-time format is YYYY-MM-DD H.', 'top-10' ); ?>
200 </p>
201 <p class="notice notice-warning">
202 <strong><?php esc_html_e( 'Backup your database before proceeding so you will be able to restore it in case anything goes wrong.', 'top-10' ); ?></strong>
203 </p>
204 <p>
205 <label><input type="checkbox" name="import_urls" id="import_urls" value="1" /> <?php esc_html_e( 'Use URLs instead of Post IDs in import', 'top-10' ); ?></label>
206 <input type="hidden" name="tptn_action" value="import_tables" />
207 <input type="hidden" name="network_wide" value="<?php echo ( is_network_admin() ? 1 : 0 ); ?>" />
208 </p>
209
210 <table class="form-table">
211 <tr>
212 <th scope="row"><?php esc_html_e( 'Import overall tables', 'top-10' ); ?></th>
213 <td><input type="file" name="overall_table_file" /><br />
214 <span class="description"><?php esc_html_e( 'CSV file', 'top-10' ); ?></span></td>
215 </tr>
216 <tr>
217 <th scope="row"><?php esc_html_e( 'Import daily tables', 'top-10' ); ?></th>
218 <td><input type="file" name="daily_table_file" /><br />
219 <span class="description"><?php esc_html_e( 'CSV file', 'top-10' ); ?></span></td>
220 </tr>
221 </table>
222 <p>
223 <?php submit_button( esc_html__( 'Import Tables', 'top-10' ), 'primary', 'tptn_import', false ); ?>
224 </p>
225
226 <?php wp_nonce_field( 'tptn_import_nonce', 'tptn_import_nonce' ); ?>
227 </form>
228 </div>
229 </div>
230
231 <?php
232 /**
233 * Action hook to add additional import/export options.
234 *
235 * @since 3.3.0
236 */
237 do_action( 'tptn_admin_import_export_tab_content' );
238 ?>
239
240 </div><!-- /#post-body-content -->
241
242 <div id="postbox-container-1" class="postbox-container">
243
244 <div id="side-sortables" class="meta-box-sortables ui-sortable">
245 <?php include_once 'sidebar.php'; ?>
246 </div><!-- /#side-sortables -->
247
248 </div><!-- /#postbox-container-1 -->
249 </div><!-- /#post-body -->
250 <br class="clear" />
251 </div><!-- /#poststuff -->
252
253 </div><!-- /.wrap -->
254
255 <?php
256 echo ob_get_clean(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
257 }
258
259
260 /**
261 * Process a settings export that generates a .csv file of the Top 10 table.
262 *
263 * @since 2.7.0
264 */
265 public static function export_tables() {
266 global $wpdb;
267
268 if ( empty( $_POST['tptn_action'] ) || 'export_tables' !== $_POST['tptn_action'] ) {
269 return;
270 }
271
272 if ( ! wp_verify_nonce( sanitize_key( $_POST['tptn_export_nonce'] ), 'tptn_export_nonce' ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated
273 return;
274 }
275
276 if ( is_network_admin() && ! current_user_can( 'manage_network_options' ) ) {
277 return;
278 }
279
280 if ( is_admin() && ! current_user_can( 'manage_options' ) ) {
281 return;
282 }
283
284 if ( isset( $_POST['tptn_export_total'] ) ) {
285 $daily = false;
286 } elseif ( isset( $_POST['tptn_export_daily'] ) ) {
287 $daily = true;
288 } else {
289 return;
290 }
291
292 if ( isset( $_POST['network_wide'] ) ) {
293 $network_wide = intval( $_POST['network_wide'] );
294 } else {
295 return;
296 }
297
298 if ( isset( $_POST['export_urls'] ) ) {
299 $export_urls = intval( $_POST['export_urls'] );
300 } else {
301 $export_urls = 0;
302 }
303
304 $table_name = Database::get_table( $daily );
305
306 $filename = array(
307 'top-ten',
308 ( $daily ? 'daily' : '' ),
309 'table',
310 ( is_network_admin() ? '' : 'blog' . get_current_blog_id() ),
311 current_time( 'Y_m_d_Hi' ),
312 );
313 $filename = array_filter( $filename );
314 $filename = implode( '-', $filename );
315 $filename = $filename . '.csv';
316
317 $results = Csv_Helper::fetch_export_data( $daily, (bool) $network_wide, get_current_blog_id() );
318
319 ignore_user_abort( true );
320
321 nocache_headers();
322 header( 'Content-Type: text/csv; charset=utf-8' );
323 header( "Content-Disposition: attachment; filename={$filename}" );
324 header( 'Expires: 0' );
325
326 $fh = fopen( 'php://output', 'w' );
327 Csv_Helper::write_export_csv( $fh, $results, $daily, (bool) $export_urls, (bool) $network_wide );
328 fclose( $fh ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fclose
329
330 exit;
331 }
332
333 /**
334 * Process a .csv file to import the table into the database.
335 *
336 * @since 2.7.0
337 */
338 public static function import_tables() {
339 if ( empty( $_POST['tptn_action'] ) || 'import_tables' !== $_POST['tptn_action'] ) {
340 return;
341 }
342
343 if ( ! wp_verify_nonce( sanitize_key( $_POST['tptn_import_nonce'] ), 'tptn_import_nonce' ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated
344 return;
345 }
346
347 if ( is_network_admin() && ! current_user_can( 'manage_network_options' ) ) {
348 return;
349 }
350
351 if ( is_admin() && ! current_user_can( 'manage_options' ) ) {
352 return;
353 }
354
355 $overall_upload = ! empty( $_FILES['overall_table_file']['tmp_name'] );
356 $daily_upload = ! empty( $_FILES['daily_table_file']['tmp_name'] );
357
358 if ( ! $overall_upload && ! $daily_upload ) {
359 return;
360 }
361
362 if ( isset( $_POST['network_wide'] ) ) {
363 $network_wide = (bool) intval( $_POST['network_wide'] );
364 } else {
365 return;
366 }
367
368 if ( isset( $_POST['import_urls'] ) ) {
369 $use_urls = (bool) intval( $_POST['import_urls'] );
370 } else {
371 $use_urls = false;
372 }
373
374 $results = array();
375
376 if ( $overall_upload ) {
377 $import_file = wp_unslash( $_FILES['overall_table_file']['tmp_name'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
378 $parsed = Csv_Helper::parse_import_file( $import_file );
379
380 if ( 0 === $parsed['total'] ) {
381 wp_safe_redirect(
382 add_query_arg(
383 array(
384 'page' => 'tptn_exim_page',
385 'file_import' => 'fail',
386 ),
387 is_network_admin() ? network_admin_url( 'admin.php' ) : admin_url( 'admin.php' )
388 )
389 );
390 exit;
391 }
392
393 $prepared = self::build_import_data( $parsed['rows'], false, $use_urls, $network_wide );
394 if ( ! empty( $prepared ) ) {
395 $results[] = Database::bulk_upsert( $prepared, false );
396 }
397 }
398
399 if ( $daily_upload ) {
400 $import_file = wp_unslash( $_FILES['daily_table_file']['tmp_name'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
401 $parsed = Csv_Helper::parse_import_file( $import_file );
402
403 if ( 0 === $parsed['total'] ) {
404 wp_safe_redirect(
405 add_query_arg(
406 array(
407 'page' => 'tptn_exim_page',
408 'file_import' => 'fail',
409 ),
410 is_network_admin() ? network_admin_url( 'admin.php' ) : admin_url( 'admin.php' )
411 )
412 );
413 exit;
414 }
415
416 $prepared = self::build_import_data( $parsed['rows'], true, $use_urls, $network_wide );
417 if ( ! empty( $prepared ) ) {
418 $results[] = Database::bulk_upsert( $prepared, true );
419 }
420 }
421
422 $all_success = ! empty( $results ) && ! in_array( false, $results, true );
423 $file_import = $all_success ? 'success' : 'fail';
424
425 wp_safe_redirect(
426 add_query_arg(
427 array(
428 'page' => 'tptn_exim_page',
429 'file_import' => $file_import,
430 ),
431 is_network_admin() ? network_admin_url( 'admin.php' ) : admin_url( 'admin.php' )
432 )
433 );
434 exit;
435 }
436
437 /**
438 * Build structured import data from parsed CSV rows.
439 *
440 * @since 4.3.0
441 *
442 * @param array $rows Parsed rows from Csv_Helper::parse_import_file().
443 * @param bool $daily Whether these are daily-table rows.
444 * @param bool $use_urls Whether to resolve URL column to post IDs.
445 * @param bool $network_wide Whether this is a network-wide import.
446 * @return array Prepared data rows for Database::bulk_upsert().
447 */
448 private static function build_import_data( array $rows, bool $daily, bool $use_urls, bool $network_wide ): array {
449 $prepared = array();
450 $url_list = array();
451
452 foreach ( $rows as $row ) {
453 $post_id = absint( $row['postnumber'] );
454 $blog_id = isset( $row['blog_id'] ) ? absint( $row['blog_id'] ) : get_current_blog_id();
455
456 if ( $use_urls && ! empty( $row['url'] ) ) {
457 $url = esc_url_raw( trim( $row['url'] ) );
458 if ( ! isset( $url_list[ $url ] ) ) {
459 $url_list[ $url ] = url_to_postid( $url );
460 }
461 $post_id = absint( $url_list[ $url ] );
462 }
463
464 if ( 0 === $post_id ) {
465 continue;
466 }
467
468 if ( ! $network_wide && ! is_network_admin() && (int) get_current_blog_id() !== $blog_id ) {
469 continue;
470 }
471
472 if ( $daily ) {
473 $raw_date = isset( $row['dp_date'] ) ? trim( $row['dp_date'] ) : '';
474 try {
475 $dp_date = ( new \DateTime( $raw_date ) )->format( 'Y-m-d H' );
476 } catch ( \Exception $e ) {
477 $dp_date = $raw_date;
478 }
479 $prepared[] = array(
480 'postnumber' => $post_id,
481 'cntaccess' => absint( $row['cntaccess'] ),
482 'dp_date' => $dp_date,
483 'blog_id' => $blog_id,
484 );
485 } else {
486 $prepared[] = array(
487 'postnumber' => $post_id,
488 'cntaccess' => absint( $row['cntaccess'] ),
489 'blog_id' => $blog_id,
490 );
491 }
492 }
493
494 return $prepared;
495 }
496
497 /**
498 * Process a settings export that generates a .json file of the Top 10 settings
499 *
500 * @since 2.7.0
501 */
502 public static function process_settings_export() {
503
504 if ( empty( $_POST['tptn_action'] ) || 'export_settings' !== $_POST['tptn_action'] ) {
505 return;
506 }
507
508 if ( ! wp_verify_nonce( sanitize_key( $_POST['tptn_export_settings_nonce'] ), 'tptn_export_settings_nonce' ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated
509 return;
510 }
511
512 if ( ! current_user_can( 'manage_options' ) ) {
513 return;
514 }
515
516 $settings = get_option( 'tptn_settings' );
517
518 ignore_user_abort( true );
519
520 nocache_headers();
521 header( 'Content-Type: application/json; charset=utf-8' );
522 header( 'Content-Disposition: attachment; filename=tptn-settings-export-' . gmdate( 'm-d-Y' ) . '.json' );
523 header( 'Expires: 0' );
524
525 echo wp_json_encode( $settings );
526 exit;
527 }
528
529 /**
530 * Process a settings import from a json file
531 *
532 * @since 2.7.0
533 */
534 public static function process_settings_import() {
535
536 if ( empty( $_POST['tptn_action'] ) || 'import_settings' !== $_POST['tptn_action'] ) {
537 return;
538 }
539
540 if ( ! wp_verify_nonce( sanitize_key( $_POST['tptn_import_settings_nonce'] ), 'tptn_import_settings_nonce' ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated
541 return;
542 }
543
544 if ( ! current_user_can( 'manage_options' ) ) {
545 return;
546 }
547
548 $filename = 'import_settings_file';
549 $extension = isset( $_FILES[ $filename ]['name'] ) ? pathinfo( sanitize_file_name( wp_unslash( $_FILES[ $filename ]['name'] ) ), PATHINFO_EXTENSION ) : '';
550
551 if ( 'json' !== $extension ) {
552 wp_die( esc_html__( 'Please upload a valid .json file', 'top-10' ) );
553 }
554
555 $import_file = isset( $_FILES[ $filename ]['tmp_name'] ) ? ( wp_unslash( $_FILES[ $filename ]['tmp_name'] ) ) : ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
556
557 if ( empty( $import_file ) ) {
558 wp_die( esc_html__( 'Please upload a file to import', 'top-10' ) );
559 }
560
561 // Retrieve the settings from the file and convert the json object to an array.
562 $settings = (array) json_decode( file_get_contents( $import_file ), true ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
563
564 update_option( 'tptn_settings', $settings );
565
566 wp_safe_redirect(
567 add_query_arg(
568 array(
569 'page' => 'tptn_exim_page',
570 'settings_import' => 'success',
571 ),
572 admin_url( 'admin.php' )
573 )
574 );
575 exit;
576 }
577 }
578