PageRenderTime 58ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/web/public_html/wp-content/plugins/wumii-related-posts/wumii-related-posts.php

https://github.com/allengaller/zenx-news
PHP | 703 lines | 499 code | 116 blank | 88 comment | 89 complexity | 29174aba6275fe011c1db46d0ca334cd MD5 | raw file
  1. <?php
  2. /*
  3. Plugin Name: 无觅相关文章插件
  4. Plugin URI: http://wordpress.org/extend/plugins/wumii-related-posts/
  5. Author: Wumii Team
  6. Version: 1.0.5.7
  7. Author URI: http://www.wumii.com
  8. Description: 利用数据挖掘的技术,智能匹配相关文章,并以图片形式展示。
  9. Copyright 2010 wumii.com (email: team[at]wumii.com)
  10. */
  11. if (!class_exists('WumiiRelatedPosts')) {
  12. class WumiiRelatedPosts {
  13. /*
  14. * !!! You must do the two things before you try to do local test with this plugin:
  15. * 1. turn on WUMII_DEBUG mode
  16. * 2. change WUMII_SERVER to "http://{computer-name}:8080"
  17. * {computer-name} is the name of computer which running a local test wumii web server.
  18. */
  19. const WUMII_DEBUG = false;
  20. const WUMII_SERVER = 'http://widget.wumii.cn';
  21. const VERSION = '1.0.5.7';
  22. const ADMIN_OPTION_NAME = 'wumii_admin_options';
  23. const PLUGIN_PATH = '/wp-content/plugins/wumii-related-posts';
  24. // admin option names
  25. const NUM_POSTS = 'num_posts';
  26. const SINGLE_PAGE_ONLY = 'single_page_only';
  27. const DISPLAY_IN_FEED = 'display_in_feed';
  28. const ENABLE_CUSTOM_POS = 'enable_custom_pos';
  29. const SCRIPT_IN_FOOTER = 'script_in_footer';
  30. const WUMII_COMMENT_PLUGIN_ENABLED = 'wumii_comment_plugin_enabled';
  31. // this containter is a stack and its size is 1.
  32. const NOTIFY_MESSAGE_CONTAINER = 'wumii_notify_message_container';
  33. const VERIFICATION_CODE = 'wumii_verification_code';
  34. private $sitePrefix;
  35. private $adminOptions;
  36. private $excludePostIds = array();
  37. private $lastRssRequestFailedTime;
  38. private $canFilledRssContentPostIds = array();
  39. // PHP 5 style constructor
  40. function __construct() {
  41. $this->WumiiRelatedPosts();
  42. }
  43. // treated as regular method since PHP 5.3.3
  44. // PHP 4 style constructor
  45. function WumiiRelatedPosts() {
  46. $this->resetAdminOptions();
  47. $persistentOptions = get_option(self::ADMIN_OPTION_NAME);
  48. if (is_array($persistentOptions)) {
  49. foreach ($this->adminOptions as $key => $value) {
  50. if (array_key_exists($key, $persistentOptions)) {
  51. $this->adminOptions[$key] = $persistentOptions[$key];
  52. }
  53. }
  54. }
  55. // get_bloginfo('url') deprecated since WordPress 3.0.0.
  56. $this->sitePrefix = function_exists('home_url') ? home_url() : get_bloginfo('url');
  57. $this->replaceCommentBox();
  58. }
  59. function getOrigTitle() {
  60. global $post;
  61. return isset($post->post_title) ? $post->post_title : '';
  62. }
  63. function showNotifyMessage() {
  64. $notifyMessage = $this->popNotifyMessage();
  65. if ($notifyMessage) {
  66. $this->printHtmlNotifyMessage(array($notifyMessage));
  67. }
  68. }
  69. function registerOptionsPage () {
  70. add_options_page('无觅相关文章插件', '无觅', 'activate_plugins', basename(__FILE__), array($this, 'printAdminPage'));
  71. }
  72. function addPluginActionLinks($links, $file) {
  73. if ($file == plugin_basename(__FILE__)) {
  74. $links[] = '<a href="options-general.php?page=wumii-related-posts.php">' . __('Settings') . '</a>';
  75. }
  76. return $links;
  77. }
  78. function addToRssContent($content) {
  79. $newContent = $content;
  80. if ($this->getAdminOption(self::DISPLAY_IN_FEED) && is_feed()) {
  81. global $post;
  82. // 1. Both "rss excerpt mode" and "rss full text mode" will call the_excerpt_rss()
  83. // function first to generate feed description.
  84. // 2. "the_excerpt_rss" apply filters process:
  85. // (1. Only run when empty(post->excerpt) && post_password_required(post))
  86. // the_content (Get the whole content and then extract excerpt.
  87. // We shouldn't add related items here since the content will
  88. // be processed by wp_trim_excerpt() later) ->
  89. // (2)
  90. // the_excerpt_rss (Here will add our related items content).
  91. // 3. "rss full text mode" applies the filters on "the_content" hook again after
  92. // the_excerpt_rss() to generate the feed content. However this time we should
  93. // add related items content.
  94. // 4. Because wordpress 2.5.x don't have function post_password_required and we have
  95. // to do a lot to check if the current user is admin, we don't show rss related items
  96. // if post excerpt is empty and it's a password required post.
  97. if (!has_excerpt() && !in_array($post->ID, $this->canFilledRssContentPostIds)) {
  98. $this->canFilledRssContentPostIds[] = $post->ID;
  99. } else {
  100. $relatedItemsHtml = $this->getRelatedItemsHtml();
  101. if ($relatedItemsHtml) {
  102. $newContent .= $relatedItemsHtml;
  103. }
  104. }
  105. }
  106. return $newContent;
  107. }
  108. private function getRelatedItemsHtml() {
  109. // Don't do anything for 30 seconds if last request failed.
  110. if (isset($this->lastRssRequestFailedTime) &&
  111. time() - $this->lastRssRequestFailedTime < 30) {
  112. return;
  113. }
  114. $encodedUrl = urlencode(get_permalink());
  115. $encodedTitle = urlencode($this->getOrigTitle());
  116. $num = $this->getAdminOption(self::NUM_POSTS);
  117. $encodedSitePrefix = urlencode($this->sitePrefix);
  118. global $wp_version;
  119. $path = "/ext/relatedItemsRss?type=1&url=$encodedUrl&title=$encodedTitle&num=$num&sitePrefix=$encodedSitePrefix&mode=3&v=" . self::VERSION . "&pf=WordPress$wp_version";
  120. $relatedItemsHtml = $this->httpGet(self::WUMII_SERVER, $path);
  121. if ($relatedItemsHtml) {
  122. return $relatedItemsHtml;
  123. } else {
  124. $this->lastRssRequestFailedTime = time();
  125. }
  126. }
  127. private function httpGet($server, $path) {
  128. global $wp_version;
  129. $response = '';
  130. if (function_exists('wp_remote_get')) { // wp_remote_get function was added in WordPress 2.7
  131. $addr = $server . $path;
  132. // Default: method: GET, timeout: 5s, redirection: 5, httpversion: 1.0, blocking: true, body: null, cookies: array()
  133. $args = array(
  134. 'user-agent' => apply_filters('http_headers_useragent', 'WordPress/' . $wp_version . '; ' . $_SERVER['HTTP_USER_AGENT']),
  135. // TODO: use batch fetch related items instead of lower the timeout.
  136. 'timeout' => 1
  137. );
  138. $raw_response = wp_remote_get($addr, $args);
  139. if (!is_wp_error($raw_response) && 200 == $raw_response['response']['code']) {
  140. $response = trim($raw_response['body']);
  141. }
  142. }
  143. // For:
  144. // 1. WordPress version < 2.7
  145. // 2. For some reason the client php is misconfigurated, the wp_remote_get function can not work properly.
  146. // Currently know wp_remote_get($url, $args) will crash if wordpress do request with WP_Http_ExtHTTP(in /wp-includes/http.php) and the PECL extension is not bundled with PHP.
  147. // (empty($response) === true) if match one of the above reasons.
  148. if (empty($response) && function_exists('fsockopen')) {
  149. $urlComponents = parse_url($server);
  150. $host = $urlComponents['host'] . ($urlComponents['port'] ? ':' . $urlComponents['port'] : '');
  151. $http_request = "GET $path HTTP/1.0\r\n";
  152. $http_request .= "Host: $host\r\n";
  153. $http_request .= "Content-Type: application/x-www-form-urlencoded; charset=" . get_option('blog_charset') . "\r\n";
  154. $http_request .= 'User-Agent: WordPress/' . $wp_version . '; ' . $_SERVER['HTTP_USER_AGENT'] . "\r\n\r\n";
  155. $answer = '';
  156. // The connection timeout is 1 second.
  157. // TODO: recover this to 5s and remove stream_set_timeout() setting when we support betch fetch related items.
  158. if( false != ($fs = @fsockopen($host, 80, $errno, $errstr, 1)) && is_resource($fs)) {
  159. // The timeout for reading data over the socket is 1 second.
  160. stream_set_timeout($fs, 1);
  161. fwrite($fs, $http_request);
  162. while (!feof($fs)) {
  163. $answer .= fgets($fs, 1160); // One TCP-IP packet
  164. }
  165. fclose($fs);
  166. $answer = explode("\r\n\r\n", $answer, 2);
  167. // Response Header: $answer[0]
  168. // Response Content: $answer[1]
  169. if (preg_match('#HTTP/.*? 200#', $answer[0])) {
  170. $response = trim($answer[1]);
  171. }
  172. }
  173. }
  174. return $response;
  175. }
  176. function addWumiiContent($content) {
  177. $newContent = $content;
  178. if ($this->canDisplayWumiiContent()) {
  179. $escapedUrl = $this->htmlEscape(get_permalink());
  180. $escapedTitle = $this->htmlEscape($this->getOrigTitle());
  181. $escapedPic = $this->htmlEscape($this->getPostThumbnailSrc());
  182. // The first line in 'WUMII_HOOK' must be an empty line. Because some blogs use 'Embeds'(http://codex.wordpress.org/Embeds)
  183. // in the post content and the embed must be on its own line.
  184. // For example, if the 'embed' happen to add before our wumii code,
  185. // then we have to make sure wumii code doesn't follow that within the same line.
  186. $newContent .= <<<WUMII_HOOK
  187. <div class="wumii-hook">
  188. <input type="hidden" name="wurl" value="$escapedUrl" />
  189. <input type="hidden" name="wtitle" value="$escapedTitle" />
  190. <input type="hidden" name="wpic" value="$escapedPic" />
  191. </div>
  192. WUMII_HOOK;
  193. }
  194. global $wp_query;
  195. if ($wp_query->current_post + 1 == $wp_query->post_count) {
  196. $newContent = $this->addScriptInPage($newContent);
  197. }
  198. return $newContent;
  199. }
  200. function echoWumiiScript() {
  201. echo $this->createWumiiScript();
  202. }
  203. function echoVerificationMeta() {
  204. $code = $this->getVerificationCode();
  205. if ($code) {
  206. echo "<meta name='wumiiVerification' content='$code' />\n";
  207. }
  208. }
  209. private function addScriptInPage($content) {
  210. if ($this->getAdminOption(self::SCRIPT_IN_FOOTER)) {
  211. add_action('wp_footer', array($this, 'echoWumiiScript'));
  212. return $content;
  213. } else {
  214. return $content . $this->createWumiiScript();
  215. }
  216. }
  217. private function createWumiiScript() {
  218. $enableCustomPos = $this->getAdminOption(self::ENABLE_CUSTOM_POS) ? 'true' : 'false';
  219. $numPosts = $this->getAdminOption(self::NUM_POSTS);
  220. $server = self::WUMII_SERVER;
  221. $script = '';
  222. if (self::WUMII_DEBUG) {
  223. $script = "<script type='text/javascript'>var wumiiDebugServer = '$server';</script>";
  224. }
  225. global $wp_version;
  226. $params = array(
  227. 'num' => $numPosts,
  228. 'mode' => 3, // Use the DisplayMode.AUTO as default
  229. 'displayInFeed' => $this->getAdminOption(self::DISPLAY_IN_FEED), // 1=true, 0=false
  230. 'version' => self::VERSION,
  231. 'pf' => 'WordPress' . $wp_version
  232. );
  233. $queryParams = '';
  234. foreach ($params as $name => $value) {
  235. $value = urlencode($value);
  236. $queryParams .= "&$name=$value";
  237. }
  238. $jsonCategories = $this->getJsonCategories();
  239. // Do not break the following html code into lines between each html tag.
  240. // One default filter in wordpress will replace "\n" with "<br />" between html tags.
  241. $script .= <<<WUMII_SCRIPT
  242. <p style="margin:0;padding:0;height:1px;overflow:hidden;">
  243. <script type="text/javascript"><!--
  244. var wumiiSitePrefix = "$this->sitePrefix";
  245. var wumiiEnableCustomPos = $enableCustomPos;
  246. var wumiiParams = "$queryParams";
  247. var wumiiCategories = $jsonCategories;
  248. //--></script><script type="text/javascript" src="$server/ext/relatedItemsWidget"></script><a href="http://www.wumii.com/widget/relatedItems" style="border:0;"><img src="http://static.wumii.cn/images/pixel.png" alt="无觅相关文章插件,快速提升流量" style="border:0;padding:0;margin:0;" /></a>
  249. </p>
  250. WUMII_SCRIPT;
  251. return $script;
  252. }
  253. private function getJsonCategories() {
  254. $categories = get_the_category();
  255. $categoryArr = array();
  256. if ($categories) {
  257. foreach($categories as $category) {
  258. $categoryArr[] = html_entity_decode($category->cat_name);
  259. }
  260. }
  261. return json_encode($categoryArr);
  262. }
  263. private function htmlEscape($str) {
  264. return htmlspecialchars(html_entity_decode($str, ENT_QUOTES, 'UTF-8'), ENT_QUOTES, 'UTF-8');
  265. }
  266. private function getPostThumbnailSrc() {
  267. // function 'get_post_thumbnail_id' need blog support
  268. if (!function_exists('get_post_thumbnail_id')) {
  269. return;
  270. }
  271. $image_info = wp_get_attachment_image_src(get_post_thumbnail_id(), 'full');
  272. if ($image_info) {
  273. return $image_info[0];
  274. }
  275. }
  276. private function canDisplayWumiiContent() {
  277. // We can identify the live-blogging post by checking if Live Blogging plugin is activated and the shortcode in the content.
  278. // The related items will show in such live blogging post only one time generally,
  279. // but if the theme call the filter on 'the_content' hook or run another 'The Loop' to fetch the post content using in some other cases before to display,
  280. // the related items will not show.
  281. // In brief, the related items show one time at most in each post.
  282. global $post;
  283. if (array_key_exists($post->ID, $this->excludePostIds)) {
  284. return false;
  285. }
  286. global $shortcode_tags; // Container for storing shortcode tags and their hook to call for the shortcode
  287. if (!empty($shortcode_tags) && is_array($shortcode_tags)
  288. && array_key_exists('liveblog', $shortcode_tags) && strpos(get_the_content(), '[liveblog]') !== false) {
  289. $this->excludePostIds[$post->ID] = 1;
  290. }
  291. return get_post_status($post->ID) == 'publish' &&
  292. get_post_type() == 'post' && // In some pages e.g. "attachment page" should not display related items
  293. empty($post->post_password) &&
  294. !is_preview() && // When create a new post and press the preview button before publish it,
  295. // the post's permalink is not the correct form as the setting in "Permalink".
  296. // We have to prevent the related items displaying in these pages.
  297. !is_feed() &&
  298. !is_page() && // In some pages e.g. "about me" also should not display.
  299. (is_single() || !$this->getAdminOption(self::SINGLE_PAGE_ONLY));
  300. }
  301. private function resetAdminOptions () {
  302. $this->adminOptions = array(
  303. self::NUM_POSTS => 8,
  304. self::SINGLE_PAGE_ONLY => true,
  305. self::DISPLAY_IN_FEED => true,
  306. self::ENABLE_CUSTOM_POS => false,
  307. self::SCRIPT_IN_FOOTER => true,
  308. self::WUMII_COMMENT_PLUGIN_ENABLED => false);
  309. }
  310. private function popNotifyMessage() {
  311. $notifyMessage = get_option(self::NOTIFY_MESSAGE_CONTAINER);
  312. if ($notifyMessage) {
  313. update_option(self::NOTIFY_MESSAGE_CONTAINER, '');
  314. }
  315. return $notifyMessage;
  316. }
  317. // This function is always executed by one user(admin).So no synchronization problem may occur.
  318. private function pushNotifyMessage($message, $type = 'updated') {
  319. if ($legacyMessage = get_option(self::NOTIFY_MESSAGE_CONTAINER)) {
  320. echo 'NOTIFY_MESSAGE_CONTAINER is not empty, legacy message: ' . $legacyMessage->getMessage();
  321. return false;
  322. }
  323. update_option(self::NOTIFY_MESSAGE_CONTAINER, new Wumii_Notify_Message($message, $type));
  324. }
  325. private function setVerificationCode($code) {
  326. update_option(self::VERIFICATION_CODE, $code);
  327. }
  328. private function getVerificationCode() {
  329. return get_option(self::VERIFICATION_CODE);
  330. }
  331. private function saveAdminOptions() {
  332. update_option(self::ADMIN_OPTION_NAME, $this->adminOptions);
  333. }
  334. private function getAdminOption($key) {
  335. return $this->adminOptions[$key];
  336. }
  337. // echo true will be 1, echo false will be 0
  338. // But echo !true will be null. So it have to strictly convert false to '0'.
  339. private function getBooleanInStr($boolean) {
  340. return $boolean ? '1' : '0';
  341. }
  342. private function addReplacementsForCheckboxState($replacementsArr, $checkboxOptionNames) {
  343. if (!is_array($checkboxOptionNames)) {
  344. return false;
  345. }
  346. foreach ($checkboxOptionNames as $optionName) {
  347. $checkState = $this->getAdminOption($optionName);
  348. $replacementsArr[$optionName . '_checked_' . $this->getBooleanInStr($checkState)] = 'checked="checked"';
  349. $replacementsArr[$optionName . '_checked_' . $this->getBooleanInStr(!$checkState)] = '';
  350. }
  351. return $replacementsArr;
  352. }
  353. private function printHtmlAdminOptionsPage() {
  354. $adminOptionTemplate = new Wumii_Template('adminOptionsPanel.html');
  355. $replacements = array('request_uri' => $_SERVER["REQUEST_URI"]);
  356. $replacements = $this->addReplacementsForCheckboxState($replacements,
  357. array(self::SINGLE_PAGE_ONLY,
  358. self::DISPLAY_IN_FEED,
  359. self::ENABLE_CUSTOM_POS,
  360. self::SCRIPT_IN_FOOTER,
  361. self::WUMII_COMMENT_PLUGIN_ENABLED));
  362. $numPost = $this->getAdminOption(self::NUM_POSTS);
  363. // We allow the num of related items from 1 to 12.
  364. for ($i = 1; $i <= 12; $i++) {
  365. if ($i == $numPost) {
  366. $replaceStr = 'selected="selected"';
  367. } else {
  368. $replaceStr = '';
  369. }
  370. $replacements['num_posts_selected_' . $i] = $replaceStr;
  371. }
  372. $replacements['verification_code'] = $this->getVerificationCode();
  373. $adminOptionTemplate->addReplacements($replacements);
  374. echo $adminOptionTemplate->render();
  375. }
  376. function printAdminPage() {
  377. $OptionsUpdatedMessage = array();
  378. if (array_key_exists('add_verification_meta', $_POST)) {
  379. // WARNING: This check is not reliable if the theme doesn't call get_header() to fetch the contents of header.php.
  380. // REASON: We don't know in which file of the theme call the function get_header(), although in almost every case themes will call it.
  381. if ($this->isHookFuncInTemplate('header.php', 'wp_head')) {
  382. $code = $_POST[self::VERIFICATION_CODE];
  383. $this->setVerificationCode($code);
  384. if ($code) {
  385. $OptionsUpdatedMessage[] = new Wumii_Notify_Message('已成功添加认证代码,现在请回到<a href="http://www.wumii.com/site/index" target="_blank">无觅网站管理中心</a>,点击“验证”按钮即可完成博客认证。');
  386. }
  387. } else {
  388. $OptionsUpdatedMessage[] = new Wumii_Notify_Message('此主题可能不支持将代码嵌入到header区域,请使用其他方法进行博客认证。', 'error');
  389. }
  390. } else {
  391. if (array_key_exists('update_wumii_settings', $_POST)) {
  392. foreach ($this->adminOptions as $key => $value) {
  393. if (array_key_exists($key, $_POST)) {
  394. $this->adminOptions[$key] = $_POST[$key];
  395. if ($key == self::WUMII_COMMENT_PLUGIN_ENABLED) {
  396. if ($_POST[$key]) {
  397. $this->replaceCommentBox();
  398. } else {
  399. $this->removeCommentBox();
  400. }
  401. }
  402. }
  403. }
  404. $OptionsUpdatedMessage[] = new Wumii_Notify_Message('设置已更新.');
  405. } else if (array_key_exists('reset_wumii_settings', $_POST)) {
  406. $this->resetAdminOptions();
  407. $OptionsUpdatedMessage[] = new Wumii_Notify_Message('设置已重置.');
  408. }
  409. if ($this->adminOptions[self::SCRIPT_IN_FOOTER]
  410. // The wp_footer action is theme-dependent.
  411. // If the theme-defined file footer.php doesn't call wp_footer(), the action will not fire.
  412. && !$this->isScriptInFooterSupported()) {
  413. $OptionsUpdatedMessage[] = new Wumii_Notify_Message('正在使用的主题可能不支持将加载脚本置于文档末尾, 建议不要开启此功能。', 'error');
  414. }
  415. $this->saveAdminOptions();
  416. }
  417. $this->printHtmlNotifyMessage($OptionsUpdatedMessage);
  418. $this->printHtmlAdminOptionsPage();
  419. }
  420. private function removeCommentBox() {
  421. if (has_filter('comments_template', 'wumii_comment')) {
  422. remove_filter('comments_template', 'wumii_comment', $this->commentFilterPriority);
  423. }
  424. }
  425. private function replaceCommentBox() {
  426. if ($this->isCommentPluginEnabled() && !is_plugin_active('wumii-comment/wumii-comment.php')) {
  427. // warn: should stay the same with wumii-comment.php
  428. if (!function_exists('wumii_comment')) {
  429. add_filter('comments_template', 'wumii_comment', is_plugin_active('duoshuo/duoshuo.php') ? 99999 : 10);
  430. function wumii_comment($file) {
  431. global $post;
  432. if (strcmp(get_option('default_comment_status'), 'open') != 0) {
  433. update_option('default_comment_status', 'open');
  434. }
  435. return dirname(__FILE__) . '/comment.php';
  436. }
  437. }
  438. }
  439. }
  440. private function printHtmlNotifyMessage($notifyMessages) {
  441. if (empty($notifyMessages) || !is_array($notifyMessages)) {
  442. return false;
  443. }
  444. foreach($notifyMessages as $msg) {
  445. $type = $msg->getType();
  446. $message = $msg->getMessage();
  447. echo "<div class='$type'><p>$message</p></div>";
  448. }
  449. }
  450. private function isHookFuncInTemplate($template, $func) {
  451. global $wp_version;
  452. $location = '';
  453. if (strcmp($wp_version, '2.7.0') >= 0) {
  454. // Only WordPress >= 2.7.0 support footer.php located in style sheet path
  455. // and it's the first path being checked in wordpress's source code.
  456. $probableLocation = get_stylesheet_directory() . '/' . $template;
  457. if (file_exists($probableLocation)) {
  458. $location = $probableLocation;
  459. }
  460. }
  461. if (!$location) {
  462. $probableLocation = get_template_directory() . '/' . $template;
  463. if (file_exists($probableLocation)) {
  464. $location = $probableLocation;
  465. }
  466. }
  467. // this template doesn't include in current theme and wordpress will use the default template instead.
  468. // Hook function must exist in the default template
  469. if (!$location) {
  470. return true;
  471. }
  472. $contents = file_get_contents($location);
  473. return $contents !== false ? (strpos($contents, $func . '()') !== false) : false;
  474. }
  475. // WARNING: This function is not reliable if theme doesn't call get_footer() to fetch the contents of footer.php.
  476. // REASON: We don't know in which file of the theme call the function get_footer(), although in almost every case themes will call it.
  477. private function isScriptInFooterSupported() {
  478. return $this->isHookFuncInTemplate('footer.php', 'wp_footer');
  479. }
  480. function checkFooterScriptSupportedByTheme($theme) {
  481. if ($this->getAdminOption(self::SCRIPT_IN_FOOTER) && !$this->isScriptInFooterSupported()) {
  482. $this->pushNotifyMessage('此主题不支持将<strong>无觅相关文章脚本</strong>置于文档末尾, 可能会导致相关文章无法显示, 建议关闭此功能.', 'error');
  483. }
  484. }
  485. function doActivation() {
  486. // now script in footer is the default setting and we need to check if it supported when activation.
  487. if (!$this->isScriptInFooterSupported()) {
  488. $this->adminOptions[self::SCRIPT_IN_FOOTER] = false;
  489. $this->saveAdminOptions();
  490. }
  491. $this->pushNotifyMessage('<strong>无觅相关文章插件: </strong>如果您的博客装有缓存(cache)插件, 请在首次启用插件时清空缓存. 另外, 启用插件后无觅爬虫会立刻去获取贵站的文章信息, 这时切记不要停掉插件, 以免影响文章的相关性.装完可来<strong><a href="http://www.wumii.com/site/index" target="_blank">无觅网站管理中心</a></strong>查看收录状况.');
  492. }
  493. function finalize() {
  494. delete_option(self::ADMIN_OPTION_NAME);
  495. delete_option(self::NOTIFY_MESSAGE_CONTAINER);
  496. delete_option(self::VERIFICATION_CODE);
  497. }
  498. function isCommentPluginEnabled() {
  499. return $this->adminOptions[self::WUMII_COMMENT_PLUGIN_ENABLED];
  500. }
  501. }
  502. class Wumii_Notify_Message {
  503. private $message;
  504. private $type;
  505. function __construct($message, $type = 'updated') {
  506. $this->Wumii_Notify_Message($message, $type);
  507. }
  508. function Wumii_Notify_Message($message, $type = 'updated') {
  509. if ($type != 'error') {
  510. $type = 'updated';
  511. }
  512. $this->message = $message;
  513. $this->type = $type;
  514. }
  515. function getMessage() {
  516. return $this->message;
  517. }
  518. function getType() {
  519. return $this->type;
  520. }
  521. }
  522. class Wumii_Template {
  523. private $htmlStrTemplate;
  524. private $keyValuePair = array();
  525. // PHP 5 Constructors
  526. function __construct($templateName) {
  527. $this->Wumii_Template($templateName);
  528. }
  529. // treated as regular method since PHP 5.3.3
  530. function Wumii_Template($templateName) {
  531. $this->htmlStrTemplate = file_get_contents($this->wumii_get_config_file_path() . WumiiRelatedPosts::PLUGIN_PATH . '/templates/' . $templateName);
  532. }
  533. function addReplacements($keyValuePair) {
  534. foreach ($keyValuePair as $key => $value) {
  535. $this->keyValuePair[$this->getReplacementStr($key)] = $value;
  536. }
  537. }
  538. function render() {
  539. return str_replace(array_keys($this->keyValuePair), array_values($this->keyValuePair), $this->htmlStrTemplate);
  540. }
  541. private function getReplacementStr($key) {
  542. return '{{' . $key . '}}';
  543. }
  544. private function wumii_get_config_file_path() {
  545. $pathname = $_SERVER['SCRIPT_FILENAME'];
  546. preg_match("/^(.+)wp-admin/Ui", $pathname, $matches);
  547. // Here if $matches[0] == 'C:/workspace/www/wordpress/wordpress/wp-admin', than matches[1] == 'C:/workspace/www/wordpress/wordpress/'.
  548. return $matches[1];
  549. }
  550. }
  551. $wumii_incompatible_plugins_in_rss = array('ozh-better-feed/wp_ozh_betterfeed.php',
  552. 'rejected-wp-keyword-link-rejected/wp_keywordlink.php');
  553. $wumii_incompatible_plugins_in_content = array('markdown-for-wordpress-and-bbpress/markdown.php');
  554. function wumii_has_incompatible_plugins($incompatiblePlugins = array()) {
  555. foreach($incompatiblePlugins as $plugin) {
  556. if (is_plugin_active($plugin)) {
  557. return true;
  558. }
  559. }
  560. return false;
  561. }
  562. require_once(ABSPATH . 'wp-admin/includes/plugin.php');
  563. $wumii_related_posts = new WumiiRelatedPosts();
  564. add_action('wp_head', array($wumii_related_posts, 'echoVerificationMeta'));
  565. add_action('admin_notices', array($wumii_related_posts, 'showNotifyMessage'));
  566. add_action('admin_menu', array($wumii_related_posts, 'registerOptionsPage'));
  567. // We need to place our content as near to the front as possible, so set the priority 1.
  568. add_action('the_content', array($wumii_related_posts, 'addWumiiContent'),
  569. wumii_has_incompatible_plugins($wumii_incompatible_plugins_in_content) ? 99999 : 1);
  570. add_action('switch_theme', array($wumii_related_posts, 'checkFooterScriptSupportedByTheme'));
  571. // function add_filter($tag, $function_to_add, $priority, $num_accepted_args)
  572. add_filter('plugin_action_links', array($wumii_related_posts, 'addPluginActionLinks'), 10, 2);
  573. add_filter('the_excerpt_rss', array($wumii_related_posts, 'addToRssContent'));
  574. // In order to avoid some plugins removing or modifing our related items in rss, we try to delay to add our content as late as possible.
  575. // Default priority is 10.
  576. add_filter('the_content', array($wumii_related_posts, 'addToRssContent'),
  577. wumii_has_incompatible_plugins($wumii_incompatible_plugins_in_rss) ? 99999 : 10);
  578. register_activation_hook(__FILE__, array($wumii_related_posts, 'doActivation'));
  579. register_deactivation_hook(__FILE__, array($wumii_related_posts, 'finalize'));
  580. } else {
  581. function classConflictException() {
  582. echo '<div class="error"><p><strong>插件冲突。</strong>您的博客正在运行一个与“无觅相关文章插件”定义了相同类名的插件,只有在关闭冲突插件以后“无觅相关文章插件”才能正常启用。</p></div>';
  583. }
  584. add_action('admin_notices', 'classConflictException');
  585. }
  586. ?>