mirror of
https://github.com/diocloid/LinkTitles.git
synced 2025-07-13 09:49:31 +02:00
Use PageContentSave rather than ArticleSave hook.
This commit also contains some refactoring which should lend itself to increased performance.
This commit is contained in:
@ -28,7 +28,6 @@
|
|||||||
|
|
||||||
/// Central class of the extension. Sets up parser hooks.
|
/// Central class of the extension. Sets up parser hooks.
|
||||||
/// This class contains only static functions; do not instantiate.
|
/// This class contains only static functions; do not instantiate.
|
||||||
/// @todo Use the current PageContentSave hook rather than the deprecated ArticleSave hook.
|
|
||||||
class LinkTitles {
|
class LinkTitles {
|
||||||
/// Setup function, hooks the extension's functions to MediaWiki events.
|
/// Setup function, hooks the extension's functions to MediaWiki events.
|
||||||
public static function setup() {
|
public static function setup() {
|
||||||
@ -36,7 +35,7 @@
|
|||||||
global $wgLinkTitlesParseOnRender;
|
global $wgLinkTitlesParseOnRender;
|
||||||
global $wgHooks;
|
global $wgHooks;
|
||||||
if ( $wgLinkTitlesParseOnEdit ) {
|
if ( $wgLinkTitlesParseOnEdit ) {
|
||||||
$wgHooks['ArticleSave'][] = 'LinkTitles::onArticleSave';
|
$wgHooks['PageContentSave'][] = 'LinkTitles::onPageContentSave';
|
||||||
};
|
};
|
||||||
if ( $wgLinkTitlesParseOnRender ) {
|
if ( $wgLinkTitlesParseOnRender ) {
|
||||||
$wgHooks['ArticleAfterFetchContent'][] = 'LinkTitles::onArticleAfterFetchContent';
|
$wgHooks['ArticleAfterFetchContent'][] = 'LinkTitles::onArticleAfterFetchContent';
|
||||||
@ -45,18 +44,18 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Event handler that is hooked to the ArticleSave event.
|
/// Event handler that is hooked to the ArticleSave event.
|
||||||
public static function onArticleSave( &$article, &$user, &$text, &$summary,
|
public static function onPageContentSave( &$wikiPage, &$user, &$content, &$summary,
|
||||||
$minor, $watchthis, $sectionanchor, &$flags, &$status ) {
|
$isMinor, $isWatch, $section, &$flags, &$status ) {
|
||||||
|
|
||||||
// To prevent time-consuming parsing of the page whenever
|
// To prevent time-consuming parsing of the page whenever
|
||||||
// it is edited and saved, we only parse it if the flag
|
// it is edited and saved, we only parse it if the flag
|
||||||
// 'minor edits' is not set.
|
// 'minor edits' is not set.
|
||||||
return $minor or self::parseContent( $article, $text );
|
return $isMinor or self::parseContent( $wikiPage, $content );
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Event handler that is hooked to the ArticleAfterFetchContent event.
|
/// Event handler that is hooked to the ArticleAfterFetchContent event.
|
||||||
/// @param $article Article object
|
/// @param $article Article object
|
||||||
/// @param $content String that holds the article content
|
/// @param $content Content object that holds the article content
|
||||||
public static function onArticleAfterFetchContent( &$article, &$content ) {
|
public static function onArticleAfterFetchContent( &$article, &$content ) {
|
||||||
// The ArticleAfterFetchContent event is triggered whenever page content
|
// The ArticleAfterFetchContent event is triggered whenever page content
|
||||||
// is retrieved from the database, i.e. also for editing etc.
|
// is retrieved from the database, i.e. also for editing etc.
|
||||||
@ -71,17 +70,16 @@
|
|||||||
|
|
||||||
/// Core function of the extension, performs the actual parsing of the content.
|
/// Core function of the extension, performs the actual parsing of the content.
|
||||||
/// @param $article Article object
|
/// @param $article Article object
|
||||||
/// @param $text String that holds the article content
|
/// @param $content Content object that holds the article content
|
||||||
/// @returns true
|
/// @returns true
|
||||||
static function parseContent( &$article, &$text ) {
|
static function parseContent( &$article, &$content ) {
|
||||||
|
|
||||||
// If the page contains the magic word '__NOAUTOLINKS__', do not parse
|
// If the page contains the magic word '__NOAUTOLINKS__', do not parse
|
||||||
// the content.
|
// the content.
|
||||||
$noAutoLinks = MagicWord::get('MAG_LINKTITLES_NOAUTOLINKS');
|
if ( $content->matchMagicWord(
|
||||||
if ( $noAutoLinks -> match( $text ) ) {
|
MagicWord::get('MAG_LINKTITLES_NOAUTOLINKS') ) ) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
$noAutoLinkTarget = MagicWord::get('MAG_LINKTITLES_NOTARGET');
|
|
||||||
|
|
||||||
// Configuration variables need to be defined here as globals.
|
// Configuration variables need to be defined here as globals.
|
||||||
global $wgLinkTitlesPreferShortTitles;
|
global $wgLinkTitlesPreferShortTitles;
|
||||||
@ -138,8 +136,11 @@
|
|||||||
'(?<=\b)\S+\@(?:\S+\.)+\S+(?=\b)' . // email addresses
|
'(?<=\b)\S+\@(?:\S+\.)+\S+(?=\b)' . // email addresses
|
||||||
')/i';
|
')/i';
|
||||||
|
|
||||||
|
// Build a blacklist of pages that are not supposed to be link
|
||||||
|
// targets. This includes the current page.
|
||||||
$black_list = str_replace( '_', ' ',
|
$black_list = str_replace( '_', ' ',
|
||||||
'("' . implode( '", "',$wgLinkTitlesBlackList ) . '")' );
|
'("' . implode( '", "',$wgLinkTitlesBlackList ) .
|
||||||
|
$myTitle->getDbKey() . '")' );
|
||||||
|
|
||||||
|
|
||||||
// Build an SQL query and fetch all page titles ordered by length from
|
// Build an SQL query and fetch all page titles ordered by length from
|
||||||
@ -175,6 +176,8 @@
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$text = $content->getContentHandler()->serializeContent($content);
|
||||||
|
|
||||||
// Iterate through the page titles
|
// Iterate through the page titles
|
||||||
foreach( $res as $row ) {
|
foreach( $res as $row ) {
|
||||||
// Obtain an instance of a Title class for the current database
|
// Obtain an instance of a Title class for the current database
|
||||||
@ -190,41 +193,33 @@
|
|||||||
// To prevent linking to pages that redirect to the current page,
|
// To prevent linking to pages that redirect to the current page,
|
||||||
// obtain the title that the target page redirects to. Will be null
|
// obtain the title that the target page redirects to. Will be null
|
||||||
// if there is no redirect.
|
// if there is no redirect.
|
||||||
$redirectTitle = $targetPage->getRedirectTarget();
|
$redirectTitle = $targetPage->getContent()->getUltimateRedirectTarget();
|
||||||
if ( $redirectTitle ) {
|
|
||||||
// If the target page redirects to the current page, exit the
|
|
||||||
// function.
|
|
||||||
if ( $redirectTitle->equals($myTitle) ) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( $noAutoLinkTarget->match($targetText) ) {
|
// Proceed only if the currently examined page does not redirect to
|
||||||
continue;
|
// our page and does not contain the no-target magic word
|
||||||
}
|
if (
|
||||||
|
!( $redirectTitle && $redirectTitle->equals($myTitle) ) &&
|
||||||
|
!( $targetPage->getContent()->matchMagicWord(
|
||||||
|
MagicWord::get('MAG_LINKTITLES_NOTARGET') ) ) ) {
|
||||||
|
|
||||||
// Only proceed if we're not operating on the very same page, if the
|
// split the page content by [[...]] groups
|
||||||
// target page does not have the __NOAUTOLINKTARGET__ magic word in
|
|
||||||
// it, and if the target page does not redirect to the current page.
|
|
||||||
if ( ! $myTitle->equals($targetTitle) ) {
|
|
||||||
// split the string by [[...]] groups
|
|
||||||
// credits to inhan @ StackOverflow for suggesting preg_split
|
// credits to inhan @ StackOverflow for suggesting preg_split
|
||||||
// see http://stackoverflow.com/questions/10672286
|
// see http://stackoverflow.com/questions/10672286
|
||||||
$arr = preg_split( $delimiter, $text, -1, PREG_SPLIT_DELIM_CAPTURE );
|
$arr = preg_split( $delimiter, $text, -1, PREG_SPLIT_DELIM_CAPTURE );
|
||||||
|
|
||||||
// Escape certain special characters in the page title to prevent
|
// Escape certain special characters in the page title to prevent
|
||||||
// regexp compilation errors
|
// regexp compilation errors
|
||||||
$escapedTitle = preg_quote($targetTitleText, '/');
|
$quotedTitle = preg_quote($targetTitleText, '/');
|
||||||
|
|
||||||
// Depending on the global configuration setting $wgCapitalLinks,
|
// Depending on the global configuration setting $wgCapitalLinks,
|
||||||
// the title has to be searched for either in a strictly case-sensitive
|
// the title has to be searched for either in a strictly case-sensitive
|
||||||
// way, or in a 'fuzzy' way where the first letter of the title may
|
// way, or in a 'fuzzy' way where the first letter of the title may
|
||||||
// be either case.
|
// be either case.
|
||||||
if ( $wgCapitalLinks && ( $escapedTitle[0] != '\\' )) {
|
if ( $wgCapitalLinks && ( $quotedTitle[0] != '\\' )) {
|
||||||
$searchTerm = '((?i)' . $escapedTitle[0] . '(?-i)' .
|
$searchTerm = '((?i)' . $quotedTitle[0] . '(?-i)' .
|
||||||
substr($escapedTitle, 1) . ')';
|
substr($quotedTitle, 1) . ')';
|
||||||
} else {
|
} else {
|
||||||
$searchTerm = '(' . $escapedTitle . ')';
|
$searchTerm = '(' . $quotedTitle . ')';
|
||||||
}
|
}
|
||||||
|
|
||||||
for ( $i = 0; $i < count( $arr ); $i+=2 ) {
|
for ( $i = 0; $i < count( $arr ); $i+=2 ) {
|
||||||
@ -286,15 +281,17 @@
|
|||||||
for ( $i = 0; $i < count( $arr ); $i+=2 ) {
|
for ( $i = 0; $i < count( $arr ); $i+=2 ) {
|
||||||
// even indexes will point to text that is not enclosed by brackets
|
// even indexes will point to text that is not enclosed by brackets
|
||||||
$arr[$i] = preg_replace_callback( '/(?<![\:\.\@\/\?\&])' .
|
$arr[$i] = preg_replace_callback( '/(?<![\:\.\@\/\?\&])' .
|
||||||
$wordStartDelim . '(' . $escapedTitle . ')' .
|
$wordStartDelim . '(' . $quotedTitle . ')' .
|
||||||
$wordEndDelim . '/i', $callback, $arr[$i], $limit, $count );
|
$wordEndDelim . '/i', $callback, $arr[$i], $limit, $count );
|
||||||
if (( $limit >= 0 ) && ( $count > 0 )) {
|
if (( $limit >= 0 ) && ( $count > 0 )) {
|
||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
$text = implode( '', $arr );
|
$text = implode( '', $arr );
|
||||||
|
// @todo check if text was changed
|
||||||
|
$content = $content->getContentHandler()->unserializeContent( $text );
|
||||||
|
} // $wgLinkTitlesSmartMode
|
||||||
}
|
}
|
||||||
}; // if ! $myTitle.equals($targetTitle)
|
|
||||||
}; // foreach $res as $row
|
}; // foreach $res as $row
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -311,10 +308,9 @@
|
|||||||
// TODO: make this namespace-aware
|
// TODO: make this namespace-aware
|
||||||
$titleObj = Title::makeTitle(0, $title);
|
$titleObj = Title::makeTitle(0, $title);
|
||||||
$page = WikiPage::factory($titleObj);
|
$page = WikiPage::factory($titleObj);
|
||||||
|
$content = $page->getContent();
|
||||||
$article = Article::newFromWikiPage($page, $context);
|
$article = Article::newFromWikiPage($page, $context);
|
||||||
$text = $article->getContent();
|
LinkTitles::parseContent($article, $content);
|
||||||
LinkTitles::parseContent($article, $text);
|
|
||||||
$content = new WikitextContent($text);
|
|
||||||
$page->doEditContent($content,
|
$page->doEditContent($content,
|
||||||
"Links to existing pages added by LinkTitles bot.",
|
"Links to existing pages added by LinkTitles bot.",
|
||||||
EDIT_MINOR | EDIT_FORCE_BOT,
|
EDIT_MINOR | EDIT_FORCE_BOT,
|
||||||
|
@ -155,7 +155,7 @@
|
|||||||
'name' => 'LinkTitles',
|
'name' => 'LinkTitles',
|
||||||
'author' => '[https://www.mediawiki.org/wiki/User:Bovender Daniel Kraus]',
|
'author' => '[https://www.mediawiki.org/wiki/User:Bovender Daniel Kraus]',
|
||||||
'url' => 'https://www.mediawiki.org/wiki/Extension:LinkTitles',
|
'url' => 'https://www.mediawiki.org/wiki/Extension:LinkTitles',
|
||||||
'version' => '2.4.0',
|
'version' => '2.4.2',
|
||||||
'descriptionmsg' => 'linktitles-desc'
|
'descriptionmsg' => 'linktitles-desc'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -5,6 +5,8 @@ MediaWiki extension that automatically adds links to words that match titles of
|
|||||||
|
|
||||||
For more information, see http://www.mediawiki.org/wiki/Extension:LinkTitles
|
For more information, see http://www.mediawiki.org/wiki/Extension:LinkTitles
|
||||||
|
|
||||||
|
Minimum requirements: MediaWiki 1.21+, PHP 5.3
|
||||||
|
|
||||||
Source code documentation can be found at the [Github project
|
Source code documentation can be found at the [Github project
|
||||||
pages](http://bovender.github.io/LinkTitles).
|
pages](http://bovender.github.io/LinkTitles).
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user