r92215 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r92214‎ | r92215 | r92216 >
Date:23:16, 14 July 2011
Author:reedy
Status:deferred
Tags:
Comment:
Import http://www.mediawiki.org/wiki/Extension:Advanced_Meta

Style changes, fixed database so it can be prefixed (when pushed through our updater)

Please feel free to improve on the code before I do
Modified paths:
  • /trunk/extensions/AdvancedMeta (added) (history)
  • /trunk/extensions/AdvancedMeta/AdvancedMeta.i18n.php (added) (history)
  • /trunk/extensions/AdvancedMeta/AdvancedMeta.php (added) (history)
  • /trunk/extensions/AdvancedMeta/AdvancedMeta.sql (added) (history)

Diff [purge]

Index: trunk/extensions/AdvancedMeta/AdvancedMeta.i18n.php
@@ -0,0 +1,54 @@
 2+<?php
 3+/*
 4+ * Public Domain
 5+ */
 6+
 7+$messages = array();
 8+
 9+$messages['en'] = array(
 10+ 'ameta-desc' => 'Allows per page meta settings (robots, keywords, description) and change title',
 11+ 'ameta-metasettings' => 'Meta settings',
 12+ 'ameta-titlealias' => 'Title Alias:',
 13+ 'ameta-keywordsadd' => 'the following keywords are added to all pages: ',
 14+ 'ameta-keywordsmodify' => 'can be modified at Mediawiki:Globalkeywords',
 15+);
 16+
 17+$messages['fr'] = array(
 18+ 'ameta-desc' => 'Permet le paramétrage des balises meta de chaque page (robots, mots clés, description) et le changement de titre',
 19+ 'ameta-metasettings' => 'Paramètres des balises meta',
 20+ 'ameta-titlealias' => 'Alias de titre:',
 21+ 'ameta-keywordsadd' => 'Les mots clés suivant sont ajouté à toutes les pages: ',
 22+ 'ameta-keywordsmodify' => 'peuvent être modifiées sur la page Mediawiki:Globalkeywords',
 23+);
 24+
 25+$messages['de'] = array(
 26+ 'ameta-desc' => 'Ermöglicht das Festlegen der Meta-Elemente „robots“, „keywords“ und „description“ sowie das Anpassen des Seitentitels',
 27+ 'ameta-metasettings' => 'Meta-Einstellungen',
 28+ 'ameta-titlealias' => 'Title:',
 29+ 'ameta-keywordsadd' => 'Die folgenden „keywords“ werden allen Seiten hinzugefügt: ',
 30+ 'ameta-keywordsmodify' => 'Sie können auf der Seite Mediawiki:Globalkeywords angepasst werden.',
 31+);
 32+
 33+$messages['zh-hans'] = array(
 34+ 'ameta-desc' => '允许为每个页面设置机器人政策、关键词和描述,以及修改标题',
 35+ 'ameta-metasettings' => 'Meta设置',
 36+ 'ameta-titlealias' => '修改标题:',
 37+ 'ameta-keywordsadd' => '以下内容自动作为关键词添加: ',
 38+ 'ameta-keywordsmodify' => '可在 Mediawiki:Globalkeywords 修改全局关键词',
 39+);
 40+
 41+$messages['zh-hant'] = array(
 42+ 'ameta-desc' => '允許為每個頁面設置機器人政策、關鍵字和描述,以及修改標題',
 43+ 'ameta-metasettings' => 'Meta設置',
 44+ 'ameta-titlealias' => '修改標題:',
 45+ 'ameta-keywordsadd' => '以下內容自動作為關鍵字添加: ',
 46+ 'ameta-keywordsmodify' => '可在 Mediawiki:Globalkeywords 修改全域關鍵字',
 47+);
 48+
 49+$messages['nl'] = array(
 50+ 'ameta-desc' => 'Maakt het mogelijk de meta-instellingen (robots, keywords, description) en de titel per pagina te veranderen',
 51+ 'ameta-metasettings' => 'Meta-instellingen',
 52+ 'ameta-titlealias' => 'Titel-alias:',
 53+ 'ameta-keywordsadd' => 'de volgende trefwoorden worden aan elke pagina toegevoegd: ',
 54+ 'ameta-keywordsmodify' => 'kan worden gewijzigd op Mediawiki:Globalkeywords',
 55+);
\ No newline at end of file
Property changes on: trunk/extensions/AdvancedMeta/AdvancedMeta.i18n.php
___________________________________________________________________
Added: svn:eol-style
156 + native
Index: trunk/extensions/AdvancedMeta/AdvancedMeta.php
@@ -0,0 +1,413 @@
 2+<?php
 3+
 4+/**
 5+ * MediaWiki Advanced Meta extension
 6+ * Add meta data to individual pages or entire namespaces
 7+ * @version 2.0.1
 8+ * @author Stephan Muller <mail@litso.com> (Main author)
 9+ * @author Bart van Heukelom <b@rtvh.nl> (Objectification)
 10+ * @author Zayoo <zayoo@126.com> (Revise & TitleAlias, refer to Extension:Add HTML Meta and Title & Extension:TitleAlias)
 11+ */
 12+
 13+$wgExtensionCredits['parserhook'][] = array(
 14+ 'name' => 'Advanced Meta',
 15+ 'author' => array( '[http://www.stephanmuller.nl Stephan Muller]', 'Bart van Heukelom, Zayoo' ),
 16+ 'descriptionmsg' => 'ameta-desc',
 17+ 'url' => 'http://www.mediawiki.org/wiki/Extension:Advanced_Meta',
 18+ 'version' => '2.0.1'
 19+);
 20+
 21+$wgExtensionMessagesFiles['MWAdvancedMeta'] = dirname( __FILE__ ) . '/MWAdvancedMeta.i18n.php';
 22+MWAdvancedMeta::setup();
 23+
 24+class MWAdvancedMeta {
 25+
 26+ private static $instance = null;
 27+
 28+ /**
 29+ * Initialise the advanced meta plugin.
 30+ * @return MWAdvancedMeta the plugin object, which you can use to set settings.
 31+ */
 32+ public static function setup() {
 33+
 34+ // check for wiki
 35+ if ( !defined( 'MEDIAWIKI' ) ) {
 36+ throw new Exception( 'This is an extension to the MediaWiki software and cannot be used standalone.' );
 37+ }
 38+
 39+ // create plugin
 40+ if ( self::$instance === null ) {
 41+ self::$instance = new self();
 42+ }
 43+ return self::$instance;
 44+
 45+ }
 46+
 47+ private $indexedPages = array( NS_MAIN, NS_PROJECT );
 48+ private $allowedUsers = array();
 49+ private $allowedUsergroups = array( 'sysop', 'bureaucrat' );
 50+ private $savedMeta = null;
 51+
 52+ public function __construct() {
 53+
 54+ /*********
 55+ * Hooks *
 56+ *********/
 57+
 58+ global $wgHooks;
 59+
 60+ // Inserts HTML for meta input fields into the edit page.
 61+ $wgHooks['ParserBeforeTidy'][] = $this;
 62+
 63+ // Before the updated text and properties of an article are saved to the database
 64+ // the new meta info is saved too
 65+ $wgHooks['ArticleSave'][] = $this;
 66+
 67+ // If a new article is created the meta is temporarily saved as article ID '0'
 68+ // Move it to the newly created article now
 69+ $wgHooks['ArticleInsertComplete'][] = $this;
 70+
 71+ // Insert meta into article
 72+ $wgHooks['OutputPageBeforeHTML'][] = $this;
 73+
 74+ // Title Alias
 75+ $wgHooks['BeforePageDisplay'][] = $this;
 76+ }
 77+
 78+ /**
 79+ * All namespaces get a robots setting of "noindex, nofollow" by default.
 80+ * Use this method to specify namespaces with interesting content, pages in which should be indexed.
 81+ * Default is NS_MAIN and NS_PROJECT.
 82+ * @param $indexedPages Array of namespace names.
 83+ */
 84+ public function setIndexedPages( array $indexedPages ) {
 85+ $this->indexedPages = $indexedPages;
 86+ }
 87+
 88+ /**
 89+ * Specify keywords that should be added to every page.
 90+ * @param $keywords The keywords in an array.
 91+ */
 92+ public function setGlobalKeywords( $keywords ) {
 93+ $this->globalKeywords = $keywords;
 94+ }
 95+
 96+ /**
 97+ * SEO can be a delicate issue. Define here who is allowed to edit the meta tags
 98+ * allow users individually, by username. Warning: Case sensitive!
 99+ */
 100+ public function setAllowedUsers( $users ) {
 101+ $this->allowedUsers = $users;
 102+ }
 103+
 104+ /**
 105+ * allow users by mediawiki's own usergroups
 106+ * or the special groups 'loggedin' and 'all' ('all' allowing even anonymous edits)
 107+ */
 108+ public function setAllowedUsergroups( $usergroups ) {
 109+ $this->allowedUsergroups = $usergroups;
 110+ }
 111+
 112+ /**
 113+ * Hook 1: in /includes/parser/Parser.php
 114+ * Loops through the different sections of the page being parsed
 115+ * and adds html for the meta input forms into the article edit pages
 116+ *
 117+ * @param object $parser The parser object
 118+ * @param string $text
 119+ *
 120+ * @global indexedpages defined in the global config section above
 121+ * @global alloweusers defined in the global config section above
 122+ *
 123+ * @return true
 124+ *
 125+ */
 126+ public function onParserBeforeTidy( &$parser, &$text ) {
 127+
 128+ global $wgTitle, $wgUser, $wgRequest;
 129+
 130+ // only run this hook for edit forms
 131+ if ( !$wgRequest->getVal( 'action' ) == ( 'edit' || 'submit' ) ) return false;
 132+
 133+ // can this user edit meta for this page?
 134+ if ( !$this->canEditMeta() ) return false;
 135+
 136+ // handle submit (preview)
 137+ if ( $wgRequest->wasPosted() ) {
 138+ // it's probably a preview, so show the newly submitted meta too, otherwise we'll lose 'em
 139+ $meta = array(
 140+ 'rindex' => ( isset( $_POST['wpIndex'] ) ) ? '1' : '0',
 141+ 'rfollow' => ( isset( $_POST['wpFollow'] ) ) ? '1' : '0',
 142+ 'titlealias' => $_POST['wpTitleAlias'],
 143+ 'keywords' => $_POST['wpKeywords'],
 144+ 'description' => $_POST['wpDescription']
 145+ );
 146+ } else {
 147+ // else just get the meta from the db
 148+ $meta = $this->getMetaByArticleID( $wgTitle->getArticleID() );
 149+
 150+ // no meta or creating a new article? make default values
 151+ if ( empty( $meta ) || $wgTitle->getArticleID() == '0' ) {
 152+ $meta = array(
 153+ 'rindex' => '1',
 154+ 'rfollow' => '1',
 155+ 'titlealias' => '',
 156+ 'keywords' => '',
 157+ 'description' => ''
 158+ );
 159+ }
 160+ }
 161+
 162+ // prepare checkboxes
 163+ $checkindex = ( $meta['rindex'] == '1' ) ? 'checked="checked"' : '' ;
 164+ $checkfollow = ( $meta['rfollow'] == '1' ) ? 'checked="checked"' : '' ;
 165+
 166+ // some mediawiki preference variables
 167+ $cols = $wgUser->getIntOption( 'cols' );
 168+ $ew = $wgUser->getOption( 'editwidth' );
 169+
 170+ $addedkeywords = wfMsg( 'globalkeywords' ) == '&lt;globalkeywords&gt;' ? '(none)' : wfMsg( 'globalkeywords' );
 171+
 172+ // define replacements
 173+ $replaceFrom[] = '<div id="editpage-copywarn">';
 174+ $replaceWith[] =
 175+ "<h2>" . wfMsg( 'ameta-metasettings' ) . "</h2>
 176+ <strong>Robots:</strong>
 177+ <label><input tabindex='2' id='wpIndex' type='checkbox' name='wpIndex' value='1' {$checkindex} accesskey='/'>
 178+ Index</label>
 179+ <label><input tabindex='3' id='wpFollow' type='checkbox' name='wpFollow' value='1' {$checkfollow} >
 180+ Follow</label>
 181+
 182+ <br /><strong>" . wfMsg( 'ameta-titlealias' ) . "</strong><br />
 183+ <input type='text' name='wpTitleAlias' id='wpTitleAlias' value='{$meta['titlealias']}' size='64'>
 184+
 185+ <br /><strong>Keywords:</strong> <small>" . wfMsg( 'ameta-keywordsadd' ) . "<a href='javascript:;' title='" . wfMsg( 'ameta-keywordsmodify' ) . "'>" . htmlspecialchars( str_replace( "$1", $wgTitle, $addedkeywords ) ) . "</a>
 186+ </small><br />
 187+ <textarea tabindex='4' name='wpKeywords' id='wpKeywords' rows='1'
 188+ cols='{$cols}'{$ew}>{$meta['keywords']}</textarea>
 189+
 190+ <br /><strong>Description:</strong><br />
 191+ <textarea tabindex='4' name='wpDescription' id='wpDescription' rows='2'
 192+ cols='{$cols}'{$ew}>{$meta['description']}</textarea>
 193+
 194+ <div id=\"editpage-copywarn\">";
 195+
 196+ // apply replacements
 197+ $text = str_replace( $replaceFrom, $replaceWith, $text );
 198+
 199+ return true;
 200+ }
 201+
 202+ /**
 203+ * Hook 2: Called during function doEdit() in /includes/Article.php
 204+ * Adds the new meta information to the database when an article is saved
 205+ *
 206+ * @param object $article The entire article and it's properties
 207+ * @param object $user The user updating the article
 208+ * @return true
 209+ *
 210+ * @global indexedpages, array of namespaces that should be indexed
 211+ *
 212+ */
 213+ public function onArticleSave( &$article, &$user ) {
 214+ $id = $article->mTitle->getArticleID();
 215+
 216+ // can this user edit meta for this page?
 217+ if ( !$this->canEditMeta() ) {
 218+ return true; // return false gives edit conflicts
 219+ }
 220+
 221+ // get meta from the posted forms
 222+ $metaData = array(
 223+ 'rindex' => isset( $_POST['wpIndex'] ) ? '1' : '0',
 224+ 'rfollow' => isset( $_POST['wpFollow'] ) ? '1' : '0',
 225+ 'titlealias' => htmlspecialchars( $_POST['wpTitleAlias'] ),
 226+ 'keywords' => htmlspecialchars( $_POST['wpKeywords'] ),
 227+ 'description' => htmlspecialchars( $_POST['wpDescription'] )
 228+ );
 229+
 230+ if ( $id == 0 ) {
 231+ // if this is an insert, we need to store the meta until we know the page id
 232+ $this->savedMeta = $metaData;
 233+ } else {
 234+ // write new metadata to the database
 235+ $this->writeMeta( $id, $metaData );
 236+ }
 237+
 238+ // empty cache for the page
 239+ $dbw = wfGetDB( DB_MASTER );
 240+ $timestamp = $dbw->timestamp();
 241+ $dbw->update( 'page',
 242+ array( 'page_touched' => $timestamp ),
 243+ array(
 244+ 'page_id' => $id ),
 245+ __METHOD__ );
 246+
 247+ return true;
 248+ }
 249+
 250+ /**
 251+ * Hook 3: Called during function doEdit() in /includes/Article.php
 252+ * Move the new meta information from a temporary id='0' to the new article's id
 253+ *
 254+ * @param object $article: the article (object) saved
 255+ * @param object $user: the user (object) who saved the article
 256+ * @param string $text: the new article content
 257+ * @param string $summary: the article summary (comment)
 258+ * @param bool $minoredit: minor edit flag
 259+ * @param bool $watchthis: not used as of 1.8 (automatically set to "null")
 260+ * @param bool $sectionanchor: not used as of 1.8 (automatically set to "null")
 261+ * @param unknown $flags: bitfield, see source code for details; passed to Article::doedit()
 262+ * @param object $revision: The newly inserted revision object (as of 1.11.0)
 263+
 264+ * @return true
 265+ *
 266+ * @global indexedpages, array of namespaces that should be indexed
 267+ *
 268+ */
 269+ function onArticleInsertComplete( &$article, &$user, $text, $summary, $minoredit,
 270+ $watchthis, $sectionanchor, &$flags, $revision ) {
 271+
 272+ // if we have saved metadata, insert it
 273+ if ( $this->savedMeta !== null ) {
 274+ // write new metadata to the database
 275+ $this->writeMeta( $article->getID(), $this->savedMeta );
 276+ $this->savedMeta = null;
 277+ }
 278+
 279+ return true;
 280+
 281+ }
 282+
 283+ /**
 284+ * Hook 4: Called during function view() in /includes/OutputPage.php
 285+ * Adds the proper meta tags to the article when a page is viewed
 286+ *
 287+ * @param object $out The outputted page
 288+ * @param string $text The file description
 289+ * @return true
 290+ */
 291+ function onOutputPageBeforeHTML( &$out, &$text ) {
 292+ global $wgTitle, $wgArticleRobotPolicies, $wgDefaultRobotPolicy;
 293+
 294+ $articleid = $wgTitle->getPrefixedText();
 295+ $addedkeywords = wfMsg( 'globalkeywords' ) == '&lt;globalkeywords&gt;' ? '' : wfMsg( 'globalkeywords' , $wgTitle );
 296+ $meta = $this->getMetaByArticleID( $wgTitle->getArticleID() );
 297+
 298+ /* robots policies */
 299+
 300+ // fallback policy
 301+ $policy = $wgDefaultRobotPolicy;
 302+
 303+ // fallback policy for pages that are not in the indexed namespaces and have no db info
 304+ if ( !in_array( $wgTitle->getnamespace(), $this->indexedPages ) ) {
 305+ $policy = 'noindex,follow';
 306+ }
 307+
 308+ // policies in the database overwrite any fallbacks
 309+ if ( !empty( $meta ) ) {
 310+ $index = ( $meta['rindex'] == '1' ) ? 'index' : 'noindex';
 311+ $follow = ( $meta['rfollow'] == '1' ) ? 'follow' : 'nofollow';
 312+ $policy = "$index,$follow";
 313+ }
 314+
 315+ /* keywords */
 316+
 317+ // fallback keywords
 318+ $keywords = array_merge( explode( ',', $addedkeywords ), $out->mKeywords ); // Global keywords should be shown even no meta data
 319+
 320+ // only overwrite keywords if any were provided (else the ones generated by mediawiki are used)
 321+ if ( !empty( $meta['keywords'] ) )
 322+ $keywords = array_merge( explode( ',', $addedkeywords ), explode( ',', $meta['keywords'] ) );
 323+
 324+
 325+ /* output all new meta values */
 326+ $out->mKeywords = $keywords;
 327+ $out->setRobotPolicy( $policy );
 328+
 329+ $wgArticleRobotPolicies[$articleid] = $policy;
 330+
 331+
 332+ if ( !empty( $meta['description'] ) )
 333+ $out->addMeta( "description", $meta['description'] );
 334+
 335+ return true;
 336+ }
 337+
 338+ /**
 339+ * Hook 5: Called during function output() in /includes/OutputPage.php
 340+ * Allows last minute changes to the output page, e.g. adding of CSS or Javascript by extensions
 341+ *
 342+ * @param object $out The OutputPage object
 343+ * @param string $sk Skin object that will be used to generate the page
 344+ * @return true
 345+ */
 346+ function onBeforePageDisplay( &$out, &$text ) {
 347+
 348+ global $wgTitle;
 349+
 350+ $meta = $this->getMetaByArticleID( $wgTitle->getArticleID() );
 351+
 352+ if ( empty( $meta ) ) {
 353+ return true;
 354+ }
 355+
 356+ if ( !empty( $meta['titlealias'] ) ) {
 357+ $out->mHTMLtitle = wfMsg( 'pagetitle', $meta['titlealias'] );
 358+ }
 359+ return true;
 360+ }
 361+
 362+ private function getMetaByArticleID( $id ) {
 363+
 364+ // get metadata from database
 365+ $dbr = wfGetDB( DB_MASTER );
 366+ $data = $dbr->select( 'ext_meta',
 367+ array( 'rindex', 'rfollow', 'titlealias', 'keywords', 'description' ),
 368+ array( 'pageid' => $id ),
 369+ __METHOD__
 370+ );
 371+ $meta = $dbr->fetchRow( $data );
 372+ $dbr->freeResult( $data );
 373+
 374+ return $meta;
 375+ }
 376+
 377+ private function writeMeta( $id, $metaData ) {
 378+ $fname = 'MWAdvancedMeta::writeMeta';
 379+ $dbw = wfGetDB( DB_MASTER );
 380+ if ( $metaData['rindex'] == '1' && $metaData['rfollow'] == '1'
 381+ && empty( $metaData['titlealias'] ) && empty( $metaData['keywords'] )
 382+ && empty( $metaData['description'] ) ) {
 383+
 384+ $dbw->delete( 'ext_meta', array( 'pageid' => $id ), __METHOD__ ); // delete meta with normal robot policies and without titlealias, keywords & description to save space
 385+ } else {
 386+ $dbw->replace(
 387+ 'ext_meta',
 388+ array( 'pageid' => $id ),
 389+ array_merge( $metaData, array( 'pageid' => $id ) ),
 390+ $fname
 391+ );
 392+ }
 393+ }
 394+
 395+ private function canEditMeta() {
 396+
 397+ global $wgUser, $wgTitle;
 398+
 399+ //$ns = $wgTitle->getNamespace();
 400+
 401+ // redirect pages don't need metadata
 402+ // TODO: make work in MediaWiki < 1.13
 403+ // if ($wgTitle->isRedirect()) {
 404+ // return false;
 405+ // }
 406+
 407+ // does the user have permission?
 408+ return ( in_array( $wgUser->getName(), $this->allowedUsers )
 409+ || in_array( 'all', $this->allowedUsergroups )
 410+ || ( in_array( 'loggedin', $this->allowedUsergroups ) && $wgUser->isLoggedIn() )
 411+ || count(array_intersect($wgUser->getGroups(), $this->allowedUsergroups)) !== 0
 412+ );
 413+ }
 414+}
\ No newline at end of file
Property changes on: trunk/extensions/AdvancedMeta/AdvancedMeta.php
___________________________________________________________________
Added: svn:eol-style
1415 + native
Index: trunk/extensions/AdvancedMeta/AdvancedMeta.sql
@@ -0,0 +1,9 @@
 2+CREATE TABLE /*_*/dbprefix_ext_meta (
 3+ `pageid` INT(8) NOT NULL,
 4+ `rindex` tinyint(1) NOT NULL,
 5+ `rfollow` tinyint(1) NOT NULL,
 6+ `titlealias` VARCHAR(255),
 7+ `keywords` text,
 8+ `description` text,
 9+ PRIMARY KEY (`pageid`)
 10+) /*$wgDBTableOptions*/;
\ No newline at end of file
Property changes on: trunk/extensions/AdvancedMeta/AdvancedMeta.sql
___________________________________________________________________
Added: svn:eol-style
111 + native
Property changes on: trunk/extensions/AdvancedMeta
___________________________________________________________________
Added: bugtraq:number
212 + true

Follow-up revisions

RevisionCommit summaryAuthorDate
r92263Followup r92215: Tweak extension credits, sort messgaes by language code...raymond18:13, 15 July 2011

Status & tagging log