Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ A wiki for phpBB with version history, side-by-side compare, and a moderation qu
- Tables, written as HTML in an article: `<table>`, `<caption>`, `<thead>`, `<tbody>`, `<tfoot>`, `<tr>`, `<th>` and `<td>`, with `colspan` and `rowspan` on a cell. BBCode and `[[links]]` work inside cells. Any other attribute (`style`, `onclick`, `class`) is dropped, and any other element (`script`, `iframe`) stays plain text. Like headings, tables work in wiki articles only; in a forum post `<table>` stays plain text. After upgrading, disable and enable the extension so the board rebuilds its cache.
- Templates: `{{Name}}`, `{{Name|first|second}}` and `{{Name|key=value}}` in an article include the live version of the article `Template:Name`, so a notice or infobox is written once and edited in one place. See [Templates](#templates).
- Categories: `[[Category:Name]]` in an article puts it in a category. The article lists its categories at the bottom, `/wiki/Category:Name` lists the articles in a category, and `/wiki/categories` lists every category. See [Categories](#categories).
- Search: `/wiki/search` and a search box on the overview find articles by their title, description and text, with highlighted snippets. It has its own index, kept current as articles are saved, approved, set offline and deleted, and three backends to choose from in the ACP (native, MySQL fulltext, PostgreSQL fulltext). See [Search](#search).
- The Wiki link in the board header shows the Wikipedia icon by default. Under **Extensions > Wiki > Settings** in the ACP the icon can be changed to any [Font Awesome](https://fontawesome.com/v4.7.0/icons/) icon name, or left blank for no icon.
- A **Start discussion** button on each article creates its discussion topic in a forum chosen under **Extensions > Wiki > Settings** in the ACP, and links the topic to the article. It shows to members who hold the "Can change the discussion topic for an article" permission and may post in that forum, and stays hidden until a forum is chosen.
- Separate permissions for viewing, editing, version history, deleting and moderating.
Expand Down Expand Up @@ -110,6 +111,27 @@ Write `[[Category:Name]]` anywhere in a wiki article to put it in a category. Th
- A template page counts for the categories it names outside `<includeonly>`, so `<noinclude>[[Category:Infobox templates]]</noinclude>` puts the template in that category. A category added inside `<includeonly>` by a template shows under the articles that use the template, but those articles are not in the category's list, which is found from the articles' own text.
- After upgrading, disable and enable the extension so the board rebuilds its cache. Articles saved before this build keep `[[Category:Name]]` as text until they are saved again or reparsed with `php bin/phpbbcli.php reparser:reparse phpbbmodders_wiki_article`.

## Search

The wiki has its own search, separate from phpBB's search of posts: **Search the wiki** on the overview, or `/wiki/search?keywords=...`.

- It searches the live version of each article: its title, its description and its text, with the markup (BBCode, links, templates, tables, categories) reduced to the words in it. Older versions and edits waiting for approval are not searched. Template and category pages are articles too, so they are found.
- Choose to match all the words or any of them, to search titles only or text only, and to sort by last edit or title. Results show the title, description, a snippet with the words marked, and the date.
- It follows the articles: saving a live article, approving a version, setting an article offline, putting it back and deleting it all update the search at once.
- The search needs the permission to read the wiki and phpBB's own "Can use search" permission, and it is off when the board's search is off.

**In the ACP**, under **Extensions > Wiki > Search**, switch the wiki search on or off, set the results per page, and choose the backend:

| Backend | For | Notes |
| --- | --- | --- |
| Native | Every database, including SQLite | Keeps its own word tables. Words in most articles are treated as common once a wiki has 100 articles or more, as in phpBB's own search |
| MySQL fulltext | MySQL | Adds fulltext indexes to the search's text table |
| PostgreSQL fulltext | PostgreSQL | Adds text-search indexes to the search's text table |

Only the backends the database can run are offered. After installing, or after switching backend, press **Create index** under **Search index** for the backend you chose; until then the native backend finds only articles saved since it was installed, and the fulltext backends find nothing. The page shows each index's statistics and can delete it.

The search keeps a plain-text copy of each live article in its own table (`wiki_search_text`); **Create index** makes that copy again from the articles before it builds the backend's index, so it is also the way to rebuild everything.

## Linking between articles

Write an article's name in double square brackets to link to it, in wiki articles and in forum posts:
Expand Down
32 changes: 32 additions & 0 deletions acp/search_info.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php
/**
*
* Wiki extension for the phpBB Forum Software package
*
* @copyright (c) 2026, phpBB Modders, https://www.phpbbmodders.com/
* @license GNU General Public License, version 2 (GPL-2.0)
*
*/

namespace phpbbmodders\wiki\acp;

/**
* Registers the Wiki search page in the ACP.
*/
class search_info
{
public function module()
{
return array(
'filename' => '\phpbbmodders\wiki\acp\search_module',
'title' => 'ACP_WIKI_SEARCH',
'modes' => array(
'settings' => array(
'title' => 'ACP_WIKI_SEARCH',
'auth' => 'ext_phpbbmodders/wiki && acl_a_board',
'cat' => array('ACP_WIKI_TITLE'),
),
),
);
}
}
50 changes: 50 additions & 0 deletions acp/search_module.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php
/**
*
* Wiki extension for the phpBB Forum Software package
*
* @copyright (c) 2026, phpBB Modders, https://www.phpbbmodders.com/
* @license GNU General Public License, version 2 (GPL-2.0)
*
*/

namespace phpbbmodders\wiki\acp;

/**
* The Wiki search page: whether the search is on, how many results a page shows, which
* search backend it uses, and building or deleting the backend's index.
*/
class search_module
{
public $u_action;
public $tpl_name;
public $page_title;

/**
* @param int $id Module id
* @param string $mode Module mode
*/
public function main($id, $mode)
{
global $phpbb_container, $phpbb_root_path, $phpEx;

$language = $phpbb_container->get('language');
$language->add_lang('acp/search');
$language->add_lang('acp_wiki', 'phpbbmodders/wiki');

if (!function_exists('adm_back_link'))
{
include($phpbb_root_path . 'includes/functions_admin.' . $phpEx);
}

$controller = $phpbb_container->get('phpbbmodders.wiki.acp_search');
$controller->set_page_url($this->u_action);

$this->tpl_name = 'acp_wiki_search';
$this->page_title = $language->lang('ACP_WIKI_SEARCH');
add_form_key('phpbbmodders_wiki_search');

$controller->settings($id, $mode);
$controller->index($id, $mode);
}
}
100 changes: 100 additions & 0 deletions adm/style/acp_wiki_search.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
<!-- INCLUDE overall_header.html -->

<h1>{L_ACP_WIKI_SEARCH}</h1>
<p>{L_WIKI_SEARCH_SETTINGS_EXPLAIN}</p>

<form id="wiki_search_settings" method="post" action="{U_ACTION}">
<fieldset>
<legend>{L_GENERAL_SEARCH_SETTINGS}</legend>
<dl>
<dt><label for="wiki_search_yes">{L_WIKI_SEARCH_ENABLE}{L_COLON}</label><br><span>{L_WIKI_SEARCH_ENABLE_EXPLAIN}</span></dt>
<dd>
<label><input type="radio" class="radio" id="wiki_search_yes" name="config[wiki_search]" value="1"<!-- IF S_WIKI_SEARCH --> checked="checked"<!-- ENDIF -->> {L_YES}</label>
<label><input type="radio" class="radio" name="config[wiki_search]" value="0"<!-- IF not S_WIKI_SEARCH --> checked="checked"<!-- ENDIF -->> {L_NO}</label>
</dd>
</dl>
<dl>
<dt><label for="wiki_per_page_search">{L_WIKI_PER_PAGE_SEARCH}{L_COLON}</label><br><span>{L_WIKI_PER_PAGE_SEARCH_EXPLAIN}</span></dt>
<dd><input id="wiki_per_page_search" type="number" min="1" max="9999" name="config[wiki_per_page_search]" value="{WIKI_PER_PAGE_SEARCH}"></dd>
</dl>
</fieldset>
<fieldset>
<legend>{L_SEARCH_TYPE}</legend>
<dl>
<dt><label for="search_type">{L_SEARCH_TYPE}{L_COLON}</label><br><span>{L_SEARCH_TYPE_EXPLAIN}</span></dt>
<dd><select id="search_type" name="config[wiki_search_type]">{S_SEARCH_TYPES}</select></dd>
</dl>
</fieldset>
<!-- IF not S_CONTINUE -->
<fieldset class="submit-buttons">
<legend>{L_SUBMIT}</legend>
<input class="button1" type="submit" id="submit" name="submit" value="{L_SUBMIT}">&nbsp;
<input class="button2" type="reset" id="reset" name="reset" value="{L_RESET}">
</fieldset>
{S_FORM_TOKEN}
<!-- ENDIF -->
</form>

<h1>{L_ACP_SEARCH_INDEX}</h1>
<!-- IF S_CONTINUE -->
<p>{L_CONTINUE_EXPLAIN}</p>
<form id="wiki_search_continue" method="post" action="{U_CONTINUE_INDEXING}">
<fieldset class="submit-buttons">
<legend>{L_SUBMIT}</legend>
<input class="button1" type="submit" id="continue" name="continue" value="{L_CONTINUE}">&nbsp;
<input class="button2" type="submit" id="cancel" name="cancel" value="{L_CANCEL}">
</fieldset>
{S_FORM_TOKEN}
</form>
<!-- ELSE -->
<script type="text/javascript">
/**
* Popup search progress bar
*/
function popup_progress_bar(progress_type) {
close_waitscreen = 0;
popup('{UA_PROGRESS_BAR}&amp;type=' + progress_type, 400, 240, '_index');
}
</script>

<p>{L_WIKI_SEARCH_INDEX_EXPLAIN}</p>
<!-- BEGIN backend -->
<form id="wiki_search_index_{backend.TYPE}" method="post" action="{U_INDEX_ACTION}">
<fieldset class="tabulated">
{backend.S_HIDDEN_FIELDS}
<legend>{L_INDEX_STATS}{L_COLON} {backend.NAME}<!-- IF backend.S_ACTIVE --> ({L_ACTIVE})<!-- ENDIF --></legend>
<!-- IF .backend.stats -->
<table class="table1 zebra-table responsive">
<caption>{backend.NAME}<!-- IF backend.S_ACTIVE --> ({L_ACTIVE})<!-- ENDIF --></caption>
<thead>
<tr>
<th>{L_STATISTIC}</th>
<th>{L_VALUE}</th>
</tr>
</thead>
<tbody>
<!-- BEGIN stats -->
<tr>
<td>{backend.stats.NAME}{L_COLON}</td>
<td>{backend.stats.VALUE}</td>
</tr>
<!-- END stats -->
</tbody>
</table>
<!-- ENDIF -->
<p class="quick">
<!-- IF backend.S_INDEXED -->
<input type="hidden" name="action" value="delete">
<input class="button2" type="submit" value="{L_DELETE_INDEX}" onclick="popup_progress_bar('delete');">
<!-- ELSE -->
<input type="hidden" name="action" value="create">
<input class="button2" type="submit" value="{L_CREATE_INDEX}" onclick="popup_progress_bar('create');">
<!-- ENDIF -->
</p>
{S_FORM_TOKEN}
</fieldset>
</form>
<!-- END backend -->
<!-- ENDIF -->

<!-- INCLUDE overall_footer.html -->
4 changes: 4 additions & 0 deletions config/routing.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ phpbbmodders_wiki_recent_changes:
path: /wiki/recent-changes
defaults: { _controller: phpbbmodders.wiki.recent_changes:page }

phpbbmodders_wiki_search:
path: /wiki/search
defaults: { _controller: phpbbmodders.wiki.search:main }

phpbbmodders_wiki_categories:
path: /wiki/categories
defaults: { _controller: phpbbmodders.wiki.category:index }
Expand Down
105 changes: 105 additions & 0 deletions config/services.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ parameters:
tables.wiki.article: '%core.table_prefix%wiki_article'
tables.wiki.file: '%core.table_prefix%wiki_file'
tables.wiki.watch: '%core.table_prefix%wiki_watch'
tables.wiki.search_text: '%core.table_prefix%wiki_search_text'
tables.wiki.search_results: '%core.table_prefix%wiki_search_results'
tables.wiki.search_wordlist: '%core.table_prefix%wiki_src_wrdlist'
tables.wiki.search_wordmatch: '%core.table_prefix%wiki_src_wrdmtch'

services:
_defaults:
Expand Down Expand Up @@ -164,6 +168,7 @@ services:
- '%core.php_ext%'
- '@phpbbmodders.wiki.watch'
- '@phpbbmodders.wiki.templates'
- '@phpbbmodders.wiki.search_sync'
phpbbmodders.wiki.compare:
class: phpbbmodders\wiki\wiki\compare
arguments:
Expand All @@ -189,6 +194,7 @@ services:
- '@phpbbmodders.wiki.files'
- '@request'
- '@phpbbmodders.wiki.watch'
- '@phpbbmodders.wiki.search_sync'
phpbbmodders.wiki.view:
class: phpbbmodders\wiki\wiki\view
arguments:
Expand Down Expand Up @@ -274,3 +280,102 @@ services:
- [set_watch, ['@phpbbmodders.wiki.watch']]
tags:
- { name: notification.type }

# Search: the three backends, the factory that picks the active one, and the
# service that keeps the search's copy of the articles current
phpbbmodders.wiki.search.fulltext.mysql:
class: phpbbmodders\wiki\search\backend\wiki_fulltext_mysql
arguments:
- '@config'
- '@dbal.conn'
- '@language'
- '@user'
- '%tables.wiki.search_text%'
- '%tables.wiki.search_results%'
- '%core.root_path%'
- '%core.php_ext%'
tags:
- { name: phpbbmodders.wiki.search.backend }

phpbbmodders.wiki.search.fulltext.native:
class: phpbbmodders\wiki\search\backend\wiki_fulltext_native
arguments:
- '@config'
- '@dbal.conn'
- '@language'
- '@user'
- '%tables.wiki.search_text%'
- '%tables.wiki.search_results%'
- '%tables.wiki.search_wordmatch%'
- '%tables.wiki.search_wordlist%'
- '%core.root_path%'
- '%core.php_ext%'
tags:
- { name: phpbbmodders.wiki.search.backend }

phpbbmodders.wiki.search.fulltext.postgres:
class: phpbbmodders\wiki\search\backend\wiki_fulltext_postgres
arguments:
- '@config'
- '@dbal.conn'
- '@language'
- '@user'
- '%tables.wiki.search_text%'
- '%tables.wiki.search_results%'
- '%core.root_path%'
- '%core.php_ext%'
tags:
- { name: phpbbmodders.wiki.search.backend }

phpbbmodders.wiki.search.backend_collection:
class: phpbb\di\service_collection
arguments:
- '@service_container'
tags:
- { name: service_collection, tag: phpbbmodders.wiki.search.backend, class_name_aware: true }

phpbbmodders.wiki.search.backend_factory:
class: phpbbmodders\wiki\search\wiki_search_backend_factory
arguments:
- '@config'
- '@phpbbmodders.wiki.search.backend_collection'

phpbbmodders.wiki.search_sync:
class: phpbbmodders\wiki\wiki\search_sync
arguments:
- '@config'
- '@dbal.conn'
- '@phpbbmodders.wiki.search.backend_factory'
- '%tables.wiki.article%'
- '%tables.wiki.search_text%'

phpbbmodders.wiki.acp_search:
class: phpbbmodders\wiki\controller\acp_search
arguments:
- '@config'
- '@language'
- '@log'
- '@request'
- '@template'
- '@user'
- '@phpbbmodders.wiki.search.backend_collection'
- '@phpbbmodders.wiki.search.backend_factory'
- '@phpbbmodders.wiki.search_sync'

phpbbmodders.wiki.search:
class: phpbbmodders\wiki\controller\search
arguments:
- '@auth'
- '@config'
- '@dbal.conn'
- '@controller.helper'
- '@language'
- '@pagination'
- '@request'
- '@template'
- '@user'
- '@phpbbmodders.wiki.search.backend_factory'
- '%tables.wiki.article%'
- '%tables.wiki.search_text%'
- '%core.root_path%'
- '%core.php_ext%'
Loading
Loading