]> BookStack Code Mirror - bookstack/blob - dev/docs/logical-theme-system.md
Merge pull request #5626 from BookStackApp/rubentalstra-development
[bookstack] / dev / docs / logical-theme-system.md
1 # Logical Theme System
2
3 BookStack allows logical customization via the theme system which enables you to add, or extend, functionality within the PHP side of the system without needing to alter the core application files.
4
5 This is part of the theme system alongside the [visual theme system](./visual-theme-system.md).
6
7 **Note:** This system is considered semi-stable. The `Theme::` system is kept maintained but specific customizations or deeper app/framework usage using this system will not be supported nor considered in any way stable. Customizations using this system should be checked after updates.
8
9 ## Getting Started
10
11 *[Video Guide](https://www.youtube.com/watch?v=YVbpm_35crQ)*
12
13 This makes use of the theme system. Create a folder for your theme within your BookStack `themes` directory. As an example we'll use `my_theme`, so we'd create a `themes/my_theme` folder.
14 You'll need to tell BookStack to use your theme via the `APP_THEME` option in your `.env` file. For example: `APP_THEME=my_theme`.
15
16 Within your theme folder create a `functions.php` file. BookStack will look for this and run it during app boot-up. Within this file you can use the `Theme` facade API, described below, to hook into certain app events.
17
18 ## `Theme` Facade API
19
20 Below details the public methods of the `Theme` facade that are considered stable:
21
22 ### `Theme::listen`
23
24 This method listens to a system event and runs the given action when that event occurs. The arguments passed to the action depend on the event. Event names are exposed as static properties on the `\BookStack\Theming\ThemeEvents` class. 
25
26 It is possible to listen to a single event using multiple actions. When dispatched, BookStack will loop over and run each action for that event.
27 If an action returns a non-null value then BookStack will stop cycling through actions at that point and make use of the non-null return value if possible (Depending on the event).
28
29 **Arguments**
30 - string $event
31 - callable $action
32
33 **Example**
34
35 ```php
36 Theme::listen(
37     \BookStack\Theming\ThemeEvents::AUTH_LOGIN,
38     function($service, $user) {
39         \Log::info("Login by {$user->name} via {$service}");
40     }
41 );
42 ```
43
44 ### `Theme::addSocialDriver`
45
46 This method allows you to register a custom social authentication driver within the system. This is primarily intended to use with [Socialite Providers](https://socialiteproviders.com/).
47
48 **Arguments**
49 - string $driverName
50 - array $config
51 - string $socialiteHandler
52 - callable|null $configureForRedirect = null
53
54 **Example**
55
56 *See "Custom Socialite Service Example" below.*
57
58 ### `Theme::registerCommand`
59
60 This method allows you to register a custom command which can then be used via the artisan console.
61
62 **Arguments**
63 - string $driverName
64 - array $config
65 - string $socialiteHandler
66
67 **Example**
68
69 *See "Custom Command Registration Example" below for a more detailed example.*
70
71 ```php
72 Theme::registerCommand(new SayHelloCommand());
73 ```
74
75 ## Available Events
76
77 All available events dispatched by BookStack are exposed as static properties on the `\BookStack\Theming\ThemeEvents` class, which can be found within the file `app/Theming/ThemeEvents.php` relative to your root BookStack folder. Alternatively, the events for the latest release can be [seen on GitHub here](https://github.com/BookStackApp/BookStack/blob/release/app/Theming/ThemeEvents.php).
78
79 The comments above each constant with the `ThemeEvents.php` file describe the dispatch conditions of the event, in addition to the arguments the action will receive. The comments may also describe any ways the return value of the action may be used. 
80
81 ## Example `functions.php` file
82
83 ```php
84 <?php
85
86 use BookStack\Facades\Theme;
87 use BookStack\Theming\ThemeEvents;
88
89 // Logs custom message on user login
90 Theme::listen(ThemeEvents::AUTH_LOGIN, function($method, $user) {
91     Log::info("Login via {$method} for {$user->name}");
92 });
93
94 // Adds a `/info` public URL endpoint that emits php debug details
95 Theme::listen(ThemeEvents::APP_BOOT, function($app) {
96     \Route::get('info', function() {
97         phpinfo(); // Don't do this on a production instance!
98     });
99 });
100 ```
101
102 ## Custom Command Registration Example
103
104 The logical theme system supports adding custom [artisan commands](https://laravel.com/docs/8.x/artisan) to BookStack.
105 These can be registered in your `functions.php` file by calling `Theme::registerCommand($command)`, where `$command` is an instance of `\Symfony\Component\Console\Command\Command`. 
106
107 Below is an example of registering a command that could then be ran using `php artisan bookstack:meow` on the command line.
108
109 ```php
110 <?php
111
112 use BookStack\Facades\Theme;
113 use Illuminate\Console\Command;
114
115 class MeowCommand extends Command
116 {
117     protected $signature = 'bookstack:meow';
118     protected $description = 'Say meow on the command line';
119
120     public function handle()
121     {
122         $this->line('Meow there!');
123     }
124 }
125
126 Theme::registerCommand(new MeowCommand);
127 ```
128
129 ## Custom Socialite Service Example
130
131 The below shows an example of adding a custom reddit socialite service to BookStack. 
132 BookStack exposes a helper function for this via `Theme::addSocialDriver` which sets the required config and event listeners in the platform.
133
134 The require statements reference composer installed dependencies within the theme folder. They are required manually since they are not auto-loaded like other app files due to being outside the main BookStack dependency list. 
135
136 ```php
137 require "vendor/socialiteproviders/reddit/Provider.php";
138 require "vendor/socialiteproviders/reddit/RedditExtendSocialite.php";
139
140 Theme::listen(ThemeEvents::APP_BOOT, function($app) {
141     Theme::addSocialDriver('reddit', [
142         'client_id' => 'abc123',
143         'client_secret' => 'def456789',
144         'name' => 'Reddit',
145     ], '\SocialiteProviders\Reddit\RedditExtendSocialite@handle');
146 });
147 ```
148
149 In some cases you may need to customize the driver before it performs a redirect. 
150 This can be done by providing a callback as a fourth parameter like so:
151
152 ```php
153 Theme::addSocialDriver('reddit', [
154     'client_id' => 'abc123',
155     'client_secret' => 'def456789',
156     'name' => 'Reddit',
157 ], '\SocialiteProviders\Reddit\RedditExtendSocialite@handle', function($driver) {
158     $driver->with(['prompt' => 'select_account']);
159     $driver->scopes(['open_id']);
160 });
161 ```
Morty Proxy This is a proxified and sanitized view of the page, visit original site.