mirror of
https://github.com/BookStackApp/BookStack.git
synced 2026-05-04 18:08:46 +03:00
Theme Modules: Added easier way to insert HTML head content
This commit is contained in:
@@ -12,7 +12,8 @@ class CustomHtmlHeadContentProvider
|
||||
{
|
||||
public function __construct(
|
||||
protected CspService $cspService,
|
||||
protected Cache $cache
|
||||
protected Cache $cache,
|
||||
protected ThemeService $themeService,
|
||||
) {
|
||||
}
|
||||
|
||||
@@ -23,8 +24,9 @@ class CustomHtmlHeadContentProvider
|
||||
public function forWeb(): string
|
||||
{
|
||||
$content = $this->getSourceContent();
|
||||
$hash = md5($content);
|
||||
$hash = md5($content) . ':' . $this->themeService->getModulesHash();
|
||||
$html = $this->cache->remember('custom-head-web:' . $hash, 86400, function () use ($content) {
|
||||
$content .= "\n" . $this->getModuleHeadContent();
|
||||
return HtmlNonceApplicator::prepare($content);
|
||||
});
|
||||
|
||||
@@ -53,4 +55,23 @@ class CustomHtmlHeadContentProvider
|
||||
{
|
||||
return setting('app-custom-head', '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get any custom head content from installed modules.
|
||||
*/
|
||||
protected function getModuleHeadContent(): string
|
||||
{
|
||||
$content = '';
|
||||
foreach ($this->themeService->getModules() as $module) {
|
||||
$headContentPath = $module->path('head');
|
||||
if (file_exists($headContentPath) && is_dir($headContentPath)) {
|
||||
$htmlFiles = glob($headContentPath . '/*.html');
|
||||
foreach ($htmlFiles as $file) {
|
||||
$content .= file_get_contents($file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,6 +126,20 @@ class ThemeService
|
||||
return $this->modules;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a hash to represent the currently loaded modules.
|
||||
*/
|
||||
public function getModulesHash(): string
|
||||
{
|
||||
$key = "";
|
||||
|
||||
foreach ($this->modules as $module) {
|
||||
$key .= $module->name . ':' . $module->version . ';';
|
||||
}
|
||||
|
||||
return md5($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Look for a specific file within the theme or its modules.
|
||||
* Returns the first file found or null if not found.
|
||||
|
||||
@@ -24,6 +24,7 @@ The content within the module folder should then follow this format:
|
||||
|
||||
- `bookstack-module.json` - REQUIRED - A JSON file containing [the metadata](#module-json-metadata) for the module.
|
||||
- `functions.php` - OPTIONAL - A PHP file containing code for the [logical theme system](logical-theme-system.md).
|
||||
- `head/` - OPTIONAL - A folder containing HTML files which will be included into the HTML head of app-views.
|
||||
- `icons/` - OPTIONAL - A folder containing any icons to use as per [the visual theme system](visual-theme-system.md#customizing-icons).
|
||||
- `lang/` - OPTIONAL - A folder containing any language files to use as per [the visual theme system](visual-theme-system.md#customizing-text-content).
|
||||
- `public/` - OPTIONAL - A folder containing any files to expose into public web-space as per [the visual theme system](visual-theme-system.md#publicly-accessible-files).
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
@inject('headContent', 'BookStack\Theming\CustomHtmlHeadContentProvider')
|
||||
|
||||
@if(setting('app-custom-head') && !request()->routeIs('settings.category'))
|
||||
@if(!request()->routeIs('settings.category'))
|
||||
<!-- Start: custom user content -->
|
||||
{!! $headContent->forWeb() !!}
|
||||
<!-- End: custom user content -->
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace Tests\Theme;
|
||||
|
||||
use BookStack\Facades\Theme;
|
||||
use BookStack\Util\CspService;
|
||||
use Tests\TestCase;
|
||||
|
||||
class ThemeModuleTest extends TestCase
|
||||
@@ -220,6 +221,23 @@ class ThemeModuleTest extends TestCase
|
||||
});
|
||||
}
|
||||
|
||||
public function test_module_can_provide_head_content()
|
||||
{
|
||||
$this->usingModuleFolder(function (string $moduleFolderPath) {
|
||||
mkdir($moduleFolderPath . '/head', 0777, true);
|
||||
file_put_contents($moduleFolderPath . '/head/hello.html', '<meta name="beans" content="hello"><script>hellofromcustomscript</script>');
|
||||
|
||||
$this->refreshApplication();
|
||||
|
||||
$cspService = $this->app->make(CspService::class);
|
||||
$nonce = $cspService->getNonce();
|
||||
|
||||
$resp = $this->asAdmin()->get('/');
|
||||
$resp->assertSee('<meta name="beans" content="hello">', false);
|
||||
$resp->assertSee('<script nonce="' . $nonce . '">hellofromcustomscript</script>', false);
|
||||
});
|
||||
}
|
||||
|
||||
protected function usingModuleFolder(callable $callback): void
|
||||
{
|
||||
$this->usingThemeFolder(function (string $themeFolder) use ($callback) {
|
||||
|
||||
Reference in New Issue
Block a user