PageRenderTime 75ms CodeModel.GetById 15ms app.highlight 47ms RepoModel.GetById 1ms app.codeStats 0ms

/admin/class-apl-admin.php

https://github.com/Advanced-Post-List/advanced-post-list
PHP | 2227 lines | 1214 code | 266 blank | 747 comment | 121 complexity | dc05c4f4aa7d94e9ee2d9c74bcd7f0e1 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1<?php
   2/**
   3 * APL Admin API: APL_Admin Class
   4 *
   5 * Admin core object to Advanced Post List
   6 *
   7 * @link https://github.com/Advanced-Post-List/advanced-post-list/
   8 *
   9 * @package advanced-post-list\APL_Core
  10 * @since 0.4.0
  11 */
  12
  13/**
  14 * APL Admin
  15 *
  16 * Admin core class.
  17 *
  18 * @since 0.4.0
  19 */
  20class APL_Admin {
  21
  22	/**
  23	 * Singleton Instance
  24	 *
  25	 * @since 0.4.0
  26	 * @access private
  27	 * @var null $instance Singleton Class Instance.
  28	 */
  29	protected static $instance = null;
  30
  31	/**
  32	 * Get Singleton Instance
  33	 *
  34	 * Singleton Get Instance.
  35	 *
  36	 * @since 0.4.0
  37	 * @access private
  38	 *
  39	 * @return object
  40	 */
  41	public static function get_instance() {
  42		if ( null === static::$instance ) {
  43			static::$instance = new static();
  44			// TODO - Catch WP Error.
  45		}
  46		return static::$instance;
  47	}
  48
  49	/**
  50	 * Throws error on object clone
  51	 *
  52	 * The whole idea of the singleton design pattern is that there is a single
  53	 * object therefore, we don't want the object to be cloned.
  54	 *
  55	 * @ignore
  56	 * @since 0.4.0
  57	 * @access private
  58	 */
  59	private function __clone() {
  60		// Cloning instances of the class is forbidden.
  61		_doing_it_wrong( __FUNCTION__, esc_html__( 'Cheatin\' huh?', 'advanced-post-list' ), APL_VERSION );
  62	}
  63
  64	/**
  65	 * Disable unserializing of the class
  66	 *
  67	 * @ignore
  68	 * @since 0.4.0
  69	 * @access protected
  70	 */
  71	private function __wakeup() {
  72		// Unserializing instances of the class is forbidden.
  73		_doing_it_wrong( __FUNCTION__, esc_html__( 'Cheatin\' huh?', 'advanced-post-list' ), APL_VERSION );
  74	}
  75
  76	/**
  77	 * Constructor
  78	 *
  79	 * Private Singleton Constructor.
  80	 *
  81	 * @ignore
  82	 * @since 0.4.0
  83	 * @access private
  84	 *
  85	 * @todo Complete Admin Encapsulation. Concept linked.
  86	 * @link https://florianbrinkmann.com/en/3815/wordpress-backend-request/
  87	 */
  88	private function __construct() {
  89		// Exit if Non-Admins access this object. Also wrapped in APL_Core.
  90		if ( ! is_admin() ) {
  91			return new WP_Error( 'apl_admin', esc_html__( 'You do not have admin capabilities in APL_Admin.', 'advanced-post-list' ) );
  92		}
  93
  94		// Initialize Core Class functions.
  95		$this->_requires();
  96		apl_notice_set_activation_review_plugin( false, false );
  97
  98		// Settings Data.
  99		add_action( 'admin_post_apl_save_general_settings', array( $this, 'save_general_settings' ) );
 100		// AJAX.
 101		add_action( 'admin_init', array( $this, 'add_settings_ajax_hooks' ) );
 102
 103		// Check if wp-admin.php is loaded, and WP_Screen is defined.
 104		// is_admin_bar_showing().
 105		if ( defined( 'WP_ADMIN' ) && WP_ADMIN && is_blog_admin() ) {
 106			// Menu & Scripts.
 107			add_action( 'admin_menu', array( $this, 'admin_menu' ) );
 108			add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue' ) );
 109
 110			// Admin Screens for Modular Screen Execution.
 111			// NOTE: Settings Page needs to hook sooner (in constructor/here).
 112			add_action( 'current_screen', array( $this, 'current_screen_hooks' ) );
 113
 114			// Hook into WP to customize Screens.
 115			add_action( 'admin_head', array( $this, 'disable_screen_boxes' ) );
 116			add_action( 'load-edit.php', array( $this, 'post_list_screen_options_all' ) );
 117			add_action( 'load-post-new.php', array( $this, 'post_list_screen_options_add_new' ) );
 118
 119			add_action( 'manage_apl_post_list_posts_columns', array( $this, 'post_list_posts_columns' ) );
 120			add_action( 'manage_apl_post_list_posts_custom_column', array( $this, 'post_list_posts_custom_column' ), 10, 2 );
 121			add_action( 'manage_edit-apl_post_list_sortable_columns', array( $this, 'post_list_sortable_columns' ) );
 122
 123			// Editor Meta Boxes.
 124			add_action( 'add_meta_boxes', array( $this, 'post_list_meta_boxes' ) );
 125			add_action( 'add_meta_boxes', array( $this, 'settings_meta_boxes' ) );
 126			if ( defined( 'ICL_SITEPRESS_VERSION' ) || defined( 'APLP_VERSION' ) ) {
 127				add_action( 'add_meta_boxes', array( $this, 'design_meta_boxes' ) );
 128			}
 129
 130			add_filter( 'mce_external_plugins', array( $this, 'mce_external_plugins' ) );
 131			add_filter( 'mce_buttons', array( $this, 'mce_buttons' ) );
 132			add_action( 'admin_head', array( $this, 'tinymce_extra_vars' ) );
 133		}
 134	}
 135
 136	/**
 137	 * Requires Files
 138	 *
 139	 * Files that this class object needs to load.
 140	 *
 141	 * @ignore
 142	 * @since 0.4.0
 143	 * @access private
 144	 */
 145	private function _requires() {
 146		// Example.
 147		// 'require_once( APL_DIR . 'includes/example.php' )'.
 148		require_once APL_DIR . 'admin/functions-admin.php';
 149		require_once APL_DIR . 'admin/export.php';
 150		require_once APL_DIR . 'admin/import.php';
 151		require_once APL_DIR . 'admin/class-apl-notices.php';
 152	}
 153
 154	/**
 155	 * Current Admin Screen Hooks
 156	 *
 157	 * Adds hooks according to the admin screen in use.
 158	 *
 159	 * @since 0.4.0
 160	 *
 161	 * @param WP_Screen $current_screen Current WP_Screen object.
 162	 */
 163	public function current_screen_hooks( $current_screen ) {
 164		if ( 'apl_post_list' === $current_screen->id || 'edit-apl_post_list' === $current_screen->id ) {
 165			// Post Data.
 166			add_action( 'draft_apl_post_list', array( $this, 'draft_post_list' ), 10, 2 );
 167
 168			add_action( 'private_apl_post_list', array( $this, 'save_post_list' ), 10, 2 );
 169			add_action( 'publish_apl_post_list', array( $this, 'save_post_list' ), 10, 2 );
 170			add_action( 'pending_apl_post_list', array( $this, 'save_post_list' ), 10, 2 );
 171			add_action( 'future_apl_post_list', array( $this, 'save_post_list' ), 10, 2 );
 172
 173			// //add_action( 'trash_apl_post_list', array( $this, 'trash_post_list' ), 10, 3 );
 174			add_action( 'wp_trash_post', array( $this, 'action_wp_trash_post_apl_post_list' ) );
 175			add_action( 'untrash_post', array( $this, 'action_untrash_post_apl_post_list' ) );
 176			add_action( 'before_delete_post', array( $this, 'action_before_delete_post_apl_post_list' ) );
 177
 178			// //if ( 'apl_post_list' === $current_screen->id ) {
 179			// //	$current_screen->add_help_tab( array(
 180			// //		'id'      => 'apl_post_list_help', //unique id for the tab.
 181			// //		'title'   => 'Testing Help Tab',   //unique visible title for the tab.
 182			// //		'content' => 'Hello World',        //actual help text.
 183			// //		//'callback' => $callback            //optional function to callback.
 184			// //	) );
 185			// //}
 186		} elseif ( 'apl_design' === $current_screen->id || 'edit-apl_design' === $current_screen->id ) {
 187			// Post Data.
 188			add_action( 'draft_apl_design', array( $this, 'draft_design' ), 10, 2 );
 189
 190			add_action( 'private_apl_design', array( $this, 'save_design' ), 10, 2 );
 191			add_action( 'publish_apl_design', array( $this, 'save_design' ), 10, 2 );
 192			add_action( 'pending_apl_design', array( $this, 'save_design' ), 10, 2 );
 193			add_action( 'future_apl_design', array( $this, 'save_design' ), 10, 2 );
 194
 195			// //add_action( 'trash_apl_post_list', array( $this, 'trash_design' ), 10, 3 );
 196			// //add_action( 'wp_trash_post', array( $this, 'action_wp_trash_post_apl_design' ) );
 197			// //add_action( 'untrash_post', array( $this, 'action_untrash_post_apl_design' ) );
 198			// //add_action( 'before_delete_post', array( $this, 'action_before_delete_post_apl_design' ) );
 199		} elseif ( 'adv-post-list_page_apl_settings' === $current_screen->id ) {
 200			// SETTINGS (Page).
 201			// DOES NOT always work as intended. Use self::_constructor().
 202		} else {
 203			// //add_filter( 'mce_external_plugins', array( $this, 'mce_external_plugins' ) );
 204			// //add_filter( 'mce_buttons', array( $this, 'mce_register_buttons' ) );
 205		}// End if().
 206
 207	}
 208
 209	/**
 210	 * APL Admin Menu
 211	 *
 212	 * Adds the Admin Menu and Scripts for APL.
 213	 *
 214	 * @since 0.4.0
 215	 *
 216	 * @see 'admin_menu' hook
 217	 * @see wp-admin/admin-header.php
 218	 * @link https://developer.wordpress.org/reference/functions/add_menu_page/
 219	 * @link https://developer.wordpress.org/reference/functions/add_submenu_page/
 220	 */
 221	public function admin_menu() {
 222		add_menu_page(
 223			__( 'Advanced Post List', 'advanced-post-list' ),
 224			__( 'Adv. Post List', 'advanced-post-list' ),
 225			'administrator',
 226			'advanced_post_list',
 227			'edit.php?post_type=apl_post_list', // Callback function if dashboard is added.
 228			'dashicons-welcome-widgets-menus',
 229			58
 230		);
 231
 232		// TODO Add APL Dashboard.
 233		// All Post Lists (Submenu) - Submenu setting is added during CPT registration.
 234		// Add New (Submenu).
 235		add_submenu_page(
 236			'advanced_post_list',
 237			__( 'Add New Post List', 'advanced-post-list' ),
 238			__( '- New Post List', 'advanced-post-list' ),
 239			'administrator',
 240			'post-new.php?post_type=apl_post_list'
 241		);
 242
 243		// Settings (Submenu).
 244		add_submenu_page(
 245			'advanced_post_list',
 246			// // edit.php?post_type=apl_post_list',
 247			__( 'APL Settings', 'advanced-post-list' ),
 248			__( 'Settings', 'advanced-post-list' ),
 249			'administrator',
 250			'apl_settings',
 251			array( $this, 'submenu_settings_page' )
 252		);
 253		add_action( 'admin_init', array( $this, 'settings_register_settings' ) );
 254
 255		// TODO - Add Help API.
 256		// EXTENSIONS.
 257		do_action( 'apl_admin_menu_ext' );
 258	}
 259
 260	/**
 261	 * Submenu Callback for Settings Page
 262	 *
 263	 * @since 0.4.0
 264	 */
 265	public function submenu_settings_page() {
 266		apl_get_template( 'admin/settings-page.php' );
 267	}
 268
 269	/**
 270	 * Registers Input Settings for Settings Page
 271	 *
 272	 * @since 0.4.0
 273	 */
 274	public function settings_register_settings() {
 275		register_setting( 'apl_settings_general', 'apl_delete_on_deactivation', 'strval' );
 276		register_setting( 'apl_settings_general', 'apl_default_empty_enable', 'strval' );
 277		register_setting( 'apl_settings_general', 'apl_default_empty_message', 'strval' );
 278
 279		// //register_setting( 'apl_settings_import_export', 'apl_export_file_name', 'strval' );
 280		// //register_setting( 'apl_settings_import_export', 'apl_import_opt', 'strval' );
 281		// //register_setting( 'apl_settings_import_export', 'apl_import_file', 'strval' );
 282		// //register_setting( 'apl_settings_import_export', 'apl_restore_database', 'strval' );
 283	}
 284
 285	/**
 286	 * APL Admin Enqueue Scripts & Styles
 287	 *
 288	 * Loads APL scripts and styles. If not in APL Admin Pages, then remove.
 289	 *
 290	 * @since 0.4.0
 291	 *
 292	 * @see wp-admin/admin-header.php
 293	 * @link https://developer.wordpress.org/reference/hooks/admin_enqueue_scripts/
 294	 *
 295	 * @param string $hook_suffix The suffix for the current Admin page.
 296	 */
 297	public function admin_enqueue( $hook_suffix ) {
 298		$screen = get_current_screen();
 299
 300		/*
 301		 * ************** REMOVE SCRIPTS & STYLES *********************
 302		 */
 303
 304		// STEP 1 - By default, remove any scripts & styles.
 305		wp_deregister_script( 'apl-admin-js' );
 306		wp_deregister_script( 'apl-admin-ui-js' );
 307		wp_deregister_script( 'apl-admin-ui-multiselect-js' );
 308		wp_deregister_script( 'apl-admin-ui-multiselect-filter-js' );
 309
 310		wp_deregister_style( 'apl-admin-css' );
 311		wp_deregister_style( 'apl-admin-ui-multiselect-css' );
 312		wp_deregister_style( 'apl-admin-ui-multiselect-filter-css' );
 313		wp_deregister_style( 'apl-admin-settings-css' );
 314
 315		if ( 'apl_post_list' === $screen->id || 'edit-apl_post_list' === $screen->id || 'apl_design' === $screen->id || 'edit-apl_design' === $screen->id ) {
 316			/*
 317			 * ************** AJAX ACTION HOOKS ***************************
 318			 */
 319
 320			// TODO - Add meta box to side to load different presets from 'edit.php'.
 321			// //add_action( 'wp_ajax_apl_load_preset', array( $this, 'hook_ajax_load_preset' ) );
 322
 323			/*
 324			 * ************** REGISTER SCRIPTS ****************************
 325			 */
 326
 327			// Step 2 - Register scripts to be enqueued.
 328			wp_register_script(
 329				'apl-admin-js',
 330				APL_URL . 'admin/js/admin.js',
 331				array(
 332					'jquery',
 333				),
 334				APL_VERSION,
 335				false
 336			);
 337
 338			wp_register_script(
 339				'apl-admin-ui-js',
 340				APL_URL . 'admin/js/admin-ui.js',
 341				array(
 342					'jquery',
 343					'jquery-ui-core',
 344					'jquery-ui-widget',
 345					'jquery-ui-tabs',
 346					'jquery-ui-spinner',
 347					'jquery-ui-slider',
 348					'jquery-ui-button',
 349					'jquery-ui-dialog',
 350					'jquery-ui-selectmenu',
 351					'jquery-ui-position',
 352					'jquery-ui-tooltip',
 353
 354				),
 355				APL_VERSION,
 356				true
 357			);
 358
 359			wp_register_script(
 360				'apl-admin-ui-multiselect-js',
 361				APL_URL . 'admin/js/jquery-multiselect/jquery.multiselect.min.js',
 362				array(
 363					'jquery',
 364					'jquery-ui-core',
 365					'jquery-ui-widget',
 366					'jquery-ui-selectmenu',
 367				),
 368				APL_VERSION,
 369				false
 370			);
 371
 372			wp_register_script(
 373				'apl-admin-ui-multiselect-filter-js',
 374				APL_URL . 'admin/js/jquery-multiselect/jquery.multiselect.filter.min.js',
 375				array(
 376					'jquery',
 377					'jquery-ui-core',
 378					'jquery-ui-widget',
 379				),
 380				APL_VERSION,
 381				false
 382			);
 383
 384			global $wp_version;
 385			if ( version_compare( $wp_version, '4.9', '>' ) && ( 'apl_post_list' === $screen->id || 'apl_design' === $screen->id ) ) {
 386				// Enqueue code editor and settings for manipulating HTML.
 387				// https://developer.wordpress.org/reference/functions/wp_enqueue_code_editor/
 388				$args = array( 'type' => 'application/x-httpd-php' );
 389				$settings = wp_enqueue_code_editor( $args );
 390
 391				if ( false !== $settings ) {
 392					wp_add_inline_script(
 393						'code-editor',
 394						sprintf(
 395							'jQuery( function() { wp.codeEditor.initialize( "apl_textarea_before", %s ); } );',
 396							wp_json_encode( $settings )
 397						)
 398					);
 399					wp_add_inline_script(
 400						'code-editor',
 401						sprintf(
 402							'jQuery( function() { wp.codeEditor.initialize( "apl_textarea_content", %s ); } );',
 403							wp_json_encode( $settings )
 404						)
 405					);
 406					wp_add_inline_script(
 407						'code-editor',
 408						sprintf(
 409							'jQuery( function() { wp.codeEditor.initialize( "apl_textarea_after", %s ); } );',
 410							wp_json_encode( $settings )
 411						)
 412					);
 413					// Empty is disabled for now, but will need to be hidden when checkbox is unchecked.
 414					// Hold off until 5.0.
 415				}
 416			}
 417
 418			// STEP 3 - Enqueue scripts.
 419			wp_enqueue_script( 'apl-admin-js' );
 420			wp_enqueue_script( 'apl-admin-ui-js' );
 421			wp_enqueue_script( 'apl-admin-ui-multiselect-js' );
 422			wp_enqueue_script( 'apl-admin-ui-multiselect-filter-js' );
 423
 424			/*
 425			 * ************** REGISTER STYLES *****************************
 426			 */
 427
 428			// Step 4 - (Register) Enqueue styles.
 429			wp_enqueue_style(
 430				'apl-admin-css',
 431				APL_URL . 'admin/css/admin.css',
 432				false,
 433				APL_VERSION,
 434				false
 435			);
 436
 437			$wp_scripts = wp_scripts();
 438			wp_enqueue_style(
 439				'apl-admin-ui-css',
 440				APL_URL . 'admin/css/jquery-ui/jquery-ui.min.css',
 441				false,
 442				APL_VERSION,
 443				false
 444			);
 445
 446			wp_enqueue_style(
 447				'apl-admin-ui-multiselect-css',
 448				APL_URL . 'admin/css/jquery-multiselect/jquery.multiselect.css',
 449				false,
 450				APL_VERSION,
 451				false
 452			);
 453
 454			wp_enqueue_style(
 455				'apl-admin-ui-multiselect-filter-css',
 456				APL_URL . 'admin/css/jquery-multiselect/jquery.multiselect.filter.css',
 457				false,
 458				APL_VERSION,
 459				false
 460			);
 461
 462			// Get values for variables to localize into JS files.
 463			// POST => TAXONOMIES.
 464			$data_post_tax = apl_get_post_tax();
 465
 466			// TAXONOMIES => TERMS.
 467			$data_tax_terms = apl_get_tax_terms();
 468
 469			$data_ui_trans = array(
 470				'tax_noneSelectedText'           => esc_html__( 'Select Taxonomy', 'advanced-post-list' ),
 471				'tax_selectedText'               => esc_html__( '# of # taxonomies selected', 'advanced-post-list' ),
 472				'author_ids_noneSelectedText'    => esc_html__( '- None -', 'advanced-post-list' ),
 473				'author_ids_selectedText'        => esc_html__( '# Selected', 'advanced-post-list' ),
 474				'post_status_1_noneSelectedText' => esc_html__( 'Select Status', 'advanced-post-list' ),
 475				'post_status_1_selectedText'     => esc_html__( 'Both', 'advanced-post-list' ),
 476				'post_status_2_noneSelectedText' => esc_html__( 'Published', 'advanced-post-list' ),
 477				'post_status_2_selectedText'     => esc_html__( '# Selected', 'advanced-post-list' ),
 478			);
 479
 480			$admin_localize    = array();
 481			$admin_ui_localize = array(
 482				'post_tax'  => $data_post_tax,
 483				'tax_terms' => $data_tax_terms,
 484				'trans'     => $data_ui_trans,
 485			);
 486
 487			// Add variables to JS files.
 488			// '../admin/js/admin.js'.
 489			// '../admin/js/admin-ui.js'.
 490			wp_localize_script( 'apl-admin-js', 'apl_admin_local', $admin_localize );
 491			wp_localize_script( 'apl-admin-ui-js', 'apl_admin_ui_local', $admin_ui_localize );
 492		// //} elseif ( 'apl_design' === $screen->id || 'edit-apl_design' === $screen->id ) {
 493			// TODO Add handling APL Designs without extra code from APL_Post_Lists..
 494		} elseif ( 'adv-post-list_page_apl_settings' === $screen->id ) {
 495			// If we are not viewing APL Post List area, then return.
 496			// SETTINGS PAGE.
 497			// SCRIPTS.
 498			wp_register_script(
 499				'apl-settings-js',
 500				APL_URL . 'admin/js/settings.js',
 501				array(
 502					'jquery',
 503					'jquery-ui-core',
 504					'jquery-ui-widget',
 505					'jquery-ui-button',
 506					'jquery-ui-dialog',
 507				),
 508				APL_VERSION,
 509				true
 510			);
 511			wp_register_script(
 512				'apl-settings-ui-js',
 513				APL_URL . 'admin/js/settings-ui.js',
 514				array(
 515					'jquery',
 516					'jquery-ui-core',
 517					'jquery-ui-widget',
 518					'jquery-ui-dialog',
 519					'jquery-ui-position',
 520					'jquery-ui-tooltip',
 521				),
 522				APL_VERSION,
 523				true
 524			);
 525
 526			wp_enqueue_script( 'postbox' );
 527			wp_enqueue_script( 'apl-settings-js' );
 528			wp_enqueue_script( 'apl-settings-ui-js' );
 529
 530			// STYLES.
 531			wp_enqueue_style(
 532				'apl-admin-settings-css',
 533				APL_URL . 'admin/css/settings.css',
 534				false,
 535				APL_VERSION,
 536				false
 537			);
 538
 539			wp_enqueue_style(
 540				'apl-admin-ui-css',
 541				APL_URL . 'admin/css/jquery-ui/jquery-ui.css',
 542				false,
 543				APL_VERSION,
 544				false
 545			);
 546
 547			$trans_arr = array(
 548				'default_alert_title'           => __( 'Alert', 'advanced-post-list' ),
 549				'default_alert_message'         => __( 'No Message to Display.', 'advanced-post-list' ),
 550				'fileName_empty_alert_title'    => __( 'Filename Required', 'advanced-post-list' ),
 551				'fileName_empty_alert_message'  => __( 'A filename doesn\'t exist. \n Please enter a filename before exporting.', 'advanced-post-list' ),
 552				'import_no_file_message'        => __( 'No file(s) selected. Please choose a JSON file to upload.', 'advanced-post-list' ),
 553				'import_no_file_title'          => __( 'No File', 'advanced-post-list' ),
 554				'import_invalid_file_message'   => __( 'Invalid file type. Please choose a JSON file to upload.', 'advanced-post-list' ),
 555				'import_invalid_file_title'     => __( 'Invalid File', 'advanced-post-list' ),
 556				'import_success_message'        => __( 'Data successfully imported.', 'advanced-post-list' ),
 557				'import_success_title'          => __( 'Complete', 'advanced-post-list' ),
 558				'import_overwrite_dialog_title' => __( 'Overwrite Presets', 'advanced-post-list' ),
 559				'fileName_char_alert_title'     => __( 'Illegal Characters', 'advanced-post-list' ),
 560				'fileName_char_alert_message1'  => __( 'Cannot use (< > : " / \\ | , ? *).', 'advanced-post-list' ),
 561				'fileName_char_alert_message2'  => __( 'Please rename your filename.', 'advanced-post-list' ),
 562
 563			);
 564			$trans_ui_arr = array(
 565				'fileName_char_alert_title'    => __( 'Illegal Characters', 'advanced-post-list' ),
 566				'fileName_char_alert_message1' => __( 'Cannot use (< > : " / \\ | , ? *).', 'advanced-post-list' ),
 567				'fileName_char_alert_message2' => __( 'Please rename your filename.', 'advanced-post-list' ),
 568			);
 569
 570			$settings_localize = array(
 571				'export_nonce'          => wp_create_nonce( 'apl_settings_export' ),
 572				'import_nonce'          => wp_create_nonce( 'apl_settings_import' ),
 573				'restoreDefaultsNonce'  => wp_create_nonce( 'apl_settings_restore_defaults' ),
 574				'trans'                 => $trans_arr,
 575			);
 576
 577			$settings_ui_localize = array(
 578				'trans' => $trans_ui_arr,
 579			);
 580
 581			wp_localize_script( 'apl-settings-js', 'apl_settings_local', $settings_localize );
 582			wp_localize_script( 'apl-settings-ui-js', 'apl_settings_ui_local', $settings_ui_localize );
 583
 584			global $post_type;
 585			do_action( 'add_meta_boxes', $hook_suffix, $post_type );
 586
 587			$screen_args = array(
 588				'max'     => 2,
 589				'default' => 2,
 590			);
 591			add_screen_option( 'layout_columns', $screen_args );
 592
 593		} else {
 594			// REGISTER.
 595			// LOCALIZE.
 596			// ENQUEUE.
 597			wp_enqueue_style(
 598				'apl-admin-wp-editor-css',
 599				APL_URL . 'admin/css/wp-editor.css',
 600				false,
 601				APL_VERSION,
 602				false
 603			);
 604		}// End if().
 605	}
 606
 607	/**
 608	 * Disables/Hides Screen Option Settings
 609	 *
 610	 * Disables / Hides the Screen Option's display Meta Boxes Settings. Basically
 611	 * prevents certain Meta Boxes from being hidden, and forces the box to display.
 612	 *
 613	 * @since 0.4.0
 614	 *
 615	 * @see 'admin_head' hook.
 616	 * @link https://wordpress.stackexchange.com/questions/149602/hiding-metabox-from-screen-options-pull-down
 617	 */
 618	public function disable_screen_boxes() {
 619		echo '<style>label[for=apl-post-list-filter-hide] { display: none; }</style>';
 620		echo '<style>#apl-post-list-filter { display: block; }</style>';
 621	}
 622
 623	/**
 624	 * Screen Options for 'All Post List' page
 625	 *
 626	 * Hook 'load-edit.php', sets additional Screen Options.
 627	 *
 628	 * @see 'load-edit.php' hook.
 629	 * @since 0.4.0
 630	 */
 631	public function post_list_screen_options_all() {
 632		$screen = get_current_screen();
 633		// Get out of here if we are not on our settings page.
 634		if ( ! is_object( $screen ) || 'edit-apl_post_list' !== $screen->id ) {
 635			return;
 636		}
 637
 638		$options = $screen->get_options();
 639	}
 640
 641	/**
 642	 * Screen Options for 'Add New' page
 643	 *
 644	 * Hook 'load-post-new.php', sets additional Screen Options.
 645	 *
 646	 * @see 'load-post-new.php' hook.
 647	 * @since 0.4.0
 648	 */
 649	public function post_list_screen_options_add_new() {
 650		$screen = get_current_screen();
 651		// Get out of here if we are not on our settings page.
 652		if ( ! is_object( $screen ) || 'apl_post_list' !== $screen->id ) {
 653			return;
 654		}
 655		$options = $screen->get_options();
 656	}
 657
 658	/**
 659	 * Post List All Posts Columns
 660	 *
 661	 * Adds additional columns to All Post Lists page.
 662	 *
 663	 * @since 0.4.0
 664	 *
 665	 * @see 'manage_apl_post_list_posts_columns'
 666	 * @uses manage_${post_type}_posts_columns
 667	 * @link https://codex.wordpress.org/Plugin_API/Filter_Reference/manage_$post_type_posts_columns
 668	 *
 669	 * @param array $columns Columns use in the 'All Post Lists' page.
 670	 * @return array
 671	 */
 672	public function post_list_posts_columns( $columns ) {
 673		$tmp_date = $columns['date'];
 674		unset( $columns['date'] );
 675
 676		$columns['post_name']     = __( 'Slug', 'advanced-post-list' );
 677		$columns['apl_shortcode'] = __( 'Shortcode', 'advanced-post-list' );
 678
 679		$columns['date'] = $tmp_date;
 680
 681		return $columns;
 682	}
 683
 684	/**
 685	 * Post List Custom Column
 686	 *
 687	 * Adds content to custom column.
 688	 *
 689	 * @since 0.4.0
 690	 *
 691	 * @uses manage_${post_type}_posts_columns hook.
 692	 * @link https://codex.wordpress.org/Plugin_API/Action_Reference/manage_$post_type_posts_custom_column
 693	 *
 694	 * @param array $column  The name of the column to display. Default: None.
 695	 * @param int   $post_id The ID of the current post. Can also be taken from the global $post->ID. Default: None.
 696	 */
 697	public function post_list_posts_custom_column( $column, $post_id ) {
 698		$args       = array(
 699			'post__in'    => array( $post_id ),
 700			'post_type'   => 'apl_post_list',
 701			'post_status' => array(
 702				'draft',
 703				'pending',
 704				'publish',
 705				'future',
 706				'private',
 707				'trash',
 708			),
 709		);
 710		$post_lists = new WP_Query( $args );
 711		$post_list  = $post_lists->post;
 712
 713		switch ( $column ) {
 714			case 'post_name':
 715				echo esc_attr( $post_list->post_name );
 716				break;
 717			case 'apl_shortcode':
 718				echo '<input value="[post_list name=\'' . esc_attr( $post_list->post_name ) . '\']" type="text" size="32" onfocus="this.select();" onclick="this.select();" readonly="readonly" />';
 719				break;
 720		}
 721	}
 722
 723	/**
 724	 * Post List Sortable Columns
 725	 *
 726	 * Sets Custom Columns to be sortable.
 727	 *
 728	 * @link https://developer.wordpress.org/reference/hooks/manage_this-screen-id_sortable_columns/
 729	 *
 730	 * @param array $columns An array of sortable columns.
 731	 * @return array
 732	 */
 733	public function post_list_sortable_columns( $columns ) {
 734		$columns['post_name'] = 'post_name';
 735
 736		return $columns;
 737	}
 738
 739	/**
 740	 * Post List Meta Boxes
 741	 *
 742	 * Hook 'add_meta_boxes', adds meta boxes used in post lists.
 743	 *
 744	 * @since 0.4.0
 745	 *
 746	 * @see $this->_construct Used by.
 747	 * @see 'add_meta_boxes' hook.
 748	 * @see wp-admin/includes/template.php
 749	 * @link https://codex.wordpress.org/Plugin_API/Action_Reference/add_meta_boxes
 750	 * @link https://developer.wordpress.org/reference/functions/add_meta_box/
 751	 */
 752	public function post_list_meta_boxes() {
 753		add_meta_box(
 754			'apl-post-list-filter',
 755			__( 'Filter Settings', 'advanced-post-list' ),
 756			array( $this, 'post_list_meta_box_filter' ),
 757			'apl_post_list',
 758			// 'normal', 'advanced', 'side'.
 759			'normal',
 760			// 'high', 'sorted', 'core', 'default', 'low'.
 761			'high'
 762		);
 763		add_meta_box(
 764			'apl-post-list-display',
 765			__( 'Display Settings', 'advanced-post-list' ),
 766			array( $this, 'post_list_meta_box_design' ),
 767			'apl_post_list',
 768			'normal',
 769			'core'
 770		);
 771	}
 772
 773	/**
 774	 * Design Meta Boxes
 775	 *
 776	 * Hook 'add_meta_boxes', adds meta boxes used in designs.
 777	 *
 778	 * @since 0.4.0
 779	 *
 780	 * @see $this->_construct Used by.
 781	 * @see 'add_meta_boxes' hook.
 782	 * @see wp-admin/includes/template.php
 783	 * @link https://codex.wordpress.org/Plugin_API/Action_Reference/add_meta_boxes
 784	 * @link https://developer.wordpress.org/reference/functions/add_meta_box/
 785	 */
 786	public function design_meta_boxes() {
 787		add_meta_box(
 788			'apl-post-list-display',
 789			__( 'Display Settings', 'advanced-post-list' ),
 790			array( $this, 'design_meta_box_design' ),
 791			'apl_design',
 792			'normal',
 793			'core'
 794		);
 795	}
 796
 797	/**
 798	 * Add Settings Page Meta Boxes
 799	 *
 800	 * @see $this->_construct Used by.
 801	 * @see 'add_meta_boxes' hook.
 802	 * @see add_meta_box();
 803	 * @link https://codex.wordpress.org/Plugin_API/Action_Reference/add_meta_boxes
 804	 * @link https://developer.wordpress.org/reference/functions/add_meta_box/
 805	 */
 806	public function settings_meta_boxes() {
 807		add_meta_box(
 808			'apl-info',
 809			__( 'About', 'advanced-post-list' ),
 810			array( $this, 'settings_meta_box_info' ),
 811			'adv-post-list_page_apl_settings',
 812			// 'normal', 'advanced', 'side'.
 813			'side',
 814			// 'high', 'sorted', 'core', 'default', 'low'.
 815			'core'
 816		);
 817		// TODO - Add Documentation Link to Admin Page/Metabox documentation.
 818		// //$title = '<a id="info16" class="info_a_link" style="float:right;">Export/Import Info<span class="ui-icon ui-icon-info info-icon" style="float:right"></span></a>';
 819		add_meta_box(
 820			'apl-general',
 821			// //$title . __( 'General Settings', 'advanced-post-list' ),
 822			__( 'General Settings', 'advanced-post-list' ),
 823			array( $this, 'settings_meta_box_general' ),
 824			'adv-post-list_page_apl_settings',
 825			'normal',
 826			'high'
 827		);
 828		add_meta_box(
 829			'apl-import-export',
 830			__( 'Import / Export', 'advanced-post-list' ),
 831			array( $this, 'settings_meta_box_import_export' ),
 832			'adv-post-list_page_apl_settings',
 833			'advanced',
 834			'core'
 835		);
 836	}
 837
 838	/**
 839	 * Settings Info Meta Box
 840	 *
 841	 * @since 0.4.0
 842	 *
 843	 * @param WP_Post $post Current WP_Post object.
 844	 * @param array   $metabox With Meta Box id, title, callback, and args elements.
 845	 */
 846	public function settings_meta_box_info( $post, $metabox ) {
 847		$args = array(
 848			'post'    => $post,
 849			'metabox' => $metabox,
 850		);
 851
 852		apl_get_template( 'admin/meta-box/settings-info.php', $args );
 853	}
 854
 855	/**
 856	 * Settings General Settings Meta Box
 857	 *
 858	 * @since 0.4.0
 859	 *
 860	 * @param WP_Post $post Current WP_Post object.
 861	 * @param array   $metabox With Meta Box id, title, callback, and args elements.
 862	 */
 863	public function settings_meta_box_general( $post, $metabox ) {
 864		$args = array(
 865			'post'    => $post,
 866			'metabox' => $metabox,
 867		);
 868
 869		apl_get_template( 'admin/meta-box/settings-general.php', $args );
 870	}
 871
 872	/**
 873	 * Settings Import/Export Meta Box
 874	 *
 875	 * @since 0.4.0
 876	 *
 877	 * @param WP_Post $post Current WP_Post object.
 878	 * @param array   $metabox With Meta Box id, title, callback, and args elements.
 879	 */
 880	public function settings_meta_box_import_export( $post, $metabox ) {
 881		$args = array(
 882			'post'    => $post,
 883			'metabox' => $metabox,
 884		);
 885
 886		apl_get_template( 'admin/meta-box/settings-import-export.php', $args );
 887	}
 888
 889	/**
 890	 * Post List Filter Meta box Template
 891	 *
 892	 * @since 0.4.0
 893	 *
 894	 * @param WP_Post $post Current WP_Post object.
 895	 * @param array   $metabox With Meta Box id, title, callback, and args elements.
 896	 */
 897	public function post_list_meta_box_filter( $post, $metabox ) {
 898		$args = array(
 899			'post'                   => $post,
 900			'metabox'                => $metabox,
 901			'apl_post_tax'           => apl_get_post_tax(),
 902			'apl_tax_terms'          => apl_get_tax_terms(),
 903			'apl_display_post_types' => apl_get_display_post_types(),
 904		);
 905
 906		apl_get_template( 'admin/meta-box/post-list-filter.php', $args );
 907	}
 908
 909	/**
 910	 * Post List Design Meta box Template
 911	 *
 912	 * Hook '$this->post_list_meta_boxes()', renders the Design Meta Box Template.
 913	 *
 914	 * @since 0.4.0
 915	 *
 916	 * @param WP_Post $post Current WP_Post object.
 917	 * @param array   $metabox With Meta Box id, title, callback, and args elements.
 918	 */
 919	public function post_list_meta_box_design( $post, $metabox ) {
 920		$args = array(
 921			'post'    => $post,
 922			'metabox' => $metabox,
 923		);
 924
 925		apl_get_template( 'admin/meta-box/post-list-design.php', $args );
 926	}
 927
 928	/**
 929	 * Post List Design Meta box Template
 930	 *
 931	 * Renders the Design Meta Box Template.
 932	 *
 933	 * @see self::design_meta_boxes()
 934	 * @since 0.4.0
 935	 *
 936	 * @param WP_Post $post Current WP_Post object.
 937	 * @param array   $metabox With Meta Box id, title, callback, and args elements.
 938	 */
 939	public function design_meta_box_design( $post, $metabox ) {
 940		$args = array(
 941			'post'    => $post,
 942			'metabox' => $metabox,
 943		);
 944
 945		apl_get_template( 'admin/meta-box/design-design.php', $args );
 946	}
 947
 948	/**
 949	 * Draft Post List
 950	 *
 951	 * Hook for draft Post Transitions with Post Lists.
 952	 *
 953	 * @since 0.4.0
 954	 *
 955	 * @param int      $post_id
 956	 * @param WP_Post  $post
 957	 */
 958	public function draft_post_list( $post_id, $post ) {
 959		if ( isset( $_REQUEST['action'] ) ) {
 960			if ( 'untrash' === $_REQUEST['action'] ) {
 961				return;
 962			}
 963		}
 964		if ( empty( $post->post_name ) ) {
 965			if ( empty( $post->post_title ) ) {
 966				$post->post_title = 'APL-' . $post->ID;
 967			}
 968
 969			remove_action( 'draft_apl_post_list', array( $this, 'draft_post_list' ) );
 970			$post->post_name = sanitize_title_with_dashes( $post->post_title );
 971
 972			$post_arr = array(
 973				'ID'         => $post->ID,
 974				'post_title' => $post->post_title,
 975				'post_name'  => $post->post_name,
 976				//'post_status' => $post->post_status,
 977			);
 978			wp_update_post( $post_arr );
 979
 980			add_action( 'draft_apl_post_list', array( $this, 'draft_post_list' ), 10, 2 );
 981		}
 982
 983		$this->post_list_process( $post_id, $post );
 984	}
 985
 986	/**
 987	 * Save Post List
 988	 *
 989	 * Hook for saving object during post transitions.
 990	 *
 991	 * @since 0.4.0
 992	 *
 993	 * @see self::current_screen_hooks() Used by.
 994	 * @see private_apl_post_list hook.
 995	 * @see publish_apl_post_list hook.
 996	 * @see pending_apl_post_list hook.
 997	 * @see future_apl_post_list hook.
 998	 * @see {status}_{post_type} Hook Transitions.
 999	 * @link https://codex.wordpress.org/Post_Status_Transitions
1000	 *
1001	 * @param int     $post_id Old post ID.
1002	 * @param WP_Post $post    Current Post object.
1003	 */
1004	public function save_post_list( $post_id, $post ) {
1005		// CHECK AJAX REFERENCE.
1006		// ACTION = editpost
1007		// Doesn't work if there is no action ( Add New )
1008		// //check_admin_referer( 'update-post_' . $post_id );
1009
1010		// //add_action( 'private_apl_post_list', array( $this, 'save_post_list' ), 10, 2 );
1011		// //add_action( 'publish_apl_post_list', array( $this, 'save_post_list' ), 10, 2 );
1012		// //add_action( 'pending_apl_post_list', array( $this, 'save_post_list' ), 10, 2 );
1013		// //add_action( 'future_apl_post_list', array( $this, 'save_post_list' ), 10, 2 );
1014
1015		$this->post_list_process( $post_id, $post );
1016
1017	}
1018
1019	/**
1020	 * Draft Design
1021	 *
1022	 * Hook for draft Post Transitions with Designs.
1023	 *
1024	 * @since 0.4.0
1025	 *
1026	 * @param int     $post_id Post ID.
1027	 * @param WP_Post $post    (New) Post Data content.
1028	 */
1029	public function draft_design( $post_id, $post ) {
1030		if ( isset( $_REQUEST['action'] ) ) {
1031			if ( 'untrash' === $_REQUEST['action'] ) {
1032				return;
1033			}
1034		}
1035
1036		if ( empty( $post->post_name ) ) {
1037			if ( empty( $post->post_title ) ) {
1038				$post->post_title = 'APL-' . $post->ID;
1039			}
1040
1041			remove_action( 'draft_apl_design', array( $this, 'draft_design' ) );
1042			$post->post_name = sanitize_title_with_dashes( $post->post_title );
1043
1044			$postarr = array(
1045				'ID'         => $post->ID,
1046				'post_title' => $post->post_title,
1047				'post_name'  => $post->post_name,
1048			);
1049			wp_update_post( $postarr );
1050
1051			add_action( 'draft_apl_design', array( $this, 'draft_design' ), 10, 2 );
1052		}
1053
1054		$this->design_process( $post_id, $post );
1055	}
1056
1057	/**
1058	 * Save Design
1059	 *
1060	 * Hook for saving object during post transitions.
1061	 *
1062	 * @since 0.4.0
1063	 *
1064	 * @see self::current_screen_hooks() Used by.
1065	 * @see private_apl_design hook.
1066	 * @see publish_apl_design hook.
1067	 * @see pending_apl_design hook.
1068	 * @see future_apl_design hook.
1069	 * @see {status}_{post_type} Hook Transitions.
1070	 * @link https://codex.wordpress.org/Post_Status_Transitions
1071	 *
1072	 * @param int     $post_id Old post ID.
1073	 * @param WP_Post $post    Current Post object.
1074	 */
1075	public function save_design( $post_id, $post ) {
1076		$this->design_process( $post_id, $post );
1077	}
1078
1079	/**
1080	 * WP_Trash_Post APL Post List
1081	 *
1082	 * Host for trash post transitions with Post Lists.
1083	 *
1084	 * @since 0.4.0
1085	 *
1086	 * @link https://developer.wordpress.org/reference/functions/wp_trash_post/
1087	 *
1088	 * @param int $post_id Post ID. Default is ID of the global $post if EMPTY_TRASH_DAYS equals true.
1089	 * @return boolean
1090	 */
1091	public function action_wp_trash_post_apl_post_list( $post_id ) {
1092		$args = array(
1093			'post__in'  => array( $post_id ),
1094			'post_type' => 'apl_post_list',
1095			//'post_status' => 'trash',
1096		);
1097		$post_lists = new WP_Query( $args );
1098		if ( 1 > $post_lists->post_count ) {
1099			return false;
1100		}
1101		$post_list = $post_lists->post;
1102
1103		if ( 'apl_post_list' !== $post_list->post_type ) {
1104			return false;
1105		}
1106
1107		$apl_post_list = new APL_Post_List( $post_list->post_name );
1108
1109		$apl_design = new APL_Design( $apl_post_list->pl_apl_design );
1110
1111		$new_post_list_slug = $post_list->post_name . '__trashed';
1112		$new_design_slug    = '';
1113		if ( ! empty( $post_list->post_name ) ) {
1114			// //$slug_suffix = apply_filters( 'apl_design_slug_suffix', '-design' );
1115			$design_slug = apply_filters( 'apl_design_trash_slug', $new_post_list_slug );
1116			// //$new_design_slug = $design_slug . $slug_suffix;
1117			$new_design_slug = $design_slug;
1118		}
1119		$apl_post_list->pl_apl_design = $new_design_slug;
1120		$apl_design->slug             = $new_design_slug;
1121
1122		$apl_design->save_design();
1123	}
1124
1125	/**
1126	 * Un-Trash for Post List
1127	 *
1128	 * Hook for untrash Post Transition with Post Lists.
1129	 *
1130	 * @since 0.4.0
1131	 * @since 0.4.4 Added stricter APL_Design object referencing.
1132	 *
1133	 * @hook `untrash_post`
1134	 * @link https://codex.wordpress.org/Plugin_API/Action_Reference/untrash_post
1135	 *
1136	 * @param int $post_id ID of the post being untrashed.
1137	 * @return boolean
1138	 */
1139	public function action_untrash_post_apl_post_list( $post_id ) {
1140		$args = array(
1141			'post__in'    => array( $post_id ),
1142			'post_type'   => 'apl_post_list',
1143			'post_status' => 'trash',
1144		);
1145
1146		$post_lists = new WP_Query( $args );
1147		if ( 1 > $post_lists->post_count ) {
1148			return false;
1149		}
1150		$post_list = $post_lists->post;
1151
1152		if ( 'apl_post_list' !== $post_list->post_type ) {
1153			return false;
1154		}
1155
1156		$apl_post_list = new APL_Post_List( $post_list->post_name );
1157
1158		$apl_design = new APL_Design( $apl_post_list->pl_apl_design_id );
1159
1160		$new_post_list_slug = str_replace( '__trashed', '', $post_list->post_name );
1161		$new_design_slug    = '';
1162		if ( ! empty( $post_list->post_name ) ) {
1163			// //$slug_suffix = apply_filters( 'apl_design_slug_suffix', '-design' );
1164			$design_slug = apply_filters( 'apl_design_trash_slug', $new_post_list_slug );
1165			// //$new_design_slug = $design_slug . $slug_suffix;
1166			$new_design_slug = $design_slug;
1167		}
1168		$apl_post_list->pl_apl_design = $new_design_slug;
1169		$apl_design->slug             = $new_design_slug;
1170
1171		$apl_design->save_design();
1172	}
1173
1174	/**
1175	 * WP_Delete_Post APL Post List
1176	 *
1177	 * Host for delete post transitions with Post Lists.
1178	 *
1179	 * @since 0.4.0
1180	 * @since 0.4.4 Added stricter APL_Design object referencing.
1181	 * @see https://codex.wordpress.org/Plugin_API/Action_Reference/before_delete_post
1182	 *
1183	 * @param int $post_id The post id that is being deleted.
1184	 * @return boolean
1185	 */
1186	public function action_before_delete_post_apl_post_list( $post_id ) {
1187		$args = array(
1188			'post__in'    => array( $post_id ),
1189			'post_type'   => 'apl_post_list',
1190			'post_status' => 'trash',
1191		);
1192
1193		$post_lists = new WP_Query( $args );
1194		if ( 1 > $post_lists->post_count ) {
1195			return false;
1196		}
1197		$post_list = $post_lists->post;
1198
1199		if ( 'apl_post_list' !== $post_list->post_type ) {
1200			return false;
1201		}
1202
1203		$apl_post_list = new APL_Post_List( $post_list->post_name );
1204		$apl_design    = new APL_Design( $apl_post_list->pl_apl_design_id );
1205
1206		$apl_design->delete_design();
1207	}
1208
1209	/**
1210	 * Save General Settings
1211	 *
1212	 * Uses a lazy REST API built into WP.
1213	 *
1214	 * @uses Hook 'admin_post_{SCREEN ID}' ex. 'admin_post_apl_save_general_settings'.
1215	 * @link https://developer.wordpress.org/reference/hooks/admin_post_action/
1216	 */
1217	public function save_general_settings() {
1218		if (
1219				! wp_verify_nonce( $_POST['apl_general_settings_nonce'], 'apl_settings_general_save' ) &&
1220				! current_user_can( 'administrator' )
1221		) {
1222			wp_die();
1223		}
1224		$options = apl_options_load();
1225
1226		$tmp_ignore_pt = array();
1227		$post_types    = get_post_types( '', 'names' );
1228		foreach ( $post_types as $post_type ) {
1229			if ( isset( $_POST[ 'apl_ignore_pt_' . $post_type ] ) ) {
1230				$input = filter_input( INPUT_POST, 'apl_ignore_pt_' . $post_type, FILTER_SANITIZE_STRING );
1231
1232				$tmp_ignore_pt[ $post_type ] = sanitize_key( $input );
1233			}
1234		}
1235		$options['ignore_post_types'] = $tmp_ignore_pt;
1236
1237		if ( isset( $_POST['apl_delete_on_deactivate'] ) ) {
1238			$input = filter_input( INPUT_POST, 'apl_delete_on_deactivate', FILTER_SANITIZE_STRING );
1239			if ( 'yes' === $input ) {
1240				$options['delete_core_db'] = true;
1241			} elseif ( 'no' === $input ) {
1242				$options['delete_core_db'] = false;
1243			} else {
1244				$options['delete_core_db'] = false;
1245			}
1246		}
1247
1248		if ( isset( $_POST['apl_default_empty_enable'] ) ) {
1249			$input = filter_input( INPUT_POST, 'apl_delete_on_deactivate', FILTER_SANITIZE_STRING );
1250			if ( 'yes' === $input ) {
1251				$options['default_empty_enable'] = true;
1252			} elseif ( 'no' === $input ) {
1253				$options['default_empty_enable'] = false;
1254			} else {
1255				$options['default_empty_enable'] = true;
1256			}
1257		}
1258
1259		$options['default_empty_output'] = '';
1260		if ( isset( $_POST['apl_default_empty_message'] ) ) {
1261			// Sanitize with admins?
1262			// TODO Possibly change to a WP_Post Object. Db update would be required.
1263			$tmp_empty_messaage = filter_input( INPUT_POST, 'apl_default_empty_message', FILTER_UNSAFE_RAW );
1264
1265			$options['default_empty_output'] = $tmp_empty_messaage;
1266		}
1267
1268		apl_options_save( $options );
1269
1270		wp_redirect( 'admin.php?page=apl_settings' );
1271		//wp_die();
1272		exit();
1273	}
1274
1275	/**
1276	 * Settings Page AJAX Hooks
1277	 *
1278	 * Add AJAX hooks for Settings Page.
1279	 *
1280	 * @uses 'wp_ajax_{name}'
1281	 */
1282	public function add_settings_ajax_hooks() {
1283		add_action( 'wp_ajax_apl_settings_export', array( $this, 'ajax_settings_export' ) );
1284		add_action( 'wp_ajax_apl_export', 'apl_export' );
1285
1286		add_action( 'wp_ajax_apl_settings_import', array( $this, 'ajax_settings_import' ) );
1287		add_action( 'wp_ajax_apl_import', 'apl_import' );
1288
1289		add_action( 'wp_ajax_apl_settings_restore_defaults', array( $this, 'ajax__restore_defaults' ) );
1290	}
1291
1292	/**
1293	 * MCE External Plugins
1294	 *
1295	 * @since 0.4.2
1296	 *
1297	 * @see 'mce_external_plugins' filter hook
1298	 * @link https://codex.wordpress.org/Plugin_API/Filter_Reference/mce_external_plugins
1299	 *
1300	 * @param array $plugin_array Other plugin's mce buttons.
1301	 * @return mixed
1302	 */
1303	public function mce_external_plugins( $plugin_array ) {
1304		$plugin_array['advanced_post_list'] = APL_URL . 'admin/js/wp-editor-mce.js';
1305
1306		return $plugin_array;
1307
1308	}
1309
1310	/**
1311	 * MCE Buttons
1312	 *
1313	 * @since 0.4.2
1314	 *
1315	 * @uses 'mce_buttons' filter hook
1316	 * @link https://codex.wordpress.org/Plugin_API/Filter_Reference/mce_buttons,_mce_buttons_2,_mce_buttons_3,_mce_buttons_4
1317	 *
1318	 * @param array $buttons Buttons for MCE Editor.
1319	 * @return mixed
1320	 */
1321	public function mce_buttons( $buttons ) {
1322		array_push( $buttons, 'apl_post_list' );
1323		array_push( $buttons, 'dropcap', 'showrecent' );
1324
1325		return $buttons;
1326	}
1327
1328	/**
1329	 * TinyMCE Extra Vars
1330	 *
1331	 * @since 0.4.0
1332	 */
1333	public function tinymce_extra_vars() {
1334		$args = array(
1335			'post_type'   => 'apl_post_list',
1336			'post_status' => array(
1337				'draft',
1338				'pending',
1339				'publish',
1340				'future',
1341				'private',
1342				'trash',
1343			),
1344		);
1345
1346		$pl_query   = new WP_Query( $args );
1347		$post_lists = array();
1348		foreach ( $pl_query->posts as $apl_post ) {
1349			$post_lists[ $apl_post->post_name ] = $apl_post->post_title;
1350		}
1351
1352		$trans = array(
1353			'button_title'          => __( 'APL Post List', 'advanced-post-list' ),
1354			'button_tooltip'        => __( 'Insert APL Shortcode', 'advanced-post-list' ),
1355			'window_title'          => __( 'APL Shortcode', 'advanced-post-list' ),
1356			'window_body_1_label'   => __( 'Post List', 'advanced-post-list' ),
1357			'window_body_1_tooltip' => __( 'Select the Post List you want.', 'advanced-post-list' ),
1358
1359		);
1360
1361		$apl_tinymce_json = wp_json_encode(
1362			array(
1363				'post_lists' => $post_lists,
1364				'trans'      => $trans,
1365			)
1366		);
1367		?>
1368		<script type="text/javascript">
1369			var apl_tinyMCE = <?php echo $apl_tinymce_json; ?>;
1370		</script>
1371		<?php
1372	}
1373
1374	/**
1375	 * AJAX Settings Page Export
1376	 *
1377	 * Handles the AJAX call for exporting data.
1378	 *
1379	 * @since 0.3
1380	 * @since 0.4.4 Added stricter APL_Design object referencing.
1381	 */
1382	public function ajax_settings_export() {
1383		check_ajax_referer( 'apl_settings_export' );
1384
1385		$rtn_data = array(
1386			'action'      => 'apl_export',
1387			'_ajax_nonce' => wp_create_nonce( 'apl_export' ),
1388		);
1389
1390		$tmp_filename = 'file_export_name';
1391		if ( isset( $_POST['filename'] ) ) {
1392			$tmp_filename = filter_input( INPUT_POST, 'filename', FILTER_SANITIZE_STRING );
1393		}
1394		$rtn_data['filename'] = $tmp_filename;
1395
1396		$export_data = array(
1397			'version'           => APL_VERSION,
1398			'apl_post_list_arr' => array(),
1399			'apl_design_arr'    => array(),
1400		);
1401
1402		$args = array(
1403			'post_type'      => 'apl_post_list',
1404			'post_status'    => 'publish',
1405			'posts_per_page' => -1,
1406		);
1407		$apl_post_lists = new WP_Query( $args );
1408
1409		foreach ( $apl_post_lists->posts as $post_obj ) {
1410			$apl_post_list  = new APL_Post_List( $post_obj->post_name );
1411			$apl_design     = new APL_Design( $apl_post_list->pl_apl_design_id );
1412
1413			$export_data['apl_post_list_arr'][] = $apl_post_list->slug;
1414			$export_data['apl_design_arr'][] = $apl_design->slug;
1415		}
1416
1417		update_option( 'apl_export_data', $export_data );
1418
1419		echo json_encode( $rtn_data );
1420
1421		wp_die();
1422	}
1423
1424	/**
1425	 * AJAX Settings Import
1426	 *
1427	 * @since 0.4.0
1428	 * @since 0.4.4 Handle 0.3 and 0.4 database types separately, and stricter handling APL_Design with APL_Post_List.
1429	 *
1430	 * @uses add_settings_ajax_hooks().
1431	 * @uses wp_ajax_apl_settings_import.
1432	 */
1433	public function ajax_settings_import() {
1434		check_ajax_referer( 'apl_settings_import' );
1435
1436		$raw_content = array();
1437		$i = 0;
1438		while ( isset( $_FILES[ 'file_' . $i ] ) ) {
1439			/**
1440			 * @type array $file_{$i} {
1441			 *     @type int    $error
1442			 *     @type string $name
1443			 *     @type int    $size
1444			 *     @type string $tmp_name
1445			 *     @type string $type
1446			 * }
1447			 */
1448			if ( isset( $_FILES[ 'file_' . $i ]['tmp_name'] ) && ! empty( $_FILES[ 'file_' . $i ]['tmp_name'] ) ) {
1449				$file_error = ( isset( $_FILES[ 'file_' . $i ]['error'] ) ) ? intval( filter_var( $_FILES[ 'file_' . $i ]['error'], FILTER_SANITIZE_NUMBER_INT ) ) : 1;
1450				$file_type  = ( isset( $_FILES[ 'file_' . $i ]['type'] ) )  ? filter_var( $_FILES[ 'file_' . $i ]['type'], FILTER_SANITIZE_STRING )                : '';
1451				$file_tmp   = ( isset( $_FILES[ 'file_' . $i ]['type'] ) )  ? filter_var( $_FILES[ 'file_' . $i ]['tmp_name'], FILTER_SANITIZE_STRING )            : '';
1452
1453				// 2 = validate_file() - windows drive paths are needed for development purposes.
1454				if ( ! $file_error && 'application/json' === $file_type && ! in_array( validate_file( $file_tmp ), array( 1, 3 ) ) ) {
1455					$file_content  = file_get_contents( $_FILES[ 'file_' . $i ]['tmp_name'] );
1456
1457					$raw_content[] = json_decode( $file_content );
1458				}
1459			}
1460			$i++;
1461		}
1462
1463		$imported_content = array();
1464		foreach ( $raw_content as $v1_content ) {
1465			$update_items = array();
1466			if (
1467					isset( $v1_content->version ) &&
1468					preg_match( '/([0-9]+)\.([0-9]+)(?:\.([0-9]+))?(?:\.([0-9]|dev|a[1-9]|b[1-9]+))?/', $v1_content->version ) )
1469			{
1470				$version = $v1_content->version;
1471			} else {
1472				return new WP_Error( 'apl_admin', __( 'Version number is missing or invalid in imported file.', 'advanced-post-list' ) );
1473			}
1474
1475			// 0.3 Database.
1476			if ( version_compare( '0.3.0', $version, '<' ) && version_compare( '0.4.0', $version, '>' ) ) {
1477				if ( isset( $v1_content->presetDbObj ) && $v1_content->presetDbObj instanceof APL_Preset_Db ) {
1478					$update_items['preset_db'] = $v1_content->presetDbObj;
1479				}
1480			}
1481
1482			// 0.4+ Database.
1483			elseif( version_compare( '0.4.0', $version, '<' ) ) {
1484				if ( isset( $v1_content->apl_post_list_arr ) && $v1_content->apl_post_list_arr instanceof APL_Post_List ) {
1485					$update_items['apl_post_list_arr'] = $v1_content->apl_post_list_arr;
1486				}
1487				if ( isset( $v1_content->apl_design_arr ) && $v1_content->apl_design_arr instanceof APL_Design ) {
1488					$update_items['apl_design_arr'] = $v1_content->apl_design_arr;
1489				}
1490			}
1491
1492			$updater = new APL_Updater( $version, $update_items, 'OBJECT' );
1493
1494			$imported_content[] = array(
1495				'apl_post_list_arr' => $updater->apl_post_list_arr,
1496				'apl_design_arr'    => $updater->apl_design_arr,
1497			);
1498
1499		}
1500
1501		$overwrite_apl_post_list = array();
1502		$overwrite_apl_design    = array();
1503
1504		$data_overwrite_post_list = array();
1505		$data_overwrite_design    = array();
1506
1507		foreach ( $imported_content as $v1_content ) {
1508			// POST LISTS.
1509			foreach ( $v1_content['apl_post_list_arr'] as $v2_post_list ) {
1510				$db_post_list = new APL_Post_List( $v2_post_list->slug );
1511				// Check if Post List (ID) already exists.
1512				if ( 0 !== $db_post_list->id ) {
1513					$overwrite_apl_post_list[]  = $v2_post_list;
1514					$data_overwrite_post_list[] = $v2_post_list->slug;
1515					// DESIGNS.
1516					foreach ( $v1_content['apl_design_arr'] as $k3_design => $v3_design ) {
1517						if ( $v3_design->slug === $v2_post_list->pl_apl_design ) {
1518							$overwrite_apl_design[]  = $v3_design;
1519							$data_overwrite_design[] = $v3_design->slug;
1520
1521							unset( $v1_content['apl_design_arr'][ $k3_design ] );
1522							break;
1523						}
1524					}
1525				} else {
1526
1527					// DESIGNS.
1528					foreach ( $v1_content['apl_design_arr'] as $k3_design => $v3_design ) {
1529						if ( $v3_design->slug === $v2_post_list->pl_apl_design ) {
1530							// Uses slug instead of ID.
1531							$db_design = new APL_Design( $v3_design->slug );
1532							if ( 0 !== $db_design->id ) {
1533								// Add Variable to Database.
1534								//$v2_post_list->pl_apl_design_id   = $v3_design->id;
1535								//$v2_post_list->pl_apl_design_slug = $v3_design->slug;
1536								//$this->import_process_post_list( $v2_post_list );
1537								$overwrite_apl_post_list[]  = $v2_post_list;
1538								$data_overwrite_post_list[] = $v2_post_list->slug;
1539
1540								$overwrite_apl_design[]  = $v3_design;
1541								$data_overwrite_design[] = $v3_design->slug;
1542							} else {
1543								// Add Variable to Database.
1544								//$db_design = $this->import_process_design( $v3_design );
1545								$db_design = $v3_design;
1546								$this->import_process_post_list_design( $v2_post_list, $db_design );
1547							}
1548
1549
1550							unset( $v1_content['apl_design_arr'][ $k3_design ] );
1551							break;
1552						}
1553					}
1554					// Add Variable to Database.
1555					//$this->import_process_post_list( $v2_post_list, $db_design );
1556
1557				}
1558			}
1559
1560			// DESIGNS.
1561			// Catch any remaining designs that may be left.
1562			foreach ( $v1_content['apl_design_arr'] as $v2_design ) {
1563				// Uses slug instead of ID.
1564				$db_design = new APL_Design( $v2_design->slug );
1565				if ( 0 !== $db_design->id ) {
1566					$overwrite_apl_design[]  = $v2_design;
1567					$data_overwrite_design[] = $v2_design->slug;
1568				} else {
1569					// Add Variable to Database.
1570					$this->import_process_design( $v2_design );
1571				}
1572			}
1573		}
1574
1575		update_option( 'apl_import_overwrite_post_list', $overwrite_apl_post_list );
1576		update_option( 'apl_import_overwrite_design', $overwrite_apl_design );
1577
1578		$rtn_data = array(
1579			'action'              => 'apl_import',
1580			'_ajax_nonce'         => wp_create_nonce( 'apl_import' ),
1581			'overwrite_post_list' => $data_overwrite_post_list,
1582			'overwrite_design'    => $data_overwrite_design,
1583		);
1584
1585		echo json_encode( $rtn_data );
1586
1587		die();
1588	}
1589
1590	/**
1591	 * AJAX - Restore Defaults
1592	 *
1593	 * @since 0.5
1594	 *
1595	 * @return void
1596	 */
1597	public function ajax__restore_defaults() {
1598		check_ajax_referer( 'apl_settings_restore_defaults' );
1599
1600		$this->restore_default_presets();
1601
1602		wp_send_json_success( 'Success' );
1603	}
1604
1605	/**
1606	 * Restore Default Presets
1607	 *
1608	 * @since 0.5
1609	 */
1610	public function restore_default_presets() {
1611		include_once APL_DIR . 'admin/includes/default-presets.php';
1612
1613		$apl_post_list_default = apl_restore_post_list_default();
1614
1615		$apl_design_excerpt_divided      = apl_restore_design_excerpt_divided();
1616		$apl_design_page_content_divided = apl_restore_design_page_content_divided();
1617		$apl_design_footer_list          = apl_restore_design_footer_list();
1618
1619		$apl_post_list_default->title         = 'Excerpt Divided';
1620		$apl_post_list_default->slug          = 'excerpt-divided';
1621		$apl_post_list_default->pl_apl_design = 'excerpt-divided';
1622		$this->import_process_post_list_design( $apl_post_list_default, $apl_design_excerpt_divided );
1623
1624		$apl_post_list_default->title         = 'Page Content Divided';
1625		$apl_post_list_default->slug          = 'page-content-divided';
1626		$apl_post_list_default->pl_apl_design = 'page-content-divided';
1627		$this->import_process_post_list_design( $apl_post_list_default, $apl_design_page_content_divided );
1628
1629		$apl_post_list_default->title         = 'Footer List';
1630		$apl_post_list_default->slug          = 'footer-list';
1631		$apl_post_list_default->pl_apl_design = 'footer-list';
1632		$this->import_process_post_list_design( $apl_post_list_default, $apl_design_footer_list );
1633	}
1634
1635	/**
1636	 * Process Import for Post Lists
1637	 *
1638	 * @ignore
1639	 * @since 0.4.0
1640	 * @since 0.4.4 Added APL…

Large files files are truncated, but you can click here to view the full file