Advertisement
Guest User

Untitled

a guest
Dec 11th, 2016
72
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 37.33 KB | None | 0 0
  1. <?php
  2. /**
  3. * Class for handling the viewing of pages in the NS_BLOG namespace.
  4. *
  5. * @file
  6. */
  7. class BlogPage extends Article {
  8.  
  9. public $title = null;
  10. public $authors = array();
  11.  
  12. public function __construct( Title $title ) {
  13. parent::__construct( $title );
  14. $this->setContent();
  15. $this->getAuthors();
  16. }
  17.  
  18. public function setContent() {
  19. // Get the page content for later use
  20. $this->pageContent = $this->getContent();
  21.  
  22. // If it's a redirect, in order to get the *real* content for later use,
  23. // we have to load the text for the real page
  24. // Note: If $this->getContent() is called anywhere before parent::view,
  25. // the real article text won't get loaded on the page
  26. if ( $this->isRedirect( $this->pageContent ) ) {
  27. wfDebugLog( 'BlogPage', __METHOD__ );
  28.  
  29. $target = $this->followRedirect();
  30. if ( !$target instanceof Title ) {
  31. // Correctly handle interwiki redirects and the like
  32. // WikiPage::followRedirect() can return either a Title, boolean
  33. // or a string! A string is returned for interwiki redirects,
  34. // and the string in question is the target URL with the rdfrom
  35. // URL parameter appended to it, which -- since it's an interwiki
  36. // URL -- won't resolve to a valid local Title.
  37. // Doing the redirection here is somewhat hacky, but ::getAuthors(),
  38. // which is called right after this function in the constructor,
  39. // attempts to read $this->pageContent...
  40. // @see https://github.com/Brickimedia/brickimedia/issues/370
  41. $this->getContext()->getOutput()->redirect( $target );
  42. } else {
  43. $rarticle = new Article( $target );
  44. $this->pageContent = $rarticle->getContent();
  45.  
  46. // If we don't clear, the page content will be [[redirect-blah]],
  47. // and not the actual page
  48. $this->clear();
  49. }
  50. }
  51. }
  52.  
  53. public function view() {
  54. global $wgBlogPageDisplay;
  55.  
  56. $context = $this->getContext();
  57. $user = $context->getUser();
  58. $output = $context->getOutput();
  59.  
  60. $sk = $context->getSkin();
  61.  
  62. wfDebugLog( 'BlogPage', __METHOD__ );
  63.  
  64. $output->setHTMLTitle( $this->getTitle()->getText() );
  65. $output->setPageTitle( $this->getTitle()->getText() );
  66.  
  67. // Don't throw a bunch of E_NOTICEs when we're viewing the page of a
  68. // nonexistent blog post
  69. if ( !$this->getID() ) {
  70. parent::view();
  71. return '';
  72. }
  73.  
  74. $output->addHTML( "\t\t" . '<div id="blog-page-container">' . "\n" );
  75.  
  76. if ( $wgBlogPageDisplay['leftcolumn'] == true ) {
  77. $output->addHTML( "\t\t\t" . '<div id="blog-page-left">' . "\n" );
  78.  
  79. $output->addHTML( "\t\t\t\t" . '<div class="blog-left-units">' . "\n" );
  80.  
  81. $output->addHTML(
  82. "\t\t\t\t\t" . '<h2>' .
  83. wfMessage( 'blog-author-title' )
  84. ->numParams( count( $this->authors ) )
  85. ->escaped() . '</h2>' . "\n"
  86. );
  87. // Why was this commented out? --ashley, 11 July 2011
  88. if ( count( $this->authors ) > 1 ) {
  89. $output->addHTML( $this->displayMultipleAuthorsMessage() );
  90. }
  91.  
  92. // Output each author's box in the order that they appear in [[Category:Opinions by X]]
  93. for ( $x = 0; $x <= count( $this->authors ); $x++ ) {
  94. $output->addHTML( $this->displayAuthorBox( $x ) );
  95. }
  96.  
  97. $output->addHTML( $this->recentEditors() );
  98. $output->addHTML( $this->recentVoters() );
  99. $output->addHTML( $this->embedWidget() );
  100.  
  101. $output->addHTML( '</div>' . "\n" );
  102.  
  103. $output->addHTML( $this->leftAdUnit() );
  104. }
  105.  
  106. $output->addHTML( "\t\t\t" . '</div><!-- #blog-page-left -->' . "\n" );
  107.  
  108. $output->addHTML( '<div id="blog-page-middle">' . "\n" );
  109. global $wgUseEditButtonFloat;
  110. if ( $wgUseEditButtonFloat == true && method_exists( $sk, 'editMenu' ) ) {
  111. $output->addHTML( $sk->editMenu() );
  112. }
  113. $output->addHTML( "<h1 class=\"page-title\">{$this->getTitle()->getText()}</h1>\n" );
  114. $output->addHTML( $this->getByLine() );
  115.  
  116. $output->addHTML( "\n<!--start Article::view-->\n" );
  117. parent::view();
  118.  
  119. // Get categories
  120. $cat = $sk->getCategoryLinks();
  121. if ( $cat ) {
  122. $output->addHTML( "\n<div id=\"catlinks\" class=\"catlinks\">{$cat}</div>\n" );
  123. }
  124.  
  125. $output->addHTML( "\n<!--end Article::view-->\n" );
  126.  
  127. $output->addHTML( '</div>' . "\n" );
  128.  
  129. if ( $wgBlogPageDisplay['rightcolumn'] == true ) {
  130. $output->addHTML( '<div id="blog-page-right">' . "\n" );
  131.  
  132. $output->addHTML( $this->getPopularArticles() );
  133. $output->addHTML( $this->getInTheNews() );
  134. $output->addHTML( $this->getCommentsOfTheDay() );
  135. $output->addHTML( $this->getRandomCasualGame() );
  136. $output->addHTML( $this->getNewArticles() );
  137.  
  138. $output->addHTML( '</div>' . "\n" );
  139. }
  140.  
  141. $output->addHTML( '<div class="cleared"></div>' . "\n" );
  142. $output->addHTML( '</div><!-- #blog-page-container -->' . "\n" );
  143. }
  144.  
  145. /**
  146. * Get the authors of this blog post and store them in the authors member
  147. * variable.
  148. */
  149. public function getAuthors() {
  150. global $wgContLang;
  151.  
  152. $articleText = $this->pageContent;
  153. $categoryName = $wgContLang->getNsText( NS_CATEGORY );
  154.  
  155. // This unbelievably weak and hacky regex is used to find out the
  156. // author's name from the category. See also getBlurb(), which uses a
  157. // similar regex.
  158. preg_match_all(
  159. "/\[\[(?:(?:c|C)ategory|{$categoryName}):\s?" .
  160. // This is an absolutely unholy, horribly hacky and otherwise
  161. // less-than-ideal solution that likely works for English only
  162. // Someone needs to come up with a better solution one of these
  163. // days than this regex soup...
  164. str_replace( ' $1', '', wfMessage( 'blog-by-user-category' )->inContentLanguage()->escaped() ) .
  165. " (.*)\]\]/",
  166. $articleText,
  167. $matches
  168. );
  169. $authors = $matches[1];
  170.  
  171. foreach ( $authors as $author ) {
  172. $authorUserId = User::idFromName( $author );
  173. $this->authors[] = array(
  174. 'user_name' => trim( $author ),
  175. 'user_id' => $authorUserId
  176. );
  177. }
  178. }
  179.  
  180. /**
  181. * Get the creation date of the page with the given ID from the revision
  182. * table and cache it in memcached.
  183. * The return value of this function can be passed to the various $wgLang
  184. * methods for i18n-compatible code.
  185. *
  186. * @param int $pageId Page ID number
  187. * @return int Page creation date
  188. */
  189. public static function getCreateDate( $pageId ) {
  190. global $wgMemc;
  191.  
  192. // Try memcached first
  193. $key = wfMemcKey( 'page', 'create_date', $pageId );
  194. $data = $wgMemc->get( $key );
  195.  
  196. if ( !$data ) {
  197. wfDebugLog( 'BlogPage', "Loading create_date for page {$pageId} from database" );
  198. $dbr = wfGetDB( DB_SLAVE );
  199. $createDate = $dbr->selectField(
  200. 'revision',
  201. 'rev_timestamp',// 'UNIX_TIMESTAMP(rev_timestamp) AS create_date',
  202. array( 'rev_page' => $pageId ),
  203. __METHOD__,
  204. array( 'ORDER BY' => 'rev_timestamp ASC' )
  205. );
  206. $wgMemc->set( $key, $createDate );
  207. } else {
  208. wfDebugLog( 'BlogPage', "Loading create_date for page {$pageId} from cache" );
  209. $createDate = $data;
  210. }
  211.  
  212. return $createDate;
  213. }
  214.  
  215. /**
  216. * Get the "by X, Y and Z" line, which also contains other nifty
  217. * information, such as the date of the last edit and the creation date.
  218. *
  219. * @return string
  220. */
  221. public function getByLine() {
  222. $lang = $this->getContext()->getLanguage();
  223.  
  224. $count = 0;
  225.  
  226. // Get date of last edit
  227. $timestamp = $this->getTimestamp();
  228. $edit_time['date'] = $lang->date( $timestamp, true );
  229. $edit_time['time'] = $lang->time( $timestamp, true );
  230. $edit_time['datetime'] = $lang->timeanddate( $timestamp, true );
  231.  
  232. // Get date of when article was created
  233. $timestamp = self::getCreateDate( $this->getId() );
  234. $create_time['date'] = $lang->date( $timestamp, true );
  235. $create_time['time'] = $lang->time( $timestamp, true );
  236. $create_time['datetime'] = $lang->timeanddate( $timestamp, true );
  237.  
  238. $output = '<div class="blog-byline">' . wfMessage( 'blog-by' )->escaped() . ' ';
  239.  
  240. $authors = '';
  241. foreach ( $this->authors as $author ) {
  242. $count++;
  243. $userTitle = Title::makeTitle( NS_USER, $author['user_name'] );
  244. if ( $authors && count( $this->authors ) > 2 ) {
  245. $authors .= ', ';
  246. }
  247. if ( $count == count( $this->authors ) && $count != 1 ) {
  248. $authors .= wfMessage( 'word-separator' )->escaped() .
  249. wfMessage( 'blog-and' ) -escaped() .
  250. wfMessage( 'word-separator' )->escaped();
  251. }
  252. $authors .= Linker::link( $userTitle, $author['user_name'] );
  253. }
  254.  
  255. $output .= $authors;
  256.  
  257. $output .= '</div>';
  258.  
  259. $edit_text = '';
  260. if ( $create_time['datetime'] != $edit_time['datetime'] ) {
  261. $edit_text = ', ' .
  262. wfMessage(
  263. 'blog-last-edited',
  264. $edit_time['datetime'],
  265. $edit_time['date'],
  266. $edit_time['time']
  267. )->escaped();
  268. }
  269. $output .= "\n" . '<div class="blog-byline-last-edited">' .
  270. wfMessage(
  271. 'blog-created',
  272. $create_time['datetime'],
  273. $create_time['date'],
  274. $create_time['time']
  275. )->escaped() .
  276. " {$edit_text}</div>";
  277. return $output;
  278. }
  279.  
  280. public function displayMultipleAuthorsMessage() {
  281. $count = 0;
  282.  
  283. $authors = '';
  284. foreach ( $this->authors as $author ) {
  285. $count++;
  286. $userTitle = Title::makeTitle( NS_USER, $author['user_name'] );
  287. if ( $authors && count( $this->authors ) > 2 ) {
  288. $authors .= ', ';
  289. }
  290. if ( $count == count( $this->authors ) ) {
  291. $authors .= wfMessage( 'word-separator' )->escaped() .
  292. wfMessage( 'blog-and' )->escaped() .
  293. wfMessage( 'word-separator' )->escaped();
  294. }
  295. $authors .= Linker::link( $userTitle, $author['user_name'] );
  296. }
  297.  
  298. $output = '<div class="multiple-authors-message">' .
  299. wfMessage( 'blog-multiple-authors', $authors )->escaped() .
  300. '</div>';
  301.  
  302. return $output;
  303. }
  304.  
  305. public function displayAuthorBox( $author_index ) {
  306. global $wgBlogPageDisplay;
  307.  
  308. $out = $this->getContext()->getOutput();
  309. if ( $wgBlogPageDisplay['author'] == false ) {
  310. return '';
  311. }
  312.  
  313. $author_user_name = $author_user_id = '';
  314. if (
  315. isset( $this->authors[$author_index] ) &&
  316. isset( $this->authors[$author_index]['user_name'] )
  317. )
  318. {
  319. $author_user_name = $this->authors[$author_index]['user_name'];
  320. }
  321. if (
  322. isset( $this->authors[$author_index] ) &&
  323. isset( $this->authors[$author_index]['user_id'] )
  324. )
  325. {
  326. $author_user_id = $this->authors[$author_index]['user_id'];
  327. }
  328.  
  329. if ( empty( $author_user_id ) ) {
  330. return '';
  331. }
  332.  
  333. $authorTitle = Title::makeTitle( NS_USER, $author_user_name );
  334.  
  335. $profile = new UserProfile( $author_user_name );
  336. $profileData = $profile->getProfile();
  337.  
  338. $avatar = new wAvatar( $author_user_id, 'm' );
  339.  
  340. $articles = $this->getAuthorArticles( $author_index );
  341. $cssFix = '';
  342. if ( !$articles ) {
  343. $cssFix = ' author-container-fix';
  344. }
  345. $output = "\t\t\t\t\t<div class=\"author-container$cssFix\">
  346. <div class=\"author-info\">
  347. <a href=\"" . htmlspecialchars( $authorTitle->getFullURL() ) . "\" rel=\"nofollow\">
  348. {$avatar->getAvatarURL()}
  349. </a>
  350. <div class=\"author-title\">
  351. <a href=\"" . htmlspecialchars( $authorTitle->getFullURL() ) .
  352. '" rel="nofollow">' .
  353. wordwrap( $author_user_name, 12, "<br />\n", true ) .
  354. '</a>
  355. </div>';
  356. // If the user has supplied some information about themselves on their
  357. // social profile, show that data here.
  358. if ( $profileData['about'] ) {
  359. $output .= $out->parse( $profileData['about'], false );
  360. }
  361. $output .= "\n\t\t\t\t\t\t</div><!-- .author-info -->
  362. <div class=\"cleared\"></div>
  363. </div><!-- .author-container -->
  364. {$this->getAuthorArticles( $author_index )}";
  365.  
  366. return $output;
  367. }
  368.  
  369. public function getAuthorArticles( $author_index ) {
  370. global $wgBlogPageDisplay, $wgMemc;
  371.  
  372. if ( $wgBlogPageDisplay['author_articles'] == false ) {
  373. return '';
  374. }
  375.  
  376. $user_name = $this->authors[$author_index]['user_name'];
  377. $user_id = $this->authors[$author_index]['user_id'];
  378.  
  379. $archiveLink = Title::makeTitle(
  380. NS_CATEGORY,
  381. wfMessage( 'blog-by-user-category', $user_name )->text()
  382. );
  383.  
  384. $articles = array();
  385.  
  386. // Try cache first
  387. $key = wfMemcKey( 'blog', 'author', 'articles', $user_id );
  388. $data = $wgMemc->get( $key );
  389.  
  390. if ( $data != '' ) {
  391. wfDebugLog( 'BlogPage', "Got blog author articles for user {$user_name} from cache" );
  392. $articles = $data;
  393. } else {
  394. wfDebugLog( 'BlogPage', "Got blog author articles for user {$user_name} from DB" );
  395. $dbr = wfGetDB( DB_SLAVE );
  396. $categoryTitle = Title::newFromText(
  397. wfMessage( 'blog-by-user-category', $user_name )->text()
  398. );
  399. $res = $dbr->select(
  400. array( 'page', 'categorylinks' ),
  401. array( 'DISTINCT(page_id) AS page_id', 'page_title' ),
  402. /* WHERE */array(
  403. 'cl_to' => array( $categoryTitle->getDBkey() ),
  404. 'page_namespace' => NS_BLOG
  405. ),
  406. __METHOD__,
  407. array(
  408. 'ORDER BY' => 'page_id DESC',
  409. 'LIMIT' => 4
  410. ),
  411. array(
  412. 'categorylinks' => array( 'INNER JOIN', 'cl_from = page_id' )
  413. )
  414. );
  415.  
  416. $array_count = 0;
  417.  
  418. foreach ( $res as $row ) {
  419. if ( $row->page_id != $this->getId() && $array_count < 3 ) {
  420. $articles[] = array(
  421. 'page_title' => $row->page_title,
  422. 'page_id' => $row->page_id
  423. );
  424.  
  425. $array_count++;
  426. }
  427. }
  428.  
  429. // Cache for half an hour
  430. $wgMemc->set( $key, $articles, 60 * 30 );
  431. }
  432.  
  433. $output = '';
  434. if ( count( $articles ) > 0 ) {
  435. $css_fix = '';
  436.  
  437. if (
  438. count( $this->getVotersList() ) == 0 &&
  439. count( $this->getEditorsList() ) == 0
  440. )
  441. {
  442. $css_fix = ' more-container-fix';
  443. }
  444.  
  445. $output .= "<div class=\"more-container{$css_fix}\">
  446. <h3>" . wfMessage( 'blog-author-more-by', $user_name )->escaped() . '</h3>';
  447.  
  448. $x = 1;
  449.  
  450. foreach ( $articles as $article ) {
  451. $articleTitle = Title::makeTitle( NS_BLOG, $article['page_title'] );
  452.  
  453. $output .= '<div class="author-article-item">
  454. <a href="' . htmlspecialchars( $articleTitle->getFullURL() ) . "\">{$articleTitle->getText()}</a>
  455. <div class=\"author-item-small\">" .
  456. wfMessage(
  457. 'blog-author-votes',
  458. BlogPage::getVotesForPage( $article['page_id'] )
  459. )->escaped() .
  460. ', ' .
  461. wfMessage(
  462. 'blog-author-comments',
  463. BlogPage::getCommentsForPage( $article['page_id'] )
  464. )->escaped() .
  465. '</div>
  466. </div>';
  467.  
  468. $x++;
  469. }
  470.  
  471. $output .= '<div class="author-archive-link">
  472. <a href="' . htmlspecialchars( $archiveLink->getFullURL() ) . '">' .
  473. wfMessage( 'blog-view-archive-link' )->escaped() .
  474. '</a>
  475. </div>
  476. </div>';
  477. }
  478.  
  479. return $output;
  480. }
  481.  
  482. /**
  483. * Get the eight newest editors for the current blog post from the revision
  484. * table.
  485. *
  486. * @return array Array containing each editors' user ID and user name
  487. */
  488. public function getEditorsList() {
  489. global $wgMemc;
  490.  
  491. $pageTitleId = $this->getId();
  492.  
  493. $key = wfMemcKey( 'recenteditors', 'list', $pageTitleId );
  494. $data = $wgMemc->get( $key );
  495. $editors = array();
  496.  
  497. if ( !$data ) {
  498. wfDebugLog( 'BlogPage', "Loading recent editors for page {$pageTitleId} from DB" );
  499. $dbr = wfGetDB( DB_SLAVE );
  500.  
  501. $where = array(
  502. 'rev_page' => $pageTitleId,
  503. 'rev_user <> 0', // exclude anonymous editors
  504. "rev_user_text <> 'MediaWiki default'", // exclude MW default
  505. );
  506.  
  507. // Get authors and exclude them
  508. foreach ( $this->authors as $author ) {
  509. $where[] = 'rev_user_text <> \'' . $author['user_name'] . '\'';
  510. }
  511.  
  512. $res = $dbr->select(
  513. 'revision',
  514. array( 'DISTINCT rev_user', 'rev_user_text' ),
  515. $where,
  516. __METHOD__,
  517. array( 'ORDER BY' => 'rev_user_text ASC', 'LIMIT' => 8 )
  518. );
  519.  
  520. foreach ( $res as $row ) {
  521. $editors[] = array(
  522. 'user_id' => $row->rev_user,
  523. 'user_name' => $row->rev_user_text
  524. );
  525. }
  526.  
  527. // Store in memcached for five minutes
  528. $wgMemc->set( $key, $editors, 60 * 5 );
  529. } else {
  530. wfDebugLog( 'BlogPage', "Loading recent editors for page {$pageTitleId} from cache" );
  531. $editors = $data;
  532. }
  533.  
  534. return $editors;
  535. }
  536.  
  537. /**
  538. * Get the avatars of the people who recently edited this blog post, if
  539. * this feature is enabled in BlogPage config.
  540. *
  541. * @return string HTML or nothing
  542. */
  543. public function recentEditors() {
  544. global $wgUploadPath, $wgBlogPageDisplay;
  545.  
  546. if ( $wgBlogPageDisplay['recent_editors'] == false ) {
  547. return '';
  548. }
  549.  
  550. $editors = $this->getEditorsList();
  551.  
  552. $output = '';
  553.  
  554. if ( count( $editors ) > 0 ) {
  555. $output .= '<div class="recent-container">
  556. <h2>' . wfMessage( 'blog-recent-editors' )->escaped() . '</h2>
  557. <div>' . wfMessage( 'blog-recent-editors-message' )->escaped() . '</div>';
  558.  
  559. foreach ( $editors as $editor ) {
  560. $avatar = new wAvatar( $editor['user_id'], 'm' );
  561. $userTitle = Title::makeTitle( NS_USER, $editor['user_name'] );
  562.  
  563. $output .= '<a href="' . htmlspecialchars( $userTitle->getFullURL() ) .
  564. "\"><img src=\"{$wgUploadPath}/avatars/{$avatar->getAvatarImage()}\" alt=\"" .
  565. $userTitle->getText() . '" border="0" /></a>';
  566. }
  567.  
  568. $output .= '</div>';
  569. }
  570.  
  571. return $output;
  572. }
  573.  
  574. /**
  575. * Get the eight newest voters for the current blog post from VoteNY's
  576. * Vote table.
  577. *
  578. * @return array Array containing each voters' user ID and user name
  579. */
  580. public function getVotersList() {
  581. global $wgMemc;
  582.  
  583. // Gets the page ID for the query
  584. $pageTitleId = $this->getId();
  585.  
  586. $key = wfMemcKey( 'recentvoters', 'list', $pageTitleId );
  587. $data = $wgMemc->get( $key );
  588.  
  589. $voters = array();
  590. if ( !$data ) {
  591. wfDebugLog( 'BlogPage', "Loading recent voters for page {$pageTitleId} from DB" );
  592. $dbr = wfGetDB( DB_SLAVE );
  593.  
  594. $where = array(
  595. 'vote_page_id' => $pageTitleId,
  596. 'vote_user_id <> 0'
  597. );
  598.  
  599. // Exclude the authors of the blog post from the list of recent
  600. // voters
  601. foreach ( $this->authors as $author ) {
  602. $where[] = 'username <> \'' . $author['user_name'] . '\'';
  603. }
  604.  
  605. $res = $dbr->select(
  606. 'Vote',
  607. array( 'DISTINCT username', 'vote_user_id', 'vote_page_id' ),
  608. $where,
  609. __METHOD__,
  610. array( 'ORDER BY' => 'vote_id DESC', 'LIMIT' => 8 )
  611. );
  612.  
  613. foreach ( $res as $row ) {
  614. $voters[] = array(
  615. 'user_id' => $row->vote_user_id,
  616. 'user_name' => $row->username
  617. );
  618. }
  619.  
  620. $wgMemc->set( $key, $voters, 60 * 5 );
  621. } else {
  622. wfDebugLog( 'BlogPage', "Loading recent voters for page {$pageTitleId} from cache" );
  623. $voters = $data;
  624. }
  625.  
  626. return $voters;
  627. }
  628.  
  629. /**
  630. * Get the avatars of the people who recently voted for this blog post, if
  631. * this feature is enabled in BlogPage config.
  632. *
  633. * @return string HTML or nothing
  634. */
  635. public function recentVoters() {
  636. global $wgBlogPageDisplay;
  637.  
  638. if ( $wgBlogPageDisplay['recent_voters'] == false ) {
  639. return '';
  640. }
  641.  
  642. $voters = $this->getVotersList();
  643.  
  644. $output = '';
  645.  
  646. if ( count( $voters ) > 0 ) {
  647. $output .= '<div class="recent-container bottom-fix">
  648. <h2>' . wfMessage( 'blog-recent-voters' )->escaped() . '</h2>
  649. <div>' . wfMessage( 'blog-recent-voters-message' )->escaped() . '</div>';
  650.  
  651. foreach ( $voters as $voter ) {
  652. $userTitle = Title::makeTitle( NS_USER, $voter['user_name'] );
  653. $avatar = new wAvatar( $voter['user_id'], 'm' );
  654.  
  655. $output .= '<a href="' . htmlspecialchars( $userTitle->getFullURL() ) .
  656. "\">{$avatar->getAvatarURL()}</a>";
  657. }
  658.  
  659. $output .= '</div>';
  660. }
  661.  
  662. return $output;
  663. }
  664.  
  665. /**
  666. * Get the embed widget, if this feature is enabled in BlogPage config.
  667. *
  668. * @return string HTML or nothing
  669. */
  670. public function embedWidget() {
  671. global $wgBlogPageDisplay, $wgServer, $wgScriptPath;
  672.  
  673. // Not enabled? ContentWidget not available?
  674. if (
  675. $wgBlogPageDisplay['embed_widget'] == false ||
  676. !is_dir( dirname( __FILE__ ) . '/../extensions/ContentWidget' )
  677. )
  678. {
  679. return '';
  680. }
  681.  
  682. $title = $this->getTitle();
  683.  
  684. $output = '';
  685. $output .= '<div class="recent-container bottom-fix"><h2>' .
  686. wfMessage( 'blog-embed-title' )->escaped() . '</h2>';
  687. $output .= '<div class="blog-widget-embed">';
  688. $output .= "<p><input type='text' size='20' onclick='this.select();' value='" .
  689. '<object width="300" height="450" id="content_widget" align="middle"> <param name="movie" value="content_widget.swf" /><embed src="' .
  690. $wgServer . $wgScriptPath . '/extensions/ContentWidget/widget.swf?page=' .
  691. urlencode( $title->getFullText() ) . '" quality="high" bgcolor="#ffffff" width="300" height="450" name="content_widget"type="application/x-shockwave-flash" /> </object>' . "' /></p></div>";
  692. $output .= '</div>';
  693.  
  694. return $output;
  695. }
  696.  
  697. /**
  698. * Get an ad unit for the left side, if this feature is enabled in BlogPage
  699. * config.
  700. *
  701. * @return string HTML or nothing
  702. */
  703. public function leftAdUnit() {
  704. global $wgBlogPageDisplay;
  705.  
  706. if ( $wgBlogPageDisplay['left_ad'] == false ) {
  707. return '';
  708. }
  709.  
  710. $output = '<div class="article-ad">
  711. <!-- BlogPage ad temporarily disabled -->
  712. </div>';
  713.  
  714. return $output;
  715. }
  716.  
  717. /**
  718. * Get some random news items from MediaWiki:Inthenews, if this feature is
  719. * enabled in BlogPage config and that interface message has some content.
  720. *
  721. * @return string HTML or nothing
  722. */
  723. public function getInTheNews() {
  724. global $wgBlogPageDisplay, $wgMemc;
  725.  
  726. if ( $wgBlogPageDisplay['in_the_news'] == false ) {
  727. return '';
  728. }
  729.  
  730. $output = '';
  731. $message = wfMessage( 'inthenews' )->inContentLanguage();
  732. if ( !$message->isDisabled() ) {
  733. $newsArray = explode( "\n\n", $message->plain() );
  734. $newsItem = $newsArray[array_rand( $newsArray )];
  735. $output = '<div class="blog-container">
  736. <h2>' . wfMessage( 'blog-in-the-news' )->escaped() . '</h2>
  737. <div>' . $this->getContext()->getOutput()->parse( $newsItem, false ) . '</div>
  738. </div>';
  739. }
  740.  
  741. return $output;
  742. }
  743.  
  744. /**
  745. * Get the five most popular blog articles, if this feature is enabled in
  746. * BlogPage config.
  747. *
  748. * @return string HTML or nothing
  749. */
  750. public function getPopularArticles() {
  751. global $wgMemc, $wgBlogPageDisplay;
  752.  
  753. if ( $wgBlogPageDisplay['popular_articles'] == false ) {
  754. return '';
  755. }
  756.  
  757. // Try cache first
  758. $key = wfMemcKey( 'blog', 'popular', 'five' );
  759. $data = $wgMemc->get( $key );
  760.  
  761. if ( $data != '' ) {
  762. wfDebugLog( 'BlogPage', 'Got popular articles from cache' );
  763. $popularBlogPosts = $data;
  764. } else {
  765. wfDebugLog( 'BlogPage', 'Got popular articles from DB' );
  766. $dbr = wfGetDB( DB_SLAVE );
  767. // Code sporked from Rob Church's NewestPages extension
  768. // @todo FIXME: adding categorylinks table and that one where
  769. // clause causes an error about "unknown column 'page_id' on ON
  770. // clause"
  771. $commentsTable = $dbr->tableName( 'Comments' );
  772. $voteTable = $dbr->tableName( 'Vote' );
  773. $res = $dbr->select(
  774. array( 'page', /*'categorylinks',*/ 'Comments', 'Vote' ),
  775. array(
  776. 'DISTINCT page_id', 'page_namespace', 'page_is_redirect',
  777. 'page_title',
  778. ),
  779. array(
  780. 'page_namespace' => NS_BLOG,
  781. 'page_is_redirect' => 0,
  782. 'page_id = Comment_Page_ID',
  783. 'page_id = vote_page_id',
  784. // If you can figure out how to do this without a subquery,
  785. // please let me know. Until that...
  786. "((SELECT COUNT(*) FROM $voteTable WHERE vote_page_id = page_id) >= 5 OR
  787. (SELECT COUNT(*) FROM $commentsTable WHERE Comment_Page_ID = page_id) >= 5)",
  788. ),
  789. __METHOD__,
  790. array(
  791. 'ORDER BY' => 'page_id DESC',
  792. 'LIMIT' => 10
  793. ),
  794. array(
  795. 'Comments' => array( 'INNER JOIN', 'page_id = Comment_Page_ID' ),
  796. 'Vote' => array( 'INNER JOIN', 'page_id = vote_page_id' )
  797. )
  798. );
  799.  
  800. $popularBlogPosts = array();
  801. foreach ( $res as $row ) {
  802. $popularBlogPosts[] = array(
  803. 'title' => $row->page_title,
  804. 'id' => $row->page_id
  805. );
  806. }
  807.  
  808. // Cache in memcached for 15 minutes
  809. $wgMemc->set( $key, $popularBlogPosts, 60 * 15 );
  810. }
  811.  
  812. $html = '<div class="listpages-container">';
  813. foreach ( $popularBlogPosts as $popularBlogPost ) {
  814. $titleObj = Title::makeTitle( NS_BLOG, $popularBlogPost['title'] );
  815. $html .= '<div class="listpages-item">
  816. <a href="' . htmlspecialchars( $titleObj->getFullURL() ) . '">' .
  817. $titleObj->getText() .
  818. '</a>
  819. </div>
  820. <div class="cleared"></div>';
  821. }
  822. $html .= '</div>'; // .listpages-container
  823.  
  824. $output = '<div class="blog-container">
  825. <h2>' . wfMessage( 'blog-popular-articles' )->escaped() . '</h2>
  826. <div>' . $html . '</div>
  827. </div>';
  828.  
  829. return $output;
  830. }
  831.  
  832. /**
  833. * Get the newest blog articles, if this feature is enabled in BlogPage
  834. * config.
  835. *
  836. * @return string HTML or nothing
  837. */
  838. public function getNewArticles() {
  839. global $wgMemc, $wgBlogPageDisplay;
  840.  
  841. if ( $wgBlogPageDisplay['new_articles'] == false ) {
  842. return '';
  843. }
  844.  
  845. // Try cache first
  846. $key = wfMemcKey( 'blog', 'new', 'five' );
  847. $data = $wgMemc->get( $key );
  848.  
  849. if ( $data != '' ) {
  850. wfDebugLog( 'BlogPage', 'Got new articles from cache' );
  851. $newBlogPosts = $data;
  852. } else {
  853. wfDebugLog( 'BlogPage', 'Got new articles from DB' );
  854. // We could do complicated LIKE stuff with the categorylinks table,
  855. // but I think we can safely assume that stuff in the NS_BLOG NS
  856. // is blog-related :)
  857. $dbr = wfGetDB( DB_SLAVE );
  858. // Code sporked from Rob Church's NewestPages extension
  859. $res = $dbr->select(
  860. 'page',
  861. array( 'page_namespace', 'page_title', 'page_is_redirect' ),
  862. array( 'page_namespace' => NS_BLOG, 'page_is_redirect' => 0 ),
  863. __METHOD__,
  864. array( 'ORDER BY' => 'page_id DESC', 'LIMIT' => 5 )
  865. );
  866.  
  867. $newBlogPosts = array();
  868. foreach ( $res as $row ) {
  869. $newBlogPosts[] = array(
  870. 'title' => $row->page_title,
  871. );
  872. }
  873.  
  874. // Cache in memcached for 15 minutes
  875. $wgMemc->set( $key, $newBlogPosts, 60 * 15 );
  876. }
  877.  
  878. $html = '<div class="listpages-container">';
  879. foreach ( $newBlogPosts as $newBlogPost ) {
  880. $titleObj = Title::makeTitle( NS_BLOG, $newBlogPost['title'] );
  881. $html .= '<div class="listpages-item">
  882. <a href="' . htmlspecialchars( $titleObj->getFullURL() ) . '">' .
  883. $titleObj->getText() .
  884. '</a>
  885. </div>
  886. <div class="cleared"></div>';
  887. }
  888. $html .= '</div>'; // .listpages-container
  889.  
  890. $output = '<div class="blog-container bottom-fix">
  891. <h2>' . wfMessage( 'blog-new-articles' )->escaped() . '</h2>
  892. <div>' . $html . '</div>
  893. </div>';
  894.  
  895. return $output;
  896. }
  897.  
  898. /**
  899. * Get a random casual game, if this feature is enabled in BlogPage config
  900. * and the RandomGameUnit extension is installed.
  901. *
  902. * @return string HTML or nothing
  903. */
  904. public function getRandomCasualGame() {
  905. global $wgBlogPageDisplay;
  906.  
  907. if (
  908. $wgBlogPageDisplay['games'] == false ||
  909. !class_exists( 'RandomGameUnit' )
  910. )
  911. {
  912. return '';
  913. }
  914.  
  915. return RandomGameUnit::getRandomGameUnit();
  916. }
  917.  
  918. /**
  919. * Get comments of the day, if this feature is enabled in BlogPage config.
  920. * Requires the Comments extension.
  921. *
  922. * @return string HTML or nothing
  923. */
  924. public function getCommentsOfTheDay() {
  925. global $wgBlogPageDisplay, $wgMemc;
  926.  
  927. if ( $wgBlogPageDisplay['comments_of_day'] == false ) {
  928. return '';
  929. }
  930.  
  931. $comments = array();
  932.  
  933. // Try cache first
  934. $key = wfMemcKey( 'comments', 'plus', '24hours' );
  935. $data = $wgMemc->get( $key );
  936.  
  937. if ( $data != '' ) {
  938. wfDebugLog( 'BlogPage', 'Got comments of the day from cache' );
  939. $comments = $data;
  940. } else {
  941. wfDebugLog( 'BlogPage', 'Got comments of the day from DB' );
  942. $dbr = wfGetDB( DB_SLAVE );
  943. $res = $dbr->select(
  944. array( 'Comments', 'page' ),
  945. array(
  946. 'Comment_Username', 'comment_ip', 'comment_text',
  947. 'comment_date', 'Comment_user_id', 'CommentID',
  948. 'IFNULL(Comment_Plus_Count - Comment_Minus_Count,0) AS Comment_Score',
  949. 'Comment_Plus_Count AS CommentVotePlus',
  950. 'Comment_Minus_Count AS CommentVoteMinus',
  951. 'Comment_Parent_ID', 'page_title', 'page_namespace'
  952. ),
  953. array(
  954. 'comment_page_id = page_id',
  955. 'UNIX_TIMESTAMP(comment_date) > ' . ( time() - ( 60 * 60 * 24 ) ),
  956. 'page_namespace' => NS_BLOG
  957. ),
  958. __METHOD__,
  959. array( 'ORDER BY' => 'Comment_Plus_Count DESC', 'LIMIT' => 5 )
  960. );
  961.  
  962. foreach ( $res as $row ) {
  963. $comments[] = array(
  964. 'user_name' => $row->Comment_Username,
  965. 'user_id' => $row->Comment_user_id,
  966. 'title' => $row->page_title,
  967. 'namespace' => $row->page_namespace,
  968. 'comment_id' => $row->CommentID,
  969. 'plus_count' => $row->CommentVotePlus,
  970. 'comment_text' => $row->comment_text
  971. );
  972. }
  973.  
  974. $wgMemc->set( $key, $comments, 60 * 15 );
  975. }
  976.  
  977. $output = '';
  978.  
  979. foreach ( $comments as $comment ) {
  980. $page_title = Title::makeTitle( $comment['namespace'], $comment['title'] );
  981.  
  982. if ( $comment['user_id'] != 0 ) {
  983. $commentPosterDisplay = $comment['user_name'];
  984. } else {
  985. $commentPosterDisplay = wfMessage( 'blog-anonymous-name' )->escaped();
  986. }
  987.  
  988. $comment['comment_text'] = strip_tags( $comment['comment_text'] );
  989. $comment_text = $this->getContext()->getLanguage()->truncate(
  990. $comment['comment_text'],
  991. ( 70 - strlen( $commentPosterDisplay ) )
  992. );
  993.  
  994. $output .= '<div class="cod-item">';
  995. $output .= "<span class=\"cod-score\">{$comment['plus_count']}</span> ";
  996. $output .= ' <span class="cod-comment"><a href="' .
  997. htmlspecialchars( $page_title->getFullURL() ) .
  998. "#comment-{$comment['comment_id']}\" title=\"{$page_title->getText()}\">{$comment_text}</a></span>";
  999. $output .= '</div>';
  1000. }
  1001.  
  1002. if ( count( $comments ) > 0 ) {
  1003. $output = '<div class="blog-container">
  1004. <h2>' . wfMessage( 'blog-comments-of-day' )->escaped() . '</h2>' .
  1005. $output .
  1006. '</div>';
  1007. }
  1008.  
  1009. return $output;
  1010. }
  1011.  
  1012. /**
  1013. * Get the amount (COUNT(*)) of comments for the given page, identified via
  1014. * its ID and cache this info in memcached for 15 minutes.
  1015. *
  1016. * @param int $id Page ID
  1017. * @return int Amount of comments
  1018. */
  1019. public static function getCommentsForPage( $id ) {
  1020. global $wgMemc;
  1021.  
  1022. // Try cache first
  1023. $key = wfMemcKey( 'blog', 'comments', 'count', 'pageid-' . $id );
  1024. $data = $wgMemc->get( $key );
  1025.  
  1026. if ( $data != '' ) {
  1027. wfDebugLog( 'BlogPage', "Got comments count for the page with ID {$id} from cache" );
  1028. $commentCount = $data;
  1029. } else {
  1030. wfDebugLog( 'BlogPage', "Got comments count for the page with ID {$id} from DB" );
  1031. $dbr = wfGetDB( DB_SLAVE );
  1032. $commentCount = (int)$dbr->selectField(
  1033. 'Comments',
  1034. 'COUNT(*) AS count',
  1035. array( 'Comment_Page_ID' => intval( $id ) ),
  1036. __METHOD__
  1037. );
  1038. // Store in memcached for 15 minutes
  1039. $wgMemc->set( $key, $commentCount, 60 * 15 );
  1040. }
  1041.  
  1042. return $commentCount;
  1043. }
  1044.  
  1045. /**
  1046. * Get the amount (COUNT(*)) of votes for the given page, identified via
  1047. * its ID and cache this info in memcached for 15 minutes.
  1048. *
  1049. * @param int $id Page ID
  1050. * @return int Amount of votes
  1051. */
  1052. public static function getVotesForPage( $id ) {
  1053. global $wgMemc;
  1054.  
  1055. // Try cache first
  1056. $key = wfMemcKey( 'blog', 'vote', 'count', 'pageid-' . $id );
  1057. $data = $wgMemc->get( $key );
  1058.  
  1059. if ( $data != '' ) {
  1060. wfDebugLog( 'BlogPage', "Got vote count for the page with ID {$id} from cache" );
  1061. $voteCount = $data;
  1062. } else {
  1063. wfDebugLog( 'BlogPage', "Got vote count for the page with ID {$id} from DB" );
  1064. $dbr = wfGetDB( DB_SLAVE );
  1065. $voteCount = (int)$dbr->selectField(
  1066. 'Vote',
  1067. 'COUNT(*) AS count',
  1068. array( 'vote_page_id' => intval( $id ) ),
  1069. __METHOD__
  1070. );
  1071. // Store in memcached for 15 minutes
  1072. $wgMemc->set( $key, $voteCount, 60 * 15 );
  1073. }
  1074.  
  1075. return $voteCount;
  1076. }
  1077.  
  1078. /**
  1079. * Get the first $maxChars characters of a page.
  1080. *
  1081. * @param string $pageTitle Page title
  1082. * @param int $namespace Namespace where the page is in
  1083. * @param int $maxChars Get the first this many characters of the page
  1084. * @param string $fontSize Font size; small, medium or large
  1085. * @return string First $maxChars characters from the page
  1086. */
  1087. public static function getBlurb( $pageTitle, $namespace, $maxChars, $fontSize = 'small' ) {
  1088. global $wgContLang;
  1089.  
  1090. // Get raw text
  1091. $title = Title::makeTitle( $namespace, $pageTitle );
  1092. $article = new Article( $title );
  1093. $text = $article->getContent();
  1094.  
  1095. // Remove some problematic characters
  1096. $text = str_replace( '* ', '', $text );
  1097. $text = str_replace( '===', '', $text );
  1098. $text = str_replace( '==', '', $text );
  1099. $text = str_replace( '{{Comments}}', '', $text ); // Template:Comments
  1100. $text = preg_replace( '@<youtube[^>]*?>.*?</youtube>@si', '', $text ); // <youtube> tags (provided by YouTube extension)
  1101. $text = preg_replace( '@<video[^>]*?>.*?</video>@si', '', $text ); // <video> tags (provided by Video extension)
  1102. $text = preg_replace( '@<comments[^>]*?>.*?</comments>@si', '', $text ); // <comments> tags (provided by Comments extension)
  1103. $text = preg_replace( '@<comments[^>]*?\/>@si', '', $text ); // more of the above -- this catches the self-closing variant, <comments />
  1104. $text = preg_replace( '@<vote[^>]*?>.*?</vote>@si', '', $text ); // <vote> tags (provided by Vote extension)
  1105. $text = preg_replace( '@<vote[^>]*?\/>@si', '', $text ); // more of the above -- this catches the self-closing variant, <vote />, although it's unlikely to ever be present in the body of a blog post
  1106. if ( class_exists( 'Video' ) ) {
  1107. $videoNS = $wgContLang->getNsText( NS_VIDEO );
  1108. if ( $videoNS === false ) {
  1109. $videoNS = 'Video';
  1110. }
  1111. // [[Video:]] links (provided by Video extension)
  1112. $text = preg_replace( "@\[\[{$videoNS}:[^\]]*?].*?\]@si", '', $text );
  1113. }
  1114. $localizedCategoryNS = $wgContLang->getNsText( NS_CATEGORY );
  1115. $text = preg_replace( "@\[\[(?:(c|C)ategory|{$localizedCategoryNS}):[^\]]*?].*?\]@si", '', $text ); // categories
  1116. // $text = preg_replace( "@\[\[{$localizedCategoryNS}:[^\]]*?].*?\]@si", '', $text ); // original version of the above line
  1117.  
  1118. // Start looking at text after content, and force no Table of Contents
  1119. $pos = strpos( $text, '<!--start text-->' );
  1120. if ( $pos !== false ) {
  1121. $text = substr( $text, $pos );
  1122. }
  1123.  
  1124. $text = '__NOTOC__ ' . $text;
  1125.  
  1126. // Run text through parser
  1127. $blurbText = $article->getContext()->getOutput()->parse( $text );
  1128. $blurbText = strip_tags( $blurbText );
  1129.  
  1130. $blurbText = preg_replace( '/&lt;comments&gt;&lt;\/comments&gt;/i', '', $blurbText );
  1131. $blurbText = preg_replace( '/&lt;vote&gt;&lt;\/vote&gt;/i', '', $blurbText );
  1132.  
  1133. // $blurbText = $text;
  1134. $pos = strpos( $blurbText, '[' );
  1135. if ( $pos !== false ) {
  1136. $blurbText = substr( $blurbText, 0, $pos );
  1137. }
  1138.  
  1139. // Take first N characters, and then make sure it ends on last full word
  1140. $max = 300;
  1141. if ( strlen( $blurbText ) > $max ) {
  1142. $blurbText = strrev( strstr( strrev( substr( $blurbText, 0, $max ) ), ' ' ) );
  1143. }
  1144.  
  1145. // Prepare blurb font size
  1146. $blurbFont = '<span class="listpages-blurb-size-';
  1147. if ( $fontSize == 'small' ) {
  1148. $blurbFont .= 'small';
  1149. } elseif ( $fontSize == 'medium' ) {
  1150. $blurbFont .= 'medium';
  1151. } elseif ( $fontSize == 'large' ) {
  1152. $blurbFont .= 'large';
  1153. }
  1154. $blurbFont .= '">';
  1155.  
  1156. // Fix multiple whitespace, returns etc
  1157. $blurbText = trim( $blurbText ); // remove trailing spaces
  1158. $blurbText = preg_replace( '/\s(?=\s)/', '', $blurbText ); // remove double whitespace
  1159. $blurbText = preg_replace( '/[\n\r\t]/', ' ', $blurbText ); // replace any non-space whitespace with a space
  1160.  
  1161. return $blurbFont . $blurbText . '. . . <a href="' .
  1162. htmlspecialchars( $title->getFullURL() ) . '">' . wfMessage( 'blog-more' )->escaped() .
  1163. '</a></span>';
  1164. }
  1165.  
  1166. /**
  1167. * Get the image associated with the given page (via the page's ID).
  1168. *
  1169. * @param int $pageId Page ID number
  1170. * @return string File name or nothing
  1171. */
  1172. public static function getPageImage( $pageId ) {
  1173. global $wgMemc;
  1174.  
  1175. $key = wfMemcKey( 'blog', 'page', 'image', $pageId );
  1176. $data = $wgMemc->get( $key );
  1177.  
  1178. if ( !$data ) {
  1179. $dbr = wfGetDB( DB_SLAVE );
  1180. $il_to = $dbr->selectField(
  1181. 'imagelinks',
  1182. array( 'il_to' ),
  1183. array( 'il_from' => intval( $pageId ) ),
  1184. __METHOD__
  1185. );
  1186. // Cache in memcached for a minute
  1187. $wgMemc->set( $key, $il_to, 60 );
  1188. } else {
  1189. wfDebugLog( 'BlogPage', "Loading image for page {$pageId} from cache\n" );
  1190. $il_to = $data;
  1191. }
  1192.  
  1193. return $il_to;
  1194. }
  1195.  
  1196. /**
  1197. * Yes, these are those fucking time-related functions once more.
  1198. * You probably have seen these in UserBoard, Comments...god knows where.
  1199. * Seriously, this stuff is all over the place.
  1200. */
  1201. public static function dateDiff( $date1, $date2 ) {
  1202. $dtDiff = $date1 - $date2;
  1203.  
  1204. $totalDays = intval( $dtDiff / ( 24 * 60 * 60 ) );
  1205. $totalSecs = $dtDiff - ( $totalDays * 24 * 60 * 60 );
  1206. $dif['w'] = intval( $totalDays / 7 );
  1207. $dif['d'] = $totalDays;
  1208. $dif['h'] = $h = intval( $totalSecs / ( 60 * 60 ) );
  1209. $dif['m'] = $m = intval( ( $totalSecs - ( $h * 60 * 60 ) ) / 60 );
  1210. $dif['s'] = $totalSecs - ( $h * 60 * 60 ) - ( $m * 60 );
  1211.  
  1212. return $dif;
  1213. }
  1214.  
  1215. public static function getTimeOffset( $time, $timeabrv, $timename ) {
  1216. $timeStr = '';
  1217. if ( $time[$timeabrv] > 0 ) {
  1218. $timeStr = wfMessage( "blog-time-$timename", $time[$timeabrv] )->text();
  1219. }
  1220. if ( $timeStr ) {
  1221. $timeStr .= ' ';
  1222. }
  1223. return $timeStr;
  1224. }
  1225.  
  1226. public static function getTimeAgo( $time ) {
  1227. $timeArray = self::dateDiff( time(), $time );
  1228. $timeStr = '';
  1229. $timeStrD = self::getTimeOffset( $timeArray, 'd', 'days' );
  1230. $timeStrH = self::getTimeOffset( $timeArray, 'h', 'hours' );
  1231. $timeStrM = self::getTimeOffset( $timeArray, 'm', 'minutes' );
  1232. $timeStrS = self::getTimeOffset( $timeArray, 's', 'seconds' );
  1233. $timeStr = $timeStrD;
  1234. if ( $timeStr < 2 ) {
  1235. $timeStr .= $timeStrH;
  1236. $timeStr .= $timeStrM;
  1237. if ( !$timeStr ) {
  1238. $timeStr .= $timeStrS;
  1239. }
  1240. }
  1241. if ( !$timeStr ) {
  1242. $timeStr = wfMessage( 'blog-time-seconds' )->numParams( 1 )->text();
  1243. }
  1244. return $timeStr;
  1245. }
  1246. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement