ed-in user. Use the field parameter to specify which field to output. Examples:' ) . ''; $message .= '

Some shortcodes from other plugins may also work, but it depends on the shortcode.

'; return $message; } private function formatShortcodeInfo($tag, $description, $exampleCode = null) { $result = sprintf('[%s] - %s', esc_html($tag), $description); if ( $exampleCode !== null ) { $result .= ' Example output:
' . $this->getExampleShortcodeOutput($exampleCode); } return $result; } private function getExampleShortcodeOutput($exampleCode) { $output = do_shortcode($exampleCode); if ( $output === '' ) { return '(empty string)'; } return sprintf('%s', esc_html($output)); } private function getPriorityHelp() { $tips = [ 'Redirects are processed from top to bottom and the first matching setting is used.', 'You can drag and drop redirects to change their priority.', 'When you create redirects for specific users their order doesn\'t matter, but you can still move them around to organize them.', ]; return ''; } private function getFirstLoginHelp() { $conditions = [ sprintf('The user was registered less than %d days ago.', self::FIRST_LOGIN_AGE_LIMIT_IN_DAYS), 'The user was registered after redirect settings were changed for the first time.', sprintf('The user has not logged in while this plugin and the "%s" module is active.', $this->tabTitle), ]; return '

A "first login" redirect happens when a new user logs in for the first time.

' . '

WordPress does not record logins, so sometimes it\'s not possible to reliably determine if a user has already logged in before or not. To help avoid unnecessary redirects, the plugin will only perform a "first login" redirect when all of the following conditions are met:

' . ''; } private function getEmergencyShutdownHelp() { return '

If something goes wrong, you can disable all custom redirects by adding this code to wp-config.php:

' . '

define(\'AME_DISABLE_REDIRECTS\', true);

' . '

Note that this only applies to redirects created using this plugin. It will not prevent other plugins or themes from redirecting users.

'; } } class Redirect { /** * @var string */ private $actorId; /** * @var string */ private $urlTemplate; /** * @var boolean */ private $shortcodesEnabled; protected function __construct( $actorId, $urlTemplate, $shortcodesEnabled = false ) { $this->actorId = $actorId; $this->urlTemplate = $urlTemplate; $this->shortcodesEnabled = $shortcodesEnabled; } public static function fromArray(array $properties) { return new static( $properties['actorId'], $properties['urlTemplate'], !empty($properties['shortcodesEnabled']) ); } /** * @return string */ public function getActorId() { return $this->actorId; } /** * @return string */ public function getUrl() { $url = $this->urlTemplate; if ( $this->shortcodesEnabled && function_exists('do_shortcode') ) { $url = do_shortcode($url); } return $url; } } class RedirectCollection { /** * @var array */ protected $rawItems = []; public function __construct($rawItems = []) { $this->rawItems = $rawItems; } /** * @param string $trigger * @return Redirect[] */ public function filterByTrigger($trigger) { if ( isset($this->rawItems[$trigger]) ) { return array_map([Redirect::class, 'fromArray'], $this->rawItems[$trigger]); } else { return []; } } /** * @return array */ public function toDbFormat() { return $this->rawItems; } /** * @param array $items * @return static */ public static function fromDbFormat($items) { return new static($items); } /** * @return array */ public function flatten() { $results = []; foreach ($this->rawItems as $trigger => $items) { foreach ($items as $properties) { if ( !is_array($properties) ) { continue; } $properties['trigger'] = $trigger; $results[] = $properties; } } return $results; } /** * Add a redirect to the collection. * * @param array $redirectProperties */ public function add($redirectProperties) { $trigger = $redirectProperties['trigger']; if ( !isset($this->rawItems[$trigger]) ) { $this->rawItems[$trigger] = []; } $this->rawItems[$trigger][] = $redirectProperties; } } abstract class Triggers { const LOGIN = 'login'; const LOGOUT = 'logout'; const REGISTRATION = 'registration'; const FIRST_LOGIN = 'firstLogin'; public static function getValues() { return [self::LOGIN, self::LOGOUT, self::REGISTRATION, self::FIRST_LOGIN]; } } class MenuExtractor { private $items = []; public function __construct($menuTree) { foreach ($menuTree as $item) { $this->processItem($item); } } private function processItem($item, $parentTitle = null) { //Skip separators. if ( !empty($item['separator']) ) { return; } $templateId = ameMenuItem::get($item, 'template_id'); $url = ameMenuItem::get($item, 'url'); $rawTitle = ameMenuItem::get($item, 'menu_title', '[Untitled]'); $fullTitle = trim(wp_strip_all_tags(ameMenuItem::remove_update_count($rawTitle))); if ( $parentTitle !== null ) { $fullTitle = $parentTitle . ' → ' . $fullTitle; } if ( empty($item['custom']) && ($templateId !== null) && !$this->looksLikeUnusableSlug($url) ) { //Add the admin URL shortcode to the URL if it looks like a relative URL that points //to a dashboard page. if ( $this->looksLikeDashboardUrl($url) ) { $url = '[ame-wp-admin]' . $url; } $this->items[] = [ 'templateId' => $templateId, 'title' => $fullTitle, 'url' => $url, ]; } if ( !empty($item['items']) ) { foreach ($item['items'] as $submenu) { $this->processItem($submenu, $fullTitle); } } } /** * @param string $url * @return boolean */ private function looksLikeDashboardUrl($url) { $scheme = wp_parse_url($url, PHP_URL_SCHEME); if ( !empty($scheme) ) { return false; } return preg_match('@^[a-z0-9][a-z0-9_-]{0,30}?\.php@i', $url) === 1; } /** * Check if a string looks like a plain admin menu slug and not a usable URL. * * Sometimes plugins create admin menus that don't have a callback function. A menu like that * will show up fine, and it can be used as a parent for other menu items. However, the menu * itself won't have a working URL, so we don't want to offer it as a redirect option. * * For example, the top level "WooCommerce" menu doesn't have a valid URL, it just has * a slug: "woocommerce". You just usually don't notice this because WordPress automatically * replaces the menu URL with the URL of the first child item. * * @param string|mixed $url * @return bool */ private function looksLikeUnusableSlug($url) { if ( !is_string($url) ) { return true; } //Technically, a menu slug could be anything, so we can't easily determine if a string //is really a slug or just a weird relative URL. However, it seems safe to assume that //a "URL" that has no dots (so no file extension or domain name) and no slashes (so no //protocol or relative directories) is probably unusable. $suspiciousSegmentLength = strcspn($url, './'); return ($suspiciousSegmentLength === strlen($url)); } public function getUsableItems() { return $this->items; } }