WordPress.php 44 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384
  1. <?php
  2. class Duoshuo_WordPress extends Duoshuo_Abstract{
  3. const VERSION = '1.2';
  4. protected static $_instance = null;
  5. /**
  6. *
  7. * @var string
  8. */
  9. public $pluginDirUrl;
  10. /**
  11. *
  12. * @var array
  13. */
  14. protected $errorMessages = array();
  15. protected $EMBED = false;
  16. public $shortName;
  17. public $secret;
  18. protected $_scriptsPrinted = false;
  19. protected static $_defaultOptions = array(
  20. 'duoshuo_debug' => 0,
  21. 'duoshuo_api_hostname' => 'api.duoshuo.com',
  22. 'duoshuo_cron_sync_enabled' => 1,
  23. 'duoshuo_seo_enabled' => 1,
  24. 'duoshuo_postpone_print_scripts'=> 0,
  25. 'duoshuo_cc_fix' => 1,
  26. 'duoshuo_sync_pingback_and_trackback'=> 0,
  27. 'duoshuo_social_login_enabled' => 1,
  28. 'duoshuo_comments_wrapper_intro'=> '',
  29. 'duoshuo_comments_wrapper_outro'=> '',
  30. 'duoshuo_last_log_id' => 0,
  31. 'duoshuo_theme' => 'default',
  32. 'duoshuo_style_patch' => 1,
  33. );
  34. protected function __construct(){
  35. $this->shortName = $this->getOption('short_name');
  36. $this->secret = $this->getOption('secret');
  37. foreach (self::$_defaultOptions as $optionName => $value)
  38. if (get_option($optionName) === false)
  39. update_option($optionName, $value);
  40. $this->pluginDirUrl = plugin_dir_url(__FILE__);
  41. }
  42. /**
  43. *
  44. * @return Duoshuo_WordPress
  45. */
  46. public static function getInstance(){
  47. if (self::$_instance === null)
  48. self::$_instance = new self();
  49. return self::$_instance;
  50. }
  51. public function timezone(){
  52. return get_option('gmt_offset');
  53. }
  54. public function getOption($key){
  55. return get_option('duoshuo_' . $key);
  56. }
  57. public function updateOption($key, $value){
  58. return update_option('duoshuo_' . $key, $value);
  59. }
  60. public function deleteOption($key){
  61. return delete_option('duoshuo_' . $key);
  62. }
  63. public function updateUserMeta($userId, $metaKey, $metaValue){
  64. return function_exists('update_user_meta')
  65. ? update_user_meta($userId, $metaKey, $metaValue)
  66. : update_usermeta($userId, $metaKey, $metaValue);
  67. }
  68. public function getUserMeta($userId, $metaKey, $single = false){
  69. //get_user_meta 从3.0开始有效: get_usermeta($user->ID, $blog_prefix.'capabilities', true);
  70. return function_exists('get_user_meta')
  71. ? get_user_meta($userId, $metaKey, true)
  72. : get_usermeta($userId, $metaKey);
  73. }
  74. public function updateThreadMeta($threadId, $metaKey, $metaValue){
  75. return update_post_meta($threadId, $metaKey, $metaValue);
  76. }
  77. public function threadKey($post){
  78. return $post->post_status == 'inherit'
  79. ? ($post->post_parent ? $post->post_parent : null)
  80. : $post->ID;
  81. }
  82. public function topPost($post){
  83. return $post->post_status == 'inherit'
  84. ? ($post->post_parent ? get_post($post->post_parent) : null)
  85. : $post;
  86. }
  87. public function get_blog_prefix(){
  88. global $wpdb;
  89. return method_exists($wpdb,'get_blog_prefix')
  90. ? $wpdb->get_blog_prefix()
  91. : $wpdb->prefix;
  92. }
  93. public function connected(){
  94. $connected_failed = get_option('duoshuo_connect_failed');
  95. return $connected_failed
  96. ? (time() - $connected_failed > 1800)
  97. : true;
  98. }
  99. public function connectFailed(){
  100. update_option('duoshuo_connect_failed', time());
  101. }
  102. public function normalizeUrl($url){
  103. if (strpos($url, '/') === 0){
  104. $siteurl = get_option('siteurl');
  105. if (strlen($siteurl) >=8 && (false !== $pos = strpos($siteurl, '/', 8)))
  106. $siteurl = substr($siteurl, 0, $pos);
  107. return $siteurl . $url;
  108. }
  109. else{
  110. return $url;
  111. }
  112. }
  113. public function allowedHtml($tags, $context = ''){
  114. if (!isset($tags['img']))
  115. $tags['img'] = array();
  116. $tags['img']['src'] = true;
  117. return $tags;
  118. }
  119. public function setJwtCookie($logged_in_cookie, $expire, $expiration, $user_id, $scheme){
  120. $jwt = $this->jwt($user_id);
  121. $secure = $scheme == 'secure_auth';
  122. $secure_logged_in_cookie = apply_filters('secure_logged_in_cookie', false, $user_id, $secure);
  123. // $httponly = false
  124. //setcookie('duoshuo_token', $jwt, $expire, PLUGINS_COOKIE_PATH, COOKIE_DOMAIN, $secure, true);
  125. setcookie('duoshuo_token', $jwt, $expire, ADMIN_COOKIE_PATH, COOKIE_DOMAIN, $secure);
  126. setcookie('duoshuo_token', $jwt, $expire, COOKIEPATH, COOKIE_DOMAIN, $secure_logged_in_cookie);
  127. if ( COOKIEPATH != SITECOOKIEPATH )
  128. setcookie('duoshuo_token', $jwt, $expire, SITECOOKIEPATH, COOKIE_DOMAIN, $secure_logged_in_cookie);
  129. $this->syncUserToRemote($user_id);
  130. }
  131. public function clearJwtCookie(){
  132. // 3.5版本之前没有定义 YEAR_IN_SECONDS
  133. //setcookie( 'duoshuo_token', ' ', time() - 31536000, PLUGINS_COOKIE_PATH, COOKIE_DOMAIN );
  134. setcookie( 'duoshuo_token', ' ', time() - 31536000, ADMIN_COOKIE_PATH, COOKIE_DOMAIN );
  135. setcookie( 'duoshuo_token', ' ', time() - 31536000, COOKIEPATH, COOKIE_DOMAIN );
  136. if ( COOKIEPATH != SITECOOKIEPATH )
  137. setcookie( 'duoshuo_token', ' ', time() - 31536000, SITECOOKIEPATH, COOKIE_DOMAIN );
  138. }
  139. public function oauthConnect(){
  140. if (!$this->connected())
  141. return ;
  142. if (!isset($_GET['code']))
  143. return false;
  144. try{
  145. $keys = array(
  146. 'code' => $_GET['code'],
  147. 'redirect_uri' => (is_ssl()?'https':'http').'://duoshuo.com/login-callback/',
  148. );
  149. $token = $this->getClient()->getAccessToken('code', $keys);
  150. if ($token['code'] != 0)
  151. return false;
  152. $this->userLogin($token);
  153. }
  154. catch(Duoshuo_Exception $e){
  155. $this->connectFailed();
  156. }
  157. }
  158. public function userLogin($token){
  159. global $wpdb, $error;
  160. nocache_headers();
  161. if (isset($token['user_key'])){//登陆成功
  162. $user = get_user_by('id', $token['user_key']);
  163. $this->updateUserMeta($user->ID, 'duoshuo_access_token', $token['access_token']);
  164. wp_clear_auth_cookie();
  165. wp_set_auth_cookie($user->ID, true, is_ssl());
  166. wp_set_current_user($user->ID);
  167. if (isset($_GET['redirect_to'])){
  168. // wordpress 采用的是redirect_to字段
  169. wp_redirect($_GET['redirect_to']);
  170. exit;
  171. }
  172. }
  173. else{
  174. if (isset($_GET['redirect_to']) && $_GET['redirect_to'] !== admin_url()){// 如果是在内容页登录,无论如何都把用户带回内容页
  175. wp_redirect($_GET['redirect_to']);
  176. exit;
  177. }
  178. else{
  179. $client = new Duoshuo_Client($this->shortName, $this->secret, null, $token['access_token']);
  180. $response = $client->request('GET', 'users/profile', array('user_id'=> $token['user_id']));
  181. if (get_option('users_can_register')){// 如果站点开启注册
  182. // 要求用户输入帐号进行绑定
  183. $query = array(
  184. 'action' => 'register',
  185. //'duoshuo_user_id' => $token['user_id'],
  186. 'duoshuo_access_token'=>$token['access_token'],
  187. );
  188. $this->duoshuoUserId = $token['user_id'];
  189. $registerUrl = site_url( 'wp-login.php?' . http_build_query($query), 'login' );
  190. $error = '<img src="' . $response['response']['avatar_url'] . '" width="50" height="50" style="float:left;margin: 0 0.5em 0 0;" />'
  191. . '<strong>' . esc_html($response['response']['name']) . '</strong>,欢迎!<br />'
  192. . '请绑定已注册的本站帐号;<br />'
  193. . '如果你还没有本站帐号,请<a href="' . esc_url($registerUrl) . '">注册</a>';
  194. }
  195. else{// 如果站点未开启注册
  196. //如果是从wp-login页面发起的请求,就不触发重定向
  197. $error = '<img src="' . $response['response']['avatar_url'] . '" width="50" height="50" style="float:left;margin: 0 0.5em 0 0;" />'
  198. . '<strong>' . esc_html($response['response']['name']) . '</strong>,欢迎!<br />'
  199. . '你还没有和本站的用户帐号绑定,<br />'
  200. . '如果你已经注册,请先登录之后绑定社交帐号';
  201. }
  202. }
  203. }
  204. }
  205. public function bindUser($user_login, $user = null){
  206. // 早期版本wp_login接口只有第一个参数
  207. if (empty($user)){
  208. $user = get_user_by('login', $user_login);
  209. }
  210. if (isset($_POST['duoshuo_user_id'])){
  211. $query = array(
  212. 'master_user_id'=> $_POST['duoshuo_user_id'],
  213. 'jwt' => $this->jwt($user->ID),
  214. 'redirect_uri' => admin_url(),
  215. );
  216. wp_redirect((is_ssl()?'https':'http').'://duoshuo.com/merge/?'. http_build_query($query, null, '&'));
  217. exit;
  218. }
  219. }
  220. public function userRegisterHook($userId){
  221. if (!$this->connected())
  222. return ;
  223. // WP_User
  224. $user = get_user_by('id', $userId);
  225. try{
  226. if (isset($_POST['user_login']) && isset($_POST['duoshuo_access_token'])){
  227. // 已登录多说帐号,且多说帐号并未与本站user_key绑定
  228. $client = new Duoshuo_Client($this->shortName, $this->secret, null, $_POST['duoshuo_access_token']);
  229. $params = array(
  230. 'user' => $this->packageUser($user),
  231. );
  232. $remoteResponse = $client->request('POST', 'sites/join', $params);
  233. // 不再需要记录duoshuo_user_id
  234. }
  235. else{
  236. // 未登录多说帐号
  237. $this->exportUsers(array($user));
  238. }
  239. }
  240. catch(Duoshuo_Exception $e){
  241. $this->connectFailed();
  242. }
  243. }
  244. public function originalCommentsNotice(){
  245. echo '<div class="updated">'
  246. . '<p>多说正在努力地为您的网站提供强大的社会化评论服务,WordPress原生评论数据现在仅用于备份;</p>'
  247. . '<p>多说会将每一条评论实时写回本地数据库,您在多说删除/审核了评论,也同样会同步到本地数据;</p>'
  248. . '<p>您在本页做的任何管理评论操作,都不会对多说评论框上的评论起作用,请访问<a href="http://' . $this->shortName . '.' . self::DOMAIN . '/admin/" target="_blank">评论管理后台</a>进行评论管理。</p>'
  249. . '</div>';
  250. }
  251. /**
  252. *
  253. * @return Duoshuo_Client
  254. */
  255. public function getClient($userId = 0){ //如果不输入参数,就是游客
  256. if ($userId !== null){
  257. $accessToken = $this->getUserMeta($userId, 'duoshuo_access_token');
  258. if (is_string($accessToken))
  259. $client = new Duoshuo_Client($this->shortName, $this->secret, $this->jwt($userId), $accessToken);
  260. }
  261. if (!isset($client))
  262. $client = new Duoshuo_Client($this->shortName, $this->secret, $this->jwt($userId));
  263. $apiHostname = $this->getOption('api_hostname');
  264. if ($apiHostname)
  265. $client->end_point = 'http://' . $apiHostname . '/';
  266. return $client;
  267. }
  268. public function config(){
  269. /*if ($_SERVER['REQUEST_METHOD'] == 'POST' && !($this->shortName && $this->secret)){
  270. self::registerSite();
  271. }*/
  272. include dirname(__FILE__) . '/config.php';
  273. }
  274. public function sync(){
  275. include dirname(__FILE__) . '/sync.php';
  276. }
  277. public function manage(){
  278. include dirname(__FILE__) . '/manage.php';
  279. }
  280. public function themes(){
  281. include dirname(__FILE__) . '/themes.php';
  282. }
  283. public function preferences(){
  284. include dirname(__FILE__) . '/preferences.php';
  285. }
  286. public function checkDependency($name){
  287. global $wp_version;
  288. switch ($name){
  289. case 'php':
  290. return array(PHP_VERSION, version_compare(PHP_VERSION, '5.3.0', '<') ? '建议升级php到5.3或以上' : true);
  291. case 'wordpress':
  292. return array($wp_version, version_compare($wp_version, '3.3.0', '<') ? '建议升级WordPress到3.3或以上' : true);
  293. case 'json':
  294. if (!extension_loaded('json'))
  295. return array('缺少json扩展', '安装并启用JSON扩展');
  296. return array(true, true);
  297. case 'curl':
  298. if (!extension_loaded('curl'))
  299. return array('缺少curl扩展', '安装并启用curl扩展');
  300. if (!function_exists('curl_init'))
  301. return array('curl_init()被禁用', '启用curl_init()函数');
  302. if (!function_exists('curl_exec'))
  303. return array('curl_exec()被禁用', '启用curl_exec()函数');
  304. return array(true, true);
  305. case 'fopen':
  306. if (!function_exists('fopen'))
  307. return array('fopen()被禁用', '启用fopen()函数');
  308. if (!function_exists('ini_get'))
  309. return array('ini_get()被禁用', '启用ini_get()函数');
  310. if (!ini_get('allow_url_fopen'))
  311. return array('allow_url_fopen被关闭', '在php.ini中设置allow_url_fopen = On');
  312. return array(true, true);
  313. case 'fsockopen':
  314. if (!function_exists('fsockopen'))
  315. return array('fsockopen()被禁用', '启用fsockopen()函数');
  316. return array(true, true);
  317. case 'hash_hmac':
  318. if (!function_exists('hash_hmac'))
  319. return array('hash_hmac()不存在', '升级php到5.3或以上');
  320. return array(true, true);
  321. default:
  322. return array(true, true);
  323. }
  324. }
  325. public function settings(){
  326. include dirname(__FILE__) . '/settings.php';
  327. }
  328. public function statistics(){
  329. include dirname(__FILE__) . '/statistics.php';
  330. }
  331. public function profile(){
  332. include dirname(__FILE__) . '/profile.php';
  333. }
  334. public function reset(){
  335. global $wpdb;
  336. //delete_option('duoshuo_short_name');
  337. // 删除状态有关的值
  338. delete_option('duoshuo_secret');
  339. delete_option('duoshuo_synchronized');
  340. delete_option('duoshuo_connect_failed');
  341. delete_option('duoshuo_notice');
  342. delete_option('duoshuo_sync_lock');
  343. // 删除所有选项
  344. foreach (self::$_defaultOptions as $optionName => $value)
  345. delete_option($optionName);
  346. // WP 2.9 以后支持这个函数
  347. if (function_exists('delete_metadata')){
  348. delete_metadata('user', 0, 'duoshuo_access_token', '', true);
  349. delete_metadata('user', 0, 'duoshuo_user_id', '', true);
  350. delete_metadata('post', 0, 'duoshuo_thread_id', '', true);
  351. delete_metadata('comment', 0, 'duoshuo_parent_id', '', true);
  352. delete_metadata('comment', 0, 'duoshuo_post_id', '', true);
  353. }
  354. //清空comment_agent字段
  355. $wpdb->get_results($wpdb->prepare("update wp_comments set comment_agent='' where comment_agent LIKE '%%Duoshuo/%%'"));
  356. $redirect_url = add_query_arg('message', 'reset', admin_url('admin.php?page=duoshuo'));
  357. wp_redirect($redirect_url);
  358. exit;
  359. }
  360. /**
  361. * 关闭默认的评论,避免spammer
  362. */
  363. public function commentsOpen($open, $post_id = null) {
  364. //if ($this->EMBED || get_post_meta($post_id, 'duoshuo_thread_id', true))
  365. // return false;
  366. $script_name = array_pop( explode( '/', $_SERVER['PHP_SELF'] ) );
  367. if (preg_match('/wp\-comments\-post\.php$/', $script_name) && get_post_meta($post_id, 'duoshuo_status', true) !== 'disabled')
  368. return false;
  369. return $open;
  370. }
  371. public function commentsTemplate($value){
  372. global $wpdb, $post, $comments;
  373. $topPost = $this->topPost($post);
  374. if ($topPost === null) // 可能是inherit 但post_parent=0
  375. return $value;
  376. if ( !( is_singular() && ( have_comments() || 'open' == $topPost->comment_status ) ) ) {
  377. return $value;
  378. }
  379. if (get_post_meta($topPost->ID, 'duoshuo_status', true) == 'disabled')
  380. return $value;
  381. /*
  382. if ( !dsq_is_installed() || !dsq_can_replace() ) {
  383. return $value;
  384. }*/
  385. $threadId = get_post_meta($topPost->ID, 'duoshuo_thread_id', true);
  386. if (empty($threadId) && $this->connected()){
  387. $this->syncUserToRemote($topPost->post_author);
  388. $this->syncPostToRemote($topPost->ID, $topPost);
  389. try{
  390. $comments = $wpdb->get_results($wpdb->prepare("SELECT * FROM $wpdb->comments where comment_post_ID = %d AND comment_agent NOT LIKE '%%Duoshuo/%%' order by comment_ID asc", $topPost->ID));
  391. $this->exportComments($comments);
  392. }
  393. catch(Duoshuo_Exception $e){
  394. $this->connectFailed();
  395. }
  396. }
  397. $this->EMBED = true;
  398. return dirname(__FILE__) . '/comments.php';
  399. // return $value;
  400. }
  401. public function commentsPopupLinkAttributes($attribs){
  402. global $post;
  403. $threadKey = $this->threadKey($post);
  404. if ($threadKey === null) // post_status = inherit, post_parent = 0
  405. return $attribs;
  406. if (has_filter('comments_number', array($this, 'commentsText')))
  407. remove_filter('comments_number', array($this, 'commentsText'));
  408. $attribs .= ' class="ds-thread-count" data-thread-key="' . $threadKey .'"';
  409. return $attribs;
  410. }
  411. public function commentsText($comment_text, $number = null){
  412. global $post;
  413. $threadKey = $this->threadKey($post);
  414. if ($threadKey === null) // post_status = inherit, post_parent = 0
  415. return $comment_text;
  416. $attribs = 'class="ds-thread-count" data-thread-key="' . $threadKey .'"';
  417. if (preg_match('/^<([a-z]+)( .*)?>(.*)<\/([a-z]+)>$/i', $comment_text, $matches) && $matches[1] == $matches[4])
  418. return "<$matches[1] $attribs$matches[2]>$matches[3]</$matches[4]>";
  419. else
  420. return "<span $attribs data-replace=\"1\">$comment_text</span>";
  421. }
  422. public function jwt($userId = null){
  423. if ($userId === null)
  424. $user = wp_get_current_user();
  425. elseif($userId != 0)
  426. $user = get_user_by( 'id', $userId);
  427. if (empty($user) || !$user->ID)
  428. return null;
  429. $token = array(
  430. 'short_name'=> $this->shortName,
  431. 'user_key' => $user->ID,
  432. 'name' => $user->display_name,
  433. );
  434. return self::encodeJWT($token, $this->secret);
  435. }
  436. /**
  437. * @deprecated
  438. * @param string|int $userId
  439. * @return mixed
  440. */
  441. public function userData($userId = null){ // null 代表当前登录用户,0代表游客
  442. if ($userId === null)
  443. $current_user = wp_get_current_user();
  444. elseif($userId != 0)
  445. $current_user = get_user_by( 'id', $userId);
  446. if (isset($current_user) && $current_user->ID) {
  447. $avatar_tag = get_avatar($current_user->ID);
  448. $avatar_data = array();
  449. preg_match('/(src)=((\'|")[^(\'|")]*(\'|"))/i', $avatar_tag, $avatar_data);
  450. $avatar = htmlspecialchars_decode(str_replace(array('"', "'"), '', $avatar_data[2]), ENT_QUOTES);
  451. return array(
  452. 'id' => $current_user->ID,
  453. 'name' => $current_user->display_name,
  454. 'avatar' => $avatar,
  455. 'email' => $current_user->user_email,
  456. );
  457. }
  458. else{
  459. return array();
  460. }
  461. }
  462. public function buildQuery($options = array()){
  463. $query = array(
  464. 'short_name' => $this->shortName,
  465. 'sso' => array(
  466. 'login'=> site_url('wp-login.php', 'login') .'?action=duoshuo_login',
  467. 'logout'=> htmlspecialchars_decode(wp_logout_url(), ENT_QUOTES),
  468. ),
  469. );
  470. if ($theme = $this->getOption('theme'))
  471. $query['theme'] = $theme;
  472. if ($this->getOption('style_patch'))
  473. $query['stylePatch'] = 'wordpress/' . str_replace(' ', '_', function_exists('wp_get_theme') ? wp_get_theme()->get('Name') : get_current_theme());
  474. if (!empty($options))
  475. $query['options'] = $options;
  476. return $query;
  477. }
  478. public function appendScripts(){
  479. if ($this->_scriptsPrinted)
  480. return;
  481. $this->_scriptsPrinted = true;
  482. ?>
  483. <script type="text/javascript">
  484. var duoshuoQuery = <?php echo json_encode($this->buildQuery());?>;
  485. duoshuoQuery.sso.login += '&redirect_to=' + encodeURIComponent(window.location.href);
  486. duoshuoQuery.sso.logout += '&redirect_to=' + encodeURIComponent(window.location.href);
  487. </script>
  488. <!-- Custon duoshuo embed script-->
  489. <script type="text/javascript" src="//www.solomp.com/wp-content/plugins/duoshuo/embed-formatted-v1.2.js" charset="UTF-8" async="async"></script>
  490. <?php if( is_ssl() ){ ?>
  491. <?php } else { ?>
  492. <?php }
  493. }
  494. /**
  495. * 在wp_print_scripts 没有执行的时候执行最传统的代码
  496. */
  497. public function printScripts(){
  498. if ($this->_scriptsPrinted)
  499. return;
  500. $this->_scriptsPrinted = true;
  501. ?>
  502. <script type="text/javascript">
  503. var duoshuoQuery = <?php echo json_encode($this->buildQuery());?>;
  504. duoshuoQuery.sso.login += '&redirect_to=' + encodeURIComponent(window.location.href);
  505. duoshuoQuery.sso.logout += '&redirect_to=' + encodeURIComponent(window.location.href);
  506. (function() {
  507. var ds = document.createElement('script');
  508. ds.type = 'text/javascript';
  509. ds.async = true;
  510. ds.charset = 'UTF-8';
  511. ds.src = (document.location.protocol == 'https:' ? 'https:' : 'http:') + '//www.solomp.com/wp-content/plugins/duoshuo/embed-formatted-v1.2.js';
  512. (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(ds);
  513. })();
  514. </script><?php
  515. }
  516. public function loginForm(){
  517. if (isset($_REQUEST['action']) && $_REQUEST['action'] === 'duoshuo_login' && isset($this->duoshuoUserId)){ // 登录后发现没有本站帐号,输入帐号进行绑定 ?>
  518. <input type="hidden" name="duoshuo_user_id" value="<?php echo $this->duoshuoUserId;?>" />
  519. <?php
  520. }
  521. elseif (isset($_REQUEST['duoshuo_access_token'])){ ?>
  522. <label><input type="checkbox" name="duoshuo_access_token" value="<?php echo $_REQUEST['duoshuo_access_token'];?>" checked="checked" /> 注册后和多说帐号绑定</label>
  523. <?php
  524. }
  525. else{
  526. $redirectUri = add_query_arg(array('action'=>'duoshuo_login', 'redirect_to'=>urlencode(admin_url())), site_url('wp-login.php', 'login'));?>
  527. <div class="ds-login" style="height:40px;"></div>
  528. <?php $this->printScripts();?>
  529. <script>
  530. if (window.duoshuoQuery && duoshuoQuery.sso)
  531. duoshuoQuery.sso.login = <?php echo json_encode($redirectUri);?>;
  532. </script>
  533. <?php
  534. }
  535. }
  536. public function connectSite(){
  537. update_option('duoshuo_short_name', $_GET['short_name']);
  538. update_option('duoshuo_secret', $_GET['secret']);
  539. $this->shortName = $_GET['short_name'];
  540. $this->secret = $_GET['secret'];
  541. ?>
  542. <script>
  543. window.parent.location = <?php echo json_encode(admin_url('admin.php?page=duoshuo'));?>;
  544. </script>
  545. <?php
  546. exit;
  547. }
  548. public function export(){
  549. global $wpdb;
  550. @set_time_limit(0);
  551. @ini_set('memory_limit', '256M');
  552. @ini_set('display_errors', $this->getOption('debug'));
  553. $progress = $this->getOption('synchronized');
  554. if (!$progress || is_numeric($progress))// 之前已经完成了导出流程
  555. $progress = 'user/0';
  556. list($type, $offset) = explode('/', $progress);
  557. try{
  558. switch($type){
  559. case 'user':
  560. $limit = 30;
  561. // 不包括user_login, user_pass
  562. $columns = array('ID', 'user_nicename', 'user_email', 'user_url', 'user_registered', 'display_name');
  563. $users = $wpdb->get_results( $wpdb->prepare("SELECT " . implode(',', $columns) . " FROM $wpdb->users order by ID asc limit %d,%d", $offset, $limit));
  564. $count = $this->exportUsers($users);
  565. break;
  566. case 'post':
  567. $limit = 10;
  568. $columns = array('ID', 'post_author', 'post_date', 'post_date_gmt', 'post_content', 'post_title', 'post_excerpt', 'post_status', 'comment_status', 'ping_status', 'post_name', 'post_modified_gmt', 'guid', 'post_type', 'post_parent');
  569. $posts = $wpdb->get_results( $wpdb->prepare("SELECT " . implode(',', $columns) . " FROM $wpdb->posts where post_type not in ('attachment', 'nav_menu_item', 'revision') and post_status not in ('auto-draft', 'draft', 'trash', 'inherit') order by ID asc limit %d,%d", $offset, $limit) );// 'inherit' 不再进行同步
  570. $count = $this->exportPosts($posts);
  571. break;
  572. case 'comment':
  573. $limit = 50;
  574. $comments = $wpdb->get_results( $wpdb->prepare("SELECT * FROM $wpdb->comments where comment_agent NOT LIKE '%%Duoshuo/%%' order by comment_ID asc limit %d,%d", $offset, $limit));
  575. $count = $this->exportComments($comments);
  576. break;
  577. default:
  578. }
  579. if ($count == $limit){
  580. $progress = $type . '/' . ($offset + $limit);
  581. }
  582. elseif($type == 'user')
  583. $progress = 'post/0';
  584. elseif($type == 'post')
  585. $progress = 'comment/0';
  586. elseif($type == 'comment')
  587. $progress = time();
  588. update_option('duoshuo_synchronized', $progress);
  589. $response = array(
  590. 'progress'=>$progress,
  591. 'code' => 0
  592. );
  593. $this->sendJsonResponse($response);
  594. }
  595. catch(Duoshuo_Exception $e){
  596. $this->sendException($e);
  597. }
  598. }
  599. public function packageOptions(){
  600. global $wp_version;
  601. $options = array(
  602. 'url' => get_option('home'),
  603. 'siteurl' => get_option('siteurl'),
  604. 'admin_email' => get_option('admin_email'),
  605. 'timezone' => get_option('timezone_string'),
  606. 'use_smilies' => get_option('use_smilies'),
  607. 'name' => html_entity_decode(get_option('blogname'), ENT_QUOTES, 'UTF-8'),
  608. 'description' => html_entity_decode(get_option('blogdescription'), ENT_QUOTES, 'UTF-8'),
  609. 'system_theme' => function_exists('wp_get_theme') ? wp_get_theme()->get('Name') : get_current_theme(),//'current_theme'=>'system_theme',
  610. 'system_version'=> $wp_version,
  611. 'plugin_version'=> self::VERSION,
  612. 'local_api_url' => $this->pluginDirUrl . 'api.php',
  613. 'oauth_proxy_url'=> $this->pluginDirUrl . 'oauth-proxy.php',
  614. );
  615. $akismet_api_key = get_option('wordpress_api_key');
  616. if ($akismet_api_key)
  617. $options['akismet_api_key'] = $akismet_api_key;
  618. return $options;
  619. }
  620. /**
  621. * 通知多说服务器更新站点信息
  622. */
  623. public function updateSite(){
  624. if (!$this->connected())
  625. return;
  626. $params = $this->packageOptions();
  627. $user = wp_get_current_user();
  628. try{
  629. $response = $this->getClient($user->ID)->request('POST', 'sites/settings', $params);
  630. if (is_string($response)){
  631. $this->errorMessages[] = $response;
  632. }
  633. elseif(isset($response['code']) && $response['code'] != 0){
  634. $this->errorMessages[] = $response['errorMessage'];
  635. }
  636. }
  637. catch(Duoshuo_Exception $e){
  638. $this->connectFailed();
  639. }
  640. }
  641. /*
  642. public function updatedOption($option, $oldvalue = null, $newvalue = null){
  643. $options = array('blogname', 'blogdescription', 'home', 'siteurl', 'admin_email', 'timezone_string', 'use_smilies', 'system_theme', 'akismet_api_key');
  644. if (in_array($option, $options))
  645. $this->needToUpdateSite = true;
  646. }*/
  647. public function syncUserToRemote($userId){
  648. if (!$this->connected())
  649. return ;
  650. // WP_User
  651. $userData = get_user_by('id', $userId);
  652. try{
  653. $this->exportUsers(array($userData));
  654. }
  655. catch(Duoshuo_Exception $e){
  656. $this->connectFailed();
  657. }
  658. }
  659. /**
  660. * 同步这篇文章到所有社交网站
  661. * @param string $postId
  662. */
  663. public function syncPostToRemote($postId, $post = null){
  664. if (!$this->connected())
  665. return;
  666. if ($post == null)
  667. $post = get_post($postId);
  668. if (in_array($post->post_type, array('nav_menu_item', 'revision', 'attachment'))
  669. || in_array($post->post_status, array('inherit', 'auto-draft', 'draft', 'trash'))) //'inherit' 不再进行同步
  670. return ;
  671. $params = $this->packageThread($post);
  672. if (isset($_POST['sync_to'])){
  673. if ($_POST['sync_to'][0] == 'placeholder')
  674. unset($_POST['sync_to'][0]);
  675. $params['sync_to'] = implode(',', $_POST['sync_to']);
  676. }
  677. try{
  678. $response = $this->getClient($post->post_author)->request('POST', 'threads/sync', $params);
  679. unset($_POST['sync_to']); //避免某些插件多次触发save_post
  680. if (is_array($response) && isset($response['code']) && $response['code'] == 0 && isset($response['response']))
  681. update_post_meta($post->ID, 'duoshuo_thread_id', $response['response']['thread_id']);
  682. }
  683. catch(Duoshuo_Exception $e){
  684. $this->connectFailed();
  685. }
  686. }
  687. public function packageUser($user){
  688. static $roleMap = array(
  689. 'administrator' => 'administrator',
  690. 'editor' => 'editor',
  691. 'author' => 'author',
  692. 'contributor' => 'user',
  693. 'subscriber' => 'user',
  694. );
  695. if ($user instanceof WP_User){ // wordpress 3.3
  696. $userData = $user->data;
  697. unset($userData->user_pass);
  698. unset($userData->user_login);
  699. $capabilities = $user->caps;
  700. }
  701. else{
  702. $userData = $user;
  703. unset($userData->user_pass);
  704. unset($userData->user_login);
  705. $capabilities = $this->getUserMeta($user->ID, $this->get_blog_prefix().'capabilities', true);
  706. }
  707. $data = array(
  708. 'user_key' => $userData->ID,
  709. 'name' => $userData->display_name,
  710. 'email' => $userData->user_email,
  711. 'url' => $userData->user_url,
  712. 'created_at'=> $userData->user_registered,
  713. 'meta' => json_encode($userData),
  714. );
  715. $avatar_data = array();
  716. if (preg_match('/(src)=((\'|")[^(\'|")]*(\'|"))/i', get_avatar($userData->ID), $avatar_data))
  717. $data['avatar_url'] = htmlspecialchars_decode(str_replace(array('"', "'"), '', $avatar_data[2]), ENT_QUOTES);
  718. foreach($roleMap as $wpRole => $role)
  719. if (isset($capabilities[$wpRole]) && $capabilities[$wpRole]){
  720. $data['role'] = $role;
  721. break;
  722. }
  723. return $data;
  724. }
  725. public function packageThread($post){
  726. $post->custom = get_post_custom($post->ID);
  727. $meta = clone ($post);
  728. unset($meta->post_title);
  729. unset($meta->post_content);
  730. unset($meta->post_excerpt);
  731. unset($meta->post_date_gmt);
  732. unset($meta->post_modified_gmt);
  733. unset($meta->post_name);
  734. unset($meta->post_status);
  735. unset($meta->comment_status);
  736. unset($meta->ping_status);
  737. unset($meta->guid);
  738. unset($meta->post_type);
  739. unset($meta->post_author);
  740. unset($meta->ID);
  741. $params = array(
  742. 'thread_key'=> $post->ID,
  743. 'author_key'=> $post->post_author,
  744. 'title' => html_entity_decode($post->post_title, ENT_QUOTES, 'UTF-8'),
  745. 'content' => $post->post_content,
  746. 'excerpt' => $post->post_excerpt,
  747. 'created_at'=> mysql2date('Y-m-d\TH:i:s+00:00', $post->post_date_gmt),
  748. 'updated_at'=> mysql2date('Y-m-d\TH:i:s+00:00', $post->post_modified_gmt),
  749. 'ip' => $_SERVER['REMOTE_ADDR'],
  750. 'url' => get_permalink($post),
  751. 'slug' => $post->post_name,
  752. 'status' => $post->post_status,
  753. 'comment_status'=> $post->comment_status,
  754. 'ping_status'=> $post->ping_status,
  755. 'guid' => $post->guid,
  756. 'type' => $post->post_type,
  757. 'meta' => json_encode($meta),
  758. 'source' => 'wordpress',
  759. );
  760. if (!class_exists('nggLoader', false) || class_exists('nggRewrite', false))
  761. $params['filtered_content'] = str_replace(']]>', ']]&gt;', apply_filters('the_content', $post->post_content));
  762. if (function_exists('get_post_thumbnail_id')){ // WordPress 2.9开始支持
  763. $post_thumbnail_id = get_post_thumbnail_id( $post->ID );
  764. if ( $post_thumbnail_id ) {
  765. $params['thumbnail'] = $this->normalizeUrl(wp_get_attachment_url($post_thumbnail_id));
  766. //$image = wp_get_attachment_image_src( $post_thumbnail_id, $size, false);
  767. //list($src, $width, $height) = $image;
  768. //$meta = wp_get_attachment_metadata($id);
  769. //'large-feature'
  770. //'post-thumbnail'
  771. }
  772. }
  773. $args = array(
  774. 'post_parent' => $post->ID,
  775. 'post_status' => 'inherit',
  776. 'post_type' => 'attachment',
  777. 'post_mime_type' => 'image',
  778. 'order' => 'ASC',
  779. 'orderby' => 'menu_order ID'
  780. );
  781. $images = array();
  782. $children = get_children($args);
  783. if (is_array($children))
  784. foreach($children as $attachment)
  785. $images[] = $this->normalizeUrl(wp_get_attachment_url($attachment->ID));
  786. if (!empty($images))
  787. $params['images'] = json_encode($images);
  788. /*
  789. $authorId = $this->getUserMeta($post->post_author, 'duoshuo_user_id', true);
  790. if (!empty($authorId))
  791. $params['author_id'] = $authorId;
  792. $threadId = get_post_meta($post->ID, 'duoshuo_thread_id', true);
  793. if (!empty($threadId))
  794. $params['thread_id'] = $threadId;*/
  795. return $params;
  796. }
  797. public function packageComment($comment){
  798. static $statusMap = array(
  799. '0' => 'pending',
  800. '1' => 'approved',
  801. 'trash' => 'deleted',
  802. 'spam' => 'spam',
  803. 'post-trashed'=>'thread-deleted',
  804. );
  805. $meta = clone ($comment);
  806. unset($meta->comment_ID);
  807. unset($meta->comment_post_ID);
  808. unset($meta->comment_author);
  809. unset($meta->comment_author_email);
  810. unset($meta->comment_author_url);
  811. unset($meta->comment_author_IP);
  812. unset($meta->comment_date_gmt);
  813. unset($meta->comment_content);
  814. unset($meta->comment_karma);
  815. unset($meta->comment_approved);
  816. unset($meta->comment_agent);
  817. unset($meta->comment_type);
  818. unset($meta->comment_parent);
  819. unset($meta->user_id);
  820. $data = array(
  821. 'thread_key' => $comment->comment_post_ID,
  822. 'post_key' => $comment->comment_ID,
  823. 'author_key' => $comment->user_id,
  824. 'author_name' => htmlspecialchars_decode($comment->comment_author, ENT_QUOTES),
  825. 'author_email' => $comment->comment_author_email,
  826. 'author_url' => $comment->comment_author_url,
  827. 'created_at' => str_replace(' ', 'T', $comment->comment_date_gmt) . '+00:00',
  828. 'message' => $comment->comment_content,
  829. 'agent' => $comment->comment_agent,
  830. 'type' => $comment->comment_type,
  831. 'ip' => $comment->comment_author_IP,
  832. 'status' => $statusMap[$comment->comment_approved],
  833. 'parent_key' => $comment->comment_parent, // TODO 接收的地方要处理一下
  834. 'meta' => json_encode($meta), // comment_date, comment_karma
  835. );
  836. //'source' => 'import',
  837. return $data;
  838. }
  839. public function exportOneComment($comment_ID){
  840. $comment = get_comment($comment_ID);
  841. return $this->exportComments(array($comment));
  842. }
  843. /**
  844. * 从服务器pull评论到本地
  845. *
  846. * @param array $posts
  847. */
  848. public function createPost($post){
  849. global $wpdb;
  850. // 将img加到白名单中,仅对WordPress 3.5.0以后有效
  851. if (!has_filter('wp_kses_allowed_html', array($this, 'allowedHtml')))
  852. add_filter('wp_kses_allowed_html', array($this, 'allowedHtml'));
  853. static $approvedMap = array(
  854. 'pending' => '0',
  855. 'approved' => '1',
  856. 'deleted' => 'trash',
  857. 'spam' => 'spam',
  858. 'thread-deleted'=>'post-trashed',
  859. );
  860. $post_id = isset($post['thread_key'])
  861. ? $post['thread_key']
  862. : $wpdb->get_var("SELECT post_id FROM $wpdb->postmeta WHERE meta_key = 'duoshuo_thread_id' AND meta_value = $post[thread_id]");
  863. if (!is_numeric($post_id)) // 找不到对应的文章
  864. return array();
  865. $data = array(
  866. 'comment_author' => trim(strip_tags($post['author_name'])),
  867. 'comment_author_email'=>$post['author_email'],
  868. 'comment_author_url'=> $post['author_url'],
  869. 'comment_author_IP' => $post['ip'],
  870. 'comment_date' => $this->rfc3339_to_mysql($post['created_at']),
  871. 'comment_date_gmt' => $this->rfc3339_to_mysql_gmt($post['created_at']),
  872. 'comment_content' => $post['message'],
  873. 'comment_approved' => $approvedMap[$post['status']],
  874. 'comment_agent' => 'Duoshuo/' . self::VERSION . ':' . $post['post_id'],
  875. 'comment_type' => $post['type'],
  876. 'comment_post_ID' => $post_id,
  877. //'comment_karma'
  878. );
  879. if ($post['parent_id']){
  880. $parent_id = $wpdb->get_var( "SELECT comment_ID FROM $wpdb->commentmeta WHERE meta_key = 'duoshuo_post_id' AND meta_value = '$post[parent_id]'");
  881. if (isset($parent_id))
  882. $data['comment_parent'] = $parent_id;
  883. }
  884. $author_id = isset($post['author_key'])
  885. ? $post['author_key']
  886. : $wpdb->get_var( "SELECT user_id FROM $wpdb->usermeta WHERE meta_key = 'duoshuo_user_id' AND meta_value = $post[author_id]");
  887. if (is_numeric($author_id))
  888. $data['user_id'] = $author_id;
  889. if (isset($post['post_key'])){
  890. $data['comment_ID'] = $post['post_key'];
  891. }
  892. elseif(isset($post['post_id'])){
  893. $data['comment_ID'] = $wpdb->get_var( "SELECT comment_ID FROM $wpdb->commentmeta WHERE meta_key = 'duoshuo_post_id' AND meta_value = '$post[post_id]'");
  894. }
  895. if(isset($data['comment_ID'])){
  896. // wp_update_comment 中会做 wp_filter_comment
  897. wp_update_comment($data);
  898. }
  899. else{
  900. $data = wp_filter_comment($data);
  901. $data['comment_ID'] = wp_insert_comment($data);
  902. }
  903. if ($post['parent_id'])
  904. update_comment_meta($data['comment_ID'], 'duoshuo_parent_id', $post['parent_id']);
  905. else
  906. delete_comment_meta($data['comment_ID'], 'duoshuo_parent_id');
  907. update_comment_meta($data['comment_ID'], 'duoshuo_post_id', $post['post_id']);
  908. return array($post_id);
  909. }
  910. public function deleteForeverPost($postIdArray){
  911. global $wpdb;
  912. $commentIdArray = $wpdb->get_col( "SELECT comment_ID FROM $wpdb->commentmeta WHERE meta_key = 'duoshuo_post_id' AND meta_value IN ('" . implode("', '", $postIdArray) . "')");
  913. if (count($commentIdArray)){
  914. $commentIdArray = $wpdb->get_col( "SELECT comment_ID FROM $wpdb->comments WHERE comment_ID IN ('" . implode("', '", $commentIdArray) . "')");
  915. foreach ($commentIdArray as $commentId)
  916. wp_delete_comment($commentId, true);
  917. }
  918. return array();
  919. }
  920. public function deletePost($postIdArray){
  921. global $wpdb;
  922. $commentIdArray = $wpdb->get_col( "SELECT comment_ID FROM $wpdb->commentmeta WHERE meta_key = 'duoshuo_post_id' AND meta_value IN ('" . implode("', '", $postIdArray) . "')");
  923. if (count($commentIdArray)){
  924. $commentIdArray = $wpdb->get_col( "SELECT comment_ID FROM $wpdb->comments WHERE comment_ID IN ('" . implode("', '", $commentIdArray) . "')");
  925. foreach ($commentIdArray as $commentId)
  926. wp_trash_comment($commentId);
  927. }
  928. return array();
  929. }
  930. public function spamPost($postIdArray){
  931. global $wpdb;
  932. $commentIdArray = $wpdb->get_col( "SELECT comment_ID FROM $wpdb->commentmeta WHERE meta_key = 'duoshuo_post_id' AND meta_value IN ('" . implode("', '", $postIdArray) . "')");
  933. if (count($commentIdArray)){
  934. $commentIdArray = $wpdb->get_col( "SELECT comment_ID FROM $wpdb->comments WHERE comment_ID IN ('" . implode("', '", $commentIdArray) . "')");
  935. foreach($commentIdArray as $commentId)
  936. wp_spam_comment($commentId);
  937. }
  938. return array();
  939. }
  940. public function approvePost($postIdArray){
  941. global $wpdb;
  942. $commentIdArray = $wpdb->get_col( "SELECT comment_ID FROM $wpdb->commentmeta WHERE meta_key = 'duoshuo_post_id' AND meta_value IN ('" . implode("', '", $postIdArray) . "')");
  943. if (count($commentIdArray)){
  944. $commentIdArray = $wpdb->get_col( "SELECT comment_ID FROM $wpdb->comments WHERE comment_ID IN ('" . implode("', '", $commentIdArray) . "')");
  945. foreach ($commentIdArray as $commentId)
  946. wp_set_comment_status($commentId, 'approve');
  947. }
  948. return array();
  949. }
  950. public function notices(){
  951. foreach($this->errorMessages as $message)
  952. echo '<div class="updated"><p><strong>'.$message.'</strong></p></div>';
  953. $duoshuo_notice = $this->getOption('notice');
  954. if (!empty($duoshuo_notice)){//系统推送的通知
  955. echo '<div class="updated">'.$duoshuo_notice.'</div>';
  956. }
  957. elseif ($duoshuo_notice === false){
  958. update_option('duoshuo_notice', '');
  959. }
  960. $messages = array(
  961. 'registered'=>'<strong>注册成功,请同步数据</strong>',
  962. 'reset' =>'<strong>已重置</strong>',
  963. );
  964. if (isset($_GET['message']) && isset($messages[$_GET['message']]))
  965. echo '<div class="updated"><p>'.$messages[$_GET['message']].'</p></div>';
  966. }
  967. public function showException($e){
  968. echo '<div class="updated fade"><p>' . $e->getMessage() . '</p></div>';
  969. }
  970. public function sendException($e){
  971. $response = array(
  972. 'code' => $e->getCode(),
  973. 'errorMessage'=>$e->getMessage(),
  974. );
  975. echo json_encode($response);
  976. exit;
  977. }
  978. public function sendJsonResponse($response){
  979. if (!headers_sent()) {
  980. nocache_headers();
  981. header('Content-type: application/json; charset=UTF-8');
  982. }
  983. echo json_encode($response);
  984. exit;
  985. }
  986. //发布文章时候的同步设置
  987. public function syncOptions(){
  988. global $post;
  989. switch($post->post_status){
  990. case 'auto-draft':
  991. case 'inherit':
  992. case 'draft':
  993. case 'trash':
  994. break;
  995. case 'publish':
  996. break;
  997. default:
  998. }
  999. $query = array(
  1000. 'callback' => 'getSyncOptionsCallback',
  1001. //'require' => 'site,visitor,serverTime',
  1002. 'jwt' => $this->jwt(),
  1003. );
  1004. if ($post->ID)
  1005. $query['thread_key'] = $post->ID;
  1006. $jsonpUrl = (is_ssl()?'https':'http').'://' . $this->shortName . '.duoshuo.com/api/users/syncOptions.jsonp?' . http_build_query($query, null, '&');
  1007. ?>
  1008. <script>
  1009. function getSyncOptionsCallback(rsp){
  1010. var serviceNames = {
  1011. 'weibo' : '新浪微博',
  1012. 'qq' : 'QQ',
  1013. 'qzone' : 'QQ空间',
  1014. 'qqt' : '腾讯微博',
  1015. 'renren' : '人人网',
  1016. 'douban' : '豆瓣网',
  1017. 'msn' : 'MSN',
  1018. 'netease' : '网易微博',
  1019. 'kaixin' : '开心网',
  1020. 'sohu' : '搜狐微博',
  1021. 'baidu' : '百度',
  1022. 'taobao' : '淘宝网',
  1023. 'google' : '谷歌'
  1024. },
  1025. html = '';
  1026. if (!rsp.response){
  1027. html += '<p>你还没有绑定社交帐号,绑定后即可同时发布微博</p>';
  1028. }
  1029. else{
  1030. html += '<input type="hidden" name="sync_to[]" value="placeholder" />\
  1031. <ul class="ds-connected-sites">';
  1032. jQuery.each(rsp.response, function(key, info){
  1033. var service = key.split('_')[1];
  1034. html += '\
  1035. <li><label>\
  1036. <input type="checkbox" name="sync_to[]" value="' + key + '"' + (info.checked ? ' checked="checked"' : '') + (info.expired ? ' disabled="disabled" style="visibility:hidden;"' : '') + '/>\
  1037. <span class="service-icon icon-' + service + '"></span>'
  1038. + serviceNames[service]
  1039. + (info.avatar_url ? '<img src="' + info.avatar_url + '" alt="' + info.name + '" style="width:16px;height:16px;" />' : '')
  1040. + info.name
  1041. + (info.expired ? '(<a href="<?= is_ssl()?'https':'http' ?>://duoshuo.com/settings/accounts/" target="_blank">已过期,请更新授权</a>)' : '')
  1042. + '</label>\
  1043. </li>';
  1044. });
  1045. html += '<li><label><input type="checkbox" onchange="var c = this.checked;jQuery(\'.ds-connected-sites :checkbox\').each(function(){this.checked = c});" /> 全选</label></li>\
  1046. </ul>\
  1047. <p>温馨提示:系统会优先采用文章摘要来发布微博</p>';
  1048. }
  1049. html += '<p><a href="<?php echo admin_url('admin.php?page=duoshuo-profile');?>">绑定更多社交网站</a></p>';
  1050. jQuery('#duoshuo-sidebox .inside').html(html);
  1051. }
  1052. (function() {
  1053. var ds = document.createElement('script');
  1054. ds.type = 'text/javascript';
  1055. ds.async = true;
  1056. ds.charset = 'UTF-8';
  1057. ds.src = '<?php echo $jsonpUrl;?>';
  1058. (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(ds);
  1059. })();
  1060. </script>
  1061. <?php
  1062. }
  1063. public function commentStatusMetaBoxOptions($post){?>
  1064. <br /><input name="duoshuo_status" type="hidden" value="enabled" />
  1065. <label for="duoshuo_status" class="selectit"><input name="duoshuo_status" type="checkbox" id="duoshuo_status" value="disabled" <?php checked(get_post_meta($post->ID, 'duoshuo_status', true), 'disabled'); ?> /> <?php _e( '这个页面不启用多说评论框' ); ?></label>
  1066. <?php
  1067. }
  1068. public function savePostDuoshuoStatus($postId){
  1069. if (isset($_POST['duoshuo_status'])){
  1070. if ($_POST['duoshuo_status'] == 'disabled')
  1071. update_post_meta($postId, 'duoshuo_status', 'disabled');
  1072. else
  1073. delete_post_meta($postId, 'duoshuo_status');
  1074. }
  1075. }
  1076. public function managePostComments($post){
  1077. //这里应该嵌入一个iframe框
  1078. }
  1079. public function syncLogAction(){
  1080. @set_time_limit(0);
  1081. @ini_set('memory_limit', '256M');
  1082. @ini_set('display_errors', $this->getOption('debug'));
  1083. try{
  1084. $response = array(
  1085. 'count' => $this->syncLog(),
  1086. 'code' => 0
  1087. );
  1088. $this->sendJsonResponse($response);
  1089. }
  1090. catch(Duoshuo_Exception $e){
  1091. if ($e->getCode() == Duoshuo_Exception::REQUEST_TIMED_OUT){
  1092. $this->connectFailed();
  1093. $this->updateOption('sync_lock', 0);
  1094. }
  1095. $this->sendException($e);
  1096. }
  1097. }
  1098. public function actionsFilter($actions){
  1099. /**
  1100. * TODO
  1101. $actions['ds-comments'] = '<a href="javascript:void(0);">管理评论</a>';
  1102. */
  1103. return $actions;
  1104. }
  1105. public function pluginActionLinks($links, $file) {
  1106. if (empty($this->shortName) || empty($this->secret)) // 如果已经设置好了站点信息,就不显示安装 || !is_numeric($this->getOption('synchronized'))
  1107. array_unshift($links, '<a href="' . admin_url('admin.php?page=duoshuo') . '">'.__('Install').'</a>');
  1108. else
  1109. array_unshift($links, '<a href="' . admin_url('admin.php?page=duoshuo-settings') . '">'.__('Settings').'</a>');
  1110. return $links;
  1111. }
  1112. public function dashboardWidget(){
  1113. if ( !$widget_options = get_option( 'dashboard_widget_options' ) )
  1114. $widget_options = array();
  1115. if ( !isset($widget_options['dashboard_duoshuo']) )
  1116. $widget_options['dashboard_duoshuo'] = array();
  1117. $widgets = get_option( 'dashboard_widget_options' );
  1118. $total_items = isset( $widgets['dashboard_duoshuo'] ) && isset( $widgets['dashboard_duoshuo']['items'] )
  1119. ? absint( $widgets['dashboard_duoshuo']['items'] ) : 5;
  1120. echo '<ul class="ds-recent-comments" data-num-items="' . $total_items . '"></ul>';
  1121. $this->printScripts();
  1122. }
  1123. /**
  1124. * The recent comments dashboard widget control.
  1125. *
  1126. * @since 3.0.0
  1127. */
  1128. public function dashboardWidgetControl() {
  1129. if ( !$widget_options = get_option( 'dashboard_widget_options' ) )
  1130. $widget_options = array();
  1131. if ( !isset($widget_options['dashboard_duoshuo']) )
  1132. $widget_options['dashboard_duoshuo'] = array();
  1133. if ( 'POST' == $_SERVER['REQUEST_METHOD'] && isset($_POST['widget-duoshuo']) ) {
  1134. $number = absint( $_POST['widget-duoshuo']['items'] );
  1135. $widget_options['dashboard_duoshuo']['items'] = $number;
  1136. update_option( 'dashboard_widget_options', $widget_options );
  1137. }
  1138. $number = isset( $widget_options['dashboard_duoshuo']['items'] ) ? (int) $widget_options['dashboard_duoshuo']['items'] : '';
  1139. echo '<p><label for="comments-number">' . __('Number of comments to show:') . '</label>';
  1140. echo '<input id="comments-number" name="widget-duoshuo[items]" type="text" value="' . $number . '" size="3" /></p>';
  1141. }
  1142. public function registerSettings(){
  1143. register_setting('duoshuo', 'duoshuo_short_name');
  1144. register_setting('duoshuo', 'duoshuo_secret');
  1145. foreach (self::$_defaultOptions as $optionName => $value)
  1146. register_setting('duoshuo', $optionName);
  1147. }
  1148. public function updateLocalOptions(){
  1149. foreach (self::$_defaultOptions as $optionName => $value)
  1150. if (isset($_POST[$optionName]))
  1151. update_option($optionName, stripslashes($_POST[$optionName]));
  1152. //stripslashes($_POST['duoshuo_comments_wrapper_intro'])
  1153. //stripslashes($_POST['duoshuo_comments_wrapper_outro'])
  1154. }
  1155. }