diff --git a/mod/wiki/parser/markups/html.php b/mod/wiki/parser/markups/html.php
index fc1545d931e..ad12c34b454 100644
--- a/mod/wiki/parser/markups/html.php
+++ b/mod/wiki/parser/markups/html.php
@@ -46,6 +46,15 @@ class html_parser extends nwiki_parser {
parent::before_parsing();
$this->minheaderlevel = $this->find_min_header_level($this->string);
+
+ // Protect all explicit links from further wiki parsing. The link text may contain another URL which would get
+ // converted into another link via {@see nwiki_parser::$tagrules} 'url' element.
+ if (preg_match_all('/]+?>(.*?)<\/a>/is', $this->string, $matches)) {
+ foreach (array_unique($matches[0]) as $match) {
+ $this->string = str_replace($match, $this->protect($match), $this->string);
+ }
+ }
+
$this->rules($this->string);
}
diff --git a/mod/wiki/tests/wikiparser_test.php b/mod/wiki/tests/wikiparser_test.php
index 909c2c17e39..003eff0f52f 100644
--- a/mod/wiki/tests/wikiparser_test.php
+++ b/mod/wiki/tests/wikiparser_test.php
@@ -39,6 +39,92 @@ require_once($CFG->dirroot . '/mod/wiki/parser/parser.php');
class mod_wiki_wikiparser_test extends basic_testcase {
+ /**
+ * URL inside the clickable text of some link should not be turned into a new link via the url_tag_rule.
+ *
+ * @dataProvider urls_inside_link_text_provider
+ * @param string $markup Markup of the Wiki page the text is part of.
+ * @param string $input The input text.
+ * @param string $output The expected output HTML as a result of the parsed input text.
+ */
+ public function test_urls_inside_link_text(string $markup, string $input, string $output) {
+
+ $parsingresult = wiki_parser_proxy::parse($input, $markup, [
+ 'link_callback' => '/mod/wiki/locallib.php:wiki_parser_link',
+ 'link_callback_args' => ['swid' => 1],
+ ]);
+
+ $this->assertContains($output, $parsingresult['parsed_text']);
+ }
+
+ /**
+ * Provides data sets for {@see self::test_urls_inside_link_text()}.
+ *
+ * @return array
+ */
+ public function urls_inside_link_text_provider() {
+ return [
+ 'creole implicit link' => [
+ 'markup' => 'creole',
+ 'input' => 'Visit https://site.url for more information.',
+ 'output' => 'Visit https://site.url for more information.',
+ ],
+ 'creole explicit link' => [
+ 'markup' => 'creole',
+ 'input' => 'Visit [[https://site.url]] for more information.',
+ 'output' => 'Visit https://site.url for more information.',
+ ],
+ 'creole explicit link with text' => [
+ 'markup' => 'creole',
+ 'input' => 'Visit [[https://site.url|http://www.site.url]] for more information.',
+ 'output' => 'Visit http://www.site.url for more information.',
+ ],
+ 'nwiki implicit link' => [
+ 'markup' => 'nwiki',
+ 'input' => 'Visit https://site.url for more information.',
+ 'output' => 'Visit https://site.url for more information.',
+ ],
+ 'nwiki explicit link' => [
+ 'markup' => 'nwiki',
+ 'input' => 'Visit [https://site.url] for more information.',
+ 'output' => 'Visit https://site.url for more information.',
+ ],
+ 'nwiki explicit link with space separated text' => [
+ 'markup' => 'nwiki',
+ 'input' => 'Visit [https://site.url http://www.site.url] for more information.',
+ 'output' => 'Visit http://www.site.url for more information.',
+ ],
+ 'nwiki explicit link with pipe separated text' => [
+ 'markup' => 'nwiki',
+ 'input' => 'Visit [https://site.url|http://www.site.url] for more information.',
+ 'output' => 'Visit http://www.site.url for more information.',
+ ],
+ 'html implicit link' => [
+ 'markup' => 'html',
+ 'input' => 'Visit https://site.url for more information.',
+ 'output' => 'Visit https://site.url for more information.',
+ ],
+ 'html explicit link with text' => [
+ 'markup' => 'html',
+ 'input' => 'Visit http://www.site.url for more information.',
+ 'output' => 'Visit http://www.site.url for more information.',
+ ],
+ 'html wiki link to non-existing page' => [
+ 'markup' => 'html',
+ 'input' => 'Visit [[Another page]] for more information.',
+ 'output' => 'Visit ' .
+ 'Another page for more information.',
+ ],
+ 'html wiki link inside an explicit link' => [
+ // The explicit href URL takes precedence here, the [[...]] is not turned into a wiki link.
+ 'markup' => 'html',
+ 'input' => 'Visit [[Another page]] for more information.',
+ 'output' => 'Visit [[Another page]] for more information.',
+ ],
+ ];
+ }
+
function testCreoleMarkup() {
$this->assertTestFiles('creole');
}