/bp-forums/bbpress/xmlrpc.php

  1. <?php 
  2. /** 
  3. * XML-RPC protocol support for bbPress 
  4. * 
  5. * @since 1.0 
  6. * @package bbPress 
  7. */ 
  8.  
  9.  
  10.  
  11. /** 
  12. * Whether this is an XML-RPC Request 
  13. * 
  14. * @since 1.0 
  15. * @var bool 
  16. */ 
  17. define( 'XMLRPC_REQUEST', true ); 
  18.  
  19. // Get rid of cookies sent by some browser-embedded clients 
  20. $_COOKIE = array(); 
  21.  
  22. // A bug in PHP < 5.2.2 makes $HTTP_RAW_POST_DATA not set by default 
  23. if ( !isset( $HTTP_RAW_POST_DATA ) ) { 
  24. $HTTP_RAW_POST_DATA = file_get_contents( 'php://input' ); 
  25.  
  26. // Fix for mozBlog and other cases where '<?xml' isn't on the very first line 
  27. if ( isset( $HTTP_RAW_POST_DATA ) ) { 
  28. $HTTP_RAW_POST_DATA = trim( $HTTP_RAW_POST_DATA ); 
  29.  
  30. // Load bbPress 
  31. require_once( './bb-load.php' ); 
  32.  
  33.  
  34.  
  35. // If the service discovery data is requested then return it and exit 
  36. if ( isset( $_GET['rsd'] ) ) { 
  37. header( 'Content-Type: text/xml; charset=UTF-8', true ); 
  38. echo '<?xml version="1.0" encoding="UTF-8"?'.'>' . "\n"; 
  39. echo '<rsd version="1.0" xmlns="http://archipelago.phrasewise.com/rsd">' . "\n"; 
  40. echo ' <service>' . "\n"; 
  41. echo ' <engineName>bbPress</engineName>' . "\n"; 
  42. echo ' <engineLink>http://bbpress.org/</engineLink>' . "\n"; 
  43. echo ' <homePageLink>' . bb_get_uri() . '</homePageLink>' . "\n"; 
  44. echo ' <apis>' . "\n"; 
  45. echo ' <api name="bbPress" blogID="1" preferred="true" apiLink="' . bb_get_uri( 'xmlrpc.php' ) . '" />' . "\n"; 
  46. echo ' </apis>' . "\n"; 
  47. echo ' </service>' . "\n"; 
  48. echo '</rsd>' . "\n"; 
  49. exit; 
  50.  
  51. // Load the XML-RPC server/client classes 
  52. if ( ! class_exists( 'IXR_Value' ) ) { 
  53. require_once( BACKPRESS_PATH . '/class.ixr.php' ); 
  54.  
  55. /** 
  56. * XML-RPC server class to allow for remote publishing 
  57. * 
  58. * @since 1.0 
  59. * @package bbPress 
  60. * @subpackage Publishing 
  61. * @uses class IXR_Server 
  62. */ 
  63. class BB_XMLRPC_Server extends IXR_Server 
  64. /** 
  65. * Stores the last error generated by the class 
  66. * 
  67. * @since 1.0 
  68. * @var object|boolean An instance of the IXR_Error class or false if no error exists 
  69. */ 
  70. var $error = false; 
  71.  
  72. /** 
  73. * Site options which can be manipulated using XML-RPC 
  74. * 
  75. * @since 1.0 
  76. * @var array 
  77. */ 
  78. var $site_options = array(); 
  79.  
  80. /** 
  81. * Whether read-only methods require authentication 
  82. * 
  83. * @since 1.0 
  84. * @var boolean 
  85. **/ 
  86. var $auth_readonly = false; 
  87.  
  88. /** 
  89. * Whether user switching is allowed 
  90. * 
  91. * @since 1.0 
  92. * @var boolean 
  93. **/ 
  94. var $allow_user_switching = false; 
  95.  
  96. /** 
  97. * Initialises the XML-RPC server 
  98. * 
  99. * @since 1.0 
  100. * @return void 
  101. */ 
  102. function __construct() 
  103. // bbPress publishing API 
  104. if ( bb_get_option( 'enable_xmlrpc' ) ) { 
  105. $this->methods = array( 
  106. // - Demo 
  107. 'demo.sayHello' => 'this:sayHello',  
  108. 'demo.addTwoNumbers' => 'this:addTwoNumbers',  
  109. // - Forums 
  110. 'bb.getForumCount' => 'this:bb_getForumCount',  
  111. 'bb.getForums' => 'this:bb_getForums',  
  112. 'bb.getForum' => 'this:bb_getForum',  
  113. 'bb.newForum' => 'this:bb_newForum',  
  114. 'bb.editForum' => 'this:bb_editForum',  
  115. 'bb.deleteForum' => 'this:bb_deleteForum',  
  116. // - Topics 
  117. 'bb.getTopicCount' => 'this:bb_getTopicCount',  
  118. 'bb.getTopics' => 'this:bb_getTopics',  
  119. 'bb.getTopic' => 'this:bb_getTopic',  
  120. 'bb.newTopic' => 'this:bb_newTopic',  
  121. 'bb.editTopic' => 'this:bb_editTopic',  
  122. 'bb.deleteTopic' => 'this:bb_deleteTopic', // Also undeletes 
  123. 'bb.moveTopic' => 'this:bb_moveTopic',  
  124. 'bb.stickTopic' => 'this:bb_stickTopic', // Also unsticks 
  125. 'bb.closeTopic' => 'this:bb_closeTopic', // Also opens 
  126. 'bb.getTopicStatusList' => 'this:bb_getTopicStatusList',  
  127. // - Posts (replies) 
  128. 'bb.getPostCount' => 'this:bb_getPostCount',  
  129. 'bb.getPosts' => 'this:bb_getPosts',  
  130. 'bb.getPost' => 'this:bb_getPost',  
  131. 'bb.newPost' => 'this:bb_newPost',  
  132. 'bb.editPost' => 'this:bb_editPost',  
  133. 'bb.deletePost' => 'this:bb_deletePost', // Also undeletes 
  134. 'bb.getPostStatusList' => 'this:bb_getPostStatusList',  
  135. // - Topic Tags 
  136. 'bb.getHotTopicTags' => 'this:bb_getHotTopicTags',  
  137. 'bb.getTopicTagCount' => 'this:bb_getTopicTagCount',  
  138. 'bb.getTopicTags' => 'this:bb_getTopicTags',  
  139. 'bb.getTopicTag' => 'this:bb_getTopicTag',  
  140. 'bb.addTopicTags' => 'this:bb_addTopicTags',  
  141. 'bb.removeTopicTags' => 'this:bb_removeTopicTags',  
  142. 'bb.renameTopicTag' => 'this:bb_renameTopicTag',  
  143. 'bb.mergeTopicTags' => 'this:bb_mergeTopicTags',  
  144. 'bb.destroyTopicTag' => 'this:bb_destroyTopicTag',  
  145. // - Options 
  146. 'bb.getOptions' => 'this:bb_getOptions',  
  147. 'bb.setOptions' => 'this:bb_setOptions' 
  148. ); 
  149.  
  150. // Pingback 
  151. if ( bb_get_option( 'enable_pingback' ) ) { 
  152. $this->methods = array_merge( (array)$this->methods, array( 
  153. 'pingback.ping' => 'this:pingback_ping',  
  154. 'pingback.extensions.getPingbacks' => 'this:pingback_extensions_getPingbacks' 
  155. ) ); 
  156.  
  157. // Tells read-only methods whether they require authentication or not 
  158. $this->auth_readonly = apply_filters( 'bb_xmlrpc_auth_readonly', $this->auth_readonly ); 
  159.  
  160. // Whether or not to allow user switching 
  161. $this->allow_user_switching = bb_get_option( 'bb_xmlrpc_allow_user_switching' ); 
  162.  
  163. $this->initialise_site_option_info(); 
  164. $this->methods = apply_filters( 'bb_xmlrpc_methods', $this->methods ); 
  165. $this->IXR_Server( $this->methods ); 
  166.  
  167. function BB_XMLRPC_Server() 
  168. $this->__construct(); 
  169.  
  170. /** 
  171. * Utility methods 
  172. */ 
  173.  
  174. /** 
  175. * Checks the user credentials supplied in the request to make sure they are valid 
  176. * 
  177. * @since 1.0 
  178. * @return integer|boolean The user id if the user is valid, otherwise false 
  179. * @param string $user_login The users login 
  180. * @param string $user_pass The users password in plain text 
  181. * @param string $capability The capability to check (optional) 
  182. * @param string $message The message to pass back in the error if the capability check fails (optional) 
  183. */ 
  184. function authenticate( $user_login, $user_pass, $capability = 'read', $message = false ) 
  185. if ( is_array( $user_login ) ) { 
  186. $auth_user_login = (string) $user_login[0]; 
  187. $switch_user_login = (string) $user_login[1]; 
  188. } else { 
  189. $auth_user_login = (string) $user_login; 
  190. $switch_user_login = false; 
  191.  
  192. // Check the login 
  193. $user = bb_check_login( $auth_user_login, $user_pass ); 
  194. if ( !$user || is_wp_error( $user ) ) { 
  195. $this->error = new IXR_Error( 403, __( 'Authentication failed.' ) ); 
  196. return false; 
  197.  
  198. // Set the current user 
  199. $user = bb_set_current_user( $user->ID ); 
  200.  
  201. // Make sure they are allowed to do this 
  202. if ( !bb_current_user_can( $capability ) ) { 
  203. if ( !$message ) { 
  204. $message = __( 'You do not have permission to read this.' ); 
  205. $this->error = new IXR_Error( 403, $message ); 
  206. return false; 
  207.  
  208. // Switch the user if requested and allowed 
  209. if ( $switch_user_login && $this->allow_user_switching && bb_current_user_can( 'edit_users' ) ) { 
  210. $user = $this->switch_user( $switch_user_login, $capability, $message ); 
  211.  
  212. return $user; 
  213.  
  214. /** 
  215. * Switches the currently active user for incognito actions 
  216. * 
  217. * @since 1.0 
  218. * @return integer|boolean The user id if the user is valid, otherwise false 
  219. * @param string $user_login The users login 
  220. * @param string $capability The capability to check (optional) 
  221. * @param string $message The message to pass back in the error if the capability check fails (optional) 
  222. */ 
  223. function switch_user( $user_login, $capability = 'read', $message = false ) 
  224. // Just get the user, authentication has already been established by the  
  225. $user = bb_get_user( $user_login, array( 'by' => 'login' ) ); 
  226. if ( !$user || is_wp_error( $user ) ) { 
  227. $this->error = new IXR_Error( 400, __( 'User switching failed, the requested user does not exist.' ) ); 
  228. return false; 
  229.  
  230. // Set the current user 
  231. $user = bb_set_current_user( $user->ID ); 
  232.  
  233. // Make sure they are allowed to do this 
  234. if ( !bb_current_user_can( $capability ) ) { 
  235. if ( !$message ) { 
  236. $message = __( 'You do not have permission to read this.' ); 
  237. $this->error = new IXR_Error( 403, $message ); 
  238. return false; 
  239.  
  240. return $user; 
  241.  
  242. /** 
  243. * Sanitises data from XML-RPC request parameters 
  244. * 
  245. * @since 1.0 
  246. * @return mixed The sanitised variable, should come back with the same type 
  247. * @param $array mixed The variable to be sanitised 
  248. * @uses $bbdb BackPress database class instance 
  249. */ 
  250. function escape( &$array ) 
  251. global $bbdb; 
  252.  
  253. if ( !is_array( $array ) ) { 
  254. // Escape it 
  255. $array = $bbdb->escape( $array ); 
  256. } elseif ( count( $array ) ) { 
  257. foreach ( (array) $array as $k => $v ) { 
  258. if ( is_array( $v ) ) { 
  259. // Recursively sanitize arrays 
  260. $this->escape( $array[$k] ); 
  261. } elseif ( is_object( $v ) ) { 
  262. // Don't sanitise objects - shouldn't happen anyway 
  263. } else { 
  264. // Escape it 
  265. $array[$k] = $bbdb->escape( $v ); 
  266.  
  267. return $array; 
  268.  
  269. /** 
  270. * Prepares forum data for return in an XML-RPC object 
  271. * 
  272. * @since 1.0 
  273. * @return array The prepared forum data 
  274. * @param array|object The unprepared forum data 
  275. **/ 
  276. function prepare_forum( $forum ) 
  277. // Cast to an array 
  278. $_forum = (array) $forum; 
  279. // Set the URI 
  280. $_forum['forum_uri'] = get_forum_link( $_forum['forum_id'] ); 
  281. // Give this a definite value 
  282. if ( !isset( $_forum['forum_is_category'] ) ) { 
  283. $_forum['forum_is_category'] = 0; 
  284. // Allow plugins to modify the data 
  285. return apply_filters( 'bb_xmlrpc_prepare_forum', $_forum, (array) $forum ); 
  286.  
  287. /** 
  288. * Prepares topic data for return in an XML-RPC object 
  289. * 
  290. * @since 1.0 
  291. * @return array The prepared topic data 
  292. * @param array|object The unprepared topic data 
  293. **/ 
  294. function prepare_topic( $topic ) 
  295. // Cast to an array 
  296. $_topic = (array) $topic; 
  297. // Set the URI 
  298. $_topic['topic_uri'] = get_topic_link( $_topic['topic_id'] ); 
  299. // Set readable times 
  300. $_topic['topic_start_time_since'] = bb_since( $_topic['topic_start_time'] ); 
  301. $_topic['topic_time_since'] = bb_since( $_topic['topic_time'] ); 
  302. // Set the display names 
  303. $_topic['topic_poster_display_name'] = get_user_display_name( $_topic['topic_poster'] ); 
  304. $_topic['topic_last_poster_display_name'] = get_user_display_name( $_topic['topic_last_poster'] ); 
  305. // Remove some sensitive user ids 
  306. unset( 
  307. $_topic['topic_poster'],  
  308. $_topic['topic_last_poster'] 
  309. ); 
  310. // Allow plugins to modify the data 
  311. return apply_filters( 'bb_xmlrpc_prepare_topic', $_topic, (array) $topic ); 
  312.  
  313. /** 
  314. * Prepares post data for return in an XML-RPC object 
  315. * 
  316. * @since 1.0 
  317. * @return array The prepared post data 
  318. * @param array|object The unprepared post data 
  319. **/ 
  320. function prepare_post( $post ) 
  321. // Cast to an array 
  322. $_post = (array) $post; 
  323. // Set the URI 
  324. $_post['post_uri'] = get_post_link( $_post['post_id'] ); 
  325. // Set readable times 
  326. $_post['post_time_since'] = bb_since( $_post['post_time'] ); 
  327. // Set the display names 
  328. $_post['poster_display_name'] = get_user_display_name( $_post['poster_id'] ); 
  329. // Remove some sensitive data 
  330. unset( 
  331. $_post['poster_id'],  
  332. $_post['poster_ip'],  
  333. $_post['pingback_queued'] 
  334. ); 
  335. // Allow plugins to modify the data 
  336. return apply_filters( 'bb_xmlrpc_prepare_post', $_post, (array) $post ); 
  337.  
  338. /** 
  339. * Prepares topic tag data for return in an XML-RPC object 
  340. * 
  341. * @since 1.0 
  342. * @return array The prepared topic tag data 
  343. * @param array|object The unprepared topic tag data 
  344. **/ 
  345. function prepare_topic_tag( $tag ) 
  346. // Cast to an array 
  347. $_tag = (array) $tag; 
  348. // Set the URI 
  349. $_tag['topic_tag_uri'] = bb_get_tag_link( $tag ); 
  350. // Consistent nomenclature 
  351. $_tag['topic_tag_name'] = (string) $_tag['name']; 
  352. $_tag['topic_tag_slug'] = (string) $_tag['slug']; 
  353. $_tag['topic_tag_count'] = (int) $_tag['count']; 
  354. // Remove some sensitive data 
  355. unset( 
  356. $_tag['object_id'],  
  357. $_tag['name'],  
  358. $_tag['slug'],  
  359. $_tag['count'],  
  360. $_tag['term_id'],  
  361. $_tag['term_group'],  
  362. $_tag['term_taxonomy_id'],  
  363. $_tag['taxonomy'],  
  364. $_tag['description'],  
  365. $_tag['parent'],  
  366. $_tag['count'],  
  367. $_tag['user_id'],  
  368. $_tag['tag_id'],  
  369. $_tag['tag'],  
  370. $_tag['raw_tag'],  
  371. $_tag['tag_count'] 
  372. ); 
  373. // Allow plugins to modify the data 
  374. return apply_filters( 'bb_xmlrpc_prepare_topic_tag', $_tag, (array) $tag ); 
  375.  
  376.  
  377.  
  378. /** 
  379. * bbPress publishing API - Demo XML-RPC methods 
  380. */ 
  381.  
  382. /** 
  383. * Hello world demo function for XML-RPC 
  384. * 
  385. * @since 1.0 
  386. * @return string The phrase 'Hello!' 
  387. * @param array $args Arguments passed by the XML-RPC call 
  388. * @param string $args[0] The username for authentication 
  389. * @param string $args[1] The password for authentication 
  390. * 
  391. * XML-RPC request to get a greeting 
  392. * <methodCall> 
  393. * <methodName>demo.sayHello</methodName> 
  394. * <params> 
  395. * <param><value><string>joeblow</string></value></param> 
  396. * <param><value><string>123password</string></value></param> 
  397. * </params> 
  398. * </methodCall> 
  399. */ 
  400. function sayHello( $args ) 
  401. // Escape args 
  402. $this->escape( $args ); 
  403.  
  404. // Get the login credentials 
  405. $username = $args[0]; 
  406. $password = (string) $args[1]; 
  407.  
  408. // Check the user is valid 
  409. if ( $this->auth_readonly && !$this->authenticate( $username, $password ) ) { 
  410. return $this->error; 
  411.  
  412. return 'Hello!'; 
  413.  
  414. /** 
  415. * Adds two numbers together as a demo of XML-RPC 
  416. * 
  417. * @since 1.0 
  418. * @return integer The sum of the two supplied numbers 
  419. * @param array $args Arguments passed by the XML-RPC call 
  420. * @param string $args[0] The username for authentication 
  421. * @param string $args[1] The password for authentication 
  422. * @param integer $args[2] The first number to be added 
  423. * @param integer $args[3] The second number to be added 
  424. * 
  425. * XML-RPC request to get the sum of two numbers 
  426. * <methodCall> 
  427. * <methodName>demo.addTwoNumbers</methodName> 
  428. * <params> 
  429. * <param><value><string>joeblow</string></value></param> 
  430. * <param><value><string>123password</string></value></param> 
  431. * <param><value><int>5</int></value></param> 
  432. * <param><value><int>102</int></value></param> 
  433. * </params> 
  434. * </methodCall> 
  435. */ 
  436. function addTwoNumbers( $args ) 
  437. // Escape args 
  438. $this->escape( $args ); 
  439.  
  440. // Get the login credentials 
  441. $username = $args[0]; 
  442. $password = (string) $args[1]; 
  443.  
  444. // Check the user is valid 
  445. if ( $this->auth_readonly && !$this->authenticate( $username, $password ) ) { 
  446. return $this->error; 
  447.  
  448. $number1 = (int) $args[2]; 
  449. $number2 = (int) $args[3]; 
  450.  
  451. return ( $number1 + $number2 ); 
  452.  
  453.  
  454.  
  455. /** 
  456. * bbPress publishing API - Forum XML-RPC methods 
  457. */ 
  458.  
  459. /** 
  460. * Returns a numerical count of forums 
  461. * 
  462. * @since 1.0 
  463. * @return integer|object The number of forums when successfully executed or an IXR_Error object on failure 
  464. * @param array $args Arguments passed by the XML-RPC call 
  465. * @param string $args[0] The username for authentication 
  466. * @param string $args[1] The password for authentication 
  467. * @param integer|string $args[2] The parent forum's id or slug (optional) 
  468. * @param integer $args[3] The depth of child forums to retrieve (optional) 
  469. * 
  470. * XML-RPC request to get a count of all forums in the bbPress instance 
  471. * <methodCall> 
  472. * <methodName>bb.getForumCount</methodName> 
  473. * <params> 
  474. * <param><value><string>joeblow</string></value></param> 
  475. * <param><value><string>123password</string></value></param> 
  476. * </params> 
  477. * </methodCall> 
  478. * 
  479. * XML-RPC request to get a count of all child forums in the forum with id number 34 
  480. * <methodCall> 
  481. * <methodName>bb.getForumCount</methodName> 
  482. * <params> 
  483. * <param><value><string>joeblow</string></value></param> 
  484. * <param><value><string>123password</string></value></param> 
  485. * <param><value><int>34</int></value></param> 
  486. * </params> 
  487. * </methodCall> 
  488. * 
  489. * XML-RPC request to get a count of all child forums in the forum with slug "first-forum" 
  490. * <methodCall> 
  491. * <methodName>bb.getForumCount</methodName> 
  492. * <params> 
  493. * <param><value><string>joeblow</string></value></param> 
  494. * <param><value><string>123password</string></value></param> 
  495. * <param><value><string>first-forum</string></value></param> 
  496. * </params> 
  497. * </methodCall> 
  498. * 
  499. * XML-RPC request to get a count of all child forums in the forum with id number 34 no more than 2 forums deep in the hierarchy 
  500. * <methodCall> 
  501. * <methodName>bb.getForumCount</methodName> 
  502. * <params> 
  503. * <param><value><string>joeblow</string></value></param> 
  504. * <param><value><string>123password</string></value></param> 
  505. * <param><value><int>34</int></value></param> 
  506. * <param><value><int>2</int></value></param> 
  507. * </params> 
  508. * </methodCall> 
  509. */ 
  510. function bb_getForumCount( $args ) 
  511. do_action( 'bb_xmlrpc_call', 'bb.getForumCount' ); 
  512.  
  513. // Escape args 
  514. $this->escape( $args ); 
  515.  
  516. // Get the login credentials 
  517. $username = $args[0]; 
  518. $password = (string) $args[1]; 
  519.  
  520. // Check the user is valid 
  521. if ( $this->auth_readonly ) { 
  522. $user = $this->authenticate( $username, $password ); 
  523.  
  524. do_action( 'bb_xmlrpc_call_authenticated', 'bb.getForumCount' ); 
  525.  
  526. // If an error was raised by authentication or by an action then return it 
  527. if ( $this->error ) { 
  528. return $this->error; 
  529.  
  530. // Setup an array to store arguments to pass to bb_get_forums() function 
  531. $get_forums_args = array( 
  532. 'child_of' => 0,  
  533. 'hierarchical' => 0,  
  534. 'depth' => 0 
  535. ); 
  536.  
  537. // Can be numeric id or slug 
  538. $forum_id = isset( $args[2] ) ? $args[2] : false; 
  539.  
  540. if ( $forum_id ) { 
  541. // Check for bad data 
  542. if ( !is_string( $forum_id ) && !is_integer( $forum_id ) ) { 
  543. $this->error = new IXR_Error( 400, __( 'The forum id is invalid.' ) ); 
  544. return $this->error; 
  545. // Check the requested forum exists 
  546. if ( !$forum = bb_get_forum( $forum_id ) ) { 
  547. $this->error = new IXR_Error( 400, __( 'The forum does not exist.' ) ); 
  548. return $this->error; 
  549. // Add the specific forum to the arguments 
  550. $get_forums_args['child_of'] = (int) $forum->forum_id; 
  551.  
  552. // Can only be an integer 
  553. $depth = (int) $args[3]; 
  554.  
  555. if ( $depth > 0 ) { 
  556. // Add the depth to traverse to the arguments 
  557. $get_forums_args['depth'] = $depth; 
  558. // Only make it hierarchical if the depth > 1 
  559. if ( $depth > 1 ) { 
  560. $get_forums_args['hierarchical'] = 1; 
  561.  
  562. // Get the forums. Return 0 when no forums exist 
  563. if ( !$forums = bb_get_forums( $get_forums_args ) ) { 
  564. $count = 0; 
  565. } else { 
  566. $count = count( $forums ); 
  567.  
  568. do_action( 'bb_xmlrpc_call_return', 'bb.getForumCount' ); 
  569.  
  570. // Return a count of the forums 
  571. return $count; 
  572.  
  573. /** 
  574. * Returns details of multiple forums 
  575. * 
  576. * @since 1.0 
  577. * @return array|object An array containing details of all returned forums when successfully executed or an IXR_Error object on failure 
  578. * @param array $args Arguments passed by the XML-RPC call 
  579. * @param string $args[0] The username for authentication 
  580. * @param string $args[1] The password for authentication 
  581. * @param integer|string $args[2] The parent forum's id or slug (optional) 
  582. * @param integer $args[3] The depth of child forums to retrieve (optional) 
  583. * 
  584. * XML-RPC request to get all forums in the bbPress instance 
  585. * <methodCall> 
  586. * <methodName>bb.getForums</methodName> 
  587. * <params> 
  588. * <param><value><string>joeblow</string></value></param> 
  589. * <param><value><string>123password</string></value></param> 
  590. * </params> 
  591. * </methodCall> 
  592. * 
  593. * XML-RPC request to get all child forums in the forum with id number 34 
  594. * <methodCall> 
  595. * <methodName>bb.getForums</methodName> 
  596. * <params> 
  597. * <param><value><string>joeblow</string></value></param> 
  598. * <param><value><string>123password</string></value></param> 
  599. * <param><value><int>34</int></value></param> 
  600. * </params> 
  601. * </methodCall> 
  602. * 
  603. * XML-RPC request to get all child forums in the forum with slug "first-forum" 
  604. * <methodCall> 
  605. * <methodName>bb.getForums</methodName> 
  606. * <params> 
  607. * <param><value><string>joeblow</string></value></param> 
  608. * <param><value><string>123password</string></value></param> 
  609. * <param><value><string>first-forum</string></value></param> 
  610. * </params> 
  611. * </methodCall> 
  612. * 
  613. * XML-RPC request to get all child forums in the forum with id number 34 no more than 2 forums deep in the hierarchy 
  614. * <methodCall> 
  615. * <methodName>bb.getForums</methodName> 
  616. * <params> 
  617. * <param><value><string>joeblow</string></value></param> 
  618. * <param><value><string>123password</string></value></param> 
  619. * <param><value><int>34</int></value></param> 
  620. * <param><value><int>2</int></value></param> 
  621. * </params> 
  622. * </methodCall> 
  623. */ 
  624. function bb_getForums( $args ) 
  625. do_action( 'bb_xmlrpc_call', 'bb.getForums' ); 
  626.  
  627. // Escape args 
  628. $this->escape( $args ); 
  629.  
  630. // Get the login credentials 
  631. $username = $args[0]; 
  632. $password = (string) $args[1]; 
  633.  
  634. // Check the user is valid 
  635. if ( $this->auth_readonly ) { 
  636. $user = $this->authenticate( $username, $password ); 
  637.  
  638. do_action( 'bb_xmlrpc_call_authenticated', 'bb.getForums' ); 
  639.  
  640. // If an error was raised by authentication or by an action then return it 
  641. if ( $this->error ) { 
  642. return $this->error; 
  643.  
  644. // Setup an array to store arguments to pass to bb_get_forums() function 
  645. $get_forums_args = array( 
  646. 'child_of' => 0,  
  647. 'hierarchical' => 0,  
  648. 'depth' => 0 
  649. ); 
  650.  
  651. // Can be numeric id or slug 
  652. $forum_id = isset( $args[2] ) ? $args[2] : false; 
  653.  
  654. if ( $forum_id ) { 
  655. // Check for bad data 
  656. if ( !is_string( $forum_id ) && !is_integer( $forum_id ) ) { 
  657. $this->error = new IXR_Error( 400, __( 'The forum id is invalid.' ) ); 
  658. return $this->error; 
  659. // First check the requested forum exists 
  660. if ( !$forum = bb_get_forum( $forum_id ) ) { 
  661. $this->error = new IXR_Error( 400, __( 'The forum does not exist.' ) ); 
  662. return $this->error; 
  663. // Add the specific forum to the arguments 
  664. $get_forums_args['child_of'] = (int) $forum->forum_id; 
  665.  
  666. // Can only be an integer 
  667. $depth = (int) $args[3]; 
  668.  
  669. if ( $depth > 0 ) { 
  670. // Add the depth to traverse to to the arguments 
  671. $get_forums_args['depth'] = $depth; 
  672. // Only make it hierarchical if the depth > 1 
  673. if ( $depth > 1 ) { 
  674. $get_forums_args['hierarchical'] = 1; 
  675.  
  676. // Get the forums. Return an error when no forums exist 
  677. if ( !$forums = bb_get_forums( $get_forums_args ) ) { 
  678. $this->error = new IXR_Error( 404, __( 'No forums found.' ) ); 
  679. return $this->error; 
  680.  
  681. // Only include "safe" data in the array 
  682. $_forums = array(); 
  683. foreach ( $forums as $forum ) { 
  684. $_forums[] = $this->prepare_forum( $forum ); 
  685.  
  686. do_action( 'bb_xmlrpc_call_return', 'bb.getForums' ); 
  687.  
  688. // Return the forums 
  689. return $_forums; 
  690.  
  691. /** 
  692. * Returns details of a forum 
  693. * 
  694. * @since 1.0 
  695. * @return array|object An array containing details of the returned forum when successfully executed or an IXR_Error object on failure 
  696. * @param string $args[0] The username for authentication 
  697. * @param string $args[1] The password for authentication 
  698. * @param integer|string $args[2] The forum's id or slug 
  699. * 
  700. * XML-RPC request to get the forum with id number 34 
  701. * <methodCall> 
  702. * <methodName>bb.getForum</methodName> 
  703. * <params> 
  704. * <param><value><string>joeblow</string></value></param> 
  705. * <param><value><string>123password</string></value></param> 
  706. * <param><value><int>34</int></value></param> 
  707. * </params> 
  708. * </methodCall> 
  709. * 
  710. * XML-RPC request to get the forum with slug "first-forum" 
  711. * <methodCall> 
  712. * <methodName>bb.getForum</methodName> 
  713. * <params> 
  714. * <param><value><string>joeblow</string></value></param> 
  715. * <param><value><string>123password</string></value></param> 
  716. * <param><value><string>first-forum</string></value></param> 
  717. * </params> 
  718. * </methodCall> 
  719. */ 
  720. function bb_getForum( $args ) 
  721. do_action( 'bb_xmlrpc_call', 'bb.getForum' ); 
  722.  
  723. // Escape args 
  724. $this->escape( $args ); 
  725.  
  726. // Get the login credentials 
  727. $username = $args[0]; 
  728. $password = (string) $args[1]; 
  729.  
  730. // Check the user is valid 
  731. if ( $this->auth_readonly ) { 
  732. $user = $this->authenticate( $username, $password ); 
  733.  
  734. do_action( 'bb_xmlrpc_call_authenticated', 'bb.getForum' ); 
  735.  
  736. // If an error was raised by authentication or by an action then return it 
  737. if ( $this->error ) { 
  738. return $this->error; 
  739.  
  740. // Can be numeric id or slug 
  741. $forum_id = isset( $args[2] ) ? $args[2] : false; 
  742.  
  743. // Check for bad data 
  744. if ( !$forum_id || ( !is_string( $forum_id ) && !is_integer( $forum_id ) ) ) { 
  745. $this->error = new IXR_Error( 400, __( 'The forum id is invalid.' ) ); 
  746. return $this->error; 
  747.  
  748. // Check the requested forum exists 
  749. if ( !$forum = bb_get_forum( $forum_id ) ) { 
  750. $this->error = new IXR_Error( 404, __( 'No forum found.' ) ); 
  751. return $this->error; 
  752.  
  753. // Only include "safe" data in the array 
  754. $forum = $this->prepare_forum( $forum ); 
  755.  
  756. do_action( 'bb_xmlrpc_call_return', 'bb.getForum' ); 
  757.  
  758. // Return the forums 
  759. return $forum; 
  760.  
  761. /** 
  762. * Creates a new forum 
  763. * 
  764. * @since 1.0 
  765. * @return array|object The forum data when successfully created or an IXR_Error object on failure 
  766. * @param array $args Arguments passed by the XML-RPC call 
  767. * @param string $args[0] The username for authentication 
  768. * @param string $args[1] The password for authentication 
  769. * @param array $args[2] The values for the various settings in the new forum 
  770. * @param string $args[2]['name'] The name of the forum 
  771. * @param string $args[2]['description'] The description of the forum (optional) 
  772. * @param integer|string $args[2]['parent_id'] The unique id of the parent forum for this forum (optional) 
  773. * @param integer $args[2]['order'] The position of the forum in the forum list (optional) 
  774. * @param integer $args[2]['is_category'] Whether the forum is simply a container category (optional) 
  775. * 
  776. * XML-RPC request to create a new sub-forum called "A new forum" inside the parent forum with id 2 
  777. * <methodCall> 
  778. * <methodName>bb.newForum</methodName> 
  779. * <params> 
  780. * <param><value><string>joeblow</string></value></param> 
  781. * <param><value><string>123password</string></value></param> 
  782. * <param><value><struct> 
  783. * <member> 
  784. * <name>name</name> 
  785. * <value><string>A new forum</string></value> 
  786. * </member> 
  787. * <member> 
  788. * <name>parent_id</name> 
  789. * <value><integer>2</integer></value> 
  790. * </member> 
  791. * </struct></value></param> 
  792. * </params> 
  793. * </methodCall> 
  794. */ 
  795. function bb_newForum( $args ) 
  796. do_action( 'bb_xmlrpc_call', 'bb.newForum' ); 
  797.  
  798. // Escape args 
  799. $this->escape( $args ); 
  800.  
  801. // Get the login credentials 
  802. $username = $args[0]; 
  803. $password = (string) $args[1]; 
  804.  
  805. // Check the user is valid 
  806. $user = $this->authenticate( $username, $password, 'manage_forums', __( 'You do not have permission to manage forums.' ) ); 
  807.  
  808. do_action( 'bb_xmlrpc_call_authenticated', 'bb.newForum' ); 
  809.  
  810. // If an error was raised by authentication or by an action then return it 
  811. if ( $this->error ) { 
  812. return $this->error; 
  813.  
  814. // Make sure there is something for us to do 
  815. if ( !$args[2] || !is_array( $args[2] ) || !count( $args[2] ) ) { 
  816. $this->error = new IXR_Error( 400, __( 'The forum data is invalid.' ) ); 
  817. return $this->error; 
  818.  
  819. $structure = (array) $args[2]; 
  820.  
  821. // Minimum requirement is a name for the new forum 
  822. if ( !isset( $structure['name'] ) || !$structure['name'] ) { 
  823. $this->error = new IXR_Error( 400, __( 'The forum name is invalid.' ) ); 
  824. return $this->error; 
  825.  
  826. // Inject structure into an array suitable for bb_new_forum() 
  827. $bb_new_forum_args = array( 
  828. 'forum_name' => (string) $structure['name'],  
  829. 'forum_desc' => (string) $structure['description'],  
  830. 'forum_parent' => (int) $structure['parent_id'],  
  831. 'forum_order' => (int) $structure['order'],  
  832. 'forum_is_category' => (int) $structure['is_category'] 
  833. ); 
  834.  
  835. // Remove empty settings so that changes to the defaults in bb_new_forum() are honoured 
  836. $bb_new_forum_args = array_filter( $bb_new_forum_args ); 
  837.  
  838. // Leave the require until the very end 
  839. require_once( BB_PATH . 'bb-admin/includes/functions.bb-admin.php' ); 
  840.  
  841. // Create the forum 
  842. if ( !$forum_id = (int) bb_new_forum( $bb_new_forum_args ) ) { 
  843. $this->error = new IXR_Error( 500, __( 'The forum could not be created.' ) ); 
  844. return $this->error; 
  845.  
  846. // Only include "safe" data in the array 
  847. $forum = $this->prepare_forum( bb_get_forum( $forum_id ) ); 
  848.  
  849. do_action( 'bb_xmlrpc_call_return', 'bb.newForum' ); 
  850.  
  851. return $forum; 
  852.  
  853. /** 
  854. * Edits an existing forum 
  855. * 
  856. * @since 1.0 
  857. * @return array|object The forum data when successfully edited or an IXR_Error object on failure 
  858. * @param array $args Arguments passed by the XML-RPC call 
  859. * @param string $args[0] The username for authentication 
  860. * @param string $args[1] The password for authentication 
  861. * @param array $args[2] The values for the various settings in the new forum, at least one must be specified 
  862. * @param integer|string $args[2]['forum_id'] The unique id of the forum to be edited 
  863. * @param string $args[2]['name'] The name of the forum (optional) 
  864. * @param string $args[2]['slug'] The slug for the forum (optional) 
  865. * @param string $args[2]['description'] The description of the forum (optional) 
  866. * @param integer $args[2]['parent_id'] The unique id of the parent forum for this forum (optional) 
  867. * @param integer $args[2]['order'] The position of the forum in the forum list (optional) 
  868. * @param integer $args[2]['is_category'] Whether the forum is simply a container category (optional) 
  869. * 
  870. * XML-RPC request to edit a forum with id 11, changing the description 
  871. * <methodCall> 
  872. * <methodName>bb.editForum</methodName> 
  873. * <params> 
  874. * <param><value><string>joeblow</string></value></param> 
  875. * <param><value><string>123password</string></value></param> 
  876. * <param><value><struct> 
  877. * <member> 
  878. * <name>forum_id</name> 
  879. * <value><integer>11</integer></value> 
  880. * </member> 
  881. * <member> 
  882. * <name>description</name> 
  883. * <value><string>This is a great forum for all sorts of reasons.</string></value> 
  884. * </member> 
  885. * </struct></value></param> 
  886. * </params> 
  887. * </methodCall> 
  888. */ 
  889. function bb_editForum( $args ) 
  890. do_action( 'bb_xmlrpc_call', 'bb.editForum' ); 
  891.  
  892. // Escape args 
  893. $this->escape( $args ); 
  894.  
  895. // Get the login credentials 
  896. $username = $args[0]; 
  897. $password = (string) $args[1]; 
  898.  
  899. // Check the user is valid 
  900. $user = $this->authenticate( $username, $password, 'manage_forums', __( 'You do not have permission to manage forums.' ) ); 
  901.  
  902. do_action( 'bb_xmlrpc_call_authenticated', 'bb.editForum' ); 
  903.  
  904. // If an error was raised by authentication or by an action then return it 
  905. if ( $this->error ) { 
  906. return $this->error; 
  907.  
  908. // Make sure there is something for us to do 
  909. if ( !$args[2] || !is_array( $args[2] ) || !count( $args[2] ) ) { 
  910. $this->error = new IXR_Error( 400, __( 'The forum data is invalid.' ) ); 
  911. return $this->error; 
  912.  
  913. $structure = (array) $args[2]; 
  914.  
  915. // Can be numeric id or slug 
  916. $forum_id = isset( $structure['forum_id'] ) ? $structure['forum_id'] : false; 
  917.  
  918. // Check for bad data 
  919. if ( !$forum_id || ( !is_string( $forum_id ) && !is_integer( $forum_id ) ) ) { 
  920. $this->error = new IXR_Error( 400, __( 'The forum id is invalid.' ) ); 
  921. return $this->error; 
  922.  
  923. // Check the requested forum exists 
  924. if ( !$forum = bb_get_forum( $forum_id ) ) { 
  925. $this->error = new IXR_Error( 400, __( 'No forum found.' ) ); 
  926. return $this->error; 
  927.  
  928. // Cast the forum object as an array 
  929. $forum = (array) $forum; 
  930. // The forum id may have been a slug, so make sure it's an integer here 
  931. $forum_id = (int) $forum['forum_id']; 
  932.  
  933. // Remove some unneeded indexes 
  934. unset( $forum['topics'] ); 
  935. unset( $forum['posts'] ); 
  936.  
  937. // Add one if it isn't there 
  938. if ( !isset( $forum['forum_is_category'] ) ) { 
  939. $forum['forum_is_category'] = 0; 
  940.  
  941. // Validate the name for the forum 
  942. if ( isset( $structure['name'] ) && !$structure['name'] ) { 
  943. $this->error = new IXR_Error( 400, __( 'The forum name is invalid.' ) ); 
  944. return $this->error; 
  945.  
  946. // Inject structure into an array suitable for bb_update_forum() 
  947. $bb_update_forum_args = array( 
  948. 'forum_name' => $structure['name'] 
  949. ); 
  950.  
  951. // Slug cannot be blank 
  952. if ( isset( $structure['slug'] ) && $structure['slug'] !== '' ) { 
  953. $bb_update_forum_args['forum_slug'] = $structure['slug']; 
  954.  
  955. // Description can be nothing 
  956. if ( isset( $structure['description'] ) ) { 
  957. $bb_update_forum_args['forum_desc'] = $structure['description']; 
  958.  
  959. // Parent forum ID must be an integer and it can be 0 
  960. if ( isset( $structure['parent_id'] ) && is_integer( $structure['parent_id'] ) ) { 
  961. $bb_update_forum_args['forum_parent'] = $structure['parent_id']; 
  962.  
  963. // Order must be an integer and it can be 0 
  964. if ( isset( $structure['order'] ) && is_integer( $structure['order'] ) ) { 
  965. $bb_update_forum_args['forum_order'] = $structure['order']; 
  966.  
  967. // Category flag must be an integer and it can be 0 
  968. if ( isset( $structure['is_category'] ) && is_integer( $structure['is_category'] ) ) { 
  969. $bb_update_forum_args['forum_is_category'] = $structure['is_category']; 
  970.  
  971. // Merge the changes into the existing data for the forum 
  972. $bb_update_forum_args = wp_parse_args( $bb_update_forum_args, $forum ); 
  973.  
  974. // Leave the require until the very end 
  975. require_once( BB_PATH . 'bb-admin/includes/functions.bb-admin.php' ); 
  976.  
  977. // Update the forum 
  978. if ( !bb_update_forum( $bb_update_forum_args ) ) { 
  979. $this->error = new IXR_Error( 500, __( 'The forum could not be edited.' ) ); 
  980. return $this->error; 
  981.  
  982. // Only include "safe" data in the array 
  983. $forum = $this->prepare_forum( bb_get_forum( $forum_id ) ); 
  984.  
  985. do_action( 'bb_xmlrpc_call_return', 'bb.editForum' ); 
  986.  
  987. return $forum; 
  988.  
  989. /** 
  990. * Deletes a forum 
  991. * 
  992. * @since 1.0 
  993. * @return integer|object 1 when successfully deleted or an IXR_Error object on failure 
  994. * @param array $args Arguments passed by the XML-RPC call 
  995. * @param string $args[0] The username for authentication 
  996. * @param string $args[1] The password for authentication 
  997. * @param integer|string $args[2] The unique id of the forum to be deleted 
  998. * 
  999. * XML-RPC request to delete a forum with the slug "naughty-forum" 
  1000. * <methodCall> 
  1001. * <methodName>bb.deleteForum</methodName> 
  1002. * <params> 
  1003. * <param><value><string>joeblow</string></value></param> 
  1004. * <param><value><string>123password</string></value></param> 
  1005. * <param><value><string>naughty-forum</string></value></param> 
  1006. * </params> 
  1007. * </methodCall> 
  1008. */ 
  1009. function bb_deleteForum( $args ) 
  1010. do_action( 'bb_xmlrpc_call', 'bb.deleteForum' ); 
  1011.  
  1012. // Escape args 
  1013. $this->escape( $args ); 
  1014.  
  1015. // Get the login credentials 
  1016. $username = $args[0]; 
  1017. $password = (string) $args[1]; 
  1018.  
  1019. // Check the user is valid 
  1020. $user = $this->authenticate( $username, $password, 'delete_forums', __( 'You do not have permission to delete forums.' ) ); 
  1021.  
  1022. do_action( 'bb_xmlrpc_call_authenticated', 'bb.deleteForum' ); 
  1023.  
  1024. // If an error was raised by authentication or by an action then return it 
  1025. if ( $this->error ) { 
  1026. return $this->error; 
  1027.  
  1028. // Can be numeric id or slug 
  1029. $forum_id = isset( $args[2] ) ? $args[2] : false; 
  1030.  
  1031. // Check for bad data 
  1032. if ( !$forum_id || ( !is_string( $forum_id ) && !is_integer( $forum_id ) ) ) { 
  1033. $this->error = new IXR_Error( 400, __( 'The forum id is invalid.' ) ); 
  1034. return $this->error; 
  1035.  
  1036. // Check the requested forum exists 
  1037. if ( !$forum = bb_get_forum( $forum_id ) ) { 
  1038. $this->error = new IXR_Error( 400, __( 'No forum found.' ) ); 
  1039. return $this->error; 
  1040.  
  1041. // Cast the forum object as an array 
  1042. $forum = (array) $forum; 
  1043. // The forum id may have been a slug, so make sure it's an integer here 
  1044. $forum_id = (int) $forum['forum_id']; 
  1045.  
  1046. // Make sure they are allowed to delete this forum specifically 
  1047. if ( !bb_current_user_can( 'delete_forum', $forum_id ) ) { 
  1048. $this->error = new IXR_Error( 403, __( 'You do not have permission to delete this forum.' ) ); 
  1049. return $this->error; 
  1050.  
  1051. // Leave the require until the very end 
  1052. require_once( BB_PATH . 'bb-admin/includes/functions.bb-admin.php' ); 
  1053.  
  1054. // Delete the forum 
  1055. if ( !bb_delete_forum( $forum_id ) ) { 
  1056. $this->error = new IXR_Error( 500, __( 'The forum could not be deleted.' ) ); 
  1057. return $this->error; 
  1058.  
  1059. $result = 1; 
  1060.  
  1061. do_action( 'bb_xmlrpc_call_return', 'bb.deleteForum' ); 
  1062.  
  1063. return $result; 
  1064.  
  1065.  
  1066.  
  1067. /** 
  1068. * bbPress publishing API - Topic XML-RPC methods 
  1069. */ 
  1070.  
  1071. /** 
  1072. * Returns a numerical count of topics 
  1073. * 
  1074. * @since 1.0 
  1075. * @return integer|object The number of topics when successfully executed or an IXR_Error object on failure 
  1076. * @param array $args Arguments passed by the XML-RPC call 
  1077. * @param string $args[0] The username for authentication 
  1078. * @param string $args[1] The password for authentication 
  1079. * @param integer|string $args[2] The forum id or slug (optional) 
  1080. * 
  1081. * XML-RPC request to get a count of all topics in the bbPress instance 
  1082. * <methodCall> 
  1083. * <methodName>bb.getTopicCount</methodName> 
  1084. * <params> 
  1085. * <param><value><string>joeblow</string></value></param> 
  1086. * <param><value><string>123password</string></value></param> 
  1087. * </params> 
  1088. * </methodCall> 
  1089. * 
  1090. * XML-RPC request to get a count of all topics in the forum with id number 34 
  1091. * <methodCall> 
  1092. * <methodName>bb.getTopicCount</methodName> 
  1093. * <params> 
  1094. * <param><value><string>joeblow</string></value></param> 
  1095. * <param><value><string>123password</string></value></param> 
  1096. * <param><value><int>34</int></value></param> 
  1097. * </params> 
  1098. * </methodCall> 
  1099. * 
  1100. * XML-RPC request to get a count of all topics in the forum with slug "first-forum" 
  1101. * <methodCall> 
  1102. * <methodName>bb.getTopicCount</methodName> 
  1103. * <params> 
  1104. * <param><value><string>joeblow</string></value></param> 
  1105. * <param><value><string>123password</string></value></param> 
  1106. * <param><value><string>first-forum</string></value></param> 
  1107. * </params> 
  1108. * </methodCall> 
  1109. */ 
  1110. function bb_getTopicCount( $args ) 
  1111. do_action( 'bb_xmlrpc_call', 'bb.getTopicCount' ); 
  1112.  
  1113. // Escape args 
  1114. $this->escape( $args ); 
  1115.  
  1116. // Get the login credentials 
  1117. $username = $args[0]; 
  1118. $password = (string) $args[1]; 
  1119.  
  1120. // Check the user is valid 
  1121. if ( $this->auth_readonly ) { 
  1122. $user = $this->authenticate( $username, $password ); 
  1123.  
  1124. do_action( 'bb_xmlrpc_call_authenticated', 'bb.getTopicCount' ); 
  1125.  
  1126. // If an error was raised by authentication or by an action then return it 
  1127. if ( $this->error ) { 
  1128. return $this->error; 
  1129.  
  1130. // Can be numeric id or slug 
  1131. if ( isset( $args[2] ) && $forum_id = $args[2] ) { 
  1132. // Check for bad data 
  1133. if ( !is_string( $forum_id ) && !is_integer( $forum_id ) ) { 
  1134. $this->error = new IXR_Error( 400, __( 'The forum id is invalid.' ) ); 
  1135. return $this->error; 
  1136. // Check the requested forum exists 
  1137. if ( !$forum = bb_get_forum( $forum_id ) ) { 
  1138. $this->error = new IXR_Error( 400, __( 'The forum does not exist.' ) ); 
  1139. return $this->error; 
  1140.  
  1141. // OK, let's trust the count in the forum table 
  1142. $count = (int) $forum->topics; 
  1143. } else { 
  1144. // Get all forums 
  1145. $forums = bb_get_forums(); 
  1146.  
  1147. // Return an error when no forums exist 
  1148. if ( !$forums ) { 
  1149. $this->error = new IXR_Error( 400, __( 'No forums found.' ) ); 
  1150. return $this->error; 
  1151.  
  1152. // Count the topics 
  1153. $count = 0; 
  1154. foreach ( $forums as $forum ) { 
  1155. $count += (int) $forum->topics; 
  1156.  
  1157. do_action( 'bb_xmlrpc_call_return', 'bb.getTopicCount' ); 
  1158.  
  1159. // Return the count of topics 
  1160. return $count; 
  1161.  
  1162. /** 
  1163. * Returns details of the latest topics 
  1164. * 
  1165. * @since 1.0 
  1166. * @return array|object The topics when successfully executed or an IXR_Error object on failure 
  1167. * @param array $args Arguments passed by the XML-RPC call 
  1168. * @param string $args[0] The username for authentication 
  1169. * @param string $args[1] The password for authentication 
  1170. * @param integer|string $args[2] The forum id or slug (optional) 
  1171. * @param integer $args[3] The number of topics to return (optional) 
  1172. * @param integer $args[4] The number of the page to return (optional) 
  1173. * 
  1174. * XML-RPC request to get all topics in the bbPress instance 
  1175. * <methodCall> 
  1176. * <methodName>bb.getTopics</methodName> 
  1177. * <params> 
  1178. * <param><value><string>joeblow</string></value></param> 
  1179. * <param><value><string>123password</string></value></param> 
  1180. * </params> 
  1181. * </methodCall> 
  1182. * 
  1183. * XML-RPC request to get all topics in the forum with id number 34 
  1184. * <methodCall> 
  1185. * <methodName>bb.getTopics</methodName> 
  1186. * <params> 
  1187. * <param><value><string>joeblow</string></value></param> 
  1188. * <param><value><string>123password</string></value></param> 
  1189. * <param><value><int>34</int></value></param> 
  1190. * </params> 
  1191. * </methodCall> 
  1192. * 
  1193. * XML-RPC request to get topics 6 to 10 in the forum with slug "first-forum" 
  1194. * <methodCall> 
  1195. * <methodName>bb.getTopics</methodName> 
  1196. * <params> 
  1197. * <param><value><string>joeblow</string></value></param> 
  1198. * <param><value><string>123password</string></value></param> 
  1199. * <param><value><string>first-forum</string></value></param> 
  1200. * <param><value><int>5</int></value></param> 
  1201. * <param><value><int>2</int></value></param> 
  1202. * </params> 
  1203. * </methodCall> 
  1204. */ 
  1205. function bb_getTopics( $args ) 
  1206. do_action( 'bb_xmlrpc_call', 'bb.getTopics' ); 
  1207.  
  1208. // Escape args 
  1209. $this->escape( $args ); 
  1210.  
  1211. // Get the login credentials 
  1212. $username = $args[0]; 
  1213. $password = (string) $args[1]; 
  1214.  
  1215. // Check the user is valid 
  1216. if ( $this->auth_readonly ) { 
  1217. $user = $this->authenticate( $username, $password ); 
  1218.  
  1219. do_action( 'bb_xmlrpc_call_authenticated', 'bb.getTopics' ); 
  1220.  
  1221. // If an error was raised by authentication or by an action then return it 
  1222. if ( $this->error ) { 
  1223. return $this->error; 
  1224.  
  1225. // Setup an array to store arguments to pass to get_topics() function 
  1226. $get_topics_args = array( 
  1227. 'forum' => false,  
  1228. 'number' => false,  
  1229. 'page' => false 
  1230. ); 
  1231.  
  1232. // Can be numeric id or slug 
  1233. if ( isset( $args[2] ) && $forum_id = $args[2] ) { 
  1234. // Check for bad data 
  1235. if ( !is_string( $forum_id ) && !is_integer( $forum_id ) ) { 
  1236. $this->error = new IXR_Error( 400, __( 'The forum id is invalid.' ) ); 
  1237. return $this->error; 
  1238. // Check the requested forum exists 
  1239. if ( !$forum = bb_get_forum( $forum_id ) ) { 
  1240. $this->error = new IXR_Error( 400, __( 'The forum does not exist.' ) ); 
  1241. return $this->error; 
  1242.  
  1243. // The forum id may have been a slug, so make sure it's an integer here 
  1244. $get_topics_args['forum'] = (int) $forum->forum_id; 
  1245.  
  1246. // Can only be an integer 
  1247. if ( isset( $args[3] ) && $number = (int) $args[3] ) { 
  1248. $get_topics_args['number'] = $number; 
  1249.  
  1250. // Can only be an integer 
  1251. if ( isset( $args[4] ) && $page = (int) $args[4] ) { 
  1252. $get_topics_args['page'] = $page; 
  1253.  
  1254. // Get the topics 
  1255. if ( !$topics = get_latest_topics( $get_topics_args ) ) { 
  1256. $this->error = new IXR_Error( 400, __( 'No topics found.' ) ); 
  1257. return $this->error; 
  1258.  
  1259. // Only include "safe" data in the array 
  1260. $_topics = array(); 
  1261. foreach ( $topics as $topic ) { 
  1262. $_topics[] = $this->prepare_topic( $topic ); 
  1263.  
  1264. do_action( 'bb_xmlrpc_call_return', 'bb.getTopics' ); 
  1265.  
  1266. // Return the topics 
  1267. return $_topics; 
  1268.  
  1269. /** 
  1270. * Returns details of a topic 
  1271. * 
  1272. * @since 1.0 
  1273. * @return array|object An array containing details of the returned topic when successfully executed or an IXR_Error object on failure 
  1274. * @param string $args[0] The username for authentication 
  1275. * @param string $args[1] The password for authentication 
  1276. * @param integer|string $args[2] The topic's id or slug 
  1277. * 
  1278. * XML-RPC request to get the topic with id number 105 
  1279. * <methodCall> 
  1280. * <methodName>bb.getTopic</methodName> 
  1281. * <params> 
  1282. * <param><value><string>joeblow</string></value></param> 
  1283. * <param><value><string>123password</string></value></param> 
  1284. * <param><value><int>105</int></value></param> 
  1285. * </params> 
  1286. * </methodCall> 
  1287. * 
  1288. * XML-RPC request to get the topic with slug "cheesy-biscuits" 
  1289. * <methodCall> 
  1290. * <methodName>bb.getTopic</methodName> 
  1291. * <params> 
  1292. * <param><value><string>joeblow</string></value></param> 
  1293. * <param><value><string>123password</string></value></param> 
  1294. * <param><value><string>cheesy-biscuits</string></value></param> 
  1295. * </params> 
  1296. * </methodCall> 
  1297. */ 
  1298. function bb_getTopic( $args ) 
  1299. do_action( 'bb_xmlrpc_call', 'bb.getTopic' ); 
  1300.  
  1301. // Escape args 
  1302. $this->escape( $args ); 
  1303.  
  1304. // Get the login credentials 
  1305. $username = $args[0]; 
  1306. $password = (string) $args[1]; 
  1307.  
  1308. // Check the user is valid 
  1309. if ( $this->auth_readonly ) { 
  1310. $user = $this->authenticate( $username, $password ); 
  1311.  
  1312. do_action( 'bb_xmlrpc_call_authenticated', 'bb.getTopic' ); 
  1313.  
  1314. // If an error was raised by authentication or by an action then return it 
  1315. if ( $this->error ) { 
  1316. return $this->error; 
  1317.  
  1318. // Can be numeric id or slug 
  1319. $topic_id = isset( $args[2] ) ? $args[2] : false; 
  1320.  
  1321. // Check for bad data 
  1322. if ( !$topic_id || ( !is_string( $topic_id ) && !is_integer( $topic_id ) ) ) { 
  1323. $this->error = new IXR_Error( 400, __( 'The topic id is invalid.' ) ); 
  1324. return $this->error; 
  1325.  
  1326. // Check the requested topic exists 
  1327. if ( !$topic = get_topic( $topic_id ) ) { 
  1328. $this->error = new IXR_Error( 400, __( 'No topic found.' ) ); 
  1329. return $this->error; 
  1330.  
  1331. // Only include "safe" data in the array 
  1332. $topic = $this->prepare_topic( $topic ); 
  1333.  
  1334. do_action( 'bb_xmlrpc_call_return', 'bb.getTopic' ); 
  1335.  
  1336. // Return the topic 
  1337. return $topic; 
  1338.  
  1339. /** 
  1340. * Creates a new topic 
  1341. * 
  1342. * @since 1.0 
  1343. * @return array|object The topic data when successfully created or an IXR_Error object on failure 
  1344. * @param array $args Arguments passed by the XML-RPC call 
  1345. * @param string $args[0] The username for authentication 
  1346. * @param string $args[1] The password for authentication 
  1347. * @param array $args[2] The values for the various parameters in the new topic 
  1348. * @param string $args[2]['title'] The title of the topic 
  1349. * @param string $args[2]['text'] The text of the topic 
  1350. * @param integer|string $args[2]['forum_id'] The unique id of the forum which will contain this topic, slugs are OK to use too 
  1351. * @param string|array $args[2]['tags'] A comma delimited string or an array of tags to add to the topic (optional) 
  1352. * 
  1353. * XML-RPC request to create a new topic called "Insane monkeys" inside the forum with id 2 
  1354. * <methodCall> 
  1355. * <methodName>bb.newTopic</methodName> 
  1356. * <params> 
  1357. * <param><value><string>joeblow</string></value></param> 
  1358. * <param><value><string>123password</string></value></param> 
  1359. * <param><value><struct> 
  1360. * <member> 
  1361. * <name>title</name> 
  1362. * <value><string>Insane monkeys</string></value> 
  1363. * </member> 
  1364. * <member> 
  1365. * <name>text</name> 
  1366. * <value><string>I just saw some insane monkeys eating bananas, did anyone else see that?</string></value> 
  1367. * </member> 
  1368. * <member> 
  1369. * <name>forum_id</name> 
  1370. * <value><integer>2</integer></value> 
  1371. * </member> 
  1372. * <member> 
  1373. * <name>tags</name> 
  1374. * <value><string>monkeys, bananas</string></value> 
  1375. * </member> 
  1376. * </struct></value></param> 
  1377. * </params> 
  1378. * </methodCall> 
  1379. */ 
  1380. function bb_newTopic( $args ) 
  1381. do_action( 'bb_xmlrpc_call', 'bb.newTopic' ); 
  1382.  
  1383. // Escape args 
  1384. $this->escape( $args ); 
  1385.  
  1386. // Get the login credentials 
  1387. $username = $args[0]; 
  1388. $password = (string) $args[1]; 
  1389.  
  1390. // Check the user is valid 
  1391. $user = $this->authenticate( $username, $password, 'write_topics', __( 'You do not have permission to write topics.' ) ); 
  1392.  
  1393. // Additionally they need to be able to write posts 
  1394. if ( !$this->error && !bb_current_user_can( 'write_posts' ) ) { 
  1395. $this->error = new IXR_Error( 403, __( 'You do not have permission to write posts.' ) ); 
  1396.  
  1397. do_action( 'bb_xmlrpc_call_authenticated', 'bb.newTopic' ); 
  1398.  
  1399. // If an error was raised by authentication or by an action then return it 
  1400. if ( $this->error ) { 
  1401. return $this->error; 
  1402.  
  1403. // Make sure there is something for us to do 
  1404. if ( !$args[2] || !is_array( $args[2] ) || !count( $args[2] ) ) { 
  1405. $this->error = new IXR_Error( 400, __( 'The topic data is invalid.' ) ); 
  1406. return $this->error; 
  1407.  
  1408. $structure = (array) $args[2]; 
  1409.  
  1410. // Can be numeric id or slug 
  1411. $forum_id = isset( $structure['forum_id'] ) ? $structure['forum_id'] : false; 
  1412.  
  1413. // Check for bad data 
  1414. if ( !$forum_id || ( !is_string( $forum_id ) && !is_integer( $forum_id ) ) ) { 
  1415. $this->error = new IXR_Error( 400, __( 'The forum id is invalid.' ) ); 
  1416. return $this->error; 
  1417.  
  1418. // Check the requested forum exists 
  1419. if ( !$forum = bb_get_forum( $forum_id ) ) { 
  1420. $this->error = new IXR_Error( 400, __( 'No forum found.' ) ); 
  1421. return $this->error; 
  1422.  
  1423. // The forum id may have been a slug, so make sure it's an integer here 
  1424. $forum_id = (int) $forum->forum_id; 
  1425.  
  1426. // Make sure they are allowed to write topics to this forum 
  1427. if ( !bb_current_user_can( 'write_topic', $forum_id ) ) { 
  1428. $this->error = new IXR_Error( 403, __( 'You do not have permission to write topics to this forum.' ) ); 
  1429. return $this->error; 
  1430.  
  1431. // The topic requires a title 
  1432. if ( !isset( $structure['title'] ) || !$structure['title'] ) { 
  1433. $this->error = new IXR_Error( 400, __( 'The topic title is invalid.' ) ); 
  1434. return $this->error; 
  1435.  
  1436. // The topic requires text 
  1437. if ( !isset( $structure['text'] ) || !$structure['text'] ) { 
  1438. $this->error = new IXR_Error( 400, __( 'The topic text is invalid.' ) ); 
  1439. return $this->error; 
  1440.  
  1441. // Inject structure into an array suitable for bb_insert_topic() 
  1442. $bb_insert_topic_args = array( 
  1443. 'topic_title' => (string) $structure['title'],  
  1444. 'forum_id' => $forum_id,  
  1445. 'tags' => (string) trim( $structure['tags'] ) 
  1446. ); 
  1447.  
  1448. // Remove empty settings so that changes to the defaults in bb_insert_topic() are honoured 
  1449. $bb_insert_topic_args = array_filter( $bb_insert_topic_args ); 
  1450.  
  1451. // Create the topic 
  1452. if ( !$topic_id = bb_insert_topic( $bb_insert_topic_args ) ) { 
  1453. $this->error = new IXR_Error( 500, __( 'The topic could not be created.' ) ); 
  1454. return $this->error; 
  1455.  
  1456. // Inject structure into an array suitable for bb_insert_post() 
  1457. $bb_insert_post_args = array( 
  1458. 'topic_id' => (int) $topic_id,  
  1459. 'post_text' => (string) $structure['text'] 
  1460. ); 
  1461.  
  1462. // Create the post 
  1463. if ( !$post_id = bb_insert_post( $bb_insert_post_args ) ) { 
  1464. $this->error = new IXR_Error( 500, __( 'The post could not be created.' ) ); 
  1465. return $this->error; 
  1466.  
  1467. // Only include "safe" data in the array 
  1468. $topic = $this->prepare_topic( get_topic( $topic_id ) ); 
  1469.  
  1470. do_action( 'bb_xmlrpc_call_return', 'bb.newTopic' ); 
  1471.  
  1472. return $topic; 
  1473.  
  1474. /** 
  1475. * Edits an existing topic 
  1476. * 
  1477. * @since 1.0 
  1478. * @return array|object The topic data when successfully edited or an IXR_Error object on failure 
  1479. * @param array $args Arguments passed by the XML-RPC call 
  1480. * @param string $args[0] The username for authentication 
  1481. * @param string $args[1] The password for authentication 
  1482. * @param array $args[2] The values for the various parameters in the edited topic 
  1483. * @param integer|string $args[2]['topic_id'] The topic's id or slug 
  1484. * @param string $args[2]['title'] The title of the topic 
  1485. * @param string $args[2]['text'] The text of the topic 
  1486. * 
  1487. * XML-RPC request to edit the title of a topic with the slug "insane-monkeys" 
  1488. * <methodCall> 
  1489. * <methodName>bb.editTopic</methodName> 
  1490. * <params> 
  1491. * <param><value><string>joeblow</string></value></param> 
  1492. * <param><value><string>123password</string></value></param> 
  1493. * <param><value><struct> 
  1494. * <member> 
  1495. * <name>topic_id</name> 
  1496. * <value><string>insane-monkeys</string></value> 
  1497. * </member> 
  1498. * <member> 
  1499. * <name>title</name> 
  1500. * <value><string>Very insane monkeys</string></value> 
  1501. * </member> 
  1502. * </struct></value></param> 
  1503. * </params> 
  1504. * </methodCall> 
  1505. */ 
  1506. function bb_editTopic( $args ) 
  1507. do_action( 'bb_xmlrpc_call', 'bb.editTopic' ); 
  1508.  
  1509. // Escape args 
  1510. $this->escape( $args ); 
  1511.  
  1512. // Get the login credentials 
  1513. $username = $args[0]; 
  1514. $password = (string) $args[1]; 
  1515.  
  1516. // Check the user is valid 
  1517. $user = $this->authenticate( $username, $password, 'edit_topics', __( 'You do not have permission to edit topics.' ) ); 
  1518.  
  1519. // Additionally they need to be able to edit posts 
  1520. if ( !$this->error && !bb_current_user_can( 'edit_posts' ) ) { 
  1521. $this->error = new IXR_Error( 403, __( 'You do not have permission to edit posts.' ) ); 
  1522.  
  1523. do_action( 'bb_xmlrpc_call_authenticated', 'bb.editTopic' ); 
  1524.  
  1525. // If an error was raised by authentication or by an action then return it 
  1526. if ( $this->error ) { 
  1527. return $this->error; 
  1528.  
  1529. // Make sure there is something for us to do 
  1530. if ( !$args[2] || !is_array( $args[2] ) || !count( $args[2] ) ) { 
  1531. $this->error = new IXR_Error( 400, __( 'The topic data is invalid.' ) ); 
  1532. return $this->error; 
  1533.  
  1534. $structure = (array) $args[2]; 
  1535.  
  1536. // Can be numeric id or slug 
  1537. $topic_id = isset( $structure['topic_id'] ) ? $structure['topic_id'] : false; 
  1538.  
  1539. // Check for bad data 
  1540. if ( !$topic_id || ( !is_string( $topic_id ) && !is_integer( $topic_id ) ) ) { 
  1541. $this->error = new IXR_Error( 400, __( 'The topic id is invalid.' ) ); 
  1542. return $this->error; 
  1543.  
  1544. // Check the requested topic exists 
  1545. if ( !$topic = get_topic( $topic_id ) ) { 
  1546. $this->error = new IXR_Error( 400, __( 'No topic found.' ) ); 
  1547. return $this->error; 
  1548.  
  1549. // The topic id may have been a slug, so make sure it's an integer here 
  1550. $topic_id = (int) $topic->topic_id; 
  1551.  
  1552. // Make sure they are allowed to edit this topic 
  1553. if ( !bb_current_user_can( 'edit_topic', $topic_id ) ) { 
  1554. $this->error = new IXR_Error( 403, __( 'You do not have permission to edit this topic.' ) ); 
  1555. return $this->error; 
  1556.  
  1557. // Get the first post in the topic (that's where the content is) 
  1558. if ( !$post = bb_get_first_post( $topic_id ) ) { 
  1559. $this->error = new IXR_Error( 400, __( 'No posts found.' ) ); 
  1560. return $this->error; 
  1561.  
  1562. $post_id = (int) $post->post_id; 
  1563.  
  1564. // Make sure they are allowed to edit this post 
  1565. if ( !bb_current_user_can( 'edit_post', $post_id ) ) { 
  1566. $this->error = new IXR_Error( 403, __( 'You do not have permission to edit this post.' ) ); 
  1567. return $this->error; 
  1568.  
  1569. // The topic requires a title 
  1570. if ( isset( $structure['title'] ) && !$structure['title'] ) { 
  1571. $this->error = new IXR_Error( 400, __( 'The topic title is invalid.' ) ); 
  1572. return $this->error; 
  1573.  
  1574. // The topic requires text 
  1575. if ( isset( $structure['text'] ) && !$structure['text'] ) { 
  1576. $this->error = new IXR_Error( 400, __( 'The topic text is invalid.' ) ); 
  1577. return $this->error; 
  1578.  
  1579. if ( $structure['title'] ) { 
  1580. if ( !bb_insert_topic( array( 'topic_title' => (string) $structure['title'], 'topic_id' => $topic_id ) ) ) { 
  1581. $this->error = new IXR_Error( 500, __( 'The topic could not be edited.' ) ); 
  1582. return $this->error; 
  1583.  
  1584. if ( $structure['text'] ) { 
  1585. if ( !bb_insert_post( array( 'post_text' => (string) $structure['text'], 'post_id' => $post_id, 'topic_id'=> $topic_id ) ) ) { 
  1586. $this->error = new IXR_Error( 500, __( 'The post could not be edited.' ) ); 
  1587. return $this->error; 
  1588.  
  1589. // Only include "safe" data in the array 
  1590. $topic = $this->prepare_topic( get_topic( $topic_id ) ); 
  1591.  
  1592. do_action( 'bb_xmlrpc_call_return', 'bb.editTopic' ); 
  1593.  
  1594. return $topic; 
  1595.  
  1596. /** 
  1597. * Deletes a topic 
  1598. * 
  1599. * @since 1.0 
  1600. * @return integer|object 0 if already changed, 1 when successfully changed or an IXR_Error object on failure 
  1601. * @param array $args Arguments passed by the XML-RPC call 
  1602. * @param string $args[0] The username for authentication 
  1603. * @param string $args[1] The password for authentication 
  1604. * @param integer|string $args[2] The unique id of the topic to be deleted 
  1605. * @param integer $args[3] 1 deletes the topic, 0 undeletes the topic 
  1606. * 
  1607. * XML-RPC request to delete a topic with id of 34 
  1608. * <methodCall> 
  1609. * <methodName>bb.deleteTopic</methodName> 
  1610. * <params> 
  1611. * <param><value><string>joeblow</string></value></param> 
  1612. * <param><value><string>123password</string></value></param> 
  1613. * <param><value><integer>34</integer></value></param> 
  1614. * </params> 
  1615. * </methodCall> 
  1616. */ 
  1617. function bb_deleteTopic( $args ) 
  1618. do_action( 'bb_xmlrpc_call', 'bb.deleteTopic' ); 
  1619.  
  1620. // Escape args 
  1621. $this->escape( $args ); 
  1622.  
  1623. // Get the login credentials 
  1624. $username = $args[0]; 
  1625. $password = (string) $args[1]; 
  1626.  
  1627. // Check the user is valid 
  1628. $user = $this->authenticate( $username, $password, 'delete_topics', __( 'You do not have permission to delete topics.' ) ); 
  1629.  
  1630. do_action( 'bb_xmlrpc_call_authenticated', 'bb.deleteTopic' ); 
  1631.  
  1632. // If an error was raised by authentication or by an action then return it 
  1633. if ( $this->error ) { 
  1634. return $this->error; 
  1635.  
  1636. // Can be numeric id or slug 
  1637. $topic_id = isset( $args[2] ) ? $args[2] : false; 
  1638.  
  1639. // Check for bad data 
  1640. if ( !$topic_id || ( !is_string( $topic_id ) && !is_integer( $topic_id ) ) ) { 
  1641. $this->error = new IXR_Error( 400, __( 'The topic id is invalid.' ) ); 
  1642. return $this->error; 
  1643.  
  1644. // Check the requested topic exists 
  1645. if ( !$topic = get_topic( $topic_id ) ) { 
  1646. $this->error = new IXR_Error( 400, __( 'No topic found.' ) ); 
  1647. return $this->error; 
  1648.  
  1649. // The topic id may have been a slug, so make sure it's an integer here 
  1650. $topic_id = (int) $topic->topic_id; 
  1651.  
  1652. $delete = isset( $args[3] ) ? (int) $args[3] : 1; 
  1653.  
  1654. // Don't do anything if already set that way 
  1655. if ( $delete === (int) $topic->topic_status ) { 
  1656. return 0; 
  1657.  
  1658. // Make sure they are allowed to delete this topic 
  1659. if ( !bb_current_user_can( 'delete_topic', $topic_id ) ) { 
  1660. $this->error = new IXR_Error( 403, __( 'You do not have permission to delete this topic.' ) ); 
  1661. return $this->error; 
  1662.  
  1663. // Delete the topic 
  1664. if ( !bb_delete_topic( $topic_id, $delete ) ) { 
  1665. $this->error = new IXR_Error( 500, __( 'The topic could not be deleted.' ) ); 
  1666. return $this->error; 
  1667.  
  1668. $result = 1; 
  1669.  
  1670. do_action( 'bb_xmlrpc_call_return', 'bb.deleteTopic' ); 
  1671.  
  1672. return $result; 
  1673.  
  1674. /** 
  1675. * Moves a topic to a different forum 
  1676. * 
  1677. * @since 1.0 
  1678. * @return integer|object the forum id where the topic lives after the method is called or an IXR_Error object on failure 
  1679. * @param array $args Arguments passed by the XML-RPC call 
  1680. * @param string $args[0] The username for authentication 
  1681. * @param string $args[1] The password for authentication 
  1682. * @param integer|string $args[2] The unique id of the topic to be moved 
  1683. * @param integer|string $args[3] The unique id of the forum to be moved to 
  1684. * 
  1685. * XML-RPC request to move the topic with id of 34 to forum with slug of "better-forum" 
  1686. * <methodCall> 
  1687. * <methodName>bb.moveTopic</methodName> 
  1688. * <params> 
  1689. * <param><value><string>joeblow</string></value></param> 
  1690. * <param><value><string>123password</string></value></param> 
  1691. * <param><value><integer>34</integer></value></param> 
  1692. * <param><value><string>better-forum</string></value></param> 
  1693. * </params> 
  1694. * </methodCall> 
  1695. */ 
  1696. function bb_moveTopic( $args ) 
  1697. do_action( 'bb_xmlrpc_call', 'bb.moveTopic' ); 
  1698.  
  1699. // Escape args 
  1700. $this->escape( $args ); 
  1701.  
  1702. // Get the login credentials 
  1703. $username = $args[0]; 
  1704. $password = (string) $args[1]; 
  1705.  
  1706. // Check the user is valid 
  1707. $user = $this->authenticate( $username, $password, 'move_topics', __( 'You do not have permission to move topics.' ) ); 
  1708.  
  1709. do_action( 'bb_xmlrpc_call_authenticated', 'bb.moveTopic' ); 
  1710.  
  1711. // If an error was raised by authentication or by an action then return it 
  1712. if ( $this->error ) { 
  1713. return $this->error; 
  1714.  
  1715. // Can be numeric id or slug 
  1716. $topic_id = isset( $args[2] ) ? $args[2] : false; 
  1717.  
  1718. // Check for bad data 
  1719. if ( !$topic_id || ( !is_string( $topic_id ) && !is_integer( $topic_id ) ) ) { 
  1720. $this->error = new IXR_Error( 400, __( 'The topic id is invalid.' ) ); 
  1721. return $this->error; 
  1722.  
  1723. // Check the requested topic exists 
  1724. if ( !$topic = get_topic( $topic_id ) ) { 
  1725. $this->error = new IXR_Error( 400, __( 'No topic found.' ) ); 
  1726. return $this->error; 
  1727.  
  1728. // The topic id may have been a slug, so make sure it's an integer here 
  1729. $topic_id = (int) $topic->topic_id; 
  1730.  
  1731. // Can be numeric id or slug 
  1732. $forum_id = isset( $args[3] ) ? $args[3] : false; 
  1733.  
  1734. // Check for bad data 
  1735. if ( !$forum_id || ( !is_string( $forum_id ) && !is_integer( $forum_id ) ) ) { 
  1736. $this->error = new IXR_Error( 400, __( 'The forum id is invalid.' ) ); 
  1737. return $this->error; 
  1738.  
  1739. // Check the requested topic exists 
  1740. if ( !$forum = bb_get_forum( $forum_id ) ) { 
  1741. $this->error = new IXR_Error( 400, __( 'No forum found.' ) ); 
  1742. return $this->error; 
  1743.  
  1744. // The forum id may have been a slug, so make sure it's an integer here 
  1745. $forum_id = (int) $forum->forum_id; 
  1746.  
  1747. // Only move it if it isn't already there 
  1748. if ( $forum_id !== (int) $topic->forum_id ) { 
  1749. // Make sure they are allowed to move this topic specifically to this forum 
  1750. if ( !bb_current_user_can( 'move_topic', $topic_id, $forum_id ) ) { 
  1751. $this->error = new IXR_Error( 403, __( 'You are not allowed to move this topic to this forum.' ) ); 
  1752. return $this->error; 
  1753.  
  1754. // Move the topic 
  1755. if ( !bb_move_topic( $topic_id, $forum_id ) ) { 
  1756. $this->error = new IXR_Error( 500, __( 'The topic could not be moved.' ) ); 
  1757. return $this->error; 
  1758.  
  1759. do_action( 'bb_xmlrpc_call_return', 'bb.moveTopic' ); 
  1760.  
  1761. return $forum_id; 
  1762.  
  1763. /** 
  1764. * Sticks a topic to the top of a forum or the front page 
  1765. * 
  1766. * @since 1.0 
  1767. * @return integer|object 0 if it is already stuck to the desired location, 1 when successfully stuck or an IXR_Error object on failure 
  1768. * @param array $args Arguments passed by the XML-RPC call 
  1769. * @param string $args[0] The username for authentication 
  1770. * @param string $args[1] The password for authentication 
  1771. * @param integer|string $args[2] The unique id of the topic to be stuck 
  1772. * @param integer $args[3] 0 unsticks, 1 sticks, 2 sticks to front (optional) 
  1773. * 
  1774. * XML-RPC request to stick the topic with id of 34 to the front page 
  1775. * <methodCall> 
  1776. * <methodName>bb.stickTopic</methodName> 
  1777. * <params> 
  1778. * <param><value><string>joeblow</string></value></param> 
  1779. * <param><value><string>123password</string></value></param> 
  1780. * <param><value><integer>34</integer></value></param> 
  1781. * <param><value><integer>1</integer></value></param> 
  1782. * </params> 
  1783. * </methodCall> 
  1784. */ 
  1785. function bb_stickTopic( $args ) 
  1786. do_action( 'bb_xmlrpc_call', 'bb.stickTopic' ); 
  1787.  
  1788. // Escape args 
  1789. $this->escape( $args ); 
  1790.  
  1791. // Get the login credentials 
  1792. $username = $args[0]; 
  1793. $password = (string) $args[1]; 
  1794.  
  1795. // Check the user is valid 
  1796. $user = $this->authenticate( $username, $password, 'stick_topics', __( 'You do not have permission to stick topics.' ) ); 
  1797.  
  1798. do_action( 'bb_xmlrpc_call_authenticated', 'bb.stickTopic' ); 
  1799.  
  1800. // If an error was raised by authentication or by an action then return it 
  1801. if ( $this->error ) { 
  1802. return $this->error; 
  1803.  
  1804. // Can be numeric id or slug 
  1805. $topic_id = isset( $args[2] ) ? $args[2] : false; 
  1806.  
  1807. // Check for bad data 
  1808. if ( !$topic_id || ( !is_string( $topic_id ) && !is_integer( $topic_id ) ) ) { 
  1809. $this->error = new IXR_Error( 400, __( 'The topic id is invalid.' ) ); 
  1810. return $this->error; 
  1811.  
  1812. // Check the requested topic exists 
  1813. if ( !$topic = get_topic( $topic_id ) ) { 
  1814. $this->error = new IXR_Error( 400, __( 'No topic found.' ) ); 
  1815. return $this->error; 
  1816.  
  1817. // The topic id may have been a slug, so make sure it's an integer here 
  1818. $topic_id = (int) $topic->topic_id; 
  1819.  
  1820. // Make sure they are allowed to stick this topic 
  1821. if ( !bb_current_user_can( 'stick_topic', $topic_id ) ) { 
  1822. $this->error = new IXR_Error( 403, __( 'You do not have permission to stick this topic.' ) ); 
  1823. return $this->error; 
  1824.  
  1825. // Stick to where? 
  1826. $where = isset( $args[3] ) ? (int) $args[3] : 1; 
  1827.  
  1828. // Forget it if it's already there 
  1829. if ( $where === (int) $topic->topic_sticky ) { 
  1830. return 0; 
  1831.  
  1832. // Stick the topic 
  1833. if ( !bb_stick_topic( $topic_id, $where ) ) { 
  1834. $this->error = new IXR_Error( 500, __( 'The topic could not be stuck.' ) ); 
  1835. return $this->error; 
  1836.  
  1837. $result = 1; 
  1838.  
  1839. do_action( 'bb_xmlrpc_call_return', 'bb.stickTopic' ); 
  1840.  
  1841. return $result; 
  1842.  
  1843.  
  1844.  
  1845. /** 
  1846. * Closes a topic 
  1847. * 
  1848. * @since 1.0 
  1849. * @return integer|object 0 when already changed, 1 when successfully changed or an IXR_Error object on failure 
  1850. * @param array $args Arguments passed by the XML-RPC call 
  1851. * @param string $args[0] The username for authentication 
  1852. * @param string $args[1] The password for authentication 
  1853. * @param integer|string $args[2] The unique id of the topic to be closed 
  1854. * @param integer $args[2] 0 closes, 1 opens (optional) 
  1855. * 
  1856. * XML-RPC request to close the topic with slug of "really-old-topic" 
  1857. * <methodCall> 
  1858. * <methodName>bb.closeTopic</methodName> 
  1859. * <params> 
  1860. * <param><value><string>joeblow</string></value></param> 
  1861. * <param><value><string>123password</string></value></param> 
  1862. * <param><value><string>really-old-topic</string></value></param> 
  1863. * </params> 
  1864. * </methodCall> 
  1865. * 
  1866. * XML-RPC request to open the topic with slug of "really-old-topic" 
  1867. * <methodCall> 
  1868. * <methodName>bb.closeTopic</methodName> 
  1869. * <params> 
  1870. * <param><value><string>joeblow</string></value></param> 
  1871. * <param><value><string>123password</string></value></param> 
  1872. * <param><value><string>really-old-topic</string></value></param> 
  1873. * <param><value><integer>1</integer></value></param> 
  1874. * </params> 
  1875. * </methodCall> 
  1876. */ 
  1877. function bb_closeTopic( $args ) 
  1878. do_action( 'bb_xmlrpc_call', 'bb.closeTopic' ); 
  1879.  
  1880. // Escape args 
  1881. $this->escape( $args ); 
  1882.  
  1883. // Get the login credentials 
  1884. $username = $args[0]; 
  1885. $password = (string) $args[1]; 
  1886.  
  1887. // Check the user is valid 
  1888. $user = $this->authenticate( $username, $password, 'close_topics', __( 'You do not have permission to close topics.' ) ); 
  1889.  
  1890. do_action( 'bb_xmlrpc_call_authenticated', 'bb.closeTopic' ); 
  1891.  
  1892. // If an error was raised by authentication or by an action then return it 
  1893. if ( $this->error ) { 
  1894. return $this->error; 
  1895.  
  1896. // Can be numeric id or slug 
  1897. $topic_id = isset( $args[2] ) ? $args[2] : false; 
  1898.  
  1899. // Check for bad data 
  1900. if ( !$topic_id || ( !is_string( $topic_id ) && !is_integer( $topic_id ) ) ) { 
  1901. $this->error = new IXR_Error( 400, __( 'The topic id is invalid.' ) ); 
  1902. return $this->error; 
  1903.  
  1904. // Check the requested topic exists 
  1905. if ( !$topic = get_topic( $topic_id ) ) { 
  1906. $this->error = new IXR_Error( 400, __( 'No topic found.' ) ); 
  1907. return $this->error; 
  1908.  
  1909. // The topic id may have been a slug, so make sure it's an integer here 
  1910. $topic_id = (int) $topic->topic_id; 
  1911.  
  1912. // Make sure they are allowed to close this topic 
  1913. if ( !bb_current_user_can( 'close_topic', $topic_id ) ) { 
  1914. $this->error = new IXR_Error( 403, __( 'You do not have permission to close this topic.' ) ); 
  1915. return $this->error; 
  1916.  
  1917. // Open or close? 
  1918. $close = isset( $args[3] ) ? (int) $args[3] : 0; 
  1919.  
  1920. // Forget it if it's already matching 
  1921. if ( $close === (int) $topic->topic_open ) { 
  1922. return 0; 
  1923.  
  1924. // Close the topic 
  1925. if ( !$close && !bb_close_topic( $topic_id ) ) { 
  1926. $this->error = new IXR_Error( 500, __( 'The topic could not be closed.' ) ); 
  1927. return $this->error; 
  1928.  
  1929. // Open the topic 
  1930. if ( $close && !bb_open_topic( $topic_id ) ) { 
  1931. $this->error = new IXR_Error( 500, __( 'The topic could not be opened.' ) ); 
  1932. return $this->error; 
  1933.  
  1934. $result = 1; 
  1935.  
  1936. do_action( 'bb_xmlrpc_call_return', 'bb.closeTopic' ); 
  1937.  
  1938. return $result; 
  1939.  
  1940.  
  1941.  
  1942. /** 
  1943. * bbPress publishing API - Post XML-RPC methods 
  1944. */ 
  1945.  
  1946. /** 
  1947. * Returns a numerical count of posts 
  1948. * 
  1949. * @since 1.0 
  1950. * @return integer|object The number of topics when successfully executed or an IXR_Error object on failure 
  1951. * @param array $args Arguments passed by the XML-RPC call 
  1952. * @param string $args[0] The username for authentication 
  1953. * @param string $args[1] The password for authentication 
  1954. * @param integer|string $args[2] The topic id or slug 
  1955. * 
  1956. * XML-RPC request to get a count of all posts in the topic with slug "countable-topic" 
  1957. * <methodCall> 
  1958. * <methodName>bb.getPostCount</methodName> 
  1959. * <params> 
  1960. * <param><value><string>joeblow</string></value></param> 
  1961. * <param><value><string>123password</string></value></param> 
  1962. * <param><value><string>countable-topic</string></value></param> 
  1963. * </params> 
  1964. * </methodCall> 
  1965. */ 
  1966. function bb_getPostCount( $args ) 
  1967. do_action( 'bb_xmlrpc_call', 'bb.getPostCount' ); 
  1968.  
  1969. // Escape args 
  1970. $this->escape( $args ); 
  1971.  
  1972. // Get the login credentials 
  1973. $username = $args[0]; 
  1974. $password = (string) $args[1]; 
  1975.  
  1976. // Check the user is valid 
  1977. if ( $this->auth_readonly ) { 
  1978. $user = $this->authenticate( $username, $password ); 
  1979.  
  1980. do_action( 'bb_xmlrpc_call_authenticated', 'bb.getPostCount' ); 
  1981.  
  1982. // If an error was raised by authentication or by an action then return it 
  1983. if ( $this->error ) { 
  1984. return $this->error; 
  1985.  
  1986. // Can be numeric id or slug 
  1987. $topic_id = isset( $args[2] ) ? $args[2] : false; 
  1988.  
  1989. // Check for bad data 
  1990. if ( !$topic_id || ( !is_string( $topic_id ) && !is_integer( $topic_id ) ) ) { 
  1991. $this->error = new IXR_Error( 400, __( 'The topic id is invalid.' ) ); 
  1992. return $this->error; 
  1993.  
  1994. // Check the requested topic exists 
  1995. if ( !$topic = get_topic( $topic_id ) ) { 
  1996. $this->error = new IXR_Error( 400, __( 'No topic found.' ) ); 
  1997. return $this->error; 
  1998.  
  1999. // OK, let's trust the count in the topic table 
  2000. $count = $topic->topic_posts; 
  2001.  
  2002. do_action( 'bb_xmlrpc_call_return', 'bb.getPostCount' ); 
  2003.  
  2004. // Return the count of posts 
  2005. return $count; 
  2006.  
  2007. /** 
  2008. * Returns details of the posts in a given topic 
  2009. * 
  2010. * @since 1.0 
  2011. * @return array|object The posts when successfully executed or an IXR_Error object on failure 
  2012. * @param array $args Arguments passed by the XML-RPC call 
  2013. * @param string $args[0] The username for authentication 
  2014. * @param string $args[1] The password for authentication 
  2015. * @param integer|string $args[2] The topic id or slug 
  2016. * @param integer $args[3] The number of posts to return (optional) 
  2017. * @param integer $args[4] The number of the page to return (optional) 
  2018. * 
  2019. * XML-RPC request to get all posts in the topic with id number 53 
  2020. * <methodCall> 
  2021. * <methodName>bb.getPosts</methodName> 
  2022. * <params> 
  2023. * <param><value><string>joeblow</string></value></param> 
  2024. * <param><value><string>123password</string></value></param> 
  2025. * <param><value><int>53</int></value></param> 
  2026. * </params> 
  2027. * </methodCall> 
  2028. * 
  2029. * XML-RPC request to get the latest 5 posts in the topic with id number 341 
  2030. * <methodCall> 
  2031. * <methodName>bb.getPosts</methodName> 
  2032. * <params> 
  2033. * <param><value><string>joeblow</string></value></param> 
  2034. * <param><value><string>123password</string></value></param> 
  2035. * <param><value><int>341</int></value></param> 
  2036. * <param><value><int>5</int></value></param> 
  2037. * </params> 
  2038. * </methodCall> 
  2039. * 
  2040. * XML-RPC request to get posts 11 to 20 in the topic with slug "long-topic" 
  2041. * <methodCall> 
  2042. * <methodName>bb.getPosts</methodName> 
  2043. * <params> 
  2044. * <param><value><string>joeblow</string></value></param> 
  2045. * <param><value><string>123password</string></value></param> 
  2046. * <param><value><string>long-topic</string></value></param> 
  2047. * <param><value><int>10</int></value></param> 
  2048. * <param><value><int>2</int></value></param> 
  2049. * </params> 
  2050. * </methodCall> 
  2051. */ 
  2052. function bb_getPosts( $args ) 
  2053. do_action( 'bb_xmlrpc_call', 'bb.getPosts' ); 
  2054.  
  2055. // Escape args 
  2056. $this->escape( $args ); 
  2057.  
  2058. // Get the login credentials 
  2059. $username = $args[0]; 
  2060. $password = (string) $args[1]; 
  2061.  
  2062. // Check the user is valid 
  2063. if ( $this->auth_readonly ) { 
  2064. $user = $this->authenticate( $username, $password ); 
  2065.  
  2066. do_action( 'bb_xmlrpc_call_authenticated', 'bb.getPosts' ); 
  2067.  
  2068. // If an error was raised by authentication or by an action then return it 
  2069. if ( $this->error ) { 
  2070. return $this->error; 
  2071.  
  2072. // Can be numeric id or slug 
  2073. $topic_id = isset( $args[2] ) ? $args[2] : false; 
  2074.  
  2075. // Check for bad data 
  2076. if ( !$topic_id || ( !is_string( $topic_id ) && !is_integer( $topic_id ) ) ) { 
  2077. $this->error = new IXR_Error( 400, __( 'The topic id is invalid.' ) ); 
  2078. return $this->error; 
  2079.  
  2080. // Check the requested topic exists 
  2081. if ( !$topic = get_topic( $topic_id ) ) { 
  2082. $this->error = new IXR_Error( 400, __( 'No topic found.' ) ); 
  2083. return $this->error; 
  2084.  
  2085. // The topic id may have been a slug, so make sure it's an integer here 
  2086. $topic_id = (int) $topic->topic_id; 
  2087.  
  2088. // Setup an array to store arguments to pass to get_thread() function 
  2089. $get_thread_args = array(); 
  2090.  
  2091. // Can only be an integer 
  2092. if ( isset( $args[3] ) && $per_page = (int) $args[3] ) { 
  2093. $get_thread_args['per_page'] = $per_page; 
  2094.  
  2095. // Can only be an integer 
  2096. if ( isset( $args[4] ) && $page = (int) $args[4] ) { 
  2097. $get_thread_args['page'] = $page; 
  2098.  
  2099. // Get the posts 
  2100. if ( !$posts = get_thread( $topic_id, $get_thread_args ) ) { 
  2101. $this->error = new IXR_Error( 500, __( 'No posts found.' ) ); 
  2102. return $this->error; 
  2103.  
  2104. // Only include "safe" data in the array 
  2105. $_posts = array(); 
  2106. foreach ( $posts as $post ) { 
  2107. $_posts[] = $this->prepare_post( $post ); 
  2108.  
  2109. do_action( 'bb_xmlrpc_call_return', 'bb.getPosts' ); 
  2110.  
  2111. // Return the posts 
  2112. return $_posts; 
  2113.  
  2114. /** 
  2115. * Returns details of a post 
  2116. * 
  2117. * @since 1.0 
  2118. * @return array|object An array containing details of the returned post when successfully executed or an IXR_Error object on failure 
  2119. * @param array $args Arguments passed by the XML-RPC call 
  2120. * @param string $args[0] The username for authentication 
  2121. * @param string $args[1] The password for authentication 
  2122. * @param integer $args[2] The post's id 
  2123. * 
  2124. * XML-RPC request to get the post with id number 32 
  2125. * <methodCall> 
  2126. * <methodName>bb.getPost</methodName> 
  2127. * <params> 
  2128. * <param><value><string>joeblow</string></value></param> 
  2129. * <param><value><string>123password</string></value></param> 
  2130. * <param><value><int>32</int></value></param> 
  2131. * </params> 
  2132. * </methodCall> 
  2133. */ 
  2134. function bb_getPost( $args ) 
  2135. do_action( 'bb_xmlrpc_call', 'bb.getPost' ); 
  2136.  
  2137. // Escape args 
  2138. $this->escape( $args ); 
  2139.  
  2140. // Get the login credentials 
  2141. $username = $args[0]; 
  2142. $password = (string) $args[1]; 
  2143.  
  2144. // Check the user is valid 
  2145. if ( $this->auth_readonly ) { 
  2146. $user = $this->authenticate( $username, $password ); 
  2147.  
  2148. do_action( 'bb_xmlrpc_call_authenticated', 'bb.getPost' ); 
  2149.  
  2150. // If an error was raised by authentication or by an action then return it 
  2151. if ( $this->error ) { 
  2152. return $this->error; 
  2153.  
  2154. // Can be numeric id or slug 
  2155. $post_id = isset( $args[2] ) ? (int) $args[2] : false; 
  2156.  
  2157. // Check for bad data 
  2158. if ( !$post_id ) { 
  2159. $this->error = new IXR_Error( 400, __( 'The post id is invalid.' ) ); 
  2160. return $this->error; 
  2161.  
  2162. // Check the requested post exists 
  2163. if ( !$post = bb_get_post( $post_id ) ) { 
  2164. $this->error = new IXR_Error( 400, __( 'No post found.' ) ); 
  2165. return $this->error; 
  2166.  
  2167. // Only include "safe" data in the array 
  2168. $_post = $this->prepare_post( $post ); 
  2169.  
  2170. do_action( 'bb_xmlrpc_call_return', 'bb.getPost' ); 
  2171.  
  2172. // Return the post 
  2173. return $_post; 
  2174.  
  2175. /** 
  2176. * Creates a new post in a given topic 
  2177. * 
  2178. * @since 1.0 
  2179. * @return array|object The post data when successfully created or an IXR_Error object on failure 
  2180. * @param array $args Arguments passed by the XML-RPC call 
  2181. * @param string $args[0] The username for authentication 
  2182. * @param string $args[1] The password for authentication 
  2183. * @param array $args[2] The values for the various parameters in the new topic 
  2184. * @param string $args[2]['text'] The text of the topic 
  2185. * @param integer|string $args[2]['topic_id'] The unique id of the topic which will contain this topic, slugs are OK to use too 
  2186. * 
  2187. * XML-RPC request to create a new post in the topic with slug "totally-worth-it" 
  2188. * <methodCall> 
  2189. * <methodName>bb.newPost</methodName> 
  2190. * <params> 
  2191. * <param><value><string>joeblow</string></value></param> 
  2192. * <param><value><string>123password</string></value></param> 
  2193. * <param><value><struct> 
  2194. * <member> 
  2195. * <name>text</name> 
  2196. * <value><string>I agree, it is totally worth it.</string></value> 
  2197. * </member> 
  2198. * <member> 
  2199. * <name>topic_id</name> 
  2200. * <value><string>totally-worth-it</string></value> 
  2201. * </member> 
  2202. * </struct></value></param> 
  2203. * </params> 
  2204. * </methodCall> 
  2205. */ 
  2206. function bb_newPost( $args ) 
  2207. do_action( 'bb_xmlrpc_call', 'bb.newPost' ); 
  2208.  
  2209. // Escape args 
  2210. $this->escape( $args ); 
  2211.  
  2212. // Get the login credentials 
  2213. $username = $args[0]; 
  2214. $password = (string) $args[1]; 
  2215.  
  2216. // Check the user is valid 
  2217. $user = $this->authenticate( $username, $password, 'write_posts', __( 'You do not have permission to write posts.' ) ); 
  2218.  
  2219. do_action( 'bb_xmlrpc_call_authenticated', 'bb.newPost' ); 
  2220.  
  2221. // If an error was raised by authentication or by an action then return it 
  2222. if ( $this->error ) { 
  2223. return $this->error; 
  2224.  
  2225. // Make sure there is something for us to do 
  2226. if ( !$args[2] || !is_array( $args[2] ) || !count( $args[2] ) ) { 
  2227. $this->error = new IXR_Error( 400, __( 'The post data is invalid.' ) ); 
  2228. return $this->error; 
  2229.  
  2230. $structure = (array) $args[2]; 
  2231.  
  2232. // Can be numeric id or slug 
  2233. $topic_id = isset( $structure['topic_id'] ) ? $structure['topic_id'] : false; 
  2234.  
  2235. // Check for bad data 
  2236. if ( !$topic_id || ( !is_string( $topic_id ) && !is_integer( $topic_id ) ) ) { 
  2237. $this->error = new IXR_Error( 400, __( 'The topic id is invalid.' ) ); 
  2238. return $this->error; 
  2239.  
  2240. // Check the requested topic exists 
  2241. if ( !$topic = get_topic( $topic_id ) ) { 
  2242. $this->error = new IXR_Error( 400, __( 'No topic found.' ) ); 
  2243. return $this->error; 
  2244.  
  2245. // The topic id may have been a slug, so make sure it's an integer here 
  2246. $topic_id = (int) $topic->topic_id; 
  2247.  
  2248. // Make sure they are allowed to write posts to this topic 
  2249. if ( !bb_current_user_can( 'write_post', $topic_id ) ) { 
  2250. $this->error = new IXR_Error( 403, __( 'You do not have permission to write posts to this topic.' ) ); 
  2251. return $this->error; 
  2252.  
  2253. // The post requires text 
  2254. if ( !isset( $structure['text'] ) || !$structure['text'] ) { 
  2255. $this->error = new IXR_Error( 400, __( 'The post text is invalid.' ) ); 
  2256. return $this->error; 
  2257.  
  2258. // Inject structure into an array suitable for bb_insert_post() 
  2259. $bb_insert_post_args = array( 
  2260. 'topic_id' => $topic_id,  
  2261. 'post_text' => (string) $structure['text'] 
  2262. ); 
  2263.  
  2264. // Create the post 
  2265. if ( !$post_id = bb_insert_post( $bb_insert_post_args ) ) { 
  2266. $this->error = new IXR_Error( 500, __( 'The post could not be created.' ) ); 
  2267. return $this->error; 
  2268.  
  2269. // Only include "safe" data in the array 
  2270. $post = $this->prepare_forum( bb_get_post( $post_id ) ); 
  2271.  
  2272. do_action( 'bb_xmlrpc_call_return', 'bb.newPost' ); 
  2273.  
  2274. return $post; 
  2275.  
  2276. /** 
  2277. * Edits an existing post 
  2278. * 
  2279. * @since 1.0 
  2280. * @return array|object The post data when successfully edited or an IXR_Error object on failure 
  2281. * @param array $args Arguments passed by the XML-RPC call 
  2282. * @param string $args[0] The username for authentication 
  2283. * @param string $args[1] The password for authentication 
  2284. * @param array $args[2] The values for the various parameters in the new topic 
  2285. * @param integer $args[2]['post_id'] The unique id of the post 
  2286. * @param string $args[2]['text'] The text of the topic 
  2287. * 
  2288. * XML-RPC request to edit the text of the post with an id of 452 
  2289. * <methodCall> 
  2290. * <methodName>bb.editPost</methodName> 
  2291. * <params> 
  2292. * <param><value><string>joeblow</string></value></param> 
  2293. * <param><value><string>123password</string></value></param> 
  2294. * <param><value><struct> 
  2295. * <member> 
  2296. * <name>post_id</name> 
  2297. * <value><int>452</int></value> 
  2298. * </member> 
  2299. * <member> 
  2300. * <name>text</name> 
  2301. * <value><string>For now I will withhold my opinion.</string></value> 
  2302. * </member> 
  2303. * </struct></value></param> 
  2304. * </params> 
  2305. * </methodCall> 
  2306. */ 
  2307. function bb_editPost( $args ) 
  2308. do_action( 'bb_xmlrpc_call', 'bb.editPost' ); 
  2309.  
  2310. // Escape args 
  2311. $this->escape( $args ); 
  2312.  
  2313. // Get the login credentials 
  2314. $username = $args[0]; 
  2315. $password = (string) $args[1]; 
  2316.  
  2317. // Check the user is valid 
  2318. $user = $this->authenticate( $username, $password, 'edit_posts', __( 'You do not have permission to edit posts.' ) ); 
  2319.  
  2320. do_action( 'bb_xmlrpc_call_authenticated', 'bb.editPost' ); 
  2321.  
  2322. // If an error was raised by authentication or by an action then return it 
  2323. if ( $this->error ) { 
  2324. return $this->error; 
  2325.  
  2326. // Make sure there is something for us to do 
  2327. if ( !$args[2] || !is_array( $args[2] ) || !count( $args[2] ) ) { 
  2328. $this->error = new IXR_Error( 400, __( 'The post data is invalid.' ) ); 
  2329. return $this->error; 
  2330.  
  2331. $structure = (array) $args[2]; 
  2332.  
  2333. // Can be numeric id or slug 
  2334. $post_id = isset( $structure['post_id'] ) ? (int) $structure['post_id'] : false; 
  2335.  
  2336. // Check for bad data 
  2337. if ( !$post_id ) { 
  2338. $this->error = new IXR_Error( 400, __( 'The post id is invalid.' ) ); 
  2339. return $this->error; 
  2340.  
  2341. // Check the requested topic exists 
  2342. if ( !$post = bb_get_post( $post_id ) ) { 
  2343. $this->error = new IXR_Error( 400, __( 'No post found.' ) ); 
  2344. return $this->error; 
  2345.  
  2346. // Re-assign the post id 
  2347. $post_id = (int) $post->post_id; 
  2348.  
  2349. // Make sure they are allowed to edit this post 
  2350. if ( !bb_current_user_can( 'edit_post', $post_id ) ) { 
  2351. $this->error = new IXR_Error( 403, __( 'You do not have permission to edit this post.' ) ); 
  2352. return $this->error; 
  2353.  
  2354. // The post requires text 
  2355. if ( !isset( $structure['text'] ) || !$structure['text'] ) { 
  2356. $this->error = new IXR_Error( 400, __( 'The post text is invalid.' ) ); 
  2357. return $this->error; 
  2358.  
  2359. // Inject structure into an array suitable for bb_insert_post() 
  2360. $bb_insert_post_args = array( 
  2361. 'post_id' => $post_id,  
  2362. 'post_text' => (string) $structure['text'] 
  2363. ); 
  2364.  
  2365. // Create the post 
  2366. if ( !$post_id = bb_insert_post( $bb_insert_post_args ) ) { 
  2367. $this->error = new IXR_Error( 500, __( 'The post could not be edited.' ) ); 
  2368. return $this->error; 
  2369.  
  2370. // Only include "safe" data in the array 
  2371. $post = $this->prepare_forum( bb_get_post( $post_id ) ); 
  2372.  
  2373. do_action( 'bb_xmlrpc_call_return', 'bb.editPost' ); 
  2374.  
  2375. return $post; 
  2376.  
  2377. /** 
  2378. * Deletes an existing post 
  2379. * 
  2380. * @since 1.0 
  2381. * @return integer|object 1 when successfully deleted, 0 when already deleted or an IXR_Error object on failure 
  2382. * @param array $args Arguments passed by the XML-RPC call 
  2383. * @param string $args[0] The username for authentication 
  2384. * @param string $args[1] The password for authentication 
  2385. * @param array $args[2] The unique id of the post 
  2386. * @param array $args[3] 1 deletes the post, 0 undeletes the post (optional) 
  2387. * 
  2388. * XML-RPC request to delete the post with an id of 4301 
  2389. * <methodCall> 
  2390. * <methodName>bb.editPost</methodName> 
  2391. * <params> 
  2392. * <param><value><string>joeblow</string></value></param> 
  2393. * <param><value><string>123password</string></value></param> 
  2394. * <param><value><int>4301</int></value></param> 
  2395. * </params> 
  2396. * </methodCall> 
  2397. */ 
  2398. function bb_deletePost( $args ) 
  2399. do_action( 'bb_xmlrpc_call', 'bb.deletePost' ); 
  2400.  
  2401. // Escape args 
  2402. $this->escape( $args ); 
  2403.  
  2404. // Get the login credentials 
  2405. $username = $args[0]; 
  2406. $password = (string) $args[1]; 
  2407.  
  2408. // Check the user is valid 
  2409. $user = $this->authenticate( $username, $password, 'delete_posts', __( 'You do not have permission to delete posts.' ) ); 
  2410.  
  2411. do_action( 'bb_xmlrpc_call_authenticated', 'bb.deletePost' ); 
  2412.  
  2413. // If an error was raised by authentication or by an action then return it 
  2414. if ( $this->error ) { 
  2415. return $this->error; 
  2416.  
  2417. // Can be numeric id or slug 
  2418. $post_id = isset( $args[2] ) ? (int) $args[2] : false; 
  2419.  
  2420. // Check for bad data 
  2421. if ( !$post_id ) { 
  2422. $this->error = new IXR_Error( 400, __( 'The post id is invalid.' ) ); 
  2423. return $this->error; 
  2424.  
  2425. // Check the requested topic exists 
  2426. if ( !$post = bb_get_post( $post_id ) ) { 
  2427. $this->error = new IXR_Error( 400, __( 'No post found.' ) ); 
  2428. return $this->error; 
  2429.  
  2430. // Re-assign the post id 
  2431. $post_id = (int) $post->post_id; 
  2432.  
  2433. // Make sure they are allowed to delete this post 
  2434. if ( !bb_current_user_can( 'delete_post', $post_id ) ) { 
  2435. $this->error = new IXR_Error( 403, __( 'You do not have permission to delete this post.' ) ); 
  2436. return $this->error; 
  2437.  
  2438. $status = isset( $args[3] ) ? (int) $args[3] : 1; 
  2439.  
  2440. if ( $status === (int) $post->post_status ) { 
  2441. return 0; 
  2442.  
  2443. // Delete the post 
  2444. if ( !$post_id = bb_delete_post( $post_id, $status ) ) { 
  2445. $this->error = new IXR_Error( 500, __( 'The post could not be edited.' ) ); 
  2446. return $this->error; 
  2447.  
  2448. $result = 1; 
  2449.  
  2450. do_action( 'bb_xmlrpc_call_return', 'bb.deletePost' ); 
  2451.  
  2452. return $result; 
  2453.  
  2454.  
  2455.  
  2456. /** 
  2457. * bbPress publishing API - Topic Tag XML-RPC methods 
  2458. */ 
  2459.  
  2460. /** 
  2461. * Returns the hot tags in order of hotness in a given forum or all hot tags 
  2462. * 
  2463. * @since 1.0 
  2464. * @return integer|object The tag data when successfully executed or an IXR_Error object on failure 
  2465. * @param array $args Arguments passed by the XML-RPC call 
  2466. * @param string $args[0] The username for authentication 
  2467. * @param string $args[1] The password for authentication 
  2468. * @param integer $args[2] The number of tags to return (optional) 
  2469. * @param integer|string $args[3] The forum id or slug (optional) 
  2470. * 
  2471. * XML-RPC request to get the 20 hottest tags in the forum with slug "hawtness" 
  2472. * <methodCall> 
  2473. * <methodName>bb.getTopicTags</methodName> 
  2474. * <params> 
  2475. * <param><value><string>joeblow</string></value></param> 
  2476. * <param><value><string>123password</string></value></param> 
  2477. * <param><value><int>20</int></value></param> 
  2478. * <param><value><string>hawtness</string></value></param> 
  2479. * </params> 
  2480. * </methodCall> 
  2481. */ 
  2482. function bb_getHotTopicTags( $args ) 
  2483. do_action( 'bb_xmlrpc_call', 'bb.getHotTopicTags' ); 
  2484.  
  2485. // Escape args 
  2486. $this->escape( $args ); 
  2487.  
  2488. // Get the login credentials 
  2489. $username = $args[0]; 
  2490. $password = (string) $args[1]; 
  2491.  
  2492. // Check the user is valid 
  2493. if ( $this->auth_readonly ) { 
  2494. $user = $this->authenticate( $username, $password ); 
  2495.  
  2496. do_action( 'bb_xmlrpc_call_authenticated', 'bb.getHotTopicTags' ); 
  2497.  
  2498. // If an error was raised by authentication or by an action then return it 
  2499. if ( $this->error ) { 
  2500. return $this->error; 
  2501.  
  2502. // Must be a number 
  2503. $per_page = isset( $args[2] ) ? (integer) $args[2] : false; 
  2504.  
  2505. // Can be numeric id or slug 
  2506. $forum_id = isset( $args[3] ) ? $args[3] : false; 
  2507.  
  2508. if ( $forum_id ) { 
  2509. // Check for bad data 
  2510. if ( !is_string( $forum_id ) && !is_integer( $forum_id ) ) { 
  2511. $this->error = new IXR_Error( 400, __( 'The forum id is invalid.' ) ); 
  2512. return $this->error; 
  2513.  
  2514. // Check the requested forum exists 
  2515. if ( !$forum = bb_get_forum( $forum_id ) ) { 
  2516. $this->error = new IXR_Error( 404, __( 'No forum found.' ) ); 
  2517. return $this->error; 
  2518.  
  2519. global $bbdb; 
  2520. $topic_ids = $bbdb->get_col( $bbdb->prepare( "SELECT topic_id FROM `" . $bbdb->topics . "` WHERE `topic_status` = 0 AND `topic_open` = 1 AND `tag_count` > 0 AND `forum_id` = %s;", $forum_id ) ); 
  2521.  
  2522. if ( !count( $topic_ids ) ) { 
  2523. $this->error = new IXR_Error( 400, __( 'No topics found.' ) ); 
  2524. return $this->error; 
  2525.  
  2526. global $wp_taxonomy_object; 
  2527. $tags = $wp_taxonomy_object->get_object_terms( $topic_ids, 'bb_topic_tag', array( 'fields' => 'all_with_object_id', 'orderby' => 'count', 'order' => 'DESC' ) ); 
  2528.  
  2529. if ( !$tags || is_wp_error( $tags ) ) { 
  2530. $this->error = new IXR_Error( 500, __( 'Could not retrieve hot topic tags.' ) ); 
  2531. return $this->error; 
  2532. if ( !count( $tags ) ) { 
  2533. $this->error = new IXR_Error( 500, __( 'No hot topic tags found.' ) ); 
  2534. return $this->error; 
  2535. global $bb_log; 
  2536. $bb_log->debug($tags); 
  2537.  
  2538. for ( $i = 0; isset( $tags[$i] ); $i++ ) { 
  2539. _bb_make_tag_compat( $tags[$i] ); 
  2540. $bb_log->debug($tags); 
  2541.  
  2542. // Only include "safe" data in the array 
  2543. $_tags = array(); 
  2544. foreach ( $tags as $tag ) { 
  2545. $_tag = $this->prepare_topic_tag( $tag ); 
  2546. if ( !in_array( $_tag, $_tags ) ) { 
  2547. $_tags[] = $_tag; 
  2548.  
  2549. if ( $per_page ) { 
  2550. $_tags = array_slice( $_tags, 0, $per_page ); 
  2551. } else { 
  2552. if ( !$tags = bb_get_top_tags( array( 'get' => 'all', 'number' => $per_page ) ) ) { 
  2553. $this->error = new IXR_Error( 500, __( 'No hot topic tags found.' ) ); 
  2554. return $this->error; 
  2555.  
  2556. // Only include "safe" data in the array 
  2557. $_tags = array(); 
  2558. foreach ( $tags as $tag ) { 
  2559. $_tags[] = $this->prepare_topic_tag( $tag ); 
  2560.  
  2561. do_action( 'bb_xmlrpc_call', 'bb.getHotTopicTags' ); 
  2562.  
  2563. return $_tags; 
  2564.  
  2565. /** 
  2566. * Returns a numerical count of tags in a given topic or all tags 
  2567. * 
  2568. * @since 1.0 
  2569. * @return integer|object The number of topics when successfully executed or an IXR_Error object on failure 
  2570. * @param array $args Arguments passed by the XML-RPC call 
  2571. * @param string $args[0] The username for authentication 
  2572. * @param string $args[1] The password for authentication 
  2573. * @param integer|string $args[2] The topic id or slug (optional) 
  2574. * 
  2575. * XML-RPC request to get a count of all tags in the topic with slug "woot-frist-topic" 
  2576. * <methodCall> 
  2577. * <methodName>bb.getTopicTagCount</methodName> 
  2578. * <params> 
  2579. * <param><value><string>joeblow</string></value></param> 
  2580. * <param><value><string>123password</string></value></param> 
  2581. * <param><value><string>woot-frist-topic</string></value></param> 
  2582. * </params> 
  2583. * </methodCall> 
  2584. */ 
  2585. function bb_getTopicTagCount( $args ) 
  2586. do_action( 'bb_xmlrpc_call', 'bb.getTopicTagCount' ); 
  2587.  
  2588. // Escape args 
  2589. $this->escape( $args ); 
  2590.  
  2591. // Get the login credentials 
  2592. $username = $args[0]; 
  2593. $password = (string) $args[1]; 
  2594.  
  2595. // Check the user is valid 
  2596. if ( $this->auth_readonly ) { 
  2597. $user = $this->authenticate( $username, $password ); 
  2598.  
  2599. do_action( 'bb_xmlrpc_call_authenticated', 'bb.getTopicTagCount' ); 
  2600.  
  2601. // If an error was raised by authentication or by an action then return it 
  2602. if ( $this->error ) { 
  2603. return $this->error; 
  2604.  
  2605. // Can be numeric id or slug 
  2606. $topic_id = isset( $args[2] ) ? $args[2] : false; 
  2607.  
  2608. // Check for bad data 
  2609. if ( $topic_id ) { 
  2610. if ( !is_string( $topic_id ) && !is_integer( $topic_id ) ) { 
  2611. $this->error = new IXR_Error( 400, __( 'The topic id is invalid.' ) ); 
  2612. return $this->error; 
  2613.  
  2614. // Check the requested topic exists 
  2615. if ( !$topic = get_topic( $topic_id ) ) { 
  2616. $this->error = new IXR_Error( 400, __( 'No topic found.' ) ); 
  2617. return $this->error; 
  2618.  
  2619. // The topic id may have been a slug, so make sure it's an integer here 
  2620. $topic_id = (int) $topic->topic_id; 
  2621.  
  2622. // Now get the tags 
  2623. if ( !$tags = bb_get_topic_tags( $topic_id ) ) { 
  2624. $tags = array(); 
  2625.  
  2626. // Count the tags 
  2627. $count = count( $tags ); 
  2628. } else { 
  2629. global $wp_taxonomy_object; 
  2630. $count = $wp_taxonomy_object->count_terms( 'bb_topic_tag' ); 
  2631. if ( is_wp_error( $count ) ) { 
  2632. $this->error = new IXR_Error( 500, __( 'Could not get a count of all topic tags.' ) ); 
  2633. return $this->error; 
  2634.  
  2635. do_action( 'bb_xmlrpc_call_return', 'bb.getTopicTagCount' ); 
  2636.  
  2637. // Return the count of tags 
  2638. return $count; 
  2639.  
  2640. /** 
  2641. * Returns the tags in a given topic or all tags 
  2642. * 
  2643. * @since 1.0 
  2644. * @return integer|object The tag data when successfully executed or an IXR_Error object on failure 
  2645. * @param array $args Arguments passed by the XML-RPC call 
  2646. * @param string $args[0] The username for authentication 
  2647. * @param string $args[1] The password for authentication 
  2648. * @param integer|string $args[2] The topic id or slug (optional) 
  2649. * 
  2650. * XML-RPC request to get all tags in the topic with slug "woot-frist-topic" 
  2651. * <methodCall> 
  2652. * <methodName>bb.getTopicTags</methodName> 
  2653. * <params> 
  2654. * <param><value><string>joeblow</string></value></param> 
  2655. * <param><value><string>123password</string></value></param> 
  2656. * <param><value><string>woot-frist-topic</string></value></param> 
  2657. * </params> 
  2658. * </methodCall> 
  2659. */ 
  2660. function bb_getTopicTags( $args ) 
  2661. do_action( 'bb_xmlrpc_call', 'bb.getTopicTags' ); 
  2662.  
  2663. // Escape args 
  2664. $this->escape( $args ); 
  2665.  
  2666. // Get the login credentials 
  2667. $username = $args[0]; 
  2668. $password = (string) $args[1]; 
  2669.  
  2670. // Check the user is valid 
  2671. if ( $this->auth_readonly ) { 
  2672. $user = $this->authenticate( $username, $password ); 
  2673.  
  2674. do_action( 'bb_xmlrpc_call_authenticated', 'bb.getTopicTags' ); 
  2675.  
  2676. // If an error was raised by authentication or by an action then return it 
  2677. if ( $this->error ) { 
  2678. return $this->error; 
  2679.  
  2680. // Can be numeric id or slug 
  2681. $topic_id = isset( $args[2] ) ? $args[2] : false; 
  2682.  
  2683. // Check for bad data 
  2684. if ( $topic_id ) { 
  2685. if ( !is_string( $topic_id ) && !is_integer( $topic_id ) ) { 
  2686. $this->error = new IXR_Error( 400, __( 'The topic id is invalid.' ) ); 
  2687. return $this->error; 
  2688.  
  2689. // Check the requested topic exists 
  2690. if ( !$topic = get_topic( $topic_id ) ) { 
  2691. $this->error = new IXR_Error( 400, __( 'No topic found.' ) ); 
  2692. return $this->error; 
  2693.  
  2694. // The topic id may have been a slug, so make sure it's an integer here 
  2695. $topic_id = (int) $topic->topic_id; 
  2696.  
  2697. // Now get the tags 
  2698. if ( !$tags = bb_get_topic_tags( $topic_id ) ) { 
  2699. $this->error = new IXR_Error( 500, __( 'No topic tags found.' ) ); 
  2700. return $this->error; 
  2701. } else { 
  2702. global $wp_taxonomy_object; 
  2703. $tags = $wp_taxonomy_object->get_terms( 'bb_topic_tag', array( 'get' => 'all' ) ); 
  2704. if ( is_wp_error( $tags ) ) { 
  2705. $this->error = new IXR_Error( 500, __( 'Could not retrieve all topic tags.' ) ); 
  2706. return $this->error; 
  2707. for ( $i = 0; isset( $tags[$i] ); $i++ ) { 
  2708. _bb_make_tag_compat( $tags[$i] ); 
  2709.  
  2710. // Only include "safe" data in the array 
  2711. $_tags = array(); 
  2712. foreach ( $tags as $tag ) { 
  2713. $_tags[] = $this->prepare_topic_tag( $tag ); 
  2714.  
  2715. do_action( 'bb_xmlrpc_call_return', 'bb.getTopicTags' ); 
  2716.  
  2717. // Return the tags 
  2718. return $_tags; 
  2719.  
  2720. /** 
  2721. * Returns the topics which are tagged with the given tag 
  2722. * 
  2723. * @since 1.0 
  2724. * @return integer|object The topic data when successfully executed or an IXR_Error object on failure 
  2725. * @param array $args Arguments passed by the XML-RPC call 
  2726. * @param string $args[0] The username for authentication 
  2727. * @param string $args[1] The password for authentication 
  2728. * @param string $args[2] The tag name or slug 
  2729. * @param integer $args[3] The number of topics to return (optional) 
  2730. * @param integer $args[4] The number of the page to return (optional) 
  2731. * 
  2732. * XML-RPC request to get the latest 10 topics tagged with the tag "apples" 
  2733. * <methodCall> 
  2734. * <methodName>bb.getTopicTag</methodName> 
  2735. * <params> 
  2736. * <param><value><string>joeblow</string></value></param> 
  2737. * <param><value><string>123password</string></value></param> 
  2738. * <param><value><string>apples</string></value></param> 
  2739. * <param><value><string>10</string></value></param> 
  2740. * </params> 
  2741. * </methodCall> 
  2742. */ 
  2743. function bb_getTopicTag( $args ) 
  2744. do_action( 'bb_xmlrpc_call', 'bb.getTopicTag' ); 
  2745.  
  2746. // Escape args 
  2747. $this->escape( $args ); 
  2748.  
  2749. // Get the login credentials 
  2750. $username = $args[0]; 
  2751. $password = (string) $args[1]; 
  2752.  
  2753. // Check the user is valid 
  2754. if ( $this->auth_readonly ) { 
  2755. $user = $this->authenticate( $username, $password ); 
  2756.  
  2757. do_action( 'bb_xmlrpc_call_authenticated', 'bb.getTopicTag' ); 
  2758.  
  2759. // If an error was raised by authentication or by an action then return it 
  2760. if ( $this->error ) { 
  2761. return $this->error; 
  2762.  
  2763. // Can only be a string 
  2764. $tag_id = isset( $args[2] ) ? (string) $args[2] : false; 
  2765.  
  2766. // Check for bad data 
  2767. if ( !$tag_id ) { 
  2768. $this->error = new IXR_Error( 400, __( 'The tag id is invalid.' ) ); 
  2769. return $this->error; 
  2770.  
  2771. // Check the requested topic exists 
  2772. if ( !$tag = bb_get_tag( $tag_id ) ) { 
  2773. $this->error = new IXR_Error( 400, __( 'No tag found.' ) ); 
  2774. return $this->error; 
  2775.  
  2776. // Get the numeric tag id 
  2777. $tag_id = (int) $tag->tag_id; 
  2778.  
  2779. // Setup an array to store arguments to pass to get_tagged_topics() function 
  2780. $get_topics_args = array( 
  2781. 'tag_id' => false,  
  2782. 'number' => false,  
  2783. 'page' => false 
  2784. ); 
  2785.  
  2786. // Can only be an integer 
  2787. if ( isset( $args[3] ) && $number = (int) $args[3] ) { 
  2788. $get_topics_args['number'] = $number; 
  2789.  
  2790. // Can only be an integer 
  2791. if ( isset( $args[4] ) && $page = (int) $args[4] ) { 
  2792. $get_topics_args['page'] = $page; 
  2793.  
  2794. // Now get the topics 
  2795. if ( !$topics = get_tagged_topics( $tag_id ) ) { 
  2796. $this->error = new IXR_Error( 500, __( 'No topics found.' ) ); 
  2797. return $this->error; 
  2798.  
  2799. // Only include "safe" data in the array 
  2800. $_topics = array(); 
  2801. foreach ( $topics as $topic ) { 
  2802. $_topics[] = $this->prepare_topic( $topic ); 
  2803.  
  2804. do_action( 'bb_xmlrpc_call_return', 'bb.getTopicTag' ); 
  2805.  
  2806. // Return the topics 
  2807. return $_topics; 
  2808.  
  2809. /** 
  2810. * Adds the specified tags to the specified topic 
  2811. * 
  2812. * @since 1.0 
  2813. * @return array|object The tags which were added when successfully executed or an IXR_Error object on failure 
  2814. * @param array $args Arguments passed by the XML-RPC call 
  2815. * @param string $args[0] The username for authentication 
  2816. * @param string $args[1] The password for authentication 
  2817. * @param string|integer $args[2] The topic id or slug 
  2818. * @param string|array $args[3] The tags to add to the topic 
  2819. * 
  2820. * XML-RPC request to add the tag "banana" to the topic with id 219 
  2821. * <methodCall> 
  2822. * <methodName>bb.addTopicTags</methodName> 
  2823. * <params> 
  2824. * <param><value><string>joeblow</string></value></param> 
  2825. * <param><value><string>123password</string></value></param> 
  2826. * <param><value><int>219</int></value></param> 
  2827. * <param><value><string>banana</string></value></param> 
  2828. * </params> 
  2829. * </methodCall> 
  2830. * 
  2831. * XML-RPC request to add the tags "banana" and "man" to the topic with id 219 
  2832. * <methodCall> 
  2833. * <methodName>bb.addTopicTags</methodName> 
  2834. * <params> 
  2835. * <param><value><string>joeblow</string></value></param> 
  2836. * <param><value><string>123password</string></value></param> 
  2837. * <param><value><int>219</int></value></param> 
  2838. * <param><value><string>banana, man</string></value></param> 
  2839. * </params> 
  2840. * </methodCall> 
  2841. * 
  2842. * XML-RPC request to add the tags "banana" and "man" to the topic with id 219 using an array 
  2843. * <methodCall> 
  2844. * <methodName>bb.addTopicTags</methodName> 
  2845. * <params> 
  2846. * <param><value><string>joeblow</string></value></param> 
  2847. * <param><value><string>123password</string></value></param> 
  2848. * <param><value><int>219</int></value></param> 
  2849. * <param><value><array> 
  2850. * <data><value><string>banana</string></value></data> 
  2851. * <data><value><string>man</string></value></data> 
  2852. * </array></value></param> 
  2853. * </params> 
  2854. * </methodCall> 
  2855. */ 
  2856. function bb_addTopicTags( $args ) 
  2857. do_action( 'bb_xmlrpc_call', 'bb.addTopicTags' ); 
  2858.  
  2859. // Escape args 
  2860. $this->escape( $args ); 
  2861.  
  2862. // Get the login credentials 
  2863. $username = $args[0]; 
  2864. $password = (string) $args[1]; 
  2865.  
  2866. // Check the user is valid 
  2867. $user = $this->authenticate( $username, $password, 'edit_tags', __( 'You do not have permission to edit tags.' ) ); 
  2868.  
  2869. do_action( 'bb_xmlrpc_call_authenticated', 'bb.addTopicTags' ); 
  2870.  
  2871. // If an error was raised by authentication or by an action then return it 
  2872. if ( $this->error ) { 
  2873. return $this->error; 
  2874.  
  2875. // Can be numeric id or slug 
  2876. $topic_id = isset( $args[2] ) ? $args[2] : false; 
  2877.  
  2878. // Check for bad data 
  2879. if ( !$topic_id || ( !is_string( $topic_id ) && !is_integer( $topic_id ) ) ) { 
  2880. $this->error = new IXR_Error( 400, __( 'The topic id is invalid.' ) ); 
  2881. return $this->error; 
  2882.  
  2883. // Check the requested topic exists 
  2884. if ( !$topic = get_topic( $topic_id ) ) { 
  2885. $this->error = new IXR_Error( 400, __( 'No topic found.' ) ); 
  2886. return $this->error; 
  2887.  
  2888. // The topic id may have been a slug, so make sure it's an integer here 
  2889. $topic_id = (int) $topic->topic_id; 
  2890.  
  2891. // Make sure they are allowed to add tags to this topic 
  2892. if ( !bb_current_user_can( 'add_tag_to', $topic_id ) ) { 
  2893. $this->error = new IXR_Error( 403, __( 'You do not have permission to add tags to this topic.' ) ); 
  2894. return $this->error; 
  2895.  
  2896. $tags = isset( $args[3] ) ? $args[3] : false; 
  2897.  
  2898. // Check for bad data 
  2899. if ( !$tags || ( !is_string( $tags ) && !is_array( $tags ) ) ) { 
  2900. $this->error = new IXR_Error( 400, __( 'The tag data is invalid.' ) ); 
  2901. return $this->error; 
  2902.  
  2903. // Add the tags 
  2904. if ( !$tag_ids = bb_add_topic_tags( $topic_id, $tags ) ) { 
  2905. $this->error = new IXR_Error( 500, __( 'The tags could not be added.' ) ); 
  2906. return $this->error; 
  2907.  
  2908. // Only include "safe" data in the array 
  2909. $_tags = array(); 
  2910. foreach ( $tag_ids as $tag_id ) { 
  2911. $_tags[] = $this->prepare_topic_tag( bb_get_tag( $tag_id ) ); 
  2912.  
  2913. do_action( 'bb_xmlrpc_call_return', 'bb.addTopicTags' ); 
  2914.  
  2915. // Return the tags which were added as an array 
  2916. return $_tags; 
  2917.  
  2918. /** 
  2919. * Removes the specified tags from the specified topic 
  2920. * 
  2921. * @since 1.0 
  2922. * @return integer|object 1 when successfully executed or an IXR_Error object on failure 
  2923. * @param array $args Arguments passed by the XML-RPC call 
  2924. * @param string $args[0] The username for authentication 
  2925. * @param string $args[1] The password for authentication 
  2926. * @param string|integer $args[2] The topic id or slug 
  2927. * @param string|array $args[3] The tags to remove from the topic 
  2928. * 
  2929. * XML-RPC request to remove the tag "banana" to the topic with id 219 
  2930. * <methodCall> 
  2931. * <methodName>bb.removeTopicTags</methodName> 
  2932. * <params> 
  2933. * <param><value><string>joeblow</string></value></param> 
  2934. * <param><value><string>123password</string></value></param> 
  2935. * <param><value><int>219</int></value></param> 
  2936. * <param><value><string>banana</string></value></param> 
  2937. * </params> 
  2938. * </methodCall> 
  2939. * 
  2940. * XML-RPC request to remove the tags "banana" and "man" to the topic with id 219 
  2941. * <methodCall> 
  2942. * <methodName>bb.removeTopicTags</methodName> 
  2943. * <params> 
  2944. * <param><value><string>joeblow</string></value></param> 
  2945. * <param><value><string>123password</string></value></param> 
  2946. * <param><value><int>219</int></value></param> 
  2947. * <param><value><string>banana, man</string></value></param> 
  2948. * </params> 
  2949. * </methodCall> 
  2950. * 
  2951. * XML-RPC request to remove the tags "banana" and "man" to the topic with id 219 using an array 
  2952. * <methodCall> 
  2953. * <methodName>bb.removeTopicTags</methodName> 
  2954. * <params> 
  2955. * <param><value><string>joeblow</string></value></param> 
  2956. * <param><value><string>123password</string></value></param> 
  2957. * <param><value><int>219</int></value></param> 
  2958. * <param><value><array> 
  2959. * <data><value><string>banana</string></value></data> 
  2960. * <data><value><string>man</string></value></data> 
  2961. * </array></value></param> 
  2962. * </params> 
  2963. * </methodCall> 
  2964. */ 
  2965. function bb_removeTopicTags( $args ) 
  2966. do_action( 'bb_xmlrpc_call', 'bb.removeTopicTags' ); 
  2967.  
  2968. // Escape args 
  2969. $this->escape( $args ); 
  2970.  
  2971. // Get the login credentials 
  2972. $username = $args[0]; 
  2973. $password = (string) $args[1]; 
  2974.  
  2975. // Check the user is valid 
  2976. $user = $this->authenticate( $username, $password, 'edit_tags', __( 'You do not have permission to edit tags.' ) ); 
  2977.  
  2978. do_action( 'bb_xmlrpc_call_authenticated', 'bb.removeTopicTags' ); 
  2979.  
  2980. // If an error was raised by authentication or by an action then return it 
  2981. if ( $this->error ) { 
  2982. return $this->error; 
  2983.  
  2984. // Can be numeric id or slug 
  2985. $topic_id = isset( $args[2] ) ? $args[2] : false; 
  2986.  
  2987. // Check for bad data 
  2988. if ( !$topic_id || ( !is_string( $topic_id ) && !is_integer( $topic_id ) ) ) { 
  2989. $this->error = new IXR_Error( 400, __( 'The topic id is invalid.' ) ); 
  2990. return $this->error; 
  2991.  
  2992. // Check the requested topic exists 
  2993. if ( !$topic = get_topic( $topic_id ) ) { 
  2994. $this->error = new IXR_Error( 400, __( 'No topic found.' ) ); 
  2995. return $this->error; 
  2996.  
  2997. // The topic id may have been a slug, so make sure it's an integer here 
  2998. $topic_id = (int) $topic->topic_id; 
  2999.  
  3000. // Make sure they are allowed to add tags to this topic 
  3001. if ( !bb_current_user_can( 'add_tag_to', $topic_id ) ) { 
  3002. $this->error = new IXR_Error( 403, __( 'You do not have permission to remove tags from this topic.' ) ); 
  3003. return $this->error; 
  3004.  
  3005. $tags = isset( $args[3] ) ? $args[3] : false; 
  3006.  
  3007. // Check for bad data 
  3008. if ( !$tags || ( !is_string( $tags ) && !is_array( $tags ) ) ) { 
  3009. $this->error = new IXR_Error( 400, __( 'The tag data is invalid.' ) ); 
  3010. return $this->error; 
  3011.  
  3012. // Add the tags 
  3013. if ( !bb_remove_topic_tags( $topic_id, $tags ) ) { 
  3014. $this->error = new IXR_Error( 500, __( 'The tags could not be removed.' ) ); 
  3015. return $this->error; 
  3016.  
  3017. $result = 1; 
  3018.  
  3019. do_action( 'bb_xmlrpc_call_return', 'bb.removeTopicTags' ); 
  3020.  
  3021. // Return the result 
  3022. return $result; 
  3023.  
  3024. /** 
  3025. * Renames the specified tag to a new tag name 
  3026. * 
  3027. * @since 1.0 
  3028. * @return array|object The tag data when successfully renamed or an IXR_Error object on failure 
  3029. * @param array $args Arguments passed by the XML-RPC call 
  3030. * @param string $args[0] The username for authentication 
  3031. * @param string $args[1] The password for authentication 
  3032. * @param string $args[2] The tag name or slug 
  3033. * @param string $args[3] The new tag name (slug is auto-generated) 
  3034. * 
  3035. * XML-RPC request to rename the tag "banana" to "bananas" 
  3036. * <methodCall> 
  3037. * <methodName>bb.renameTopicTag</methodName> 
  3038. * <params> 
  3039. * <param><value><string>joeblow</string></value></param> 
  3040. * <param><value><string>123password</string></value></param> 
  3041. * <param><value><string>banana</string></value></param> 
  3042. * <param><value><string>bananas</string></value></param> 
  3043. * </params> 
  3044. * </methodCall> 
  3045. */ 
  3046. function bb_renameTopicTag( $args ) 
  3047. do_action( 'bb_xmlrpc_call', 'bb.renameTopicTag' ); 
  3048.  
  3049. // Escape args 
  3050. $this->escape( $args ); 
  3051.  
  3052. // Get the login credentials 
  3053. $username = $args[0]; 
  3054. $password = (string) $args[1]; 
  3055.  
  3056. // Check the user is valid 
  3057. $user = $this->authenticate( $username, $password, 'manage_tags', __( 'You do not have permission to manage tags.' ) ); 
  3058.  
  3059. do_action( 'bb_xmlrpc_call_authenticated', 'bb.renameTopicTag' ); 
  3060.  
  3061. // If an error was raised by authentication or by an action then return it 
  3062. if ( $this->error ) { 
  3063. return $this->error; 
  3064.  
  3065. // Can only be a string 
  3066. $tag_id = isset( $args[2] ) ? (string) $args[2] : false; 
  3067.  
  3068. // Check for bad data 
  3069. if ( !$tag_id ) { 
  3070. $this->error = new IXR_Error( 400, __( 'The tag id is invalid.' ) ); 
  3071. return $this->error; 
  3072.  
  3073. // Check the requested tag exists 
  3074. if ( !$tag = bb_get_tag( $tag_id ) ) { 
  3075. $this->error = new IXR_Error( 400, __( 'No tag found.' ) ); 
  3076. return $this->error; 
  3077.  
  3078. // Get the numeric tag id 
  3079. $tag_id = (int) $tag->tag_id; 
  3080.  
  3081. // Can only be a string 
  3082. $tag_name = isset( $args[3] ) ? (string) $args[3] : false; 
  3083.  
  3084. // Check for bad data 
  3085. if ( !$tag_name || $tag_name == $tag->tag_name ) { 
  3086. $this->error = new IXR_Error( 400, __( 'The tag name is invalid.' ) ); 
  3087. return $this->error; 
  3088.  
  3089. // Rename the tag 
  3090. if ( !$new_tag = bb_rename_tag( $tag_id, $tag_name ) ) { 
  3091. $this->error = new IXR_Error( 500, __( 'The tag could not be renamed.' ) ); 
  3092. return $this->error; 
  3093.  
  3094. // Only include "safe" data in the array 
  3095. $new_tag = $this->prepare_topic_tag( $new_tag ); 
  3096.  
  3097. do_action( 'bb_xmlrpc_call_return', 'bb.renameTopicTag' ); 
  3098.  
  3099. // Return the tag 
  3100. return $new_tag; 
  3101.  
  3102. /** 
  3103. * Merges the specified tags 
  3104. * 
  3105. * @since 1.0 
  3106. * @return array|object The tag data when successfully merged or an IXR_Error object on failure 
  3107. * @param array $args Arguments passed by the XML-RPC call 
  3108. * @param string $args[0] The username for authentication 
  3109. * @param string $args[1] The password for authentication 
  3110. * @param string $args[2] The old tag name or slug to be destroyed 
  3111. * @param string $args[3] The new tag name or slug where the old tag will be merged to 
  3112. * 
  3113. * XML-RPC request to merge the tag "banana" into the tag "apple" 
  3114. * <methodCall> 
  3115. * <methodName>bb.mergeTopicTags</methodName> 
  3116. * <params> 
  3117. * <param><value><string>joeblow</string></value></param> 
  3118. * <param><value><string>123password</string></value></param> 
  3119. * <param><value><string>banana</string></value></param> 
  3120. * <param><value><string>apple</string></value></param> 
  3121. * </params> 
  3122. * </methodCall> 
  3123. */ 
  3124. function bb_mergeTopicTags( $args ) 
  3125. do_action( 'bb_xmlrpc_call', 'bb.mergeTopicTags' ); 
  3126.  
  3127. // Escape args 
  3128. $this->escape( $args ); 
  3129.  
  3130. // Get the login credentials 
  3131. $username = $args[0]; 
  3132. $password = (string) $args[1]; 
  3133.  
  3134. // Check the user is valid 
  3135. $user = $this->authenticate( $username, $password, 'manage_tags', __( 'You do not have permission to manage tags.' ) ); 
  3136.  
  3137. do_action( 'bb_xmlrpc_call_authenticated', 'bb.mergeTopicTags' ); 
  3138.  
  3139. // If an error was raised by authentication or by an action then return it 
  3140. if ( $this->error ) { 
  3141. return $this->error; 
  3142.  
  3143. // Can only be strings 
  3144. $old_tag_id = isset( $args[2] ) ? (string) $args[2] : false; 
  3145. $new_tag_id = isset( $args[3] ) ? (string) $args[3] : false; 
  3146.  
  3147. // Check for bad data 
  3148. if ( !$old_tag_id ) { 
  3149. $this->error = new IXR_Error( 400, __( 'The old tag id is invalid.' ) ); 
  3150. return $this->error; 
  3151. if ( !$new_tag_id ) { 
  3152. $this->error = new IXR_Error( 400, __( 'The new tag id is invalid.' ) ); 
  3153. return $this->error; 
  3154.  
  3155. // Check the requested tags exist 
  3156. if ( !$old_tag = bb_get_tag( $old_tag_id ) ) { 
  3157. $this->error = new IXR_Error( 400, __( 'No old tag found.' ) ); 
  3158. return $this->error; 
  3159. if ( !$new_tag = bb_get_tag( $new_tag_id ) ) { 
  3160. $this->error = new IXR_Error( 400, __( 'No new tag found.' ) ); 
  3161. return $this->error; 
  3162.  
  3163. // Get the numeric tag id
  3164. $old_tag_id = (int) $old_tag->tag_id; 
  3165. $new_tag_id = (int) $new_tag->tag_id; 
  3166.  
  3167. // Rename the tag 
  3168. if ( !$result = bb_rename_tag( $old_tag_id, $new_tag_id ) ) { 
  3169. $this->error = new IXR_Error( 500, __( 'The tags could not be merged.' ) ); 
  3170. return $this->error; 
  3171.  
  3172. // Get the merged tag 
  3173. $new_tag = bb_get_tag( $new_tag_id ); 
  3174.  
  3175. // Only include "safe" data in the array 
  3176. $new_tag = $this->prepare_topic_tag( $new_tag ); 
  3177.  
  3178. do_action( 'bb_xmlrpc_call_return', 'bb.mergeTopicTags' ); 
  3179.  
  3180. // Return the tag 
  3181. return $new_tag; 
  3182.  
  3183. /** 
  3184. * Destroys the specified tag 
  3185. * 
  3186. * @since 1.0 
  3187. * @return integer|object 1 when successfully deleted or an IXR_Error object on failure 
  3188. * @param array $args Arguments passed by the XML-RPC call 
  3189. * @param string $args[0] The username for authentication 
  3190. * @param string $args[1] The password for authentication 
  3191. * @param string $args[2] The tag name or slug to be destroyed 
  3192. * 
  3193. * XML-RPC request to destroy the tag "banana" 
  3194. * <methodCall> 
  3195. * <methodName>bb.destroyTopicTag</methodName> 
  3196. * <params> 
  3197. * <param><value><string>joeblow</string></value></param> 
  3198. * <param><value><string>123password</string></value></param> 
  3199. * <param><value><string>banana</string></value></param> 
  3200. * </params> 
  3201. * </methodCall> 
  3202. */ 
  3203. function bb_destroyTopicTag( $args ) 
  3204. do_action( 'bb_xmlrpc_call', 'bb.destroyTopicTag' ); 
  3205.  
  3206. // Escape args 
  3207. $this->escape( $args ); 
  3208.  
  3209. // Get the login credentials 
  3210. $username = $args[0]; 
  3211. $password = (string) $args[1]; 
  3212.  
  3213. // Check the user is valid 
  3214. $user = $this->authenticate( $username, $password, 'manage_tags', __( 'You do not have permission to manage tags.' ) ); 
  3215.  
  3216. do_action( 'bb_xmlrpc_call_authenticated', 'bb.destroyTopicTag' ); 
  3217.  
  3218. // If an error was raised by authentication or by an action then return it 
  3219. if ( $this->error ) { 
  3220. return $this->error; 
  3221.  
  3222. // Can only be a string 
  3223. $tag_id = isset( $args[2] ) ? (string) $args[2] : false; 
  3224.  
  3225. // Check for bad data 
  3226. if ( !$tag_id ) { 
  3227. $this->error = new IXR_Error( 400, __( 'The tag id is invalid.' ) ); 
  3228. return $this->error; 
  3229.  
  3230. // Check the requested tag exists 
  3231. if ( !$tag = bb_get_tag( $tag_id ) ) { 
  3232. $this->error = new IXR_Error( 400, __( 'No tag found.' ) ); 
  3233. return $this->error; 
  3234.  
  3235. // Get the numeric tag id 
  3236. $tag_id = (int) $tag->tag_id; 
  3237.  
  3238. // Destroy the tag 
  3239. if ( !$result = bb_destroy_tag( $tag_id ) ) { 
  3240. $this->error = new IXR_Error( 500, __( 'The tag could not be destroyed.' ) ); 
  3241. return $this->error; 
  3242.  
  3243. $result = 1; 
  3244.  
  3245. do_action( 'bb_xmlrpc_call_return', 'bb.destroyTopicTag' ); 
  3246.  
  3247. // Return the tag 
  3248. return $result; 
  3249.  
  3250.  
  3251.  
  3252. /** 
  3253. * bbPress publishing API - Options XML-RPC methods 
  3254. */ 
  3255.  
  3256. /** 
  3257. * Initialises site options which can be manipulated using XML-RPC 
  3258. * 
  3259. * @since 1.0 
  3260. * @return void 
  3261. */ 
  3262. function initialise_site_option_info() 
  3263. $this->site_options = array( 
  3264. // Read only options 
  3265. 'software_name' => array( 
  3266. 'desc' => __( 'Software Name' ),  
  3267. 'readonly' => true,  
  3268. 'value' => 'bbPress' 
  3269. ),  
  3270. 'software_version' => array( 
  3271. 'desc' => __( 'Software Version' ),  
  3272. 'readonly' => true,  
  3273. 'option' => 'version' 
  3274. ),  
  3275. 'site_url' => array( 
  3276. 'desc' => __( 'Site URL' ),  
  3277. 'readonly' => true,  
  3278. 'option' => 'uri' 
  3279. ),  
  3280.  
  3281. // Updatable options 
  3282. 'site_name' => array( 
  3283. 'desc' => __( 'Site Name' ),  
  3284. 'readonly' => false,  
  3285. 'option' => 'name' 
  3286. ),  
  3287. 'site_description' => array( 
  3288. 'desc' => __( 'Site Description' ),  
  3289. 'readonly' => false,  
  3290. 'option' => 'description' 
  3291. ),  
  3292. 'time_zone' => array( 
  3293. 'desc' => __( 'Time Zone' ),  
  3294. 'readonly' => false,  
  3295. 'option' => 'gmt_offset' 
  3296. ),  
  3297. 'datetime_format' => array( 
  3298. 'desc' => __( 'Date/Time Format' ),  
  3299. 'readonly' => false,  
  3300. 'option' => 'datetime_format' 
  3301. ),  
  3302. 'date_format' => array( 
  3303. 'desc' => __( 'Date Format' ),  
  3304. 'readonly' => false,  
  3305. 'option' => 'date_format' 
  3306. ); 
  3307.  
  3308. $this->site_options = apply_filters( 'xmlrpc_site_options', $this->site_options ); 
  3309.  
  3310. /** 
  3311. * Compiles site options into an array suitable to be passed back through the XML-RPC server 
  3312. * 
  3313. * @since 1.0 
  3314. * @return array The site options in an array 
  3315. * @param array $options An array of options to fetch and return 
  3316. */ 
  3317. function _getOptions( $options ) 
  3318. $data = array(); 
  3319. foreach ( $options as $option ) { 
  3320. if ( array_key_exists( $option, $this->site_options ) ) { 
  3321. $data[$option] = $this->site_options[$option]; 
  3322.  
  3323. // Is the value static or dynamic? 
  3324. if ( isset( $data[$option]['option'] ) ) { 
  3325. $data[$option]['value'] = bb_get_option( $data[$option]['option'] ); 
  3326. unset( $data[$option]['option'] ); 
  3327.  
  3328. return $data; 
  3329.  
  3330. /** 
  3331. * Gets the specified site options 
  3332. * 
  3333. * @since 1.0 
  3334. * @return array|object An array containing the specified options when successfully executed or an IXR_Error object on failure 
  3335. * @param array $args Arguments passed by the XML-RPC call 
  3336. * @param string $args[0] The username for authentication 
  3337. * @param string $args[1] The password for authentication 
  3338. * @param array $args[2] The options to be retrieved, when omitted the method returns all options (optional) 
  3339. * 
  3340. * XML-RPC request to get all site options 
  3341. * <methodCall> 
  3342. * <methodName>bb.getOptions</methodName> 
  3343. * <params> 
  3344. * <param><value><string>joeblow</string></value></param> 
  3345. * <param><value><string>123password</string></value></param> 
  3346. * </params> 
  3347. * </methodCall> 
  3348. * 
  3349. * XML-RPC request to get the site name and site description 
  3350. * <methodCall> 
  3351. * <methodName>bb.getOptions</methodName> 
  3352. * <params> 
  3353. * <param><value><string>joeblow</string></value></param> 
  3354. * <param><value><string>123password</string></value></param> 
  3355. * <param><value><array> 
  3356. * <data><value><string>site_name</string></value></data> 
  3357. * <data><value><string>site_description</string></value></data> 
  3358. * </array></value></param> 
  3359. * </params> 
  3360. * </methodCall> 
  3361. */ 
  3362. function bb_getOptions( $args ) 
  3363. do_action( 'bb_xmlrpc_call', 'bb.getOptions' ); 
  3364.  
  3365. // Escape args 
  3366. $this->escape( $args ); 
  3367.  
  3368. // Get the login credentials 
  3369. $username = $args[0]; 
  3370. $password = (string) $args[1]; 
  3371.  
  3372. // Check the user is valid 
  3373. if ( $this->auth_readonly ) { 
  3374. $user = $this->authenticate( $username, $password ); 
  3375.  
  3376. do_action( 'bb_xmlrpc_call_authenticated', 'bb.getOptions' ); 
  3377.  
  3378. // If an error was raised by authentication or by an action then return it 
  3379. if ( $this->error ) { 
  3380. return $this->error; 
  3381.  
  3382. // If there are parameters supplied then make sure they are in an array 
  3383. $options = isset( $args[2] ) ? (array) $args[2] : false; 
  3384.  
  3385. // If no specific options where asked for, return all of them 
  3386. if ( !$options || !count( $options ) ) { 
  3387. $options = array_keys( $this->site_options ); 
  3388.  
  3389. do_action( 'bb_xmlrpc_call_return', 'bb.getOptions' ); 
  3390.  
  3391. return $this->_getOptions( $options ); 
  3392.  
  3393. /** 
  3394. * Sets the specified site options to the specified values 
  3395. * 
  3396. * @since 1.0 
  3397. * @return array|object An array containing the specified options when successfully executed or an IXR_Error object on failure 
  3398. * @param array $args Arguments passed by the XML-RPC call 
  3399. * @param string $args[0] The username for authentication 
  3400. * @param string $args[1] The password for authentication 
  3401. * @param array $args[2] The options to be updated along with the new value of the option 
  3402. * 
  3403. * XML-RPC request to set the site name and site description 
  3404. * <methodCall> 
  3405. * <methodName>bb.setOptions</methodName> 
  3406. * <params> 
  3407. * <param><value><string>joeblow</string></value></param> 
  3408. * <param><value><string>123password</string></value></param> 
  3409. * <param><value><struct> 
  3410. * <member> 
  3411. * <name>site_name</name> 
  3412. * <value><string>Awesome forums</string></value> 
  3413. * </member> 
  3414. * <member> 
  3415. * <name>site_description</name> 
  3416. * <value><string>My totally awesome forums will kick your butt</string></value> 
  3417. * </member> 
  3418. * </struct></value></param> 
  3419. * </params> 
  3420. * </methodCall> 
  3421. */ 
  3422. function bb_setOptions( $args ) 
  3423. do_action( 'bb_xmlrpc_call', 'bb.setOptions' ); 
  3424.  
  3425. // Escape args 
  3426. $this->escape( $args ); 
  3427.  
  3428. // Get the login credentials 
  3429. $username = $args[0]; 
  3430. $password = (string) $args[1]; 
  3431.  
  3432. // Check the user is valid 
  3433. $user = $this->authenticate( $username, $password, 'manage_options', __( 'You are not allowed to manage options.' ) ); 
  3434.  
  3435. do_action( 'bb_xmlrpc_call_authenticated', 'bb.setOptions' ); 
  3436.  
  3437. // If an error was raised by authentication or by an action then return it 
  3438. if ( $this->error ) { 
  3439. return $this->error; 
  3440.  
  3441. // Make sure there is something for us to do 
  3442. if ( !$args[2] || !is_array( $args[2] ) || !count( $args[2] ) ) { 
  3443. $this->error = new IXR_Error( 400, __( 'The options data is invalid.' ) ); 
  3444. return $this->error; 
  3445.  
  3446. $options = (array) $args[2]; 
  3447.  
  3448. // Update the requested options 
  3449. foreach( $options as $o_name => $o_value ) { 
  3450. $option_names[] = $o_name; 
  3451.  
  3452. // If there is no value set skip it 
  3453. if ( empty( $o_value ) ) { 
  3454. continue; 
  3455.  
  3456. // If the option doesn't exist skip it 
  3457. if ( !array_key_exists( $o_name, $this->site_options ) ) { 
  3458. continue; 
  3459.  
  3460. // If the option is readonly skip it 
  3461. if ( $this->site_options[$o_name]['readonly'] == true ) { 
  3462. continue; 
  3463.  
  3464. // Everything is good, update the option 
  3465. bb_update_option( $this->site_options[$o_name]['option'], $o_value ); 
  3466.  
  3467. $_options = $this->_getOptions( $option_names ); 
  3468.  
  3469. do_action( 'bb_xmlrpc_call_return', 'bb.setOptions' ); 
  3470.  
  3471. // Now return the updated values 
  3472. return $_options; 
  3473.  
  3474.  
  3475.  
  3476. /** 
  3477. * Pingback XML-RPC methods 
  3478. */ 
  3479.  
  3480. /** 
  3481. * Processes pingback requests 
  3482. * 
  3483. * @since 1.0 
  3484. * @link http://www.hixie.ch/specs/pingback/pingback 
  3485. * @return string|object A message of success or an IXR_Error object on failure 
  3486. * @param array $args Arguments passed by the XML-RPC call 
  3487. * @param string $args[0] The full URI of the post where the pingback is being sent from 
  3488. * @param string $args[1] The full URI of the post where the pingback is being sent to 
  3489. * 
  3490. * XML-RPC request to register a pingback 
  3491. * <methodCall> 
  3492. * <methodName>pingback.ping</methodName> 
  3493. * <params> 
  3494. * <param><value><string>http://example.org/2008/09/post-containing-a-link/</string></value></param> 
  3495. * <param><value><string>http://example.com/2008/08/post-being-linked-to/</string></value></param> 
  3496. * </params> 
  3497. * </methodCall> 
  3498. */ 
  3499. function pingback_ping( $args ) 
  3500. do_action( 'bb_xmlrpc_call', 'pingback.ping' ); 
  3501.  
  3502. $this->escape( $args ); 
  3503.  
  3504. // No particular need to sanitise 
  3505. $link_from = (string) $args[0]; 
  3506. $link_to = (string) $args[1]; 
  3507.  
  3508. // Tidy up ampersands in the URLs 
  3509. $link_from = str_replace( '&', '&', $link_from ); 
  3510. $link_to = str_replace( '&', '&', $link_to ); 
  3511. $link_to = str_replace( '&', '&', $link_to ); 
  3512.  
  3513. // Check if the topic linked to is in our site - a little more strict than WordPress, doesn't pull out the www if added 
  3514. if ( !bb_match_domains( $link_to, bb_get_uri() ) ) { 
  3515. // These are not the droids you are looking for 
  3516. $this->error = new IXR_Error( 0, __( 'This is not the site you are trying to pingback.' ) ); 
  3517. return $this->error; 
  3518.  
  3519. // Get the topic 
  3520. if ( $topic_to = bb_get_topic_from_uri( $link_to ) ) { 
  3521. // Topics shouldn't ping themselves 
  3522. if ( $topic_from = bb_get_topic_from_uri( $link_from ) ) { 
  3523. if ( $topic_from->topic_id === $topic_to->topic_id ) { 
  3524. $this->error = new IXR_Error( 0, __( 'The source URL and the target URL cannot both point to the same resource.' ) ); 
  3525. return $this->error; 
  3526. } else { 
  3527. $this->error = new IXR_Error ( 33, __( 'The specified target URL cannot be used as a target. It either doesn\'t exist, or it is not a pingback-enabled resource.' ) ); 
  3528. return $this->error; 
  3529.  
  3530. // Let's check that the remote site didn't already pingback this entry 
  3531. $query = new BB_Query( 'post', array( 'topic_id' => $topic_to->topic_id, 'append_meta' => true ), 'get_thread' ); 
  3532. $posts_to = $query->results; 
  3533. unset( $query ); 
  3534.  
  3535. // Make sure we have some posts in the topic, this error should never happen really 
  3536. if ( !$posts_to || !is_array( $posts_to ) || !count( $posts_to ) ) { 
  3537. $this->error = new IXR_Error( 0, __( 'The specified target topic does not contain any posts.' ) ); 
  3538. return $this->error; 
  3539.  
  3540. // Check if we already have a pingback from this URL 
  3541. foreach ( $posts_to as $post ) { 
  3542. if ( isset( $post->pingback_uri ) && trim( $post->pingback_uri ) === trim( $link_from ) ) { 
  3543. $this->error = new IXR_Error( 48, __( 'The pingback has already been registered.' ) ); 
  3544. return $this->error; 
  3545. unset( $posts_to, $post ); 
  3546.  
  3547. // Give time for the server sending the pingback to finish publishing it's post 
  3548. sleep(1); 
  3549.  
  3550. // Let's check the remote site for valid URL and content 
  3551. $link_from_source = wp_remote_fopen( $link_from ); 
  3552. if ( !$link_from_source ) { 
  3553. $this->error = new IXR_Error( 16, __( 'The source URL does not exist.' ) ); 
  3554. return $this->error; 
  3555.  
  3556. // Allow plugins to filter here 
  3557. $link_from_source = apply_filters( 'bb_pre_remote_source', $link_from_source, $link_to ); 
  3558.  
  3559. // Work around bug in strip_tags() 
  3560. $link_from_source = str_replace( '<!DOC', '<DOC', $link_from_source ); 
  3561.  
  3562. // Normalize spaces 
  3563. $link_from_source = preg_replace( '/[\s\r\n\t]+/', ' ', $link_from_source ); 
  3564.  
  3565. // Turn certain elements to double line returns 
  3566. $link_from_source = preg_replace( "/ <(h1|h2|h3|h4|h5|h6|p|th|td|li|dt|dd|pre|caption|input|textarea|button|body)[^>]*>/", "\n\n", $link_from_source ); 
  3567.  
  3568. // Find the title of the page 
  3569. preg_match( '|<title>([^<]*?)</title>|is', $link_from_source, $link_from_title ); 
  3570. $link_from_title = $link_from_title[1]; 
  3571. if ( empty( $link_from_title ) ) { 
  3572. $this->error = new IXR_Error( 32, __( 'We cannot find a title on that page.' ) ); 
  3573. return $this->error; 
  3574.  
  3575. // Strip out all tags except anchors 
  3576. $link_from_source = strip_tags( $link_from_source, '<a>' ); // just keep the tag we need 
  3577.  
  3578. // Split the source into paragraphs 
  3579. $link_from_paragraphs = explode( "\n\n", $link_from_source ); 
  3580.  
  3581. // Prepare the link to search for in preg_match() once here 
  3582. $preg_target = preg_quote( $link_to ); 
  3583.  
  3584. // Loop through the paragraphs looking for the context for the url 
  3585. foreach ( $link_from_paragraphs as $link_from_paragraph ) { 
  3586. // The url exists 
  3587. if ( strpos( $link_from_paragraph, $link_to ) !== false ) { 
  3588. // But is it in an anchor tag 
  3589. preg_match( 
  3590. "|<a[^>]+?" . $preg_target . "[^>]*>([^>]+?)</a>|",  
  3591. $link_from_paragraph,  
  3592. $context 
  3593. ); 
  3594. // If the URL isn't in an anchor tag, keep looking 
  3595. if ( empty( $context ) ) { 
  3596. continue; 
  3597.  
  3598. // We're going to use this fake tag to mark the context in a bit 
  3599. // the marker is needed in case the link text appears more than once in the paragraph 
  3600. $excerpt = preg_replace( '|\</?wpcontext\>|', '', $link_from_paragraph ); 
  3601.  
  3602. // Prevent really long link text 
  3603. if ( strlen( $context[1] ) > 100 ) { 
  3604. $context[1] = substr( $context[1], 0, 100 ) . '...'; 
  3605.  
  3606. // Set up the marker around the context 
  3607. $marker = '<wpcontext>' . $context[1] . '</wpcontext>'; 
  3608. // Swap out the link for our marker 
  3609. $excerpt = str_replace( $context[0], $marker, $excerpt ); 
  3610. // Strip all tags except for our context marker 
  3611. $excerpt = trim( strip_tags( $excerpt, '<wpcontext>' ) ); 
  3612. // Make the marker safe for use in regexp 
  3613. $preg_marker = preg_quote( $marker ); 
  3614. // Reduce the excerpt to only include 100 characters on either side of the link 
  3615. $excerpt = preg_replace( "|.*?\s(.{0, 100}" . $preg_marker . "{0, 100})\s.*|s", '$1', $excerpt ); 
  3616. // Strip tags again, to remove the marker wrapper 
  3617. $excerpt = strip_tags( $excerpt ); 
  3618. break; 
  3619.  
  3620. // Make sure the link to the target was found in the excerpt 
  3621. if ( empty( $context ) ) { 
  3622. $this->error = new IXR_Error( 17, __( 'The source URL does not contain a link to the target URL, and so cannot be used as a source.' ) ); 
  3623. return $this->error; 
  3624.  
  3625. // Add whacky prefix and suffix to the excerpt and sanitize 
  3626. $excerpt = '[...] ' . esc_html( $excerpt ) . ' [...]'; 
  3627. $this->escape( $excerpt ); 
  3628.  
  3629. // Build an array of post data to insert then insert a new post 
  3630. $postdata = array( 
  3631. 'topic_id' => $topic_to->topic_id,  
  3632. 'post_text' => $excerpt,  
  3633. 'poster_id' => 0,  
  3634. ); 
  3635. if ( !$post_ID = bb_insert_post( $postdata ) ) { 
  3636. $this->error = new IXR_Error( 0, __( 'The pingback could not be added.' ) ); 
  3637. return $this->error; 
  3638.  
  3639. // Add meta to let us know where the pingback came from 
  3640. $link_from = str_replace( '&', '&', $link_from ); 
  3641. $this->escape( $link_from ); 
  3642. bb_update_postmeta( $post_ID, 'pingback_uri', $link_from ); 
  3643.  
  3644. // Add the title to meta 
  3645. $this->escape( $link_from_title ); 
  3646. bb_update_postmeta( $post_ID, 'pingback_title', $link_from_title ); 
  3647.  
  3648. // Action for plugins and what not 
  3649. do_action( 'bb_pingback_post', $post_ID ); 
  3650.  
  3651. // Return success message, complete with emoticon 
  3652. return sprintf( __( 'Pingback from %1$s to %2$s registered. Keep the web talking! :-)' ), $link_from, $link_to ); 
  3653.  
  3654.  
  3655.  
  3656. /** 
  3657. * Returns an array of URLs that pingbacked the given URL 
  3658. * 
  3659. * @since 1.0 
  3660. * @link http://www.aquarionics.com/misc/archives/blogite/0198.html 
  3661. * @return array The array of URLs that pingbacked the given topic 
  3662. * @param array $args Arguments passed by the XML-RPC call 
  3663. * @param string $args[0] The full URI of the post where the pingback is being sent from 
  3664. * @param string $args[1] The full URI of the post where the pingback is being sent to 
  3665. * 
  3666. * XML-RPC request to get all pingbacks on a topic 
  3667. * <methodCall> 
  3668. * <methodName>pingback.ping</methodName> 
  3669. * <params> 
  3670. * <param><value><string>http://example.com/2008/08/post-tobe-queried/</string></value></param> 
  3671. * </params> 
  3672. * </methodCall> 
  3673. */ 
  3674. function pingback_extensions_getPingbacks( $args ) 
  3675. do_action( 'bb_xmlrpc_call', 'pingback.extensions.getPingbacks' ); 
  3676.  
  3677. $this->escape( $args ); 
  3678.  
  3679. // Don't accept arrays of arguments 
  3680. if ( is_array( $args ) ) { 
  3681. $this->error = new IXR_Error( 404, __( 'The requested method only accepts one parameter.' ) ); 
  3682. return $this->error; 
  3683. } else { 
  3684. $url = (string) $args; 
  3685.  
  3686. // Tidy up ampersands in the URI 
  3687. $url = str_replace( '&', '&', $url ); 
  3688. $url = str_replace( '&', '&', $url ); 
  3689.  
  3690. // Check if the URI is in our site 
  3691. if ( !bb_match_domains( $url, bb_get_uri() ) ) { 
  3692. // These are not the droids you are looking for 
  3693. $this->error = new IXR_Error( 0, __( 'The specified target URL is not on this domain.' ) ); 
  3694. return $this->error; 
  3695.  
  3696. // Make sure the specified URI is in fact associated with a topic 
  3697. if ( !$topic = bb_get_topic_from_uri( $url ) ) { 
  3698. $this->error = new IXR_Error( 33, __( 'The specified target URL cannot be used as a target. It either doesn\'t exist, or it is not a pingback-enabled resource.' ) ); 
  3699. return $this->error; 
  3700.  
  3701. // Grab the posts from the topic 
  3702. $query = new BB_Query( 'post', array( 'topic_id' => $topic_to->topic_id, 'append_meta' => true ), 'get_thread' ); 
  3703. $posts_to = $query->results; 
  3704. unset( $query ); 
  3705.  
  3706. // Check for pingbacks in the post meta data 
  3707. $pingbacks = array(); 
  3708. foreach ( $posts_to as $post ) { 
  3709. if ( isset( $post->pingback_uri ) ) { 
  3710. $pingbacks[] = $post->pingback_uri; 
  3711. unset( $post ); 
  3712.  
  3713. // This will return an empty array on failure 
  3714. return $pingbacks; 
  3715.  
  3716.  
  3717.  
  3718. /** 
  3719. * Initialises the XML-RPC server 
  3720. * 
  3721. * @since 1.0 
  3722. * @var object The instance of the XML-RPC server class 
  3723. */ 
  3724. $bb_xmlrpc_server = new BB_XMLRPC_Server(); 
.