Empty when the payload is fine. */ public static function collect(Validation $validate): array { $post = Request::post(); if (!isset($post['existing_menu']) && !isset($post['menu'])) { $validate->wpDieMessage(); } $errors = []; if (!$validate->pagesFound()) { $errors[] = self::error('pages', 'no_pages', __('There are no pages to save.', 'admin-options-pages')); } $missingTitles = $validate->noPageTitleFound(); if ($missingTitles) { $errors[] = self::error('pages', 'missing_title', __('Every page needs a menu title.', 'admin-options-pages')); } foreach ((array) $validate->notCorrectFieldNames() as $name) { /* translators: %s: the option name */ $errors[] = self::error('field_name', 'invalid_field_name', sprintf(__('"%s" is not a valid option name.', 'admin-options-pages'), $name)); } foreach ($validate->fieldsWithoutName() as [$pageKey, $fieldKey]) { $errors[] = self::error( sprintf('pages[%s][fields][%s][field_name]', $pageKey, $fieldKey), 'missing_field_name', __('Every field with an option needs an option name.', 'admin-options-pages') ); } foreach (array_keys((array) $validate->duplicatedFieldNames()) as $name) { /* translators: %s: the option name */ $errors[] = self::error('field_name', 'duplicated_field_name', sprintf(__('The option name "%s" is used more than once.', 'admin-options-pages'), $name)); } foreach ((array) $validate->duplicatedOptionNames() as $name) { /* translators: %s: the option name */ $errors[] = self::error('field_name', 'option_name_in_use', sprintf(__('The option name "%s" is already in use.', 'admin-options-pages'), $name)); } if (self::menuSlugInUse(self::menuSlug($post))) { $errors[] = self::error( isset($post['existing_menu']) ? 'existing_menu.menu_slug' : 'pages[0][subpage_slug]', 'menu_slug_in_use', __('This menu is already used by another options page.', 'admin-options-pages') ); } if (isset($post['existing_menu'])) { $validate->existingMenu(); return $errors; } if ($validate->notCorrectMenuPosition()) { $errors[] = self::error('menu.menu_position', 'invalid_menu_position', __('The menu position is not valid.', 'admin-options-pages')); } if ($validate->notCorrectMenuTitle()) { $errors[] = self::error('menu.menu_title', 'invalid_menu_title', __('The menu title is not valid.', 'admin-options-pages')); } if (!$validate->menuIcon()) { $errors[] = self::error('menu.menu_icon', 'invalid_menu_icon', __('The menu icon is not valid.', 'admin-options-pages')); } return $errors; } /** * Run the rules on a payload that is not the current request. * * @param array $post The payload in the shape of the editor form. * @param array $get `page` and `optionpage`, as the flow needs them. */ public static function errors(array $post, array $get = []): array { try { return Request::run($post, $get, function () { return self::collect(new Validation()); }); } catch (ValidationFailed $failure) { return [self::error('', 'rejected', $failure->getMessage())]; } } /** * The menu_slug the payload is stored under: the WordPress menu it adds pages to, or the slug of its first page. */ private static function menuSlug(array $post): string { $slug = isset($post['existing_menu']) ? ($post['existing_menu']['menu_slug'] ?? '') : ($post['pages'][0]['subpage_slug'] ?? ''); return is_string($slug) ? $slug : ''; } /** * Whether another stored menu has this menu_slug. It is the key of a menu, also outside this site (an export, the * files of Pro), so it must be unique. The menu being edited (or overwritten by an import) is not "another". */ private static function menuSlugInUse(string $slug): bool { if ($slug === '' || !PageRepository::tableExists()) { return false; } $editing = (Request::get()['page'] ?? '') === SubpageCreate::SLUG ? 0 : (int) (Request::get()['optionpage'] ?? 0); foreach (PageRepository::rows() as $row) { if ((string) $row->menu_slug === $slug && (int) $row->id !== $editing) { return true; } } return false; } private static function error(string $field, string $code, string $message): array { return ['field' => $field, 'code' => $code, 'message' => $message]; } }