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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ A wiki for phpBB with version history, side-by-side compare, and a moderation qu
- 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). The board's own search can show the matching articles in a block of their own, with an "Also search the Wiki" option. 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.
- Custom BBCodes (the ones added on the ACP's **Posting > BBCodes** page) can be made wiki-only under **Extensions > Wiki > BBCodes**: a ticked one works in wiki articles and nowhere else, and its button shows only in the wiki editor. A forum post, private message or signature using it is refused with phpBB's usual "You cannot use certain BBCodes" message. Text saved before keeps its formatting.
- Separate permissions for viewing, editing, version history, deleting and moderating.

## Screenshots
Expand Down
32 changes: 32 additions & 0 deletions acp/bbcodes_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 BBCodes page in the ACP.
*/
class bbcodes_info
{
public function module()
{
return array(
'filename' => '\phpbbmodders\wiki\acp\bbcodes_module',
'title' => 'ACP_WIKI_BBCODES',
'modes' => array(
'settings' => array(
'title' => 'ACP_WIKI_BBCODES',
'auth' => 'ext_phpbbmodders/wiki && acl_a_bbcode',
'cat' => array('ACP_WIKI_TITLE'),
),
),
);
}
}
78 changes: 78 additions & 0 deletions acp/bbcodes_module.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<?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 BBCodes page: which of the BBCodes the admin added under Posting, BBCodes work only
* in wiki articles (see wiki\wiki_only_bbcodes).
*/
class bbcodes_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_admin_path, $phpbb_container, $phpbb_root_path, $phpEx;

$language = $phpbb_container->get('language');
$request = $phpbb_container->get('request');
$template = $phpbb_container->get('template');
$wiki_only_bbcodes = $phpbb_container->get('phpbbmodders.wiki.wiki_only_bbcodes');

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

$language->add_lang('acp_wiki', 'phpbbmodders/wiki');

$this->tpl_name = 'acp_wiki_bbcodes';
$this->page_title = $language->lang('ACP_WIKI_BBCODES');
add_form_key('phpbbmodders_wiki_bbcodes');

if ($request->is_set_post('submit'))
{
if (!check_form_key('phpbbmodders_wiki_bbcodes'))
{
trigger_error($language->lang('FORM_INVALID') . adm_back_link($this->u_action), E_USER_WARNING);
}

$wiki_only_bbcodes->save($request->variable('wiki_only_bbcodes', array(0)));

trigger_error($language->lang('CONFIG_UPDATED') . adm_back_link($this->u_action));
}

$wiki_only = $wiki_only_bbcodes->ids();
foreach ($wiki_only_bbcodes->custom_bbcodes() as $row)
{
$template->assign_block_vars('wiki_only_bbcodes', array(
'ID' => (int) $row['bbcode_id'],
'TAG' => rtrim($row['bbcode_tag'], '='),
'HELPLINE' => $language->is_set($row['bbcode_helpline']) ? $language->lang($row['bbcode_helpline']) : $row['bbcode_helpline'],
'S_CHECKED' => in_array((int) $row['bbcode_id'], $wiki_only, true),
));
}

// The explanations link to phpBB's own BBCodes page
$u_bbcodes = append_sid("{$phpbb_admin_path}index.$phpEx", 'i=acp_bbcodes&amp;mode=bbcodes');
$template->assign_vars(array(
'WIKI_ONLY_BBCODES_EXPLAIN' => $language->lang('WIKI_ONLY_BBCODES_EXPLAIN', $u_bbcodes),
'WIKI_ONLY_BBCODES_NONE' => $language->lang('WIKI_ONLY_BBCODES_NONE', $u_bbcodes),
'U_ACTION' => $this->u_action,
));
}
}
29 changes: 29 additions & 0 deletions adm/style/acp_wiki_bbcodes.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<!-- INCLUDE overall_header.html -->


<h1>{L_ACP_WIKI_BBCODES}</h1>

<p>{WIKI_ONLY_BBCODES_EXPLAIN}</p>

<form id="wiki_bbcodes" method="post" action="{U_ACTION}">
<fieldset>
<legend>{L_WIKI_ONLY_BBCODES}</legend>
<!-- BEGIN wiki_only_bbcodes -->
<dl>
<dt><label for="wiki_only_bbcode_{wiki_only_bbcodes.ID}">[{wiki_only_bbcodes.TAG}]</label><!-- IF wiki_only_bbcodes.HELPLINE --><br><span>{wiki_only_bbcodes.HELPLINE}</span><!-- ENDIF --></dt>
<dd><label><input type="checkbox" class="radio" id="wiki_only_bbcode_{wiki_only_bbcodes.ID}" name="wiki_only_bbcodes[]" value="{wiki_only_bbcodes.ID}"<!-- IF wiki_only_bbcodes.S_CHECKED --> checked="checked"<!-- ENDIF -->> {L_WIKI_ONLY_BBCODE}</label></dd>
</dl>
<!-- BEGINELSE -->
<p><strong>{WIKI_ONLY_BBCODES_NONE}</strong></p>
<!-- END wiki_only_bbcodes -->
</fieldset>

<fieldset class="submit-buttons">
<legend>{L_SUBMIT}</legend>
<input class="button1" type="submit" id="submit" name="submit" value="{L_SUBMIT}">
<input class="button2" type="reset" id="reset" name="reset" value="{L_RESET}">
{S_FORM_TOKEN}
</fieldset>
</form>

<!-- INCLUDE overall_footer.html -->
8 changes: 8 additions & 0 deletions config/services.yml
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,13 @@ services:
- '@language'
- '%tables.wiki.article%'
- '@user'
# The custom BBCodes an admin has made wiki-only
phpbbmodders.wiki.wiki_only_bbcodes:
class: phpbbmodders\wiki\wiki\wiki_only_bbcodes
arguments:
- '@config'
- '@dbal.conn'
- '%tables.bbcodes%'
phpbbmodders.wiki.wikilink_listener:
class: phpbbmodders\wiki\event\wikilink_listener
arguments:
Expand All @@ -326,6 +333,7 @@ services:
- '@phpbbmodders.wiki.links'
- '@phpbbmodders.wiki.files'
- '@phpbbmodders.wiki.templates'
- '@phpbbmodders.wiki.wiki_only_bbcodes'
tags:
- { name: event.listener }

Expand Down
14 changes: 9 additions & 5 deletions docs/TODO/todo-wiki-markup.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ and `WIKIMAGIC` tags and the `html:` table tags on in `core.text_formatter_s9e_p
`php bin/phpbbcli.php reparser:reparse phpbbmodders_wiki_article`. Templates are built too, in their first form: `{{Name}}`, `{{Name|a|b}}`, `{{Name|key=value}}`,
`{{{param}}}` and `{{{param|default}}}`, `<noinclude>` and `<includeonly>`, expanded when an article is
shown (see `wiki/templates.php`), nested ten deep with a loop check, with the parser functions (`#if`,
`#switch`, `#expr`, `#time`, string functions and others) and categories (`[[Category:Name]]`) on top. What is
left is listed under "Still to do" in "Templates and infoboxes" below, and in "Scope" (making admins' own
BBCodes wiki-only).
`#switch`, `#expr`, `#time`, string functions and others) and categories (`[[Category:Name]]`) on top. Admins can
make their own BBCodes wiki-only too (see "Scope"). What is left is listed under "Still to do" in
"Templates and infoboxes" below.

## Scope: wiki articles only

Expand Down Expand Up @@ -57,8 +57,12 @@ Limits:

Built, in a slightly different form: the wiki-only tags are switched on in
`core.text_formatter_s9e_parse_before` only while an article is saved or
previewed (see "Built so far"). The ACP setting for making admins' own BBCodes
wiki-only is not built.
previewed (see "Built so far"). Admins' own BBCodes are ticked under
**Extensions > Wiki > BBCodes** and kept by id, so renaming one keeps the
choice (see `wiki/wiki_only_bbcodes.php`). Their buttons are left off every
editor but the wiki's, and a forum post that uses one is refused with
phpBB's own "You cannot use certain BBCodes" message rather than shown as
plain text.

## Syntax to add

Expand Down
Binary file added docs/images/wiki-acp-bbcodes.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
40 changes: 36 additions & 4 deletions event/wikilink_listener.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,15 +58,20 @@ class wikilink_listener implements EventSubscriberInterface
/** @var \phpbbmodders\wiki\wiki\templates */
protected $templates;

/** @var \phpbbmodders\wiki\wiki\wiki_only_bbcodes */
protected $wiki_only_bbcodes;

/**
* @param \phpbb\controller\helper $helper Controller helper object
* @param \phpbb\language\language $language Language object
* @param \phpbbmodders\wiki\wiki\links $links Wiki links service
* @param \phpbbmodders\wiki\wiki\files $files Wiki files service
* @param \phpbbmodders\wiki\wiki\templates $templates Wiki templates service
* @param \phpbbmodders\wiki\wiki\wiki_only_bbcodes $wiki_only_bbcodes The admin's BBCodes kept to the wiki
*/
public function __construct(\phpbb\controller\helper $helper, \phpbb\language\language $language, \phpbbmodders\wiki\wiki\links $links, \phpbbmodders\wiki\wiki\files $files, \phpbbmodders\wiki\wiki\templates $templates)
public function __construct(\phpbb\controller\helper $helper, \phpbb\language\language $language, \phpbbmodders\wiki\wiki\links $links, \phpbbmodders\wiki\wiki\files $files, \phpbbmodders\wiki\wiki\templates $templates, \phpbbmodders\wiki\wiki\wiki_only_bbcodes $wiki_only_bbcodes)
{
$this->wiki_only_bbcodes = $wiki_only_bbcodes;
$this->templates = $templates;
$this->files = $files;
$this->helper = $helper;
Expand All @@ -83,6 +88,7 @@ public static function getSubscribedEvents()
'core.text_formatter_s9e_configure_after' => 'configure_wikilink',
'core.text_formatter_s9e_parse_before' => 'toggle_wiki_markup',
'core.text_formatter_s9e_render_after' => 'link_wikilinks',
'core.display_custom_bbcodes_modify_sql' => 'hide_wiki_only_buttons',
);
}

Expand Down Expand Up @@ -264,8 +270,8 @@ public static function wiki_tags()
}

/**
* Point rendered wiki links at their articles, and mark the ones whose
* article doesn't exist yet.
* Let the parser read the wiki's own tags, and the BBCodes the admin made wiki-only, only
* while a wiki article is saved.
*
* @param \phpbb\event\data $event The event object
* @return void
Expand All @@ -274,7 +280,7 @@ public function toggle_wiki_markup($event)
{
$parser = $event['parser']->get_parser();

foreach (self::wiki_tags() as $tag)
foreach (array_merge(self::wiki_tags(), $this->wiki_only_bbcodes->tag_names()) as $tag)
{
if (\phpbbmodders\wiki\wiki\markup::is_active())
{
Expand All @@ -297,6 +303,32 @@ public function toggle_wiki_markup($event)
}
}

/**
* Leave the wiki-only BBCodes' buttons off every editor but the wiki's.
*
* @param \phpbb\event\data $event The event object
* @return void
*/
public function hide_wiki_only_buttons($event)
{
$ids = $this->wiki_only_bbcodes->ids();
if (!$ids || \phpbbmodders\wiki\wiki\markup::is_active())
{
return;
}

$sql_ary = $event['sql_ary'];
$sql_ary['WHERE'] = '(' . $sql_ary['WHERE'] . ') AND b.bbcode_id NOT IN (' . implode(', ', $ids) . ')';
$event['sql_ary'] = $sql_ary;
}

/**
* Point rendered wiki links at their articles, and mark the ones whose
* article doesn't exist yet.
*
* @param \phpbb\event\data $event The event object
* @return void
*/
public function link_wikilinks($event)
{
$html = $event['html'];
Expand Down
5 changes: 5 additions & 0 deletions language/en/acp_wiki.php
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@
'WIKI_EDIT_CONFLICT_INVALID' => 'The choice for when two people edit an article is not one of the choices.',
'WIKI_EDIT_LOCK_MINUTES' => 'Minutes an editor holds an article',
'WIKI_EDIT_LOCK_MINUTES_EXPLAIN' => 'How long the notice names an editor, or the lock lasts, after their last sign of work. It is extended every few minutes while their edit form is open, and when they preview, so it only runs out once they have left.',

'WIKI_ONLY_BBCODES' => 'BBCodes only for the wiki',
'WIKI_ONLY_BBCODES_EXPLAIN' => 'Tick a custom BBCode to use it only in wiki articles. It then stops working in posts, private messages and signatures, and its button shows only in the wiki editor. Text saved before you tick it keeps its formatting until it is edited. Custom BBCodes are the ones added on the <a href="%s">Posting » BBCodes</a> page of the ACP.',
'WIKI_ONLY_BBCODE' => 'Only in wiki articles',
'WIKI_ONLY_BBCODES_NONE' => 'This board has no custom BBCodes yet. Add them on the <a href="%s">Posting » BBCodes</a> page of the ACP.',
'WIKI_EDIT_LOCK_MINUTES_INVALID' => 'Minutes an editor holds an article must be a number from %1$d to %2$d.',

'ACP_WIKI_STARTER_TEMPLATES_EXPLAIN' => 'Starter templates are ready-made templates for the wiki, adapted from Wikipedia and other wikis, from the <a href="https://github.com/phpbbmodders/wiki-templates">phpbbmodders/wiki-templates</a> repository. They are shared under the <a href="https://creativecommons.org/licenses/by-sa/4.0/">CC BY-SA 4.0</a> licence; each one says where it comes from at the top of its page. Get the templates first, then choose which to install. Nothing is installed until you press Install.',
Expand Down
1 change: 1 addition & 0 deletions language/en/info_acp_wiki.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
'ACP_WIKI_SETTINGS' => 'Settings',
'ACP_WIKI_SEARCH' => 'Search',
'ACP_WIKI_STARTER_TEMPLATES' => 'Starter templates',
'ACP_WIKI_BBCODES' => 'BBCodes',
'LOG_WIKI_STARTER_CHECK_FAILED' => '<strong>Could not check the wiki starter templates repository for new templates</strong><br>» GitHub could not be reached, or did not answer as expected.',
'LOG_WIKI_STARTER_INSTALLED' => '<strong>Installed wiki starter templates</strong><br>» %s',
));
41 changes: 41 additions & 0 deletions migrations/add_wiki_only_bbcodes.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?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\migrations;

/**
* The custom BBCodes an admin has made wiki-only (see wiki\wiki_only_bbcodes), and the ACP page
* choosing them. None to start with, so every BBCode keeps working where it did.
*/
class add_wiki_only_bbcodes extends \phpbb\db\migration\migration
{
public static function depends_on()
{
return array(
'\phpbbmodders\wiki\migrations\add_category_members',
);
}

public function update_data()
{
return array(
array('config.add', array('wiki_only_bbcodes', '')),

array('module.add', array(
'acp',
'ACP_WIKI_TITLE',
array(
'module_basename' => '\phpbbmodders\wiki\acp\bbcodes_module',
'modes' => array('settings'),
),
)),
);
}
}
3 changes: 2 additions & 1 deletion tests/unit/files_test.php
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@ private function parse(string $text): string
$this->createMock(\phpbb\language\language::class),
$this->createMock(\phpbbmodders\wiki\wiki\links::class),
$this->createMock(files::class),
$this->createMock(\phpbbmodders\wiki\wiki\templates::class)
$this->createMock(\phpbbmodders\wiki\wiki\templates::class),
$this->createMock(\phpbbmodders\wiki\wiki\wiki_only_bbcodes::class)
);

$configurator = new \s9e\TextFormatter\Configurator;
Expand Down
6 changes: 4 additions & 2 deletions tests/unit/markup_test.php
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,8 @@ private function parse(string $text, bool $wiki_markup = true): string
$this->createMock(\phpbb\language\language::class),
$this->createMock(\phpbbmodders\wiki\wiki\links::class),
$this->createMock(\phpbbmodders\wiki\wiki\files::class),
$this->createMock(\phpbbmodders\wiki\wiki\templates::class)
$this->createMock(\phpbbmodders\wiki\wiki\templates::class),
$this->createMock(\phpbbmodders\wiki\wiki\wiki_only_bbcodes::class)
);

$configurator = new \s9e\TextFormatter\Configurator;
Expand Down Expand Up @@ -406,7 +407,8 @@ private function render(string $text): string
$this->createMock(\phpbb\language\language::class),
$this->createMock(\phpbbmodders\wiki\wiki\links::class),
$this->createMock(\phpbbmodders\wiki\wiki\files::class),
$this->createMock(\phpbbmodders\wiki\wiki\templates::class)
$this->createMock(\phpbbmodders\wiki\wiki\templates::class),
$this->createMock(\phpbbmodders\wiki\wiki\wiki_only_bbcodes::class)
);

$configurator = new \s9e\TextFormatter\Configurator;
Expand Down
Loading
Loading