Hacks & Customizations
These hacks are unsupported customizations meant as unofficial workarounds.
They can cause instability, introduce issues and may conflict with future updates. Apply at your own risk!

View Block: Instance Total Stats

  • Author: @danb
  • Created: 25th Sep 2026
  • Updated: 25th Sep 2026
  • Last Tested On: v26.09

This hack registers a custom view block which can be used on any type of home page. This block lists total counts for shelves, books, chapters, pages and users in the system.

This was created to demonstrate custom view blocks on the release of BookStack v26.09, as can be seen in the release video here.

Considerations

  • Only English text & labels are included.
  • All users will have access to this block.

Usage

It’s advised to install this as a theme module as guided below. After installation, you’ll then find this block available as a section within the “My Account > Interface Preferences > UI Layout Preferences > Homepage” view in BookStack.

By default it will show in the “Unused” area, but you can drag it into another column then save the layout. Once configured, the totals should then show up on the homepage.

Code

functions.php
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
<?php

use BookStack\Entities\Queries\EntityQueries;
use BookStack\Facades\Theme;
use BookStack\Theming\ThemeEvents;
use BookStack\Users\Models\User;
use BookStack\View\BaseViewBlock;
use BookStack\View\ViewBlockManager;

/**
 * Define our custom block for displaying total stats.
 * We extend the BaseViewBlock which implements the required ViewBlockInterface, and provides
 * a basis which may help with forward compatibility if the interface changes in the future.
 */
class TotalStatsBlock extends BaseViewBlock
{
    // Here we inject in the EntityQueries class, which BookStack will resolve automatically
    // when creating the block instance.
    public function __construct(
        protected EntityQueries $entityQueries,
    ) {
    }

    // We provide a unique ID for this block to distinguish it from other blocks.
    // This is used as the key when the block is configured as part of a layout.
    public static function getId(): string
    {
        return 'com.bookstackapp.hacks.total-stats-block';
    }

    // We return the label which will show for this block in the configuration UI.
    public static function getLabel(): string
    {
        return 'Instance Total Stats';
    }

    // We return the view name which will be used to render the block.
    // Here it's dynamic, based on the 'homeView' variable that's set when viewing home pages,
    // so we can use different views depending on homepage type.
    public function getView(array $viewData): string
    {
        $viewName = ($viewData['homeView'] ?? 'default') === 'default' ? 'home-default' : 'home-non-default';
        return "custom-block-totals.{$viewName}";
    }

    // We return all the total counts, so that our custom block view can use this data.
    public function getViewData(array $viewData): array
    {
        return [
            'totalUsers' => User::query()->count(),
            'totalBooks' => $this->entityQueries->books->visibleForList()->count(),
            'totalChapters' => $this->entityQueries->chapters->visibleForList()->count(),
            'totalPages' => $this->entityQueries->pages->visibleForList()->count(),
            'totalShelves' => $this->entityQueries->shelves->visibleForList()->count(),
        ];
    }
}

// We listen for the VIEW_BLOCKS_REGISTER event using the theme system which, when called,
// provides us a ViewBlockManager instance that we can use to register our custom block.
// We register the block twice, once for each homepage type.
Theme::listen(ThemeEvents::VIEW_BLOCKS_REGISTER, function (ViewBlockManager $manager) {
    $manager->register('home-default', 'unused', TotalStatsBlock::class);
    $manager->register('home-non-default', 'unused', TotalStatsBlock::class);
});
custom-block-totals/home-default.blade.php
1
2
3
4
5
6
7
8
<div id="stats-totals" class="card mb-xl">
    <h3 class="card-title">Instance Stats</h3>
    <div class="px-m">
        <div class="icon-list compact">
            @include('custom-block-totals.list')
        </div>
    </div>
</div>
custom-block-totals/home-non-default.blade.php
1
2
3
4
5
6
<div id="stats-totals" class="mb-xl">
    <h5>Instance Stats</h5>
    <div class="icon-list no-hover compact">
        @include('custom-block-totals.list')
    </div>
</div>
custom-block-totals/list.blade.php
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<div class="page icon-list-item no-hover">
    <span role="presentation" class="icon text-page">@icon('page')</span>
    <div class="content">
        <span class="icon-list-item-name break-text">{{ number_format($totalPages) }} Pages</span>
    </div>
</div>

<div class="chapter icon-list-item no-hover">
    <span role="presentation" class="icon text-chapter">@icon('chapter')</span>
    <div class="content">
        <span class="icon-list-item-name break-text">{{ number_format($totalChapters) }} Chapters</span>
    </div>
</div>

<div class="book icon-list-item no-hover">
    <span role="presentation" class="icon text-book">@icon('book')</span>
    <div class="content">
        <span class="icon-list-item-name break-text">{{ number_format($totalBooks) }} Books</span>
    </div>
</div>

<div class="bookshelf icon-list-item no-hover">
    <span role="presentation" class="icon text-bookshelf">@icon('bookshelf')</span>
    <div class="content">
        <span class="icon-list-item-name break-text">{{ number_format($totalShelves) }} Shelves</span>
    </div>
</div>

<div class="icon-list-item no-hover">
    <span role="presentation" class="icon">@icon('user')</span>
    <div class="content">
        <span class="icon-list-item-name break-text">{{ number_format($totalUsers) }} Users</span>
    </div>
</div>

Install as Module (Beta)

If using BookStack v26.03 or later, you can install this hack as a theme module on your BookStack instance by running the below artisan command from your BookStack installation folder:

php artisan bookstack:install-module https://www.bookstackapp.com/hack-modules/block-totals.zip


Request an Update

Hack not working on the latest version of BookStack?
You can request this hack to be updated & tested for a small one-time fee.
This helps keeps these hacks updated & maintained in a sustainable manner.


Latest Hacks