PluginProbe
WP Data Access – App Builder for Tables, Forms, Charts, Maps & Dashboards / 5.5.73
WP Data Access – App Builder for Tables, Forms, Charts, Maps & Dashboards v5.5.73
5.5.83 5.5.82 5.5.81 5.5.80 5.5.79 5.5.77 5.5.76 5.5.75 5.5.73 5.5.72 5.5.22 5.5.23 5.5.29 5.5.3 5.5.31 5.5.32 5.5.34 5.5.35 5.5.36 5.5.37 5.5.4 5.5.40 5.5.41 5.5.42 5.5.43 All 159 releases
wp-data-access / admin / class-wp-data-access-admin.php

class-wp-data-access-admin.php in WP Data Access – App Builder for Tables, Forms, Charts, Maps & Dashboards 5.5.73, at admin/class-wp-data-access-admin.php

1,275 lines 45.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Suppress "error - 0 - No summary was found for this file" on phpdoc generation
5 *
6 * @package plugin\admin
7 */
8 use WPDataAccess\API\WPDA_API;
9 use WPDataAccess\Backup\WPDA_Data_Export;
10 use WPDataAccess\CSV_Files\WPDA_CSV_Import;
11 use WPDataAccess\Dashboard\WPDA_Dashboard;
12 use WPDataAccess\Data_Apps\WPDA_App_Builder;
13 use WPDataAccess\Data_Apps\WPDA_Data_Explorer;
14 use WPDataAccess\Global_Search\WPDA_Global_Search;
15 use WPDataAccess\List_Table\WPDA_List_View;
16 use WPDataAccess\Plugin_Table_Models\WPDA_App_Model;
17 use WPDataAccess\Plugin_Table_Models\WPDA_Design_Table_Model;
18 use WPDataAccess\Plugin_Table_Models\WPDA_Publisher_Model;
19 use WPDataAccess\Plugin_Table_Models\WPDA_User_Menus_Model;
20 use WPDataAccess\Premium\WPDAPRO_Data_Publisher\WPDAPRO_Data_Publisher_Manage_Styles;
21 use WPDataAccess\Settings\WPDA_Settings;
22 use WPDataAccess\Utilities\WPDA_Add_App_To_Menu;
23 use WPDataAccess\Utilities\WPDA_Repository;
24 use WPDataAccess\WPDA;
25 use WPDataAccess\WPDA_Navi\WPDA_Navi;
26 use WPDataProjects\WPDP;
27 /**
28 * Class WP_Data_Access_Admin
29 *
30 * Defines admin specific functionality for plugin WP Data Access.
31 *
32 * @author Peter Schulz
33 * @since 1.0.0
34 */
35 class WP_Data_Access_Admin {
36 /**
37 * Menu slug for main page
38 */
39 const PAGE_MAIN = 'wpda';
40
41 /**
42 * Menu slug for navigator page
43 */
44 const PAGE_NAVI = 'wpda_navi';
45
46 /**
47 * Menu slug for apps page
48 */
49 const PAGE_APPS = 'wpda_apps';
50
51 /**
52 * Menu slug for dashboard page
53 */
54 const PAGE_DASHBOARD = 'wpda_dashboard';
55
56 /**
57 * Menu slug for setting page
58 */
59 const PAGE_SETTINGS = 'wpdataaccess';
60
61 /**
62 * Menu slug for explorer page
63 */
64 const PAGE_EXPLORER = 'wpda_explorer';
65
66 /**
67 * Menu slug for query builder page
68 */
69 const PAGE_QUERY_BUILDER = 'wpda_query_builder';
70
71 /**
72 * Menu slug for Data Tables page
73 */
74 const PAGE_PUBLISHER = 'wpda_publisher';
75
76 /**
77 * Menu slug for charts page
78 */
79 const PAGE_CHARTS = 'wpda_charts';
80
81 /**
82 * Menu slug for designer page
83 */
84 const PAGE_DESIGNER = 'wpda_designer';
85
86 /**
87 * Plugin main page slug
88 */
89 const MAIN_PAGE_SLUG = self::PAGE_NAVI;
90
91 /**
92 * Menu slug for my tables page
93 */
94 const PAGE_MY_TABLES = 'wpda_my_tables';
95
96 /**
97 * Page hook suffix to Data Explorer page or false
98 *
99 * @var string|false
100 */
101 protected $wpda_data_explorer_menu;
102
103 /**
104 * Page hook suffix to Data Designer page or false
105 *
106 * @var string|false
107 */
108 protected $wpda_data_designer_menu;
109
110 /**
111 * Page hook suffix to Data Tables page or false
112 *
113 * @var string|false
114 */
115 protected $wpda_data_publisher_menu;
116
117 /**
118 * Page hook suffix to Charts page or false
119 *
120 * @var string|false
121 */
122 protected $wpda_charts_menu;
123
124 /**
125 * Reference to list view for Data Explorer page
126 *
127 * @var WPDA_List_View
128 */
129 protected $wpda_data_explorer_view;
130
131 /**
132 * Reference to list view for Data Designer page
133 *
134 * @var WPDA_List_View
135 */
136 protected $wpda_data_designer_view;
137
138 /**
139 * Reference to list view for Data Tables page
140 *
141 * @var WPDA_List_View
142 */
143 protected $wpda_data_publisher_view;
144
145 /**
146 * Reference to list view for Charts page
147 *
148 * @var WPDA_List_View
149 */
150 protected $wpda_charts_view;
151
152 /**
153 * Array of page hook suffixes to user defined sub menus
154 *
155 * @var array
156 */
157 protected $wpda_my_table_list_menu = array();
158
159 /**
160 * Array of list view for user defined sub menus
161 *
162 * @var array
163 */
164 protected $wpda_my_table_list_view = array();
165
166 /**
167 * Page hook suffix help page or false
168 *
169 * @var string|false
170 */
171 protected $wpda_help;
172
173 /**
174 * Menu slug or null
175 *
176 * @var null
177 */
178 protected $page = null;
179
180 /**
181 * Status loading indicator
182 *
183 * @var bool
184 */
185 protected $loaded_user_main_menu = false;
186
187 /**
188 * Main menu page
189 *
190 * @var null
191 */
192 protected $first_page = null;
193
194 /**
195 * WP_Data_Access_Admin constructor
196 *
197 * @since 1.0.0
198 */
199 public function __construct() {
200 if ( isset( $_REQUEST['page'] ) ) {
201 // phpcs:ignore WordPress.Security.NonceVerification
202 $this->page = sanitize_text_field( wp_unslash( $_REQUEST['page'] ) );
203 // phpcs:ignore WordPress.Security.NonceVerification
204 }
205 }
206
207 private function load_app_css() {
208 // WPDataAccess apps CSS.
209 wp_register_style(
210 'wpda_apps',
211 plugins_url( '../assets/css/wpda_apps.css', __FILE__ ),
212 array(),
213 WPDA::get_option( WPDA::OPTION_WPDA_VERSION )
214 );
215 }
216
217 /**
218 * Add stylesheets to back-end
219 *
220 * The following stylesheets are added:
221 * + Plugin stylesheet
222 * + Visual editor stylesheet
223 *
224 * The plugin stylesheet is used to style the setting forms {@see WPDA_Settings}, simple forms
225 * {@see \WPDataAccess\Simple_Form\WPDA_Simple_Form}.
226 *
227 * @since 1.0.0
228 *
229 * @see WPDA_Settings
230 * @see \WPDataAccess\Simple_Form\WPDA_Simple_Form
231 * @see WP_Data_Access_Public
232 */
233 public function enqueue_styles() {
234 if ( !WPDA::is_plugin_page( $this->page ) ) {
235 // Admin styles are only added to plugin admin pages.
236 // App pages still require the apps.css file.
237 $apps = WPDA_App_Model::add_to_dashboard_menu();
238 $css_added = false;
239 for ($i = 0; $i < count( $apps ) && !$css_added; $i++) {
240 $settings = json_decode( $apps[$i]['app_settings'], true );
241 if ( isset( $settings['settings']['app_menu_title'] ) && $this->page === $settings['settings']['app_menu_title'] ) {
242 $this->load_app_css();
243 $css_added = true;
244 }
245 }
246 return;
247 }
248 if ( self::PAGE_NAVI === $this->page ) {
249 // WPDataAccess CSS.
250 wp_enqueue_style(
251 'wpdanavi',
252 plugins_url( '../assets/css/wpda_navi.css', __FILE__ ),
253 array(),
254 WPDA::get_option( WPDA::OPTION_WPDA_VERSION )
255 );
256 }
257 wp_enqueue_style( 'wp-jquery-ui-core' );
258 wp_enqueue_style( 'wp-jquery-ui-dialog' );
259 wp_enqueue_style( 'wp-jquery-ui-sortable' );
260 wp_enqueue_style( 'wp-jquery-ui-tabs' );
261 $this->load_app_css();
262 // WPDataAccess CSS.
263 wp_enqueue_style(
264 'wpdataaccess',
265 plugins_url( '../assets/css/wpda_style.css', __FILE__ ),
266 array(),
267 WPDA::get_option( WPDA::OPTION_WPDA_VERSION )
268 );
269 // WPDataAccess dashboard.
270 wp_register_style(
271 'wpdataaccess_dashboard',
272 plugins_url( '../assets/css/wpda_dashboard.css', __FILE__ ),
273 array(),
274 WPDA::get_option( WPDA::OPTION_WPDA_VERSION )
275 );
276 // Add WP Data Projects stylesheet.
277 wp_enqueue_style(
278 'wpdataprojects',
279 plugins_url( '../WPDataProjects/assets/css/wpdp_style.css', __FILE__ ),
280 array(),
281 WPDA::get_option( WPDA::OPTION_WPDA_VERSION )
282 );
283 // Register datetimepicker external library.
284 wp_register_style(
285 'datetimepicker',
286 plugins_url( '../assets/css/jquery.datetimepicker.min.css', __FILE__ ),
287 array(),
288 WPDA::get_option( WPDA::OPTION_WPDA_VERSION )
289 );
290 // Register JQuery DataTables to use data tables in the dashboard.
291 wp_register_style(
292 'jquery_datatables',
293 plugins_url( '../assets/css/jquery.dataTables.min.css', __FILE__ ),
294 array(),
295 WPDA::get_option( WPDA::OPTION_WPDA_VERSION )
296 );
297 // Register JQuery DataTables Responsive to use data tables in the dashboard.
298 wp_register_style(
299 'jquery_datatables_responsive',
300 plugins_url( '../assets/css/responsive.dataTables.min.css', __FILE__ ),
301 array(),
302 WPDA::get_option( WPDA::OPTION_WPDA_VERSION )
303 );
304 if ( self::PAGE_MAIN === $this->page || self::PAGE_APPS === $this->page || self::PAGE_DASHBOARD === $this->page || self::PAGE_QUERY_BUILDER === $this->page || self::PAGE_PUBLISHER === $this->page || self::PAGE_CHARTS === $this->page ) {
305 // Load UI smoothness theme.
306 wp_enqueue_style(
307 'wpda_ui_smoothness',
308 plugins_url( '../assets/css/jquery-ui.smoothness.min.css', __FILE__ ),
309 array(),
310 WPDA::get_option( WPDA::OPTION_WPDA_VERSION )
311 );
312 } else {
313 // Load UI darkness theme.
314 wp_enqueue_style(
315 'wpda_ui_darkness',
316 plugins_url( '../assets/css/jquery-ui.min.css', __FILE__ ),
317 array(),
318 WPDA::get_option( WPDA::OPTION_WPDA_VERSION )
319 );
320 }
321 $hide_button_icons = WPDA::get_option( WPDA::OPTION_BE_HIDE_BUTTON_ICONS );
322 if ( false !== $hide_button_icons && 'on' !== $hide_button_icons ) {
323 // SAVING SPACE - According to the plugin guidelines it is allowed to include external fonts:
324 // https://developer.wordpress.org/plugins/wordpress-org/detailed-plugin-guidelines/#8-plugins-may-not-send-executable-code-via-third-party-systems .
325 // Load fontawesome icons.
326 wp_enqueue_style(
327 // phpcs:ignore WordPress.WP.EnqueuedResourceParameters
328 'wpda_fontawesome_icons',
329 WPDA::CDN_FONTAWESOME . 'all.min.css',
330 array(),
331 null,
332 false
333 );
334 }
335 if ( self::PAGE_PUBLISHER === $this->page ) {
336 wp_register_style(
337 'wpda_datatables_default',
338 plugins_url( '../assets/css/wpda_datatables_default.css', __FILE__ ),
339 array(),
340 WPDA::get_option( WPDA::OPTION_WPDA_VERSION )
341 );
342 // Add jQuery multiselect resources.
343 wp_enqueue_style(
344 'wpda_jquery_multiselect',
345 plugins_url( '../assets/css/jquery.multiselect.sortable.js.css', __FILE__ ),
346 array(),
347 WPDA::get_option( WPDA::OPTION_WPDA_VERSION ),
348 false
349 );
350 }
351 if ( self::PAGE_QUERY_BUILDER === $this->page ) {
352 // Add Query Builder resources.
353 wp_enqueue_style(
354 'wpda_query_builder',
355 plugins_url( '../assets/css/wpda_query_builder.css', __FILE__ ),
356 array(),
357 WPDA::get_option( WPDA::OPTION_WPDA_VERSION )
358 );
359 wp_enqueue_style(
360 'wpda_jquery_json_viewer',
361 plugins_url( '../assets/css/jquery.json-viewer.css', __FILE__ ),
362 array(),
363 WPDA::get_option( WPDA::OPTION_WPDA_VERSION )
364 );
365 }
366 if ( !WPDA::current_user_is_admin() ) {
367 wp_enqueue_style(
368 'wpda_non_admin',
369 plugins_url( '../assets/css/wpda_non_admin.css', __FILE__ ),
370 array(),
371 WPDA::get_option( WPDA::OPTION_WPDA_VERSION )
372 );
373 }
374 }
375
376 /**
377 * Remove icons from buttons (if configured)
378 *
379 * @return void
380 */
381 public function remove_icons() {
382 if ( !WPDA::is_plugin_page( $this->page ) ) {
383 // Only executed on plugin pages.
384 return;
385 }
386 if ( 'on' === WPDA::get_option( WPDA::OPTION_BE_HIDE_BUTTON_ICONS ) ) {
387 echo '
388 <style>
389 i.fas.wpda_icon_on_button {
390 display: none;
391 }
392 </style>
393 ';
394 }
395 }
396
397 /**
398 * Add scripts to back-end
399 *
400 * @since 1.0.0
401 *
402 * @see WP_Data_Access_Public
403 */
404 public function enqueue_scripts() {
405 if ( !WPDA::is_plugin_page( $this->page ) ) {
406 // Admin styles are only added to plugin admin pages.
407 return;
408 }
409 wp_enqueue_script( 'jquery-ui-core' );
410 wp_enqueue_script( 'jquery-ui-dialog' );
411 wp_enqueue_script( 'jquery-ui-tabs' );
412 wp_enqueue_script( 'jquery-ui-sortable' );
413 wp_enqueue_script( 'jquery-ui-tooltip' );
414 wp_enqueue_script( 'jquery-ui-autocomplete' );
415 // Register wpda rest api.
416 wp_enqueue_script(
417 'wpda_rest_api',
418 plugins_url( '../assets/js/wpda_rest_api.js', __FILE__ ),
419 array('wp-api'),
420 WPDA::get_option( WPDA::OPTION_WPDA_VERSION ),
421 false
422 );
423 wp_localize_script( 'wpda_rest_api', 'wpdaApiSettings', array(
424 'path' => WPDA_API::WPDA_NAMESPACE,
425 ) );
426 // Register wpda admin functions.
427 wp_enqueue_script(
428 'wpda_admin_scripts',
429 plugins_url( '../assets/js/wpda_admin.js', __FILE__ ),
430 array(),
431 WPDA::get_option( WPDA::OPTION_WPDA_VERSION ),
432 false
433 );
434 wp_localize_script( 'wpda_admin_scripts', 'wpda_admin_vars', array(
435 'wpda_ajaxurl' => admin_url( 'admin-ajax.php' ),
436 ) );
437 // Register dashboard.
438 wp_register_script(
439 'wpdataaccess_dashboard',
440 plugins_url( '../assets/js/wpda_dashboard.js', __FILE__ ),
441 array(),
442 WPDA::get_option( WPDA::OPTION_WPDA_VERSION ),
443 false
444 );
445 wp_localize_script( 'wpdataaccess_dashboard', 'wpda_dashboard_vars', array(
446 'wpda_ajaxurl' => admin_url( 'admin-ajax.php' ),
447 ) );
448 // Add WP Data Projects JS functions.RESEARCH.
449 wp_enqueue_script(
450 'wpdataprojects',
451 plugins_url( '../WPDataProjects/assets/js/wpdp_admin.js', __FILE__ ),
452 array(),
453 WPDA::get_option( WPDA::OPTION_WPDA_VERSION ),
454 false
455 );
456 // Register jQuery DataTables to use data tables in the dashboard.
457 wp_register_script(
458 'jquery_datatables',
459 plugins_url( '../assets/js/jquery.dataTables.min.js', __FILE__ ),
460 array(),
461 WPDA::get_option( WPDA::OPTION_WPDA_VERSION ),
462 false
463 );
464 // Register jQuery DataTables Responsive to use data tables in the dashboard.
465 wp_register_script(
466 'jquery_datatables_responsive',
467 plugins_url( '../assets/js/dataTables.responsive.min.js', __FILE__ ),
468 array(),
469 WPDA::get_option( WPDA::OPTION_WPDA_VERSION ),
470 false
471 );
472 // Ajax call to WPDA datatables implementation to use data tables in the dashboard.
473 wp_register_script(
474 'wpda_datatables',
475 plugins_url( '../assets/js/wpda_datatables.js', __FILE__ ),
476 array(),
477 WPDA::get_option( WPDA::OPTION_WPDA_VERSION ),
478 false
479 );
480 wp_localize_script( 'wpda_datatables', 'wpda_publication_vars', array(
481 'wpda_ajaxurl' => admin_url( 'admin-ajax.php' ),
482 ) );
483 // Register notify external library.
484 wp_enqueue_script(
485 'wpda_notify',
486 plugins_url( '../assets/js/notify.min.js', __FILE__ ),
487 array(),
488 WPDA::get_option( WPDA::OPTION_WPDA_VERSION ),
489 false
490 );
491 // Register datetimepicker external library.
492 wp_register_script(
493 'datetimepicker',
494 plugins_url( '../assets/js/jquery.datetimepicker.full.min.js', __FILE__ ),
495 array(),
496 WPDA::get_option( WPDA::OPTION_WPDA_VERSION ),
497 false
498 );
499 // Register clipboard.js.
500 wp_enqueue_script( 'clipboard' );
501 if ( self::PAGE_PUBLISHER === $this->page ) {
502 if ( isset( $_REQUEST['action'] ) && in_array( $_REQUEST['action'], array('view', 'new', 'edit'), true ) ) {
503 $json_editing = WPDA::get_option( WPDA::OPTION_DP_JSON_EDITING );
504 if ( WPDA::OPTION_DP_JSON_EDITING[1] === $json_editing ) {
505 // Register codeEditor to support JSON editing in Data Tables (table options advanced).
506 $cm_settings['codeEditor'] = wp_enqueue_code_editor( array(
507 'type' => 'application/json',
508 'codemirror' => array(
509 'autoRefresh' => true,
510 ),
511 ) );
512 wp_localize_script( 'wp-theme-plugin-editor', 'cm_settings', $cm_settings );
513 wp_enqueue_script( 'wp-theme-plugin-editor' );
514 }
515 // Add jQuery multiselect resources.
516 wp_enqueue_script(
517 'wpda_jquery_multiselect',
518 plugins_url( '../assets/js/jquery.multiselect.sortable.js', __FILE__ ),
519 array(),
520 WPDA::get_option( WPDA::OPTION_WPDA_VERSION ),
521 false
522 );
523 }
524 }
525 if ( self::PAGE_CHARTS === $this->page ) {
526 $this->load_google_charts();
527 }
528 if ( self::PAGE_QUERY_BUILDER === $this->page ) {
529 // Add Query Builder resources.
530 wp_enqueue_script(
531 'wpda_query_builder',
532 plugins_url( '../assets/js/wpda_query_builder.js', __FILE__ ),
533 array(),
534 WPDA::get_option( WPDA::OPTION_WPDA_VERSION ),
535 false
536 );
537 wp_enqueue_script(
538 'wpda_jquery_xml2json',
539 plugins_url( '../assets/js/jquery.xml2json.js', __FILE__ ),
540 array(),
541 WPDA::get_option( WPDA::OPTION_WPDA_VERSION ),
542 false
543 );
544 wp_enqueue_script(
545 'wpda_jquery_json_viewer',
546 plugins_url( '../assets/js/jquery.json-viewer.js', __FILE__ ),
547 array(),
548 WPDA::get_option( WPDA::OPTION_WPDA_VERSION ),
549 false
550 );
551 // Add codeEditor to query builder.
552 $cm_settings['codeEditor'] = wp_enqueue_code_editor( array(
553 'type' => 'text/x-sql',
554 'codemirror' => array(
555 'mode' => 'sql',
556 'lineNumbers' => true,
557 'autoRefresh' => true,
558 'lineWrapping' => true,
559 'styleActiveLine' => true,
560 ),
561 ) );
562 wp_enqueue_script( 'wp-theme-plugin-editor' );
563 wp_localize_script( 'wp-theme-plugin-editor', 'cm_settings', $cm_settings );
564 wp_enqueue_style( 'wp-codemirror' );
565 }
566 if ( self::PAGE_DASHBOARD === $this->page ) {
567 $this->load_google_charts();
568 // Load DBMS panels.
569 wp_enqueue_script(
570 'wpda_dbms',
571 plugins_url( '../assets/js/wpda_dbms.js', __FILE__ ),
572 array(),
573 WPDA::get_option( WPDA::OPTION_WPDA_VERSION ),
574 false
575 );
576 wp_localize_script( 'wpda_dbms', 'wpda_dbms_vars', array(
577 'wpda_ajaxurl' => admin_url( 'admin-ajax.php' ),
578 ) );
579 }
580 wp_enqueue_media();
581 }
582
583 /**
584 * Load Google Charts resources
585 *
586 * @return void
587 */
588 private function load_google_charts() {
589 // Load Google Charts.
590 wp_enqueue_script(
591 'wpda_google_charts',
592 WPDA::GOOGLE_CHARTS,
593 array(),
594 null,
595 false
596 );
597 wp_enqueue_script(
598 'wpda_google_charts_fnc',
599 plugins_url( '../assets/js/wpda_google_charts.js', __FILE__ ),
600 array(),
601 WPDA::get_option( WPDA::OPTION_WPDA_VERSION ),
602 false
603 );
604 wp_localize_script( 'wpda_google_charts_fnc', 'wpda_chart_vars', array(
605 'wpda_ajaxurl' => admin_url( 'admin-ajax.php' ),
606 'wpda_chartdir' => plugin_dir_url( __FILE__ ) . '../assets/images/google_chart_types/',
607 'wpda_premium' => ( wpda_freemius()->can_use_premium_code__premium_only() ? 'true' : 'false' ),
608 ) );
609 }
610
611 /**
612 * Hide admin notices
613 *
614 * @return void
615 */
616 public function user_admin_notices() {
617 if ( WPDA::is_plugin_page( $this->page ) && 'on' === WPDA::get_option( WPDA::OPTION_PLUGIN_HIDE_NOTICES ) ) {
618 remove_all_actions( 'admin_notices' );
619 remove_all_actions( 'all_admin_notices' );
620 }
621 }
622
623 /**
624 * Add plugin menu and sub menus
625 *
626 * Adds the following menu and sub menus to the back-end menu:
627 * + WP Data Access
628 * + Data Explorer
629 * + Data Designer
630 * + Data Projects
631 * + Manage Plugin
632 *
633 * @since 1.0.0
634 */
635 public function add_menu_items() {
636 if ( WPDA::current_user_is_admin() ) {
637 if ( 'on' === WPDA::get_option( WPDA::OPTION_PLUGIN_HIDE_ADMIN_MENU ) ) {
638 // Show Data Projects.
639 $this->add_data_projects();
640 // Hide admin menu.
641 return;
642 }
643 if ( self::PAGE_MAIN === $this->page && isset( $_REQUEST['de'] ) ) {
644 if ( 'new' === $_REQUEST['de'] ) {
645 update_user_meta( WPDA::get_current_user_id(), 'wpda_data_explorer', 'new' );
646 } elseif ( 'old' === $_REQUEST['de'] ) {
647 update_user_meta( WPDA::get_current_user_id(), 'wpda_data_explorer', 'old' );
648 }
649 }
650 if ( self::PAGE_QUERY_BUILDER === $this->page && isset( $_REQUEST['qb'] ) ) {
651 if ( 'new' === $_REQUEST['qb'] ) {
652 update_user_meta( WPDA::get_current_user_id(), 'wpda_query_builder_version', 'new' );
653 } elseif ( 'old' === $_REQUEST['qb'] ) {
654 update_user_meta( WPDA::get_current_user_id(), 'wpda_query_builder_version', 'old' );
655 }
656 }
657 // Specific list tables (and forms) can be made available for specific capabilities:
658 // managed in method add_menu_my_tables.
659 // Main menu and items are only available to admin users (set capability to 'manage_options').
660 add_menu_page(
661 'WP Data Access',
662 'WP Data Access',
663 'manage_options',
664 self::MAIN_PAGE_SLUG,
665 null,
666 'dashicons-database',
667 999999999
668 );
669 // Add navigator page to WPDA menu.
670 add_submenu_page(
671 self::MAIN_PAGE_SLUG,
672 'WP Data Access',
673 'Tool Guide',
674 'manage_options',
675 self::PAGE_NAVI,
676 array($this, 'data_navi')
677 );
678 // Add apps to menu.
679 add_submenu_page(
680 self::MAIN_PAGE_SLUG,
681 'WP Data Access',
682 'App Builder',
683 'manage_options',
684 self::PAGE_APPS,
685 array($this, 'data_apps')
686 );
687 // Add data explorer to WPDA menu.
688 $current_data_explorer_version = get_user_meta( WPDA::get_current_user_id(), 'wpda_data_explorer', true );
689 if ( isset( $_POST['explorer'] ) && 'OLD' === $_POST['explorer'] ) {
690 $current_data_explorer_version = true;
691 }
692 $this->wpda_data_explorer_menu = add_submenu_page(
693 self::MAIN_PAGE_SLUG,
694 'WP Data Access',
695 'Data Explorer',
696 'manage_options',
697 self::PAGE_MAIN,
698 array($this, ( 'new' !== $current_data_explorer_version && '' !== $current_data_explorer_version ? 'data_explorer_page' : 'data_explorer_page_new' ))
699 );
700 if ( self::PAGE_MAIN === $this->page ) {
701 if ( 'new' !== $current_data_explorer_version && '' !== $current_data_explorer_version ) {
702 $args = array(
703 'page_hook_suffix' => $this->wpda_data_explorer_menu,
704 );
705 $this->wpda_data_explorer_view = new WPDA_List_View($args);
706 }
707 }
708 // Add submenu for Query Builder.
709 $current_query_builder_version = get_user_meta( WPDA::get_current_user_id(), 'wpda_query_builder_version', true );
710 $this->wpda_data_publisher_menu = add_submenu_page(
711 self::MAIN_PAGE_SLUG,
712 'WP Data Access',
713 'SQL Query Builder',
714 'manage_options',
715 self::PAGE_QUERY_BUILDER,
716 array($this, ( $current_query_builder_version === 'old' ? 'query_builder_old' : 'query_builder' ))
717 );
718 // Add submenu for Data Tables.
719 $this->wpda_data_publisher_menu = add_submenu_page(
720 self::MAIN_PAGE_SLUG,
721 'WP Data Access',
722 'Table Builder',
723 'manage_options',
724 self::PAGE_PUBLISHER,
725 array($this, 'data_publisher_page')
726 );
727 if ( self::PAGE_PUBLISHER === $this->page ) {
728 $this->wpda_data_publisher_view = new WPDA_List_View(array(
729 'page_hook_suffix' => $this->wpda_data_publisher_menu,
730 'table_name' => WPDA_Publisher_Model::get_base_table_name(),
731 'list_table_class' => 'WPDataAccess\\Data_Publisher\\WPDA_Publisher_List_Table',
732 'edit_form_class' => 'WPDataAccess\\Data_Publisher\\WPDA_Publisher_Form',
733 ));
734 }
735 // Add Data Projects menu.
736 $wpdp = new WPDP(self::MAIN_PAGE_SLUG);
737 $wpdp->add_menu_items();
738 // Add data designer to WPDA menu.
739 $this->wpda_data_designer_menu = add_submenu_page(
740 self::MAIN_PAGE_SLUG,
741 'WP Data Access',
742 'Data Designer',
743 'manage_options',
744 self::PAGE_DESIGNER,
745 array($this, 'data_designer_page')
746 );
747 if ( self::PAGE_DESIGNER === $this->page ) {
748 $this->wpda_data_designer_view = new WPDA_List_View(array(
749 'page_hook_suffix' => $this->wpda_data_designer_menu,
750 'table_name' => WPDA_Design_Table_Model::get_base_table_name(),
751 'list_table_class' => 'WPDataAccess\\Design_Table\\WPDA_Design_Table_List_Table',
752 'edit_form_class' => 'WPDataAccess\\Design_Table\\WPDA_Design_Table_Form',
753 'subtitle' => '',
754 ));
755 }
756 } else {
757 $this->grant_access_to_dashboard();
758 $this->grant_access_to_data_publications();
759 }
760 $this->add_data_projects();
761 $this->add_apps();
762 }
763
764 /**
765 * Remove plugin sub menu items (when in dashboard mode)
766 *
767 * @param mixed $submenu_file Dashboard menu items.
768 * @return mixed
769 */
770 public function wpda_submenu_filter( $submenu_file ) {
771 if ( WPDA::current_user_is_admin() ) {
772 $hidden_submenus = array(
773 self::PAGE_DASHBOARD,
774 self::PAGE_CHARTS,
775 self::PAGE_PUBLISHER,
776 WPDP::PAGE_MAIN,
777 self::PAGE_DESIGNER,
778 WPDP::PAGE_TEMPLATES,
779 self::MAIN_PAGE_SLUG . '-account',
780 self::MAIN_PAGE_SLUG . '-wp-support-forum'
781 );
782 foreach ( $hidden_submenus as $submenu ) {
783 remove_submenu_page( self::MAIN_PAGE_SLUG, $submenu );
784 }
785 } else {
786 global $submenu;
787 $submenu[self::PAGE_MAIN][0][2] = self::PAGE_DASHBOARD;
788 // phpcs:ignore WordPress.WP.GlobalVariablesOverride
789 }
790 return $submenu_file;
791 }
792
793 /**
794 * Add apps to dashboard menu.
795 *
796 * @return void
797 */
798 protected function add_apps() {
799 // Add apps to dashbaord menu
800 $apps = new WPDA_Add_App_To_Menu();
801 $apps->add_apps_to_menu();
802 }
803
804 /**
805 * Add Data Projects and Project Templates to plugin navigation
806 *
807 * @return void
808 */
809 protected function add_data_projects() {
810 // Add Data Projects.
811 $wpdp = new WPDP();
812 $wpdp->add_projects();
813 }
814
815 /**
816 * Allow authorized users to access WP Data Access dashboard
817 *
818 * @return void
819 */
820 protected function grant_access_to_dashboard() {
821 // Check user role.
822 $user_roles = WPDA::get_current_user_roles();
823 if ( false === $user_roles || !is_array( $user_roles ) ) {
824 // Cannot determine the user roles (not able to show menus).
825 return;
826 }
827 // Check dashboard role access.
828 $dashboard_roles = get_option( \WPDataAccess\Settings\WPDA_Settings_Legacy_Dashboard::DASHBOARD_ROLES );
829 $user_has_role = false;
830 foreach ( $user_roles as $user_role ) {
831 if ( false !== strpos( $dashboard_roles, $user_role ) ) {
832 $user_has_role = true;
833 break;
834 }
835 }
836 // Check dashboard user access.
837 $dashboard_users = get_option( \WPDataAccess\Settings\WPDA_Settings_Legacy_Dashboard::DASHBOARD_USERS );
838 $user_has_access = false !== strpos( $dashboard_users, WPDA::get_current_user_login() );
839 if ( !$user_has_role && !$user_has_access ) {
840 return;
841 }
842 // User has dashboard access: add menu item.
843 $this->create_non_admin_menu( self::PAGE_DASHBOARD );
844 add_submenu_page(
845 $this->first_page,
846 'Dashboard',
847 'Dashboard',
848 WPDA::get_current_user_capability(),
849 self::PAGE_DASHBOARD,
850 array($this, 'data_dashboard_page')
851 );
852 }
853
854 /**
855 * Allow authorized users to access Data Tables
856 *
857 * @return void
858 */
859 protected function grant_access_to_data_publications() {
860 // Check user role.
861 $user_roles = WPDA::get_current_user_roles();
862 if ( false === $user_roles || !is_array( $user_roles ) ) {
863 // Cannot determine the user roles (not able to show menus).
864 return;
865 }
866 $publication_roles = WPDA::get_option( WPDA::OPTION_DP_PUBLICATION_ROLES );
867 if ( '' === $publication_roles || 'administrator' === $publication_roles ) {
868 // No access.
869 return;
870 }
871 $user_has_role = false;
872 foreach ( $user_roles as $user_role ) {
873 if ( false !== stripos( $publication_roles, $user_role ) ) {
874 $user_has_role = true;
875 }
876 }
877 if ( !$user_has_role ) {
878 // No access.
879 return;
880 }
881 // Grant access to main menu.
882 $this->create_non_admin_menu( self::PAGE_PUBLISHER );
883 // Add submenu for Data Tables.
884 $this->wpda_data_publisher_menu = add_submenu_page(
885 $this->first_page,
886 'WP Data Access',
887 'Data Tables',
888 WPDA::get_current_user_capability(),
889 self::PAGE_PUBLISHER,
890 array($this, 'data_publisher_page')
891 );
892 if ( self::PAGE_PUBLISHER === $this->page ) {
893 global $wpdb;
894 $this->wpda_data_publisher_view = new WPDA_List_View(array(
895 'page_hook_suffix' => $this->wpda_data_publisher_menu,
896 'table_name' => $wpdb->prefix . 'wpda_publisher',
897 'list_table_class' => 'WPDataAccess\\Data_Publisher\\WPDA_Publisher_List_Table',
898 'edit_form_class' => 'WPDataAccess\\Data_Publisher\\WPDA_Publisher_Form',
899 ));
900 }
901 }
902
903 /**
904 * Add dashboard page
905 *
906 * @return void
907 */
908 public function data_dashboard_page() {
909 WPDA_Dashboard::add_dashboard( true );
910 }
911
912 /**
913 * Show data explorer main page
914 *
915 * Initialization of $this->wpda_data_explorer_view is done earlier in
916 * {@see WP_Data_Access_Admin::add_menu_items()} to support screen options. This method just shows the page
917 * containing the list table.
918 *
919 * @since 1.0.0
920 *
921 * @see WP_Data_Access_Admin::add_menu_items()
922 */
923 public function data_explorer_page() {
924 WPDA_Dashboard::add_dashboard();
925 if ( isset( $_REQUEST['page_action'] ) && 'wpda_backup' === $_REQUEST['page_action'] ) {
926 // phpcs:ignore WordPress.Security.NonceVerification
927 $this->backup_page();
928 } elseif ( isset( $_REQUEST['page_action'] ) && 'wpda_import_csv' === $_REQUEST['page_action'] ) {
929 // phpcs:ignore WordPress.Security.NonceVerification
930 $this->import_csv();
931 } elseif ( isset( $_REQUEST['page_action'] ) && 'wpda_global_search' === $_REQUEST['page_action'] ) {
932 // phpcs:ignore WordPress.Security.NonceVerification
933 $this->advanced_search();
934 } else {
935 $this->wpda_data_explorer_view->show();
936 }
937 }
938
939 public function data_explorer_page_new() {
940 WPDA_Dashboard::add_dashboard();
941 if ( isset( $_REQUEST['page_action'] ) && 'wpda_backup' === $_REQUEST['page_action'] ) {
942 // phpcs:ignore WordPress.Security.NonceVerification
943 $this->backup_page();
944 } elseif ( isset( $_REQUEST['page_action'] ) && 'wpda_import_csv' === $_REQUEST['page_action'] ) {
945 // phpcs:ignore WordPress.Security.NonceVerification
946 $this->import_csv();
947 } elseif ( isset( $_REQUEST['page_action'] ) && 'wpda_global_search' === $_REQUEST['page_action'] ) {
948 // phpcs:ignore WordPress.Security.NonceVerification
949 $this->advanced_search();
950 } else {
951 $explorer = new WPDA_Data_Explorer();
952 $explorer->show();
953 }
954 }
955
956 public function data_navi() {
957 if ( isset( $_POST['wpda-legacy-tool-status'] ) ) {
958 // Legacy tools update
959 $update_status = json_decode( sanitize_text_field( wp_unslash( $_POST['wpda-legacy-tool-status'] ) ), true );
960 if ( null !== $update_status ) {
961 if ( isset(
962 $update_status['tables'],
963 $update_status['forms'],
964 $update_status['templates'],
965 $update_status['designer'],
966 $update_status['dashboards'],
967 $update_status['charts']
968 ) ) {
969 // Get current legacy tool settings
970 $option_legacy_tools = \WPDataAccess\Utilities\WPDA_Legacy_Tool_Visibility::get();
971 // Update legacy tool settings
972 $option_legacy_tools['tables'][0] = $update_status['tables'];
973 $option_legacy_tools['forms'][0] = $update_status['forms'];
974 $option_legacy_tools['templates'][0] = $update_status['templates'];
975 $option_legacy_tools['designer'][0] = $update_status['designer'];
976 $option_legacy_tools['dashboards'][0] = $update_status['dashboards'];
977 $option_legacy_tools['charts'][0] = $update_status['charts'];
978 // Save legacy tool settings
979 WPDA::set_option( WPDA::OPTION_PLUGIN_LEGACY_TOOLS, $option_legacy_tools );
980 }
981 }
982 }
983 WPDA_Dashboard::add_dashboard();
984 $navi = new WPDA_Navi();
985 $navi->show();
986 }
987
988 public function data_apps() {
989 WPDA_Dashboard::add_dashboard();
990 $wpda_app_builder = new WPDA_App_Builder();
991 $wpda_app_builder->show();
992 }
993
994 public function advanced_search() {
995 $advanced_search = new WPDA_Global_Search();
996 $advanced_search->show();
997 }
998
999 /**
1000 * Add Query Builder
1001 *
1002 * @return void
1003 */
1004 public function query_builder() {
1005 WPDA_Dashboard::add_dashboard();
1006 $query_builder = new \WPDataAccess\Data_Apps\WPDA_Query_Builder();
1007 $query_builder->show();
1008 }
1009
1010 public function query_builder_old() {
1011 WPDA_Dashboard::add_dashboard();
1012 $query_builder = new \WPDataAccess\Query_Builder\WPDA_Query_Builder();
1013 $query_builder->show();
1014 }
1015
1016 /**
1017 * Add CSV page
1018 *
1019 * @return void
1020 */
1021 public function import_csv() {
1022 $csv_import = new WPDA_CSV_Import();
1023 $csv_import->show();
1024 }
1025
1026 /**
1027 * Show data designer main page
1028 *
1029 * Initialization of $this->wpda_data_designer_view is done earlier in
1030 * {@see WP_Data_Access_Admin::add_menu_items()} to support screen options. This method just shows the page
1031 * containing the list table.
1032 *
1033 * @since 1.0.0
1034 *
1035 * @see WP_Data_Access_Admin::add_menu_items()
1036 */
1037 public function data_designer_page() {
1038 WPDA_Dashboard::add_dashboard();
1039 $data_designer_table_found = WPDA_Design_Table_Model::table_exists();
1040 if ( $data_designer_table_found ) {
1041 $this->wpda_data_designer_view->show();
1042 } else {
1043 $this->data_designer_page_not_found();
1044 }
1045 }
1046
1047 /**
1048 * Data Designer repository table not found
1049 */
1050 public function data_designer_page_not_found() {
1051 WPDA_Dashboard::add_dashboard();
1052 $wpda_repository = new WPDA_Repository();
1053 $wpda_repository->inform_user();
1054 ?>
1055 <div class="wrap">
1056 <h1 class="wp-heading-inline">
1057 <span>Data Designer</span>
1058 <a href="https://docs.legacy.wpdataaccess.com/docs/data-designer-getting-started/" target="_blank" class="wpda_tooltip" title="Plugin Help - opens in a new tab or window">
1059 <span class="dashicons dashicons-editor-help" style="text-decoration:none;vertical-align:top;font-size:30px;">
1060 </span>
1061 </a>
1062 </h1>
1063 <p>
1064 <?php
1065 echo __( 'ERROR: Repository table not found!', 'wp-data-access' );
1066 // phpcs:ignore WordPress.Security.EscapeOutput
1067 ?>
1068 </p>
1069 </div>
1070 <?php
1071 }
1072
1073 /**
1074 * Show Data Tables main page
1075 */
1076 public function data_publisher_page() {
1077 if ( WPDA::current_user_is_admin() ) {
1078 WPDA_Dashboard::add_dashboard();
1079 }
1080 $data_publisher_table_found = WPDA_Publisher_Model::table_exists();
1081 if ( $data_publisher_table_found ) {
1082 $this->wpda_data_publisher_view->show();
1083 } else {
1084 $this->data_publisher_page_not_found();
1085 }
1086 }
1087
1088 public function data_publisher_mngstl() {
1089 $mngstl = new WPDAPRO_Data_Publisher_Manage_Styles();
1090 $mngstl->show();
1091 }
1092
1093 /**
1094 * Add Charts page
1095 *
1096 * @return void
1097 */
1098 public function data_charts_page() {
1099 }
1100
1101 /**
1102 * Data Tables repository table not found
1103 */
1104 public function data_publisher_page_not_found() {
1105 if ( WPDA::current_user_is_admin() ) {
1106 WPDA_Dashboard::add_dashboard();
1107 }
1108 $wpda_repository = new WPDA_Repository();
1109 $wpda_repository->inform_user();
1110 ?>
1111 <div class="wrap">
1112 <h1 class="wp-heading-inline">
1113 <span>Data Tables</span>
1114 <a href="https://docs.legacy.wpdataaccess.com/docs/data-tables-getting-started/" target="_blank" class="wpda_tooltip" title="Plugin Help - opens in a new tab or window">
1115 <span class="dashicons dashicons-editor-help" style="text-decoration:none;vertical-align:top;font-size:30px;">
1116 </span>
1117 </a>
1118 </h1>
1119 <p>
1120 <?php
1121 echo __( 'ERROR: Repository table not found!', 'wp-data-access' );
1122 // phpcs:ignore WordPress.Security.EscapeOutput
1123 ?>
1124 </p>
1125 </div>
1126 <?php
1127 }
1128
1129 /**
1130 * Show data backup main page
1131 *
1132 * Calls a page to create automatic backups (in fact data exports) and offers possibilities to restore (in fact
1133 * data imports).
1134 *
1135 * @since 2.0.6
1136 *
1137 * @see WPDA_Data_Export::show_wp_cron()
1138 */
1139 public function backup_page() {
1140 $wpda_backup = new WPDA_Data_Export();
1141 $wp_nonce = ( isset( $_REQUEST['wp_nonce'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['wp_nonce'] ) ) : '?' );
1142 // phpcs:ignore WordPress.Security.NonceVerification
1143 if ( isset( $_REQUEST['action'] ) && wp_verify_nonce( $wp_nonce, 'wpda-backup-' . WPDA::get_current_user_login() ) ) {
1144 // phpcs:ignore WordPress.Security.NonceVerification
1145 $action = sanitize_text_field( wp_unslash( $_REQUEST['action'] ) );
1146 // phpcs:ignore WordPress.Security.NonceVerification
1147 if ( 'new' === $action ) {
1148 $wpda_backup->create_export( 'add' );
1149 } elseif ( 'add' === $action ) {
1150 $wpda_backup->wpda_add_cron_job();
1151 } elseif ( 'remove' === $action ) {
1152 $wpda_backup->wpda_remove_cron_job();
1153 } elseif ( 'edit' === $action ) {
1154 $wpda_backup->create_export( 'update' );
1155 } elseif ( 'update' === $action ) {
1156 $wpda_backup->wpda_update_cron_job();
1157 }
1158 } else {
1159 $wpda_backup->show_wp_cron();
1160 }
1161 }
1162
1163 /**
1164 * Add user defined sub menu
1165 *
1166 * WPDA allows users to create sub menu for table lists and simple forms. Sub menus can be added to the WPDA
1167 * menu or any other (external) menu. A sub menu is added to an external menu via the menu slug. Sub menus are
1168 * taken from {@see WPDA_User_Menus_Model}.
1169 *
1170 * This method is called from the admin_menu action with a lower priority to make sure other menus are available.
1171 * User defined menu items are added to available menus in this method. These can be WPDA menus or external menus
1172 * as mentioned in the according list table and edit form. WPDA menus are added to menu WP Data Tables. External
1173 * menus are added to the menu having the menu slug defined by the user.
1174 *
1175 * This method does not actually show the list tables! It just creates the menu items. When the user clicks on such
1176 * a dynamically defined menu item, method {@see WP_Data_Access_Admin::my_tables_page()} is called, which takes
1177 * care of showing the list table.
1178 *
1179 * @since 1.0.0
1180 *
1181 * @see WP_Data_Access_Admin::my_tables_page()
1182 * @see WPDA_User_Menus_Model
1183 */
1184 public function add_menu_my_tables() {
1185 $menus_shown_to_current_user = array();
1186 // Add list tables to external menus.
1187 foreach ( WPDA_User_Menus_Model::list_external_menus() as $menu ) {
1188 $user_roles = WPDA::get_current_user_roles();
1189 $user_has_role = false;
1190 if ( '' === $menu->menu_role || null === $menu->menu_role ) {
1191 $user_has_role = in_array( 'administrator', $user_roles, true );
1192 } else {
1193 $user_role_array = explode( ',', (string) $menu->menu_role );
1194 //phpcs:ignore - 8.1 proof
1195 foreach ( $user_role_array as $user_role_array_item ) {
1196 $user_has_role = in_array( $user_role_array_item, $user_roles, true );
1197 //phpcs:ignore - 8.1 proof
1198 if ( $user_has_role ) {
1199 break;
1200 }
1201 }
1202 }
1203 if ( $user_has_role ) {
1204 if ( !isset( $menus_shown_to_current_user[$menu->menu_slug . '/' . $menu->menu_name . '/' . $menu->menu_table_name . '/' . $menu->menu_schema_name] ) ) {
1205 $menu_slug = self::PAGE_EXPLORER . '_' . $menu->menu_table_name;
1206 $menu_index = $menu->menu_table_name;
1207 $this->create_non_admin_menu( $menu_slug );
1208 $this->wpda_my_table_list_menu[$menu_index] = add_submenu_page(
1209 $this->first_page,
1210 'WP Data Access : ' . strtoupper( $menu->menu_table_name ),
1211 $menu->menu_name,
1212 WPDA::get_current_user_capability(),
1213 $menu_slug,
1214 array($this, 'my_tables_page')
1215 );
1216 $this->wpda_my_table_list_view[$menu_index] = new WPDA_List_View(array(
1217 'page_hook_suffix' => $this->wpda_my_table_list_menu[$menu_index],
1218 'wpdaschema_name' => $menu->menu_schema_name,
1219 'table_name' => $menu->menu_table_name,
1220 ));
1221 $menus_shown_to_current_user[$menu->menu_slug . '/' . $menu->menu_name . '/' . $menu_index . '/' . $menu->menu_schema_name] = true;
1222 }
1223 }
1224 }
1225 }
1226
1227 /**
1228 * Show user defined menus
1229 *
1230 * A user defined menu that are added to the plugin menu in {@see WP_Data_Access_Admin::add_menu_my_tables()} is
1231 * shown here. This method is called when the user clicks on the menu item generated in
1232 * {@see WP_Data_Access_Admin::add_menu_my_tables()}.
1233 *
1234 * @since 1.0.0
1235 *
1236 * @see WP_Data_Access_Admin::add_menu_my_tables()
1237 */
1238 public function my_tables_page() {
1239 // Grab table name from menu slug.
1240 if ( null !== $this->page ) {
1241 if ( strpos( $this->page, self::PAGE_EXPLORER ) !== false ) {
1242 $table = substr( $this->page, strlen( self::PAGE_EXPLORER . '_' ) );
1243 } else {
1244 $table = substr( $this->page, strlen( self::PAGE_MY_TABLES . '_' ) );
1245 }
1246 // Show list table.
1247 $this->wpda_my_table_list_view[$table]->show();
1248 }
1249 }
1250
1251 /**
1252 * Add main menu for non admin user
1253 *
1254 * @param string $first_page First plugin page.
1255 * @return void
1256 */
1257 protected function create_non_admin_menu( $first_page ) {
1258 if ( !$this->loaded_user_main_menu ) {
1259 add_menu_page(
1260 'WP Data Access',
1261 'WP Data Access',
1262 WPDA::get_current_user_capability(),
1263 $first_page,
1264 function () {
1265 },
1266 'dashicons-database-view',
1267 999999999
1268 );
1269 $this->loaded_user_main_menu = true;
1270 $this->first_page = $first_page;
1271 }
1272 }
1273
1274 }
1275