gebruederheitz / wp-theme-docs
Add simply admin pages or a Wordpress theme documentation page to the editor.
Requires
- php: >=7.3
- doctrine/annotations: ^1.13
- gebruederheitz/simple-singleton: ^1.0
Requires (Dev)
- phpstan/phpstan: ^1.4
- szepeviktor/phpstan-wordpress: ^1.0
README
Add simply admin pages or a Wordpress theme documentation page to the editor.
Installation
via composer:
> composer require gebruederheitz/wp-theme-docs
Make sure you have Composer autoload or an alternative class loader present.
Usage
# functions.php (or controller class) use Gebruederheitz\Wordpress\Documentation\AdminPage; new AdminPage('my-extra-admin-page', 'Extra Tools', 'tools.php'); // or use the factory method AdminPage::factory('my-extra-admin-page', 'Extra Tools', 'tools.php');
This will set up a basic admin page under the "Tools" tab in
the Wordpress backend with the translated title __('Extra Tools', 'ghwp')
(/wordpress/wp-admin/tools.php?page=my-extra-admin-page
).
In its most basic state, this renders a page empty except for the title. You will need to register sections to add some content.
Constructor (and factory) arguments
AdminPage::__construct( string $menuSlug, ?string $title = null, ?string $menuLocation = 'themes.php', ?string $menuTitle = null, ?string $overridePath = null, ?string $i18nNamespace = 'ghwp' ): AdminPage
Adding sections
Section registration & custom sections
Any section you add must implement the AdminPageSectionInterface
. You can
use the method addSection()
or the filter hook to add your section to a page:
using addSection()
use Gebruederheitz\Wordpress\Documentation\AdminPage ; $page = new AdminPage('extras'); $page->addSection(new MySection()); // Using AdminPage's factory method: AdminPage::factory('extras')->addSection($mySection); // Adding multiple sections with addSection() or addSections() AdminPage::factory('extras') ->addSection($mySection) ->addSection($otherSection); AdminPage::factory('extras') ->addSections([ new MySection(), new OtherSection(), ]);
using the hook
use Gebruederheitz\Wordpress\Documentation\AdminPage ; $page = new AdminPage('extras'); function ghwp_add_doc_section(array $sections) { $sections[] = new MyDocSection(); return $sections; } add_filter($page->getSectionsHook(), 'ghwp_add_doc_section'); // OR, using 'ghwp_filter_sections_' and the page's slug: add_filter('ghwp_filter_sections_extras', 'ghwp_add_doc_section');
For convenience, you can extend the AbstractAdminPageSection
, which already
has the interface implemented, only requiring you to implement three abstract
getters to get it to run.
use Gebruederheitz\Wordpress\AdminPage\AbstractAdminPageSection; class MyDocsSection extends AbstractAdminPageSection { public function getTitle() : string{ return 'Documentation for my amazing feature'; } protected function getDefaultPartial() : string{ return __DIR__. '/../template-parts/meta/docs/feature.php'; } /* Optional: Define an override path that can be used instead of your default */ protected function getOverridePath() : string{ return get_theme_file_path('template-parts/meta/overrides/feature.php'); } /* Optional: Expose public methods for your template to use */ public function getSomeData() { return [/* ... */]; } }
The above example sets up a section with the title Documentation for my amazing feature
rendering from the template partial at the given path.
The template is passed the instance of AdminPage
and the current
section:
<?php # template-parts/meta/docs/feature.php [$docs, $section] = $args; ?> <ul> <?php foreach ($section->getSomeData() as $datum): ?> <li> <!-- Some content --> </li> <?php endforeach; ?> </ul>
Instead of setting the $partial
property (or even extending the abstract class),
you can also implement a custom rendering method:
use Gebruederheitz\Wordpress\AdminPage\AdminPageSectionInterface use Gebruederheitz\Wordpress\AdminPage\AbstractAdminPageSection; class MySecondDocsSection extends AbstractAdminPageSection { /* ... */ /** * @override */ public function render(AdminPage $docs) { get_template_part('template-parts/meta/docs/documentation', 'page', [$docs, $this]); } } /** Example of a section not extending the abstract base implementation */ class MyThirdDocsSection implements AdminPageSectionInterface { public function onPageSections(array $sections): array { $sections[] = $this; return $sections; } public function getTitle(): string { return 'My Third Docs Section is the best to date!'; } public function render(DocumentationMenu $docs) { get_template_part('template-parts/meta/docs/documentation', 'page', [$docs, $this]); } }
The theme documentation page
# functions.php (or controller class) use Gebruederheitz\Wordpress\AdminPage\Documentation\DocumentationMenu; new DocumentationMenu();
This will set up the basic documentation page under the "Appearance" tab in
the Wordpress backend with the translated title __('Theme-Help', 'ghwp')
(/wordpress/wp-admin/themes.php?page=ghwp-help
).
It's simply a preconfigured AdminPage
, so you will need to add sections. In
this case, you can add them right through the constructor by passing an array
as the first argument:
new DocumentationMenu([$sectionOne, $sectionTwo]);
Warning
Due to how PHP inheritance works, AdminPage's static
::factory()
method is available on DocumentationMenu, but it should not be used, as it will return a simple AdminPage object, not a DocumentationMenu instance.
DocumentationMenu: Changing the title and the template used
You can change the title displayed on the documentation page by passing a string as the constructor's second argument:
new \Gebruederheitz\Wordpress\Documentation\DocumentationMenu(null, 'Theme Docs!');
You can override the default template by creating a file in your theme's root
directory under template-parts/meta/docs/documentation-page.php
.
Alternatively you may override this default path by supplying a second argument to the constructor:
new DocumentationMenu(null, null, 'template-parts/special/docs.php');
Included sections
The sections included in this package all extend AbstractAdminPageSection
.
use Gebruederheitz\Wordpress\AdminPage\Documentation\DocumentationMenu; use Gebruederheitz\Wordpress\AdminPage\Documentation\Section\Shortcodes; use Gebruederheitz\Wordpress\AdminPage\Documentation\Section\Icons; new DocumentationMenu( 'My Theme', [ new Shortcodes(), new Icons(), ] ); // or $docs = new DocumentationMenu(); $docs->addSection(new Shortcodes())->addSection(new Icons()); // or $docs->addSections([new Shortcodes(), new Icons()]); // or add_filter($docs->getSectionsHook(), function(array $sections): array { $sections[] = new Shortcodes(); return $sections; });
This will register the sections and add them to the help page.
Shortcode Documentation Annotations
This module will automatically create a shortcode documentation for users based
on the annotation class ShortcodeDocumentation
. It is based on Doctrine's
annotation reader.
Documenting shortcodes
This assumes you add your shortcodes via individual classes for each shortcode
and have both the DocumentationMenu
page class and the Shortcodes
section
class up and running.
Available annotation properties:
The simplest way to document your Shortcode is to use the trait provided:
use Gebruederheitz\Wordpress\AdminPage\Documentation\Traits\withShortcodeDocumentation; use Gebruederheitz\Wordpress\AdminPage\Documentation\Annotations\ShortcodeDocumentation; /** * Class MyShortcode * * @package Ghwp\Shortcode * * @ShortcodeDocumentation( * shortcode="ghwp-my-shortcode", * description="Renders a thing.", * parameters={ * "id": "The post ID you wish to display." * }, * examples={ * "[ghwp-my-shortcode id=123 /]" * } * ) */ class MyShortcode { use withShortcodeDocumentation; /* With a dynamic class instance... */ public function __construct() { self::addDocumentation(); add_shortcode('ghwp-my-shortcode', [$this, 'renderShortcode')); } /* ...or with a static class / method */ public static function init() { self::addDocumentation(); add_shortcode('ghwp-my-shortcode', [self::class, 'renderShortcode']); } } MyShortcode::init(); /* or*/ new MyShortcode();
Alternatively, you can register your annotation yourself:
use Gebruederheitz\Wordpress\AdminPage\Documentation\Annotations\ShortcodeDocumentation; use Gebruederheitz\Wordpress\AdminPage\Documentation\Section\Shortcodes; /** * @ShortcodeDocumentation( * shortcode="ghwp-my-shortcode", * description="Renders a thing.", * parameters={ * "id": "The post ID you wish to display." * }, * examples={ * "[ghwp-my-shortcode id=123 /]" * } * ) */ class MyShortcode { /* With a dynamic class instance... */ public function __construct() { add_filter(Shortcodes::HOOK_SHORTCODE_DOCS, [$this, 'onShortcodeDocs']); add_shortcode('ghwp-my-shortcode', [$this, 'renderShortcode')); } public function onShortcodeDocs(array $docs) { $docs[] = self::class; return $docs; } }
Changing the template partial for the section
As with all section classes extending AbstractAdminPageSection
, you have
two options of modifying the default output:
Using the default override template
Create a file in your theme's root directory under template-parts/meta/docs/shortcodes.php
.
This template will be used instead of the provided default.
The section template will be called with two arguments: an instance each of
DocumentationMenu
and the section (Shortcodes
):
<?php # template-parts/meta/docs/shortcodes.php [$docs, $section] = $args; ?>
Using a different template partial location
You'll need to extend the Shortcodes
class and provide an alternative getter:
class MyShortcodes extends Shortcodes { // skip this if you want to keep the default partial and only // change the override location protected function getDefaultPartial(): string { return __DIR__ . '/../../templates/shortcodes.php'; } protected function getOverridePath(): string { return 'template-parts/meta/docs/shortcodes.php'; } }
List of SVG icon partials
This module will render a list of all icons that can be used by editors (for
instance via shortcodes). By default it searches template-parts/svg/
in your
theme's root directory recursively for .php
files, assuming they are templates
containing SVG markup.
This is most useful in conjunction with a shortcode that can render these SVG partials, for instance into button blocks.
Setting a different path for SVG partials
Same as with the Shortcodes section.
Development
Dependencies
- PHP >= 7.4
- Composer 2.x
- NVM and nodeJS LTS (v16.x)
- Nice to have: GNU Make (or drop-in alternative)
Migration
v1 to v2
- The PSR-4 namespaces changed; so instead of using
Gebruederheitz\Wordpress\Documentation\DocumentationPage
you will need to useGebruederheitz\Wordpress\AdminPage\Documentation\DocumentationPage
etc. AdminPageSectionInterface
replacesDocumentationSectionInterface
,AbstractAdminPageSections
replacesAbstractDocumentationSection
.- For a complete list of namespace and class name changes refer to the table below.
- Sections do not extend
Singleton
anymore, so you will have to construct them like any regular class instead of calling::getInstance()
. - The filter hook for documentation sections has changed from
ghwp_filter_documentation_sections
toghwp_filter_sections_ghwp-help
. You can not useDocumentationPage::HOOK_SECTIONS
anymore; either use the literal hook name, get the name via$documentationPageInstance->getSectionsHook()
, or (preferred) use$documentationPageInstance->addSection(AdminPageSectionInterface