/** * Handle menu uploads and downloads. * This is a callback for the 'admin_menu_editor_header' action. * * @param string $action * @return void */ function menu_editor_header($action = '') { $wp_menu_editor = $this->wp_menu_editor; //Handle menu download requests if ($action == 'download_menu') { $export = $this->get_exported_menu(); if (empty($export['menu']) || empty($export['filename'])) { die("Exported data not found"); } //Force file download header("Content-Description: File Transfer"); header('Content-Disposition: attachment; filename="' . $export['filename'] . '"'); header("Content-Type: application/force-download"); header("Content-Transfer-Encoding: binary"); header("Content-Length: " . strlen($export['menu'])); /* The three lines below basically make the download non-cacheable */ header("Cache-control: private"); header("Pragma: private"); header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); echo $export['menu']; die; //Handle menu uploads } elseif ($action == 'upload_menu') { header('Content-Type: text/html'); if (empty($_FILES['menu'])) { echo $wp_menu_editor->json_encode(array('error' => "No file specified")); die; } $file_data = $_FILES['menu']; if (filesize($file_data['tmp_name']) > $this->export_settings['max_file_size']) { $this->output_for_jquery_form($wp_menu_editor->json_encode(array('error' => "File too big"))); die; } //Check for general upload errors. if ($file_data['error'] != UPLOAD_ERR_OK) { switch ($file_data['error']) { case UPLOAD_ERR_INI_SIZE: $message = sprintf('The uploaded file exceeds the upload_max_filesize directive in php.ini. Limit: %s', strval(ini_get('upload_max_filesize'))); break; case UPLOAD_ERR_FORM_SIZE: $message = "The uploaded file exceeds the internal file size limit. Please contact the developer."; break; case UPLOAD_ERR_PARTIAL: $message = "The file was only partially uploaded"; break; case UPLOAD_ERR_NO_FILE: $message = "No file was uploaded"; break; case UPLOAD_ERR_NO_TMP_DIR: $message = "Missing a temporary folder"; break; case UPLOAD_ERR_CANT_WRITE: $message = "Failed to write file to disk"; break; case UPLOAD_ERR_EXTENSION: $message = "File upload stopped by a PHP extension"; break; default: $message = 'Unknown upload error #' . $file_data['error']; break; } $this->output_for_jquery_form($wp_menu_editor->json_encode(array('error' => $message))); die; } $file_contents = file_get_contents($file_data['tmp_name']); //Check if this file could plausibly contain an exported menu if (strpos($file_contents, $this->export_settings['old_format_string']) !== false) { //This is an exported menu in the old format. $data = $wp_menu_editor->json_decode($file_contents, true); if (!(isset($data['menu']) && is_array($data['menu']))) { $this->output_for_jquery_form($wp_menu_editor->json_encode(array('error' => "Unknown or corrupted file format"))); die; } try { $menu = ameMenu::load_array($data['menu'], false, true); } catch (InvalidMenuException $ex) { $this->output_for_jquery_form($wp_menu_editor->json_encode(array('error' => $ex->getMessage()))); die; } } else { if (strpos($file_contents, ameMenu::format_name) !== false) { //This is an export file in the new format. try { $menu = ameMenu::load_json($file_contents, false, true); } catch (InvalidMenuException $ex) { $this->output_for_jquery_form($wp_menu_editor->json_encode(array('error' => $ex->getMessage()))); die; } } else { //This is an unknown file. $this->output_for_jquery_form($wp_menu_editor->json_encode(array('error' => "Unknown file format"))); die; } } //Merge the imported menu with the current one. $menu['tree'] = $wp_menu_editor->menu_merge($menu['tree']); //Everything looks okay, send back the menu data $this->output_for_jquery_form(ameMenu::to_json($menu)); die; } }
private function handle_form_submission($post, $action = '') { if ($action == 'save_menu') { //Save the admin menu configuration. if (isset($post['data'])) { check_admin_referer('menu-editor-form'); //Try to decode a menu tree encoded as JSON $url = remove_query_arg(array('noheader')); try { $menu = ameMenu::load_json($post['data'], true); } catch (InvalidMenuException $ex) { $debugData = ''; $debugData .= "Exception:\n" . $ex->getMessage() . "\n\n"; $debugData .= "Used POST data:\n" . print_r($this->post, true) . "\n\n"; $debugData .= "Original POST:\n" . print_r($this->originalPost, true) . "\n\n"; $debugData .= "\$_POST global:\n" . print_r($_POST, true); $debugData = sprintf("<textarea rows=\"30\" cols=\"100\">%s</textarea>", htmlentities($debugData)); wp_die("Error: Failed to decode menu data!<br><br>\n" . "Please send this debugging information to the developer: <br>" . $debugData); return; } //Sanitize menu item properties. $menu['tree'] = ameMenu::sanitize($menu['tree']); //Discard capabilities that refer to unregistered post types or taxonomies. if (!empty($menu['granted_capabilities'])) { $capFilter = new ameGrantedCapabilityFilter(); $menu['granted_capabilities'] = $capFilter->clean_up($menu['granted_capabilities']); } //Save the custom menu $this->set_custom_menu($menu); //Redirect back to the editor and display the success message. //Also, automatically select the last selected actor (convenience feature). $query = array('message' => 1); if (isset($post['selected_actor']) && !empty($post['selected_actor'])) { $query['selected_actor'] = rawurlencode(strval($post['selected_actor'])); } wp_redirect(add_query_arg($query, $url)); die; } else { $message = "Failed to save the menu. "; if (isset($this->post['data_length']) && is_numeric($this->post['data_length'])) { $message .= sprintf('Expected to receive %d bytes of menu data in $_POST[\'data\'], but got nothing.', intval($this->post['data_length'])); } wp_die($message); } } else { if ($action == 'save_settings') { //Save overall plugin configuration (permissions, etc). check_admin_referer('save_settings'); //Plugin access setting. $valid_access_settings = array('super_admin', 'manage_options'); //On Multisite only Super Admins can choose the "Only the current user" option. if (!is_multisite() || is_super_admin()) { $valid_access_settings[] = 'specific_user'; } if (isset($this->post['plugin_access']) && in_array($this->post['plugin_access'], $valid_access_settings)) { $this->options['plugin_access'] = $this->post['plugin_access']; if ($this->options['plugin_access'] === 'specific_user') { $this->options['allowed_user_id'] = get_current_user_id(); } else { $this->options['allowed_user_id'] = null; } } //Whether to hide the plugin on the "Plugins" admin page. if (!is_multisite() || is_super_admin()) { if (!empty($this->post['hide_plugin_from_others'])) { $this->options['plugins_page_allowed_user_id'] = get_current_user_id(); } else { $this->options['plugins_page_allowed_user_id'] = null; } } //Configuration scope. The Super Admin is the only one who can change it since it affects all sites. if (is_multisite() && is_super_admin()) { $valid_scopes = array('global', 'site'); if (isset($this->post['menu_config_scope']) && in_array($this->post['menu_config_scope'], $valid_scopes)) { $this->options['menu_config_scope'] = $this->post['menu_config_scope']; } } //Security logging. $this->options['security_logging_enabled'] = !empty($this->post['security_logging_enabled']); //Hide some menu options by default. $this->options['hide_advanced_settings'] = !empty($this->post['hide_advanced_settings']); //Enable the now-obsolete "Hide" button. if ($this->is_pro_version()) { $this->options['show_deprecated_hide_button'] = !empty($this->post['show_deprecated_hide_button']); } //Menu editor colour scheme. if (!empty($this->post['ui_colour_scheme'])) { $valid_colour_schemes = array('classic', 'wp-grey', 'modern-one'); $scheme = strval($this->post['ui_colour_scheme']); if (in_array($scheme, $valid_colour_schemes)) { $this->options['ui_colour_scheme'] = $scheme; } } //Enable submenu icons. if (!empty($this->post['submenu_icons_enabled'])) { $submenu_icons_enabled = strval($this->post['submenu_icons_enabled']); $valid_icon_settings = array('never', 'if_custom', 'always'); if (in_array($submenu_icons_enabled, $valid_icon_settings, true)) { $this->options['submenu_icons_enabled'] = $submenu_icons_enabled; } } //Where to put new or unused menu items. if (!empty($this->post['unused_item_position'])) { $unused_item_position = strval($this->post['unused_item_position']); $valid_position_settings = array('relative', 'bottom'); if (in_array($unused_item_position, $valid_position_settings, true)) { $this->options['unused_item_position'] = $unused_item_position; } } //How verbose "access denied" errors should be. if (!empty($this->post['error_verbosity'])) { $error_verbosity = intval($this->post['error_verbosity']); $valid_verbosity_levels = array(self::VERBOSITY_LOW, self::VERBOSITY_NORMAL, self::VERBOSITY_VERBOSE); if (in_array($error_verbosity, $valid_verbosity_levels)) { $this->options['error_verbosity'] = $error_verbosity; } } $this->save_options(); wp_redirect(add_query_arg('updated', 1, $this->get_settings_page_url())); } } }
private function handle_form_submission($post, $action = '') { if ($action == 'save_menu') { //Save the admin menu configuration. if (isset($post['data'])) { check_admin_referer('menu-editor-form'); //Try to decode a menu tree encoded as JSON $url = remove_query_arg(array('noheader')); try { $menu = ameMenu::load_json($post['data'], true); } catch (InvalidMenuException $ex) { //Or redirect & display the error message wp_redirect(add_query_arg('message', 2, $url)); die; } //Save the custom menu $this->set_custom_menu($menu); //Redirect back to the editor and display the success message. //Also, automatically select the last selected actor (convenience feature). $query = array('message' => 1); if (isset($post['selected_actor']) && !empty($post['selected_actor'])) { $query['selected_actor'] = rawurlencode(strval($post['selected_actor'])); } wp_redirect(add_query_arg($query, $url)); die; } else { $message = "Failed to save the menu. "; if (isset($this->post['data_length']) && is_numeric($this->post['data_length'])) { $message .= sprintf('Expected to receive %d bytes of menu data in $_POST[\'data\'], but got nothing.', intval($this->post['data_length'])); } wp_die($message); } } else { if ($action == 'save_settings') { //Save overall plugin configuration (permissions, etc). check_admin_referer('save_settings'); //Plugin access setting. $valid_access_settings = array('super_admin', 'manage_options'); //On Multisite only Super Admins can choose the "Only the current user" option. if (!is_multisite() || is_super_admin()) { $valid_access_settings[] = 'specific_user'; } if (isset($this->post['plugin_access']) && in_array($this->post['plugin_access'], $valid_access_settings)) { $this->options['plugin_access'] = $this->post['plugin_access']; if ($this->options['plugin_access'] === 'specific_user') { $this->options['allowed_user_id'] = get_current_user_id(); } else { $this->options['allowed_user_id'] = null; } } //Whether to hide the plugin on the "Plugins" admin page. if (!is_multisite() || is_super_admin()) { if (!empty($this->post['hide_plugin_from_others'])) { $this->options['plugins_page_allowed_user_id'] = get_current_user_id(); } else { $this->options['plugins_page_allowed_user_id'] = null; } } //Configuration scope. The Super Admin is the only one who can change it since it affects all sites. if (is_multisite() && is_super_admin()) { $valid_scopes = array('global', 'site'); if (isset($this->post['menu_config_scope']) && in_array($this->post['menu_config_scope'], $valid_scopes)) { $this->options['menu_config_scope'] = $this->post['menu_config_scope']; } } //Security logging. $this->options['security_logging_enabled'] = !empty($this->post['security_logging_enabled']); //Hide some menu options by default. $this->options['hide_advanced_settings'] = !empty($this->post['hide_advanced_settings']); //Enable the now-obsolete "Hide" button. if ($this->is_pro_version()) { $this->options['show_deprecated_hide_button'] = !empty($this->post['show_deprecated_hide_button']); } //Menu editor colour scheme. if (!empty($this->post['ui_colour_scheme'])) { $valid_colour_schemes = array('classic', 'wp-grey'); $scheme = strval($this->post['ui_colour_scheme']); if (in_array($scheme, $valid_colour_schemes)) { $this->options['ui_colour_scheme'] = $scheme; } } //Enable submenu icons. if (!empty($this->post['submenu_icons_enabled'])) { $submenu_icons_enabled = strval($this->post['submenu_icons_enabled']); $valid_icon_settings = array('never', 'if_custom', 'always'); if (in_array($submenu_icons_enabled, $valid_icon_settings, true)) { $this->options['submenu_icons_enabled'] = $submenu_icons_enabled; } } $this->save_options(); wp_redirect(add_query_arg('updated', 1, $this->get_settings_page_url())); } } }
} } elseif ($second[$key] !== $value) { $difference[$key] = $value; } } return $difference; } add_action('admin_init', function () { global $wp_menu_editor; $menu = $wp_menu_editor->load_custom_menu(); if (empty($menu)) { return; } $compressed = ameMenu::compress($menu); $loaded = ameMenu::load_json(ameMenu::to_json($compressed)); $expected = ameMenu::load_json(ameMenu::to_json($menu)); $diff1 = ame_test_array_diff_assoc_recursive($expected, $loaded); $diff2 = ame_test_array_diff_assoc_recursive($loaded, $expected); if (!empty($diff1) || !empty($diff2)) { header('X-AME-Test-Failed: compression', true, 500); echo "<h1>Test failed: Compression causes data loss!</h1>"; echo "<p>Loading compressed and uncompressed versions of the same menu configuration produced different results.</p>"; echo '<p>Keys that are missing or different in the compressed configuration (expected vs compressed):</p>'; echo '<pre>'; echo htmlentities(print_r($diff1, true)); echo '</pre>'; echo '<h2>Reverse diff (compressed vs expected):</h2>'; echo '<pre>'; echo htmlentities(print_r($diff2, true)); echo '</pre>'; exit;
private function handle_form_submission($post, $action = '') { if ($action == 'save_menu') { if (isset($post['data'])) { check_admin_referer('menu-editor-form'); //Try to decode a menu tree encoded as JSON $url = remove_query_arg(array('noheader')); try { $menu = ameMenu::load_json($post['data'], true); } catch (InvalidMenuException $ex) { //Or redirect & display the error message wp_redirect(add_query_arg('message', 2, $url)); die; } //Save the custom menu $this->set_custom_menu($menu); //Redirect back to the editor and display the success message wp_redirect(add_query_arg('message', 1, $url)); die; } else { $message = "Failed to save the menu. "; if (isset($this->post['data_length']) && is_numeric($this->post['data_length'])) { $message .= sprintf('Expected to receive %d bytes of menu data in $_POST[\'data\'], but got nothing.', intval($this->post['data_length'])); } wp_die($message); } } }
/** * Handle menu uploads and downloads. * This is a callback for the 'admin_menu_editor_header' action. * * @param string $action * @return void */ function menu_editor_header($action = '') { $wp_menu_editor = $this->wp_menu_editor; //Handle menu download requests if ($action == 'download_menu') { $export = $this->get_exported_menu(); if (empty($export['menu']) || empty($export['filename'])) { die("Exported data not found"); } //Force file download header("Content-Description: File Transfer"); header('Content-Disposition: attachment; filename="' . $export['filename'] . '"'); header("Content-Type: application/force-download"); header("Content-Transfer-Encoding: binary"); header("Content-Length: " . strlen($export['menu'])); /* The three lines below basically make the download non-cacheable */ header("Cache-control: private"); header("Pragma: private"); header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); echo $export['menu']; die; //Handle menu uploads } elseif ($action == 'upload_menu') { header('Content-Type: text/html'); if (empty($_FILES['menu'])) { echo $wp_menu_editor->json_encode(array('error' => "No file specified")); die; } $file_data = $_FILES['menu']; if (filesize($file_data['tmp_name']) > $this->export_settings['max_file_size']) { echo '<textarea cols="50" rows="5">', $wp_menu_editor->json_encode(array('error' => "File too big")), '</textarea>'; die; } $file_contents = file_get_contents($file_data['tmp_name']); //Check if this file could plausibly contain an exported menu if (strpos($file_contents, $this->export_settings['old_format_string']) !== false) { //This is an exported menu in the old format. $data = $wp_menu_editor->json_decode($file_contents, true); if (!(isset($data['menu']) && is_array($data['menu']))) { echo '<textarea cols="50" rows="5">', $wp_menu_editor->json_encode(array('error' => "Unknown or corrupted file format")), '</textarea>'; die; } try { $menu = ameMenu::load_array($data['menu']); } catch (InvalidMenuException $ex) { echo '<textarea cols="50" rows="5">', $wp_menu_editor->json_encode(array('error' => $ex->getMessage())), '</textarea>'; die; } } else { if (strpos($file_contents, ameMenu::format_name) !== false) { //This is an export file in the new format. try { $menu = ameMenu::load_json($file_contents); } catch (InvalidMenuException $ex) { echo '<textarea cols="50" rows="5">', $wp_menu_editor->json_encode(array('error' => $ex->getMessage())), '</textarea>'; die; } } else { //This is an unknown file. echo '<textarea cols="50" rows="5">', $wp_menu_editor->json_encode(array('error' => "Unknown file format")), '</textarea>'; die; } } //Merge the imported menu with the current one. $menu['tree'] = $wp_menu_editor->menu_merge($menu['tree']); //Everything looks okay, send back the menu data die('<textarea>' . ameMenu::to_json($menu) . '</textarea>'); } }
/** * Import admin menu configuration from a JSON file. * * ## OPTIONS * * <file> * : Import file name. * * @param array $args */ public function import($args) { $fileName = $args[0]; if (!is_readable($fileName)) { WP_CLI::error('The file doesn\'t exist or isn\'t readable.'); return; } $json = file_get_contents($fileName); try { $loadedMenu = ameMenu::load_json($json); } catch (Exception $ex) { WP_CLI::error($ex->getMessage()); return; } $menuEditor = $this->getMenuEditor(); $menuEditor->set_custom_menu($loadedMenu); WP_CLI::success('Import completed.'); }
private function handle_form_submission($post) { if (isset($post['data'])) { check_admin_referer('menu-editor-form'); //Try to decode a menu tree encoded as JSON $url = remove_query_arg('noheader'); try { $menu = ameMenu::load_json($post['data'], true); } catch (InvalidMenuException $ex) { //Or redirect & display the error message wp_redirect(add_query_arg('message', 2, $url)); die; } //Save the custom menu $this->set_custom_menu($menu); //Redirect back to the editor and display the success message wp_redirect(add_query_arg('message', 1, $url)); die; } }