?
avatar ceford
ceford
27 Jun 2020

Steps to reproduce the issue

Go to Help -> Joomla Help in Administrator menu. Look down Alphabetical Index

Expected result

Items new or default in Joomla 4

Actual result

Nothing on Privacy. Some System panels not documented.

System information (as much as possible)

Additional comments

I see the index is in administrator/help/en-GB/toc.json - is that hand crafted or compiled from source somewhere.

avatar ceford ceford - open - 27 Jun 2020
avatar joomla-cms-bot joomla-cms-bot - labeled - 27 Jun 2020
avatar brianteeman
brianteeman - comment - 27 Jun 2020

It is created by the script helpTOC in the build folder

avatar brianteeman
brianteeman - comment - 27 Jun 2020

But that script is broken :(

Class MediawikiCli contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (Joomla\CMS\Application\CMSApplicationInterface::getName) in C:\htdocs\joomla-cms\build\helpTOC.php on line 46

avatar ceford
ceford - comment - 27 Jun 2020

An afterthought - should Search be removed from the Index? I see Weblinks is not present.

avatar mbabker
mbabker - comment - 28 Jun 2020

Replace the script with this:

<?php
/**
 * @package    Joomla.Build
 *
 * @copyright  Copyright (C) 2005 - 2020 Open Source Matters, Inc. All rights reserved.
 * @license    GNU General Public License version 2 or later; see LICENSE.txt
 */

// We are a valid entry point.
const _JEXEC = 1;

// Import namespaced classes
use Joomla\CMS\Factory;
use Joomla\CMS\Http\HttpFactory;
use Joomla\CMS\Version;
use Joomla\Console\Application;
use Joomla\Console\Command\AbstractCommand;
use Joomla\Mediawiki\Http;
use Joomla\Mediawiki\Mediawiki;
use Joomla\Registry\Registry;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;

/**
 * Define the application's minimum supported PHP version as a constant so it can be referenced within the application.
 */
const JOOMLA_MINIMUM_PHP = '7.2.5';

if (!defined('_JDEFINES'))
{
	define('JPATH_BASE', dirname(__DIR__));
	require_once JPATH_BASE . '/includes/defines.php';
}

// Get the framework.
require_once JPATH_BASE . '/includes/framework.php';

$command = new class extends AbstractCommand
{
	/**
	 * The default command name
	 *
	 * @var  string
	 */
	protected static $defaultName = 'build-help-toc';

	/**
	 * Initialise the command.
	 *
	 * @return  void
	 */
	protected function configure(): void
	{
		$this->setDescription('Generates the help system table of contents file');
	}

	/**
	 * Internal function to execute the command.
	 *
	 * @param   InputInterface   $input   The input to inject into the command.
	 * @param   OutputInterface  $output  The output to inject into the command.
	 *
	 * @return  integer  The command exit code
	 */
	protected function doExecute(InputInterface $input, OutputInterface $output): int
	{
		$io = new SymfonyStyle($input, $output);

		if (!class_exists(Http::class))
		{
			$io->error(
				'The `joomla/mediawiki` package is not installed. To use this script, you must run `composer install` to install development'
				. ' dependencies not tracked in this repo.'
			);

			return 1;
		}

		// Set up HTTP driver for MediaWiki
		$http = new Http([], HttpFactory::getAvailableDriver());

		// Set up options for the Mediawiki class
		$options = new Registry;
		$options->set('api.url', 'https://docs.joomla.org');

		$mediawiki = new Mediawiki($options, $http);

		$io->comment('Fetching data from docs wiki');

		// Get the category members (local hack)
		$categoryMembers = $mediawiki->categories->getCategoryMembers(
			sprintf('Category:Help_screen_%s.%s', Version::MAJOR_VERSION, Version::MINOR_VERSION),
			null,
			'max'
		);

		$members = [];

		// Loop through the result objects to get every document
		foreach ($categoryMembers->query->categorymembers as $catmembers)
		{
			foreach ($catmembers as $member)
			{
				$members[] = (string) $member['title'];
			}
		}

		// Get the language object
		$language = Factory::getLanguage();

		// Load the admin en-GB.ini language file to get the JHELP language keys
		$language->load('joomla', JPATH_ADMINISTRATOR, null, false, false);

		// Get the language strings via Reflection as the property is protected
		$refl = new ReflectionClass($language);
		$property = $refl->getProperty('strings');
		$property->setAccessible(true);
		$strings = $property->getValue($language);

		/*
		 * Now we start fancy processing so we can get the language key for the titles
		 */

		$cleanMembers = [];

		// Strip the namespace prefix off the titles and replace spaces with underscores
		$namespace = sprintf('Help%d.x:', Version::MAJOR_VERSION);

		foreach ($members as $member)
		{
			$cleanMembers[] = str_replace([$namespace, ' '], ['', '_'], $member);
		}

		// Make sure we only have an array of unique values before continuing
		$cleanMembers = array_unique($cleanMembers);

		/*
		 * Loop through the cleaned up title array and the language strings array to match things up
		 */

		$matchedMembers = [];

		foreach ($cleanMembers as $member)
		{
			foreach ($strings as $k => $v)
			{
				if ($member === $v)
				{
					$matchedMembers[] = $k;

					continue;
				}
			}
		}

		// Alpha sort the array
		asort($matchedMembers);

		// Now we strip off the JHELP_ prefix from the strings to get usable strings for both COM_ADMIN and JHELP
		$stripped = [];

		foreach ($matchedMembers as $member)
		{
			$stripped[] = str_replace('JHELP_', '', $member);
		}

		/*
		 * Check to make sure a COM_ADMIN_HELP string exists, don't include in the TOC if not
		 */

		// Load the admin com_admin language file
		$language->load('com_admin', JPATH_ADMINISTRATOR);

		$toc = [];

		foreach ($stripped as $string)
		{
			// Validate the key exists
			$io->comment(sprintf('Validating key COM_ADMIN_HELP_%s', $string));

			if ($language->hasKey('COM_ADMIN_HELP_' . $string))
			{
				$io->comment(sprintf('Adding %s', $string));

				$toc[$string] = $string;
			}
			// We check if the string for words in singular/plural form and check again
			else
			{
				$io->comment(sprintf('Inflecting %s', $string));

				if (strpos($string, '_CATEGORIES') !== false)
				{
					$inflected = str_replace('_CATEGORIES', '_CATEGORY', $string);
				}
				elseif (strpos($string, '_USERS') !== false)
				{
					$inflected = str_replace('_USERS', '_USER', $string);
				}
				elseif (strpos($string, '_CATEGORY') !== false)
				{
					$inflected = str_replace('_CATEGORY', '_CATEGORIES', $string);
				}
				elseif (strpos($string, '_USER') !== false)
				{
					$inflected = str_replace('_USER', '_USERS', $string);
				}
				else
				{
					$inflected = '';
				}

				// Now try to validate the key
				if ($inflected !== '')
				{
					$io->comment(sprintf('Validating key COM_ADMIN_HELP_%s', $inflected));

					if ($language->hasKey('COM_ADMIN_HELP_' . $inflected))
					{
						$io->comment(sprintf('Adding %s', $inflected));

						$toc[$string] = $inflected;
					}
				}
			}
		}

		$io->comment(sprintf('Number of strings: %d', count($toc)));

		// JSON encode the file and write it to JPATH_ADMINISTRATOR/help/en-GB/toc.json
		file_put_contents(JPATH_ADMINISTRATOR . '/help/en-GB/toc.json', json_encode($toc));

		$io->success('Help Screen TOC written');

		return 0;
	}
};

$input = new ArrayInput(
	[
		'command' => $command::getDefaultName(),
	]
);

$app = new class($input) extends Application
{
	/**
	 * Retrieve the application configuration object.
	 *
	 * @return  Registry
	 */
	public function getConfig()
	{
		return $this->config;
	}
};
$app->addCommand($command);

// Register the application to the factory
Factory::$application = $app;

$app->execute();

The script is updated to use the console application instead of the deprecated CLI architecture, and accounts for the change the documentation team has made in the docs wiki namespace for the help screens (the namespace is now Help4.x instead of Help3#).

The toc.json file contents should match this:

{"COMPONENTS_ACTIONLOGS":"COMPONENTS_ACTIONLOGS","COMPONENTS_ASSOCIATIONS":"COMPONENTS_ASSOCIATIONS","COMPONENTS_ASSOCIATIONS_EDIT":"COMPONENTS_ASSOCIATIONS_EDIT","COMPONENTS_BANNERS_BANNERS":"COMPONENTS_BANNERS_BANNERS","COMPONENTS_BANNERS_BANNERS_EDIT":"COMPONENTS_BANNERS_BANNERS_EDIT","COMPONENTS_BANNERS_CATEGORIES":"COMPONENTS_BANNERS_CATEGORIES","COMPONENTS_BANNERS_CATEGORY_EDIT":"COMPONENTS_BANNERS_CATEGORIES_EDIT","COMPONENTS_BANNERS_CLIENTS":"COMPONENTS_BANNERS_CLIENTS","COMPONENTS_BANNERS_CLIENTS_EDIT":"COMPONENTS_BANNERS_CLIENTS_EDIT","COMPONENTS_BANNERS_TRACKS":"COMPONENTS_BANNERS_TRACKS","COMPONENTS_CONTACTS_CONTACTS":"COMPONENTS_CONTACTS_CONTACTS","COMPONENTS_CONTACTS_CONTACTS_EDIT":"COMPONENTS_CONTACTS_CONTACTS_EDIT","COMPONENTS_CONTACT_CATEGORIES":"COMPONENTS_CONTACT_CATEGORIES","COMPONENTS_CONTACT_CATEGORY_EDIT":"COMPONENTS_CONTACT_CATEGORIES_EDIT","COMPONENTS_CONTENT_CATEGORIES":"COMPONENTS_CONTENT_CATEGORIES","COMPONENTS_CONTENT_CATEGORY_EDIT":"COMPONENTS_CONTENT_CATEGORIES_EDIT","COMPONENTS_FIELDS_FIELDS":"COMPONENTS_FIELDS_FIELDS","COMPONENTS_FIELDS_FIELDS_EDIT":"COMPONENTS_FIELDS_FIELDS_EDIT","COMPONENTS_FIELDS_FIELD_GROUPS":"COMPONENTS_FIELDS_FIELD_GROUPS","COMPONENTS_FIELDS_FIELD_GROUPS_EDIT":"COMPONENTS_FIELDS_FIELD_GROUPS_EDIT","COMPONENTS_FINDER_MANAGE_CONTENT_MAPS":"COMPONENTS_FINDER_MANAGE_CONTENT_MAPS","COMPONENTS_FINDER_MANAGE_INDEXED_CONTENT":"COMPONENTS_FINDER_MANAGE_INDEXED_CONTENT","COMPONENTS_FINDER_MANAGE_SEARCH_FILTERS":"COMPONENTS_FINDER_MANAGE_SEARCH_FILTERS","COMPONENTS_FINDER_MANAGE_SEARCH_FILTERS_EDIT":"COMPONENTS_FINDER_MANAGE_SEARCH_FILTERS_EDIT","COMPONENTS_JOOMLA_UPDATE":"COMPONENTS_JOOMLA_UPDATE","COMPONENTS_MESSAGING_INBOX":"COMPONENTS_MESSAGING_INBOX","COMPONENTS_MESSAGING_READ":"COMPONENTS_MESSAGING_READ","COMPONENTS_MESSAGING_WRITE":"COMPONENTS_MESSAGING_WRITE","COMPONENTS_NEWSFEEDS_CATEGORIES":"COMPONENTS_NEWSFEEDS_CATEGORIES","COMPONENTS_NEWSFEEDS_CATEGORY_EDIT":"COMPONENTS_NEWSFEEDS_CATEGORIES_EDIT","COMPONENTS_NEWSFEEDS_FEEDS":"COMPONENTS_NEWSFEEDS_FEEDS","COMPONENTS_NEWSFEEDS_FEEDS_EDIT":"COMPONENTS_NEWSFEEDS_FEEDS_EDIT","COMPONENTS_POST_INSTALLATION_MESSAGES":"COMPONENTS_POST_INSTALLATION_MESSAGES","COMPONENTS_PRIVACY_CAPABILITIES":"COMPONENTS_PRIVACY_CAPABILITIES","COMPONENTS_PRIVACY_CONSENTS":"COMPONENTS_PRIVACY_CONSENTS","COMPONENTS_PRIVACY_DASHBOARD":"COMPONENTS_PRIVACY_DASHBOARD","COMPONENTS_PRIVACY_REQUEST":"COMPONENTS_PRIVACY_REQUEST","COMPONENTS_PRIVACY_REQUESTS":"COMPONENTS_PRIVACY_REQUESTS","COMPONENTS_PRIVACY_REQUEST_EDIT":"COMPONENTS_PRIVACY_REQUEST_EDIT","COMPONENTS_REDIRECT_MANAGER":"COMPONENTS_REDIRECT_MANAGER","COMPONENTS_REDIRECT_MANAGER_EDIT":"COMPONENTS_REDIRECT_MANAGER_EDIT","COMPONENTS_SEARCH":"COMPONENTS_SEARCH","COMPONENTS_TAGS_MANAGER":"COMPONENTS_TAGS_MANAGER","COMPONENTS_TAGS_MANAGER_EDIT":"COMPONENTS_TAGS_MANAGER_EDIT","CONTENT_ARTICLE_MANAGER":"CONTENT_ARTICLE_MANAGER","CONTENT_ARTICLE_MANAGER_EDIT":"CONTENT_ARTICLE_MANAGER_EDIT","CONTENT_FEATURED_ARTICLES":"CONTENT_FEATURED_ARTICLES","CONTENT_MEDIA_MANAGER":"CONTENT_MEDIA_MANAGER","EXTENSIONS_EXTENSION_MANAGER_DATABASE":"EXTENSIONS_EXTENSION_MANAGER_DATABASE","EXTENSIONS_EXTENSION_MANAGER_DISCOVER":"EXTENSIONS_EXTENSION_MANAGER_DISCOVER","EXTENSIONS_EXTENSION_MANAGER_INSTALL":"EXTENSIONS_EXTENSION_MANAGER_INSTALL","EXTENSIONS_EXTENSION_MANAGER_LANGUAGES":"EXTENSIONS_EXTENSION_MANAGER_LANGUAGES","EXTENSIONS_EXTENSION_MANAGER_MANAGE":"EXTENSIONS_EXTENSION_MANAGER_MANAGE","EXTENSIONS_EXTENSION_MANAGER_UPDATE":"EXTENSIONS_EXTENSION_MANAGER_UPDATE","EXTENSIONS_EXTENSION_MANAGER_WARNINGS":"EXTENSIONS_EXTENSION_MANAGER_WARNINGS","EXTENSIONS_LANGUAGE_MANAGER_CONTENT":"EXTENSIONS_LANGUAGE_MANAGER_CONTENT","EXTENSIONS_LANGUAGE_MANAGER_EDIT":"EXTENSIONS_LANGUAGE_MANAGER_EDIT","EXTENSIONS_LANGUAGE_MANAGER_INSTALLED":"EXTENSIONS_LANGUAGE_MANAGER_INSTALLED","EXTENSIONS_LANGUAGE_MANAGER_OVERRIDES":"EXTENSIONS_LANGUAGE_MANAGER_OVERRIDES","EXTENSIONS_LANGUAGE_MANAGER_OVERRIDES_EDIT":"EXTENSIONS_LANGUAGE_MANAGER_OVERRIDES_EDIT","EXTENSIONS_MODULE_MANAGER":"EXTENSIONS_MODULE_MANAGER","EXTENSIONS_MODULE_MANAGER_EDIT":"EXTENSIONS_MODULE_MANAGER_EDIT","EXTENSIONS_PLUGIN_MANAGER":"EXTENSIONS_PLUGIN_MANAGER","EXTENSIONS_PLUGIN_MANAGER_EDIT":"EXTENSIONS_PLUGIN_MANAGER_EDIT","EXTENSIONS_TEMPLATE_MANAGER_STYLES":"EXTENSIONS_TEMPLATE_MANAGER_STYLES","EXTENSIONS_TEMPLATE_MANAGER_STYLES_EDIT":"EXTENSIONS_TEMPLATE_MANAGER_STYLES_EDIT","EXTENSIONS_TEMPLATE_MANAGER_TEMPLATES":"EXTENSIONS_TEMPLATE_MANAGER_TEMPLATES","EXTENSIONS_TEMPLATE_MANAGER_TEMPLATES_EDIT":"EXTENSIONS_TEMPLATE_MANAGER_TEMPLATES_EDIT","EXTENSIONS_TEMPLATE_MANAGER_TEMPLATES_EDIT_SOURCE":"EXTENSIONS_TEMPLATE_MANAGER_TEMPLATES_EDIT_SOURCE","MENUS_MENU_ITEM_MANAGER":"MENUS_MENU_ITEM_MANAGER","MENUS_MENU_ITEM_MANAGER_EDIT":"MENUS_MENU_ITEM_MANAGER_EDIT","MENUS_MENU_MANAGER":"MENUS_MENU_MANAGER","MENUS_MENU_MANAGER_EDIT":"MENUS_MENU_MANAGER_EDIT","SITE_GLOBAL_CONFIGURATION":"SITE_GLOBAL_CONFIGURATION","SITE_MAINTENANCE_CLEAR_CACHE":"SITE_MAINTENANCE_CLEAR_CACHE","SITE_MAINTENANCE_GLOBAL_CHECK-IN":"SITE_MAINTENANCE_GLOBAL_CHECK-IN","SITE_MAINTENANCE_PURGE_EXPIRED_CACHE":"SITE_MAINTENANCE_PURGE_EXPIRED_CACHE","SITE_SYSTEM_INFORMATION":"SITE_SYSTEM_INFORMATION","START_HERE":"START_HERE","USERS_ACCESS_LEVELS":"USERS_ACCESS_LEVELS","USERS_ACCESS_LEVELS_EDIT":"USERS_ACCESS_LEVELS_EDIT","USERS_DEBUG_USERS":"USERS_DEBUG_USER","USERS_GROUPS":"USERS_GROUPS","USERS_GROUPS_EDIT":"USERS_GROUPS_EDIT","USERS_MASS_MAIL_USERS":"USERS_MASS_MAIL_USERS","USERS_USER_MANAGER":"USERS_USER_MANAGER","USERS_USER_MANAGER_EDIT":"USERS_USER_MANAGER_EDIT","USERS_USER_NOTES":"USERS_USER_NOTES","USERS_USER_NOTES_EDIT":"USERS_USER_NOTES_EDIT"}
avatar brianteeman
brianteeman - comment - 28 Jun 2020

See #29804

avatar Quy Quy - change - 28 Jun 2020
Status New Closed
Closed_Date 0000-00-00 00:00:00 2020-06-28 16:25:41
Closed_By Quy
avatar Quy Quy - close - 28 Jun 2020

Add a Comment

Login with GitHub to post a comment