summaryrefslogtreecommitdiff
path: root/modules_v4
diff options
context:
space:
mode:
authorGreg Roach <greg@subaqua.co.uk>2021-06-22 15:34:14 +0100
committerGreg Roach <greg@subaqua.co.uk>2021-06-22 15:34:14 +0100
commit30e63383b10bafff54347985dcdbd10c40c33f62 (patch)
tree71a3a208735947727ff41a0cb4ddc4a2bddae613 /modules_v4
parentea024074a4a6fddf1e62fd2b95467c6e41c945e4 (diff)
downloadwebtrees-30e63383b10bafff54347985dcdbd10c40c33f62.tar.gz
webtrees-30e63383b10bafff54347985dcdbd10c40c33f62.tar.bz2
webtrees-30e63383b10bafff54347985dcdbd10c40c33f62.zip
Fix: #3895 - move example modules to the webtrees repository
Diffstat (limited to 'modules_v4')
-rw-r--r--modules_v4/README.md200
-rw-r--r--modules_v4/example-footer.disable/module.php85
-rw-r--r--modules_v4/example-footer.disable/resources/views/footer.phtml4
-rw-r--r--modules_v4/example-footer.disable/resources/views/page.phtml3
-rw-r--r--modules_v4/example-middleware.disable/module.php112
-rw-r--r--modules_v4/example-report.disable/module.php48
-rw-r--r--modules_v4/example-report.disable/resources/report.xml11
-rw-r--r--modules_v4/example-server-configuration.disable/ExampleServerConfigurationModule.php143
-rw-r--r--modules_v4/example-server-configuration.disable/module.php19
-rw-r--r--modules_v4/example-theme.disable/module.php66
-rw-r--r--modules_v4/example-theme.disable/resources/css/theme.css3
-rw-r--r--modules_v4/example-theme.disable/resources/views/chart-box.phtml5
-rw-r--r--modules_v4/example.disable/module.php160
13 files changed, 5 insertions, 854 deletions
diff --git a/modules_v4/README.md b/modules_v4/README.md
index a41d758268..131e3bea80 100644
--- a/modules_v4/README.md
+++ b/modules_v4/README.md
@@ -9,9 +9,9 @@ A module is a folder containing a file called `module.php`.
There may be other files in the folder, such as CSS, JS, templates,
languages, data, etc.
-To install a module, copy its folder to `modules_v4`.
+To install a module, copy its folder to `/modules_v4`.
-To uninstall it, delete its folder from `modules_v4`.
+To uninstall it, delete its folder from `/modules_v4`.
Note that module names (i.e. the folder names) must not contain
spaces or the characters `.`, `[` and `]`. It must also have a
@@ -25,198 +25,8 @@ modules containing `.` are ignored.
To write a module, you need to understand the PHP programming language.
-The rest of this document is aimed at PHP developers.
+There are several example modules available at
+https://github.com/webtrees
-TIP: The built-in modules can be found in `app/Module/*.php`.
+The built-in modules can be found in `app/Module/`.
These contain lots of useful examples that you can copy/paste.
-
-## Creating a custom module.
-
-This is the minimum code needed to create a custom module.
-
-```php
-<?php
-
-use Fisharebest\Webtrees\Module\AbstractModule;
-use Fisharebest\Webtrees\Module\ModuleCustomInterface;
-use Fisharebest\Webtrees\Module\ModuleCustomTrait;
-
-return new class extends AbstractModule implements ModuleCustomInterface {
- use ModuleCustomTrait;
-
- /**
- * How should this module be labelled on tabs, menus, etc.?
- *
- * @return string
- */
- public function title(): string
- {
- return 'My Custom module';
- }
-
- /**
- * A sentence describing what this module does.
- *
- * @return string
- */
- public function description(): string
- {
- return 'This module doesn‘t do anything';
- }
-};
-```
-
-If you plan to share your modules with other webtrees users, you should
-provide them with support/contact/version information. This way they will
-know where to go for updates, support, etc.
-Look at the functions and comments in `app/ModuleCustomTrait.php`.
-
-## Available interfaces
-
-Custom modules *must* implement `ModuleCustomInterface` interface.
-They *may* implement one or more of the following interfaces:
-
-* `ModuleAnalyticsInterface` - adds a tracking/analytics provider.
-* `ModuleBlockInterface` - adds a block to the home pages.
-* `ModuleChartInterface` - adds a chart to the chart menu.
-* `ModuleDataFixInterface` - adds a data fix to the manage-trees page.
-* `ModuleConfigInterface` - adds a configuration page to the control panel.
-* `ModuleGlobalInterface` - adds CSS and JS to all page.
-* `ModuleListInterface` - adds a list to the list menu.
-* `ModuleMenuInterface` - adds an entry to the main menu.
-* `ModuleReportInterface` - adds a report to the report menu.
-* `ModuleSidebarInterface` - adds a sidebar to the individual pages.
-* `ModuleTabInterface` - adds a tab to the individual pages.
-* `ModuleThemeInterface` - adds a theme (this interface is still being developed).
-
-For each module interface that you implement, you must also use the corresponding trait.
-If you don't do this, your module may break whenever the module interface is updated.
-
-Where possible, the interfaces won't change - however new methods may be added
-and existing methods may be deprecated.
-
-Modules may also implement the following interfaces, which allow them to integrate
-more deeply into the application.
-
-* `MiddlewareInterface` - allows a module to intercept the HTTP request/response cycle.
-
-## How to extend/modify an existing modules
-
-To create a module that is just a modified version of an existing module,
-you can extend the existing module (instead of extending `AbstractModule`).
-
-```php
-<?php
-use Fisharebest\Webtrees\Module\ModuleCustomInterface;
-use Fisharebest\Webtrees\Module\ModuleCustomTrait;
-use Fisharebest\Webtrees\Module\PedigreeChartModule;
-use Fisharebest\Webtrees\Services\ChartService;
-
-/**
- * Creating an anonymous class will prevent conflicts with other custom modules.
- */
-return new class extends PedigreeChartModule implements ModuleCustomInterface {
- use ModuleCustomTrait;
-
- /**
- * The chart needs some chart functions. We could pass in our own version here.
- */
- public function __construct()
- {
- parent::__construct(new ChartService());
- }
-
- /**
- * @return string
- */
- public function description(): string
- {
- return 'A modified version of the pedigree chart';
- }
-
- // Change the default layout...
- protected const DEFAULT_STYLE = self::STYLE_DOWN;
-
- protected const DEFAULT_PARAMETERS = [
- 'generations' => self::DEFAULT_GENERATIONS,
- 'style' => self::DEFAULT_STYLE,
- ];
-};
-```
-
-## Dependency Injection
-
-webtrees uses the “Dependency Injection” pattern extensively. This is a system for
-automatically generating objects. The advantages over using `new SomeClass()` are
-
-* Easier testing - you can pass "dummy" objects to your class.
-* Run-time resolution - you can request an Interface, and webtrees will find a specific instance for you.
-* Can swap implementations at runtime.
-
-Note that you cannot type-hint the following objects in the constructor, as they are not
-created until after the modules.
-
-* other modules
-* interfaces, such as `UserInterface` or `LocaleInterface` (the current user and language)
-* the current tree `Tree` or objects that depend on it (`Statistics`)
-as these objects are not created until after the module is created.
-
-Instead, these objects can be obtained from the request object. e.g.
-```php
-$tree = $request->getAttribute('tree');
-$user = $request->getAttribute('user');
-```
-
-```php
-<?php
-use Fisharebest\Webtrees\Module\AbstractModule;
-use Fisharebest\Webtrees\Module\ModuleCustomInterface;
-use Fisharebest\Webtrees\Module\ModuleCustomTrait;
-use Fisharebest\Webtrees\Services\TimeoutService;
-use Psr\Http\Message\ResponseInterface;
-use Psr\Http\Message\ServerRequestInterface;
-
-/**
- * Creating an anoymous class will prevent conflicts with other custom modules.
- */
-return new class extends AbstractModule implements ModuleCustomInterface {
- use ModuleCustomTrait;
-
- /** @var TimeoutService */
- protected $timeout_service;
-
- /**
- * IMPORTANT - the constructor is called for *all* modules, even ones
- * that are disabled. You should do little more than initialise your
- * private/protected members.
- *
- * @param TimeoutService $timeout_service
- */
- public function __construct(TimeoutService $timeout_service)
- {
- $this->timeout_service = $timeout_service;
- }
-
- /**
- * Methods that are called in response to HTTP requests use
- * dependency-injection. You'll almost certainly need the request
- * object.
- *
- * @param ServerRequestInterface $request
- *
- * @return ResponseInterface
- */
- public function getFooBarAction(ServerRequestInterface $request): ResponseInterface
- {
- // This assumes that there is a tree parameter in the URL.
- $tree = $request->getAttribute('tree');
-
- // This will be a User (or a GuestUser for visitors).
- $user = $request->getAttribute('user');
-
- $html = $tree->name() . '/' . $user->realName();
-
- return response($html);
- }
-};
-```
diff --git a/modules_v4/example-footer.disable/module.php b/modules_v4/example-footer.disable/module.php
deleted file mode 100644
index fc2b35a9ee..0000000000
--- a/modules_v4/example-footer.disable/module.php
+++ /dev/null
@@ -1,85 +0,0 @@
-<?php
-
-/**
- * Example footer with a link to a page of information.
- */
-
-declare(strict_types=1);
-
-namespace MyCustomNamespace;
-
-use Fisharebest\Webtrees\Module\AbstractModule;
-use Fisharebest\Webtrees\Module\ModuleCustomInterface;
-use Fisharebest\Webtrees\Module\ModuleCustomTrait;
-use Fisharebest\Webtrees\Module\ModuleFooterInterface;
-use Fisharebest\Webtrees\Module\ModuleFooterTrait;
-use Fisharebest\Webtrees\View;
-use Psr\Http\Message\ResponseInterface;
-use Psr\Http\Message\ServerRequestInterface;
-
-return new class extends AbstractModule implements ModuleCustomInterface, ModuleFooterInterface {
- use ModuleCustomTrait;
- use ModuleFooterTrait;
-
- /**
- * @return string
- */
- public function title(): string
- {
- return 'Custom footer';
- }
-
- /**
- * Bootstrap the module
- */
- public function boot(): void
- {
- // Register a namespace for our views.
- View::registerNamespace($this->name(), $this->resourcesFolder() . 'views/');
- }
-
- /**
- * Where does this module store its resources
- *
- * @return string
- */
- public function resourcesFolder(): string
- {
- return __DIR__ . '/resources/';
- }
-
- /**
- * A footer, to be added at the bottom of every page.
- *
- * @param ServerRequestInterface $request
- *
- * @return string
- */
- public function getFooter(ServerRequestInterface $request): string
- {
- $tree = $request->getAttribute('tree');
-
- $url = route('module', [
- 'module' => $this->name(),
- 'action' => 'Page',
- 'tree' => $tree ? $tree->name() : null,
- ]);
-
- return view($this->name() . '::footer', ['url' => $url]);
- }
-
- /**
- * Generate the page that will be shown when we click the link in the footer.
- *
- * @param ServerRequestInterface $request
- *
- * @return ResponseInterface
- */
- public function getPageAction(ServerRequestInterface $request): ResponseInterface
- {
- return $this->viewResponse($this->name() . '::page', [
- 'title' => $this->title(),
- 'tree' => $request->getAttribute('tree'),
- ]);
- }
-};
diff --git a/modules_v4/example-footer.disable/resources/views/footer.phtml b/modules_v4/example-footer.disable/resources/views/footer.phtml
deleted file mode 100644
index f553598505..0000000000
--- a/modules_v4/example-footer.disable/resources/views/footer.phtml
+++ /dev/null
@@ -1,4 +0,0 @@
-<div class="wt-footer wt-footer-custom text-center py-2">
- Click <a href="<?= e($url) ?>">here</a> for more information.
-</div>
-
diff --git a/modules_v4/example-footer.disable/resources/views/page.phtml b/modules_v4/example-footer.disable/resources/views/page.phtml
deleted file mode 100644
index 872336957f..0000000000
--- a/modules_v4/example-footer.disable/resources/views/page.phtml
+++ /dev/null
@@ -1,3 +0,0 @@
-<h2><?= e($title) ?></h2>
-
-<p>Be nice to fish!</p>
diff --git a/modules_v4/example-middleware.disable/module.php b/modules_v4/example-middleware.disable/module.php
deleted file mode 100644
index 8ebeff23d4..0000000000
--- a/modules_v4/example-middleware.disable/module.php
+++ /dev/null
@@ -1,112 +0,0 @@
-<?php
-
-/**
- * An example module to demonstrate middleware.
- */
-
-declare(strict_types=1);
-
-namespace MyCustomNamespace;
-
-use Fisharebest\Webtrees\Module\AbstractModule;
-use Fisharebest\Webtrees\Module\ModuleCustomInterface;
-use Fisharebest\Webtrees\Module\ModuleCustomTrait;
-use Psr\Http\Message\ResponseInterface;
-use Psr\Http\Message\ServerRequestInterface;
-use Psr\Http\Server\MiddlewareInterface;
-use Psr\Http\Server\RequestHandlerInterface;
-
-use function preg_match;
-use function response;
-
-return new class extends AbstractModule implements ModuleCustomInterface, MiddlewareInterface {
- use ModuleCustomTrait;
-
- // Regular-expressions to match unwanted bots.
- private const BAD_USER_AGENTS = [
- '/AhrefsBot/',
- '/MJ12bot/',
- '/SeznamBot/',
- ];
-
- // List of unwanted IP ranges in CIDR format, e.g. "123.45.67.89/24".
- private const BAD_IP_RANGES = [
- '127.0.0.1/32',
- ];
-
- /**
- * How should this module be identified in the control panel, etc.?
- *
- * @return string
- */
- public function title(): string
- {
- return 'My custom middleware';
- }
-
- /**
- * A sentence describing what this module does.
- *
- * @return string
- */
- public function description(): string
- {
- return 'This is an example of middleware';
- }
-
- /**
- * Code here is executed before and after we process the request/response.
- * We can block access by throwing an exception.
- *
- * @param ServerRequestInterface $request
- * @param RequestHandlerInterface $handler
- *
- * @return ResponseInterface
- */
- public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
- {
- // Code here is executed before we process the request/response.
-
- $ip_address = $request->getAttribute('client-ip');
- foreach (self::BAD_IP_RANGES as $bad_cidr) {
- if ($this->ipInCidr($ip_address, $bad_cidr)) {
- return response('IP address is not allowed: ' . $bad_cidr, 403);
- }
- }
-
- $user_agent = $request->getHeaderLine('HTTP_USER_AGENT');
- foreach (self::BAD_USER_AGENTS as $bad_user_agent) {
- if (preg_match($bad_user_agent, $user_agent)) {
- return response('User agent is not allowed: ' . $bad_user_agent, 403);
- }
- }
-
- // Generate the response.
- $response = $handler->handle($request);
-
- // Code here is executed after we process the request/response.
- // We can also modify the response.
- $response = $response->withHeader('X-Powered-By', 'Fish');
-
- return $response;
- }
-
- /**
- * Is an IP address in a CIDR range>
- *
- * @param string $ip
- * @param string $cidr
- *
- * @return bool
- */
- private function ipInCidr(string $ip, string $cidr): bool
- {
- [$net, $mask] = explode('/', $cidr);
-
- $ip_net = ip2long($net);
- $ip_mask = ~((1 << 32 - (int) $mask) - 1);
- $ip_ip = ip2long($ip);
-
- return ($ip_ip & $ip_mask) === ($ip_net & $ip_mask);
- }
-};
diff --git a/modules_v4/example-report.disable/module.php b/modules_v4/example-report.disable/module.php
deleted file mode 100644
index acde827286..0000000000
--- a/modules_v4/example-report.disable/module.php
+++ /dev/null
@@ -1,48 +0,0 @@
-<?php
-
-/**
- * Example report.
- */
-
-declare(strict_types=1);
-
-namespace MyCustomNamespace;
-
-use Fisharebest\Webtrees\Module\AbstractModule;
-use Fisharebest\Webtrees\Module\ModuleCustomInterface;
-use Fisharebest\Webtrees\Module\ModuleCustomTrait;
-use Fisharebest\Webtrees\Module\ModuleReportInterface;
-use Fisharebest\Webtrees\Module\ModuleReportTrait;
-
-return new class extends AbstractModule implements ModuleCustomInterface, ModuleReportInterface {
- use ModuleCustomTrait;
- use ModuleReportTrait;
-
- /**
- * @return string
- */
- public function title(): string
- {
- return 'Custom report';
- }
-
- /**
- * Where does this module store its resources
- *
- * @return string
- */
- public function resourcesFolder(): string
- {
- return __DIR__ . '/resources/';
- }
-
- /**
- * Name of the XML report file, relative to the resources folder.
- *
- * @return string
- */
- public function xmlFilename(): string
- {
- return 'report.xml';
- }
-};
diff --git a/modules_v4/example-report.disable/resources/report.xml b/modules_v4/example-report.disable/resources/report.xml
deleted file mode 100644
index cd4ba0cd5f..0000000000
--- a/modules_v4/example-report.disable/resources/report.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<Report>
- <Title><var var="I18N::translate('Report')" /></Title>
- <Description><var var="I18N::translate('Report')" /></Description>
-
- <Style name="text" size="10"/>
- <Doc>
- <Body>
- </Body>
- </Doc>
-</Report>
diff --git a/modules_v4/example-server-configuration.disable/ExampleServerConfigurationModule.php b/modules_v4/example-server-configuration.disable/ExampleServerConfigurationModule.php
deleted file mode 100644
index bc0d3c6ac1..0000000000
--- a/modules_v4/example-server-configuration.disable/ExampleServerConfigurationModule.php
+++ /dev/null
@@ -1,143 +0,0 @@
-<?php
-
-/**
- * An example module to modify PHP and database configuration.
- */
-
-declare(strict_types=1);
-
-namespace MyCustomNamespace;
-
-use Fisharebest\Webtrees\Module\AbstractModule;
-use Fisharebest\Webtrees\Module\ModuleCustomInterface;
-use Fisharebest\Webtrees\Module\ModuleCustomTrait;
-use Fisharebest\Webtrees\Services\ServerCheckService;
-use Illuminate\Database\Capsule\Manager as DB;
-
-class ExampleServerConfigurationModule extends AbstractModule implements ModuleCustomInterface
-{
- use ModuleCustomTrait;
-
- /** @var ServerCheckService */
- private $server_check_service;
-
- /**
- * Constructor.
- *
- * @param ServerCheckService $server_check_service
- */
- public function __construct(ServerCheckService $server_check_service)
- {
- $this->server_check_service = $server_check_service;
- }
-
- /**
- * How should this module be identified in the control panel, etc.?
- *
- * @return string
- */
- public function title(): string
- {
- return 'Server configuration';
- }
-
- /**
- * A sentence describing what this module does.
- *
- * @return string
- */
- public function description(): string
- {
- return 'Modify the server configuration';
- }
-
- /**
- * The person or organisation who created this module.
- *
- * @return string
- */
- public function customModuleAuthorName(): string
- {
- return 'Your name';
- }
-
- /**
- * If you do not have access to the PHP.INI or MYSQL.CNF files on your server, then
- * you may be able to change them.
- */
- public function boot(): void
- {
- // IMPORTANT - not all servers allow you to change these settings. Sometimes, even
- // attempting to change them can result in your script being terminated immediately.
- // We attempt to detect whether this will happen, but it is not possible to
- // do so with 100% accuracy.
-
- if (!$this->server_check_service->isFunctionDisabled('ini_set')) {
- $this->phpIni();
- }
-
- if (!$this->server_check_service->isFunctionDisabled('set_time_limit')) {
- $this->phpTimeLimit();
- }
-
- if (!$this->server_check_service->isFunctionDisabled('putenv')) {
- $this->phpEnvironment();
- }
-
- if (DB::connection()->getDriverName() === 'mysql') {
- $this->mysql();
- }
- }
-
- /**
- * Modify the PHP time limit.
- */
- private function phpTimeLimit(): void
- {
- // Set the time limit for PHP scripts.
- // Recommended settings are between 15 and 60 seconds.
- //
- // Typical webservers will not wait more than 60 seconds for a PHP response,
- // so it is pointless to allow the server to continue using resources for
- // a request that will be ignored.
-
- //set_time_limit(45);
- }
-
- /**
- * Modify the PHP environment variables.
- */
- private function phpEnvironment(): void
- {
- // Some servers block access to the system temporary folder using open_basedir...
- //
- // Create a temporary folder somewhere we have read/write access, and tell PHP to use it.
- //$tmp = __DIR__ . '/../../data/tmp';
- //if (!is_dir($tmp)) {
- // mkdir($tmp);
- //}
- //putenv('TMPDIR=' . $tmp);
- }
-
- /**
- * Modify the PHP.INI settings.
- */
- private function phpIni(): void
- {
- // Set the maximum amount of memory that PHP scripts can use.
- // Recommended settings are between 128M and 1024M
-
- //ini_set('memory_limit', '256M');
- }
-
- /**
- * Modify the MySQL connection.
- */
- private function mysql(): void
- {
- // If you get the error "The SELECT would examine more than MAX_JOIN_SIZE rows",
- // then setting this option may help.
-
- //DB::statement('SET SESSION sql_big_selects := 1');
- }
-}
diff --git a/modules_v4/example-server-configuration.disable/module.php b/modules_v4/example-server-configuration.disable/module.php
deleted file mode 100644
index 1442354391..0000000000
--- a/modules_v4/example-server-configuration.disable/module.php
+++ /dev/null
@@ -1,19 +0,0 @@
-<?php
-
-/**
- * An example module to modify PHP and database configuration.
- */
-
-declare(strict_types=1);
-
-namespace MyCustomNamespace;
-
-// Unlike the other examples, this one has a separate file for the class definition.
-// This is because the constructor has some dependencies, so we must create it
-// with "app(CustomModule::class)" rather than "new CustomModule()".
-// This means we can't use an anonymous class, and our coding standards
-// mean that the class needs to go in its own file.
-// For simple modules, it might be easier to declare the class here.
-require __DIR__ . '/ExampleServerConfigurationModule.php';
-
-return app(ExampleServerConfigurationModule::class);
diff --git a/modules_v4/example-theme.disable/module.php b/modules_v4/example-theme.disable/module.php
deleted file mode 100644
index b0f7d4b3e0..0000000000
--- a/modules_v4/example-theme.disable/module.php
+++ /dev/null
@@ -1,66 +0,0 @@
-<?php
-
-/**
- * Example theme. Here we are extending an existing theme.
- * Instead, you could extend AbstractModule and implement ModuleThemeInterface directly.
- */
-
-declare(strict_types=1);
-
-namespace MyCustomNamespace;
-
-use Fisharebest\Webtrees\Module\MinimalTheme;
-use Fisharebest\Webtrees\Module\ModuleCustomInterface;
-use Fisharebest\Webtrees\Module\ModuleCustomTrait;
-use Fisharebest\Webtrees\View;
-
-return new class extends MinimalTheme implements ModuleCustomInterface {
- use ModuleCustomTrait;
-
- /**
- * @return string
- */
- public function title(): string
- {
- return 'Custom theme';
- }
-
- /**
- * Bootstrap the module
- */
- public function boot(): void
- {
- // Register a namespace for our views.
- View::registerNamespace($this->name(), $this->resourcesFolder() . 'views/');
-
- // Replace an existing view with our own version.
- View::registerCustomView('::chart-box', $this->name() . '::chart-box');
- }
-
- /**
- * Where does this module store its resources
- *
- * @return string
- */
- public function resourcesFolder(): string
- {
- return __DIR__ . '/resources/';
- }
-
- /**
- * Add our own stylesheet to the existing stylesheets.
- *
- * @return array<string>
- */
- public function stylesheets(): array
- {
- $stylesheets = parent::stylesheets();
-
- // NOTE - a future version of webtrees will allow the modules to be stored in a private folder.
- // Only files in the /public/ folder will be accessible via the webserver.
- // Since modules cannot copy their files to the /public/ folder, they need to provide them via a callback.
- $stylesheets[] = $this->assetUrl('css/theme.css');
-
- return $stylesheets;
- }
-};
diff --git a/modules_v4/example-theme.disable/resources/css/theme.css b/modules_v4/example-theme.disable/resources/css/theme.css
deleted file mode 100644
index 0d79f0bc0a..0000000000
--- a/modules_v4/example-theme.disable/resources/css/theme.css
+++ /dev/null
@@ -1,3 +0,0 @@
-body.wt-global {
- color: orange;
-}
diff --git a/modules_v4/example-theme.disable/resources/views/chart-box.phtml b/modules_v4/example-theme.disable/resources/views/chart-box.phtml
deleted file mode 100644
index 88e68a0201..0000000000
--- a/modules_v4/example-theme.disable/resources/views/chart-box.phtml
+++ /dev/null
@@ -1,5 +0,0 @@
-<!-- A nice orange border around the existing chart box -->
-<div style="outline: dashed thick orange">
- <!-- The "::" allows us to use the original view, without being redirected to this file. -->
- <?= view('::chart-box', ['individual' => $individual]) ?>
-</div>
diff --git a/modules_v4/example.disable/module.php b/modules_v4/example.disable/module.php
deleted file mode 100644
index 2f13f9b39e..0000000000
--- a/modules_v4/example.disable/module.php
+++ /dev/null
@@ -1,160 +0,0 @@
-<?php
-
-/**
- * Example module.
- */
-
-declare(strict_types=1);
-
-namespace MyCustomNamespace;
-
-use Fisharebest\Localization\Translation;
-use Fisharebest\Webtrees\I18N;
-use Fisharebest\Webtrees\Module\AbstractModule;
-use Fisharebest\Webtrees\Module\ModuleCustomInterface;
-use Fisharebest\Webtrees\Module\ModuleCustomTrait;
-
-return new class extends AbstractModule implements ModuleCustomInterface {
- use ModuleCustomTrait;
-
- /**
- * Constructor. The constructor is called on *all* modules, even ones that are disabled.
- * This is a good place to load business logic ("services"). Type-hint the parameters and
- * they will be injected automatically.
- */
- public function __construct()
- {
- // NOTE: If your module is dependent on any of the business logic ("services"),
- // then you would type-hint them in the constructor and let webtrees inject them
- // for you. However, we can't use dependency injection on anonymous classes like
- // this one. For an example of this, see the example-server-configuration module.
- }
-
- /**
- * Bootstrap. This function is called on *enabled* modules.
- * It is a good place to register routes and views.
- *
- * @return void
- */
- public function boot(): void
- {
- }
-
- /**
- * How should this module be identified in the control panel, etc.?
- *
- * @return string
- */
- public function title(): string
- {
- return 'My custom module';
- }
-
- /**
- * A sentence describing what this module does.
- *
- * @return string
- */
- public function description(): string
- {
- return 'This module doesn‘t do anything';
- }
-
- /**
- * The person or organisation who created this module.
- *
- * @return string
- */
- public function customModuleAuthorName(): string
- {
- return 'Greg Roach';
- }
-
- /**
- * The version of this module.
- *
- * @return string
- */
- public function customModuleVersion(): string
- {
- return '1.0.0';
- }
-
- /**
- * A URL that will provide the latest version of this module.
- *
- * @return string
- */
- public function customModuleLatestVersionUrl(): string
- {
- return 'https://www.example.com/latest-version.txt';
- }
-
- /**
- * Where to get support for this module. Perhaps a github repository?
- *
- * @return string
- */
- public function customModuleSupportUrl(): string
- {
- return 'https://www.example.com/support';
- }
-
- /**
- * Additional/updated translations.
- *
- * @param string $language
- *
- * @return array<string>
- */
- public function customTranslations(string $language): array
- {
- switch ($language) {
- case 'en-AU':
- case 'en-GB':
- case 'en-US':
- return $this->englishTranslations();
-
- case 'fr':
- case 'fr-CA':
- return $this->frenchTranslations();
-
- case 'some-other-language':
- // Arrays are preferred, and faster.
- // If your module uses .MO files, then you can convert them to arrays like this.
- return (new Translation('path/to/file.mo'))->asArray();
-
- default:
- return [];
- }
- }
-
- /**
- * @return array<string,string>
- */
- protected function englishTranslations(): array
- {
- // Note the special characters used in plural and context-sensitive translations.
- return [
- 'Individual' => 'Fish',
- 'Individuals' => 'Fishes',
- '%s individual' . I18N::PLURAL . '%s individuals' => '%s fish' . I18N::PLURAL . '%s fishes',
- 'Unknown given name' . I18N::CONTEXT . '…' => '?fish?',
- 'Unknown surname' . I18N::CONTEXT . '…' => '?FISH?',
- ];
- }
-
- /**
- * @return array<string,string>
- */
- protected function frenchTranslations(): array
- {
- return [
- 'Individual' => 'Poisson',
- 'Individuals' => 'Poissons',
- '%s individual' . I18N::PLURAL . '%s individuals' => '%s poisson' . I18N::PLURAL . '%s poissons',
- 'Unknown given name' . I18N::CONTEXT . '…' => '?poission?',
- 'Unknown surname' . I18N::CONTEXT . '…' => '?POISSON?',
- ];
- }
-};