' . "\n"; echo '' . "\n"; echo ' ' . "\n"; echo ' bbPress' . "\n"; echo ' http://bbpress.org/' . "\n"; echo ' ' . bb_get_uri() . '' . "\n"; echo ' ' . "\n"; echo ' ' . "\n"; echo ' ' . "\n"; echo ' ' . "\n"; echo '' . "\n"; exit; } // Load the XML-RPC server/client classes if ( ! class_exists( 'IXR_Value' ) ) { require_once( BACKPRESS_PATH . '/class.ixr.php' ); } /** * XML-RPC server class to allow for remote publishing * * @since 1.0 * @package bbPress * @subpackage Publishing * @uses class IXR_Server */ class BB_XMLRPC_Server extends IXR_Server { /** * Stores the last error generated by the class * * @since 1.0 * @var object|boolean An instance of the IXR_Error class or false if no error exists */ var $error = false; /** * Site options which can be manipulated using XML-RPC * * @since 1.0 * @var array */ var $site_options = array(); /** * Whether read-only methods require authentication * * @since 1.0 * @var boolean **/ var $auth_readonly = false; /** * Whether user switching is allowed * * @since 1.0 * @var boolean **/ var $allow_user_switching = false; /** * Initialises the XML-RPC server * * @since 1.0 * @return void */ function __construct() { // bbPress publishing API if ( bb_get_option( 'enable_xmlrpc' ) ) { $this->methods = array( // - Demo 'demo.sayHello' => 'this:sayHello', 'demo.addTwoNumbers' => 'this:addTwoNumbers', // - Forums 'bb.getForumCount' => 'this:bb_getForumCount', 'bb.getForums' => 'this:bb_getForums', 'bb.getForum' => 'this:bb_getForum', 'bb.newForum' => 'this:bb_newForum', 'bb.editForum' => 'this:bb_editForum', 'bb.deleteForum' => 'this:bb_deleteForum', // - Topics 'bb.getTopicCount' => 'this:bb_getTopicCount', 'bb.getTopics' => 'this:bb_getTopics', 'bb.getTopic' => 'this:bb_getTopic', 'bb.newTopic' => 'this:bb_newTopic', 'bb.editTopic' => 'this:bb_editTopic', 'bb.deleteTopic' => 'this:bb_deleteTopic', // Also undeletes 'bb.moveTopic' => 'this:bb_moveTopic', 'bb.stickTopic' => 'this:bb_stickTopic', // Also unsticks 'bb.closeTopic' => 'this:bb_closeTopic', // Also opens 'bb.getTopicStatusList' => 'this:bb_getTopicStatusList', // - Posts (replies) 'bb.getPostCount' => 'this:bb_getPostCount', 'bb.getPosts' => 'this:bb_getPosts', 'bb.getPost' => 'this:bb_getPost', 'bb.newPost' => 'this:bb_newPost', 'bb.editPost' => 'this:bb_editPost', 'bb.deletePost' => 'this:bb_deletePost', // Also undeletes 'bb.getPostStatusList' => 'this:bb_getPostStatusList', // - Topic Tags 'bb.getHotTopicTags' => 'this:bb_getHotTopicTags', 'bb.getTopicTagCount' => 'this:bb_getTopicTagCount', 'bb.getTopicTags' => 'this:bb_getTopicTags', 'bb.getTopicTag' => 'this:bb_getTopicTag', 'bb.addTopicTags' => 'this:bb_addTopicTags', 'bb.removeTopicTags' => 'this:bb_removeTopicTags', 'bb.renameTopicTag' => 'this:bb_renameTopicTag', 'bb.mergeTopicTags' => 'this:bb_mergeTopicTags', 'bb.destroyTopicTag' => 'this:bb_destroyTopicTag', // - Options 'bb.getOptions' => 'this:bb_getOptions', 'bb.setOptions' => 'this:bb_setOptions' ); } // Pingback if ( bb_get_option( 'enable_pingback' ) ) { $this->methods = array_merge( (array)$this->methods, array( 'pingback.ping' => 'this:pingback_ping', 'pingback.extensions.getPingbacks' => 'this:pingback_extensions_getPingbacks' ) ); } // Tells read-only methods whether they require authentication or not $this->auth_readonly = apply_filters( 'bb_xmlrpc_auth_readonly', $this->auth_readonly ); // Whether or not to allow user switching $this->allow_user_switching = bb_get_option( 'bb_xmlrpc_allow_user_switching' ); $this->initialise_site_option_info(); $this->methods = apply_filters( 'bb_xmlrpc_methods', $this->methods ); $this->IXR_Server( $this->methods ); } function BB_XMLRPC_Server() { $this->__construct(); } /** * Utility methods */ /** * Checks the user credentials supplied in the request to make sure they are valid * * @since 1.0 * @return integer|boolean The user id if the user is valid, otherwise false * @param string $user_login The users login * @param string $user_pass The users password in plain text * @param string $capability The capability to check (optional) * @param string $message The message to pass back in the error if the capability check fails (optional) */ function authenticate( $user_login, $user_pass, $capability = 'read', $message = false ) { if ( is_array( $user_login ) ) { $auth_user_login = (string) $user_login[0]; $switch_user_login = (string) $user_login[1]; } else { $auth_user_login = (string) $user_login; $switch_user_login = false; } // Check the login $user = bb_check_login( $auth_user_login, $user_pass ); if ( !$user || is_wp_error( $user ) ) { $this->error = new IXR_Error( 403, __( 'Authentication failed.' ) ); return false; } // Set the current user $user = bb_set_current_user( $user->ID ); // Make sure they are allowed to do this if ( !bb_current_user_can( $capability ) ) { if ( !$message ) { $message = __( 'You do not have permission to read this.' ); } $this->error = new IXR_Error( 403, $message ); return false; } // Switch the user if requested and allowed if ( $switch_user_login && $this->allow_user_switching && bb_current_user_can( 'edit_users' ) ) { $user = $this->switch_user( $switch_user_login, $capability, $message ); } return $user; } /** * Switches the currently active user for incognito actions * * @since 1.0 * @return integer|boolean The user id if the user is valid, otherwise false * @param string $user_login The users login * @param string $capability The capability to check (optional) * @param string $message The message to pass back in the error if the capability check fails (optional) */ function switch_user( $user_login, $capability = 'read', $message = false ) { // Just get the user, authentication has already been established by the $user = bb_get_user( $user_login, array( 'by' => 'login' ) ); if ( !$user || is_wp_error( $user ) ) { $this->error = new IXR_Error( 400, __( 'User switching failed, the requested user does not exist.' ) ); return false; } // Set the current user $user = bb_set_current_user( $user->ID ); // Make sure they are allowed to do this if ( !bb_current_user_can( $capability ) ) { if ( !$message ) { $message = __( 'You do not have permission to read this.' ); } $this->error = new IXR_Error( 403, $message ); return false; } return $user; } /** * Sanitises data from XML-RPC request parameters * * @since 1.0 * @return mixed The sanitised variable, should come back with the same type * @param $array mixed The variable to be sanitised * @uses $bbdb BackPress database class instance */ function escape( &$array ) { global $bbdb; if ( !is_array( $array ) ) { // Escape it $array = $bbdb->escape( $array ); } elseif ( count( $array ) ) { foreach ( (array) $array as $k => $v ) { if ( is_array( $v ) ) { // Recursively sanitize arrays $this->escape( $array[$k] ); } elseif ( is_object( $v ) ) { // Don't sanitise objects - shouldn't happen anyway } else { // Escape it $array[$k] = $bbdb->escape( $v ); } } } return $array; } /** * Prepares forum data for return in an XML-RPC object * * @since 1.0 * @return array The prepared forum data * @param array|object The unprepared forum data **/ function prepare_forum( $forum ) { // Cast to an array $_forum = (array) $forum; // Set the URI $_forum['forum_uri'] = get_forum_link( $_forum['forum_id'] ); // Give this a definite value if ( !isset( $_forum['forum_is_category'] ) ) { $_forum['forum_is_category'] = 0; } // Allow plugins to modify the data return apply_filters( 'bb_xmlrpc_prepare_forum', $_forum, (array) $forum ); } /** * Prepares topic data for return in an XML-RPC object * * @since 1.0 * @return array The prepared topic data * @param array|object The unprepared topic data **/ function prepare_topic( $topic ) { // Cast to an array $_topic = (array) $topic; // Set the URI $_topic['topic_uri'] = get_topic_link( $_topic['topic_id'] ); // Set readable times $_topic['topic_start_time_since'] = bb_since( $_topic['topic_start_time'] ); $_topic['topic_time_since'] = bb_since( $_topic['topic_time'] ); // Set the display names $_topic['topic_poster_display_name'] = get_user_display_name( $_topic['topic_poster'] ); $_topic['topic_last_poster_display_name'] = get_user_display_name( $_topic['topic_last_poster'] ); // Remove some sensitive user ids unset( $_topic['topic_poster'], $_topic['topic_last_poster'] ); // Allow plugins to modify the data return apply_filters( 'bb_xmlrpc_prepare_topic', $_topic, (array) $topic ); } /** * Prepares post data for return in an XML-RPC object * * @since 1.0 * @return array The prepared post data * @param array|object The unprepared post data **/ function prepare_post( $post ) { // Cast to an array $_post = (array) $post; // Set the URI $_post['post_uri'] = get_post_link( $_post['post_id'] ); // Set readable times $_post['post_time_since'] = bb_since( $_post['post_time'] ); // Set the display names $_post['poster_display_name'] = get_user_display_name( $_post['poster_id'] ); // Remove some sensitive data unset( $_post['poster_id'], $_post['poster_ip'], $_post['pingback_queued'] ); // Allow plugins to modify the data return apply_filters( 'bb_xmlrpc_prepare_post', $_post, (array) $post ); } /** * Prepares topic tag data for return in an XML-RPC object * * @since 1.0 * @return array The prepared topic tag data * @param array|object The unprepared topic tag data **/ function prepare_topic_tag( $tag ) { // Cast to an array $_tag = (array) $tag; // Set the URI $_tag['topic_tag_uri'] = bb_get_tag_link( $tag ); // Consistent nomenclature $_tag['topic_tag_name'] = (string) $_tag['name']; $_tag['topic_tag_slug'] = (string) $_tag['slug']; $_tag['topic_tag_count'] = (int) $_tag['count']; // Remove some sensitive data unset( $_tag['object_id'], $_tag['name'], $_tag['slug'], $_tag['count'], $_tag['term_id'], $_tag['term_group'], $_tag['term_taxonomy_id'], $_tag['taxonomy'], $_tag['description'], $_tag['parent'], $_tag['count'], $_tag['user_id'], $_tag['tag_id'], $_tag['tag'], $_tag['raw_tag'], $_tag['tag_count'] ); // Allow plugins to modify the data return apply_filters( 'bb_xmlrpc_prepare_topic_tag', $_tag, (array) $tag ); } /** * bbPress publishing API - Demo XML-RPC methods */ /** * Hello world demo function for XML-RPC * * @since 1.0 * @return string The phrase 'Hello!' * @param array $args Arguments passed by the XML-RPC call * @param string $args[0] The username for authentication * @param string $args[1] The password for authentication * * XML-RPC request to get a greeting * * demo.sayHello * * joeblow * 123password * * */ function sayHello( $args ) { // Escape args $this->escape( $args ); // Get the login credentials $username = $args[0]; $password = (string) $args[1]; // Check the user is valid if ( $this->auth_readonly && !$this->authenticate( $username, $password ) ) { return $this->error; } return 'Hello!'; } /** * Adds two numbers together as a demo of XML-RPC * * @since 1.0 * @return integer The sum of the two supplied numbers * @param array $args Arguments passed by the XML-RPC call * @param string $args[0] The username for authentication * @param string $args[1] The password for authentication * @param integer $args[2] The first number to be added * @param integer $args[3] The second number to be added * * XML-RPC request to get the sum of two numbers * * demo.addTwoNumbers * * joeblow * 123password * 5 * 102 * * */ function addTwoNumbers( $args ) { // Escape args $this->escape( $args ); // Get the login credentials $username = $args[0]; $password = (string) $args[1]; // Check the user is valid if ( $this->auth_readonly && !$this->authenticate( $username, $password ) ) { return $this->error; } $number1 = (int) $args[2]; $number2 = (int) $args[3]; return ( $number1 + $number2 ); } /** * bbPress publishing API - Forum XML-RPC methods */ /** * Returns a numerical count of forums * * @since 1.0 * @return integer|object The number of forums when successfully executed or an IXR_Error object on failure * @param array $args Arguments passed by the XML-RPC call * @param string $args[0] The username for authentication * @param string $args[1] The password for authentication * @param integer|string $args[2] The parent forum's id or slug (optional) * @param integer $args[3] The depth of child forums to retrieve (optional) * * XML-RPC request to get a count of all forums in the bbPress instance * * bb.getForumCount * * joeblow * 123password * * * * XML-RPC request to get a count of all child forums in the forum with id number 34 * * bb.getForumCount * * joeblow * 123password * 34 * * * * XML-RPC request to get a count of all child forums in the forum with slug "first-forum" * * bb.getForumCount * * joeblow * 123password * first-forum * * * * 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 * * bb.getForumCount * * joeblow * 123password * 34 * 2 * * */ function bb_getForumCount( $args ) { do_action( 'bb_xmlrpc_call', 'bb.getForumCount' ); // Escape args $this->escape( $args ); // Get the login credentials $username = $args[0]; $password = (string) $args[1]; // Check the user is valid if ( $this->auth_readonly ) { $user = $this->authenticate( $username, $password ); } do_action( 'bb_xmlrpc_call_authenticated', 'bb.getForumCount' ); // If an error was raised by authentication or by an action then return it if ( $this->error ) { return $this->error; } // Setup an array to store arguments to pass to bb_get_forums() function $get_forums_args = array( 'child_of' => 0, 'hierarchical' => 0, 'depth' => 0 ); // Can be numeric id or slug $forum_id = isset( $args[2] ) ? $args[2] : false; if ( $forum_id ) { // Check for bad data if ( !is_string( $forum_id ) && !is_integer( $forum_id ) ) { $this->error = new IXR_Error( 400, __( 'The forum id is invalid.' ) ); return $this->error; } // Check the requested forum exists if ( !$forum = bb_get_forum( $forum_id ) ) { $this->error = new IXR_Error( 400, __( 'The forum does not exist.' ) ); return $this->error; } // Add the specific forum to the arguments $get_forums_args['child_of'] = (int) $forum->forum_id; } // Can only be an integer $depth = (int) $args[3]; if ( $depth > 0 ) { // Add the depth to traverse to the arguments $get_forums_args['depth'] = $depth; // Only make it hierarchical if the depth > 1 if ( $depth > 1 ) { $get_forums_args['hierarchical'] = 1; } } // Get the forums. Return 0 when no forums exist if ( !$forums = bb_get_forums( $get_forums_args ) ) { $count = 0; } else { $count = count( $forums ); } do_action( 'bb_xmlrpc_call_return', 'bb.getForumCount' ); // Return a count of the forums return $count; } /** * Returns details of multiple forums * * @since 1.0 * @return array|object An array containing details of all returned forums when successfully executed or an IXR_Error object on failure * @param array $args Arguments passed by the XML-RPC call * @param string $args[0] The username for authentication * @param string $args[1] The password for authentication * @param integer|string $args[2] The parent forum's id or slug (optional) * @param integer $args[3] The depth of child forums to retrieve (optional) * * XML-RPC request to get all forums in the bbPress instance * * bb.getForums * * joeblow * 123password * * * * XML-RPC request to get all child forums in the forum with id number 34 * * bb.getForums * * joeblow * 123password * 34 * * * * XML-RPC request to get all child forums in the forum with slug "first-forum" * * bb.getForums * * joeblow * 123password * first-forum * * * * XML-RPC request to get all child forums in the forum with id number 34 no more than 2 forums deep in the hierarchy * * bb.getForums * * joeblow * 123password * 34 * 2 * * */ function bb_getForums( $args ) { do_action( 'bb_xmlrpc_call', 'bb.getForums' ); // Escape args $this->escape( $args ); // Get the login credentials $username = $args[0]; $password = (string) $args[1]; // Check the user is valid if ( $this->auth_readonly ) { $user = $this->authenticate( $username, $password ); } do_action( 'bb_xmlrpc_call_authenticated', 'bb.getForums' ); // If an error was raised by authentication or by an action then return it if ( $this->error ) { return $this->error; } // Setup an array to store arguments to pass to bb_get_forums() function $get_forums_args = array( 'child_of' => 0, 'hierarchical' => 0, 'depth' => 0 ); // Can be numeric id or slug $forum_id = isset( $args[2] ) ? $args[2] : false; if ( $forum_id ) { // Check for bad data if ( !is_string( $forum_id ) && !is_integer( $forum_id ) ) { $this->error = new IXR_Error( 400, __( 'The forum id is invalid.' ) ); return $this->error; } // First check the requested forum exists if ( !$forum = bb_get_forum( $forum_id ) ) { $this->error = new IXR_Error( 400, __( 'The forum does not exist.' ) ); return $this->error; } // Add the specific forum to the arguments $get_forums_args['child_of'] = (int) $forum->forum_id; } // Can only be an integer $depth = (int) $args[3]; if ( $depth > 0 ) { // Add the depth to traverse to to the arguments $get_forums_args['depth'] = $depth; // Only make it hierarchical if the depth > 1 if ( $depth > 1 ) { $get_forums_args['hierarchical'] = 1; } } // Get the forums. Return an error when no forums exist if ( !$forums = bb_get_forums( $get_forums_args ) ) { $this->error = new IXR_Error( 404, __( 'No forums found.' ) ); return $this->error; } // Only include "safe" data in the array $_forums = array(); foreach ( $forums as $forum ) { $_forums[] = $this->prepare_forum( $forum ); } do_action( 'bb_xmlrpc_call_return', 'bb.getForums' ); // Return the forums return $_forums; } /** * Returns details of a forum * * @since 1.0 * @return array|object An array containing details of the returned forum when successfully executed or an IXR_Error object on failure * @param string $args[0] The username for authentication * @param string $args[1] The password for authentication * @param integer|string $args[2] The forum's id or slug * * XML-RPC request to get the forum with id number 34 * * bb.getForum * * joeblow * 123password * 34 * * * * XML-RPC request to get the forum with slug "first-forum" * * bb.getForum * * joeblow * 123password * first-forum * * */ function bb_getForum( $args ) { do_action( 'bb_xmlrpc_call', 'bb.getForum' ); // Escape args $this->escape( $args ); // Get the login credentials $username = $args[0]; $password = (string) $args[1]; // Check the user is valid if ( $this->auth_readonly ) { $user = $this->authenticate( $username, $password ); } do_action( 'bb_xmlrpc_call_authenticated', 'bb.getForum' ); // If an error was raised by authentication or by an action then return it if ( $this->error ) { return $this->error; } // Can be numeric id or slug $forum_id = isset( $args[2] ) ? $args[2] : false; // Check for bad data if ( !$forum_id || ( !is_string( $forum_id ) && !is_integer( $forum_id ) ) ) { $this->error = new IXR_Error( 400, __( 'The forum id is invalid.' ) ); return $this->error; } // Check the requested forum exists if ( !$forum = bb_get_forum( $forum_id ) ) { $this->error = new IXR_Error( 404, __( 'No forum found.' ) ); return $this->error; } // Only include "safe" data in the array $forum = $this->prepare_forum( $forum ); do_action( 'bb_xmlrpc_call_return', 'bb.getForum' ); // Return the forums return $forum; } /** * Creates a new forum * * @since 1.0 * @return array|object The forum data when successfully created or an IXR_Error object on failure * @param array $args Arguments passed by the XML-RPC call * @param string $args[0] The username for authentication * @param string $args[1] The password for authentication * @param array $args[2] The values for the various settings in the new forum * @param string $args[2]['name'] The name of the forum * @param string $args[2]['description'] The description of the forum (optional) * @param integer|string $args[2]['parent_id'] The unique id of the parent forum for this forum (optional) * @param integer $args[2]['order'] The position of the forum in the forum list (optional) * @param integer $args[2]['is_category'] Whether the forum is simply a container category (optional) * * XML-RPC request to create a new sub-forum called "A new forum" inside the parent forum with id 2 * * bb.newForum * * joeblow * 123password * * * name * A new forum * * * parent_id * 2 * * * * */ function bb_newForum( $args ) { do_action( 'bb_xmlrpc_call', 'bb.newForum' ); // Escape args $this->escape( $args ); // Get the login credentials $username = $args[0]; $password = (string) $args[1]; // Check the user is valid $user = $this->authenticate( $username, $password, 'manage_forums', __( 'You do not have permission to manage forums.' ) ); do_action( 'bb_xmlrpc_call_authenticated', 'bb.newForum' ); // If an error was raised by authentication or by an action then return it if ( $this->error ) { return $this->error; } // Make sure there is something for us to do if ( !$args[2] || !is_array( $args[2] ) || !count( $args[2] ) ) { $this->error = new IXR_Error( 400, __( 'The forum data is invalid.' ) ); return $this->error; } $structure = (array) $args[2]; // Minimum requirement is a name for the new forum if ( !isset( $structure['name'] ) || !$structure['name'] ) { $this->error = new IXR_Error( 400, __( 'The forum name is invalid.' ) ); return $this->error; } // Inject structure into an array suitable for bb_new_forum() $bb_new_forum_args = array( 'forum_name' => (string) $structure['name'], 'forum_desc' => (string) $structure['description'], 'forum_parent' => (int) $structure['parent_id'], 'forum_order' => (int) $structure['order'], 'forum_is_category' => (int) $structure['is_category'] ); // Remove empty settings so that changes to the defaults in bb_new_forum() are honoured $bb_new_forum_args = array_filter( $bb_new_forum_args ); // Leave the require until the very end require_once( BB_PATH . 'bb-admin/includes/functions.bb-admin.php' ); // Create the forum if ( !$forum_id = (int) bb_new_forum( $bb_new_forum_args ) ) { $this->error = new IXR_Error( 500, __( 'The forum could not be created.' ) ); return $this->error; } // Only include "safe" data in the array $forum = $this->prepare_forum( bb_get_forum( $forum_id ) ); do_action( 'bb_xmlrpc_call_return', 'bb.newForum' ); return $forum; } /** * Edits an existing forum * * @since 1.0 * @return array|object The forum data when successfully edited or an IXR_Error object on failure * @param array $args Arguments passed by the XML-RPC call * @param string $args[0] The username for authentication * @param string $args[1] The password for authentication * @param array $args[2] The values for the various settings in the new forum, at least one must be specified * @param integer|string $args[2]['forum_id'] The unique id of the forum to be edited * @param string $args[2]['name'] The name of the forum (optional) * @param string $args[2]['slug'] The slug for the forum (optional) * @param string $args[2]['description'] The description of the forum (optional) * @param integer $args[2]['parent_id'] The unique id of the parent forum for this forum (optional) * @param integer $args[2]['order'] The position of the forum in the forum list (optional) * @param integer $args[2]['is_category'] Whether the forum is simply a container category (optional) * * XML-RPC request to edit a forum with id 11, changing the description * * bb.editForum * * joeblow * 123password * * * forum_id * 11 * * * description * This is a great forum for all sorts of reasons. * * * * */ function bb_editForum( $args ) { do_action( 'bb_xmlrpc_call', 'bb.editForum' ); // Escape args $this->escape( $args ); // Get the login credentials $username = $args[0]; $password = (string) $args[1]; // Check the user is valid $user = $this->authenticate( $username, $password, 'manage_forums', __( 'You do not have permission to manage forums.' ) ); do_action( 'bb_xmlrpc_call_authenticated', 'bb.editForum' ); // If an error was raised by authentication or by an action then return it if ( $this->error ) { return $this->error; } // Make sure there is something for us to do if ( !$args[2] || !is_array( $args[2] ) || !count( $args[2] ) ) { $this->error = new IXR_Error( 400, __( 'The forum data is invalid.' ) ); return $this->error; } $structure = (array) $args[2]; // Can be numeric id or slug $forum_id = isset( $structure['forum_id'] ) ? $structure['forum_id'] : false; // Check for bad data if ( !$forum_id || ( !is_string( $forum_id ) && !is_integer( $forum_id ) ) ) { $this->error = new IXR_Error( 400, __( 'The forum id is invalid.' ) ); return $this->error; } // Check the requested forum exists if ( !$forum = bb_get_forum( $forum_id ) ) { $this->error = new IXR_Error( 400, __( 'No forum found.' ) ); return $this->error; } // Cast the forum object as an array $forum = (array) $forum; // The forum id may have been a slug, so make sure it's an integer here $forum_id = (int) $forum['forum_id']; // Remove some unneeded indexes unset( $forum['topics'] ); unset( $forum['posts'] ); // Add one if it isn't there if ( !isset( $forum['forum_is_category'] ) ) { $forum['forum_is_category'] = 0; } // Validate the name for the forum if ( isset( $structure['name'] ) && !$structure['name'] ) { $this->error = new IXR_Error( 400, __( 'The forum name is invalid.' ) ); return $this->error; } // Inject structure into an array suitable for bb_update_forum() $bb_update_forum_args = array( 'forum_name' => $structure['name'] ); // Slug cannot be blank if ( isset( $structure['slug'] ) && $structure['slug'] !== '' ) { $bb_update_forum_args['forum_slug'] = $structure['slug']; } // Description can be nothing if ( isset( $structure['description'] ) ) { $bb_update_forum_args['forum_desc'] = $structure['description']; } // Parent forum ID must be an integer and it can be 0 if ( isset( $structure['parent_id'] ) && is_integer( $structure['parent_id'] ) ) { $bb_update_forum_args['forum_parent'] = $structure['parent_id']; } // Order must be an integer and it can be 0 if ( isset( $structure['order'] ) && is_integer( $structure['order'] ) ) { $bb_update_forum_args['forum_order'] = $structure['order']; } // Category flag must be an integer and it can be 0 if ( isset( $structure['is_category'] ) && is_integer( $structure['is_category'] ) ) { $bb_update_forum_args['forum_is_category'] = $structure['is_category']; } // Merge the changes into the existing data for the forum $bb_update_forum_args = wp_parse_args( $bb_update_forum_args, $forum ); // Leave the require until the very end require_once( BB_PATH . 'bb-admin/includes/functions.bb-admin.php' ); // Update the forum if ( !bb_update_forum( $bb_update_forum_args ) ) { $this->error = new IXR_Error( 500, __( 'The forum could not be edited.' ) ); return $this->error; } // Only include "safe" data in the array $forum = $this->prepare_forum( bb_get_forum( $forum_id ) ); do_action( 'bb_xmlrpc_call_return', 'bb.editForum' ); return $forum; } /** * Deletes a forum * * @since 1.0 * @return integer|object 1 when successfully deleted or an IXR_Error object on failure * @param array $args Arguments passed by the XML-RPC call * @param string $args[0] The username for authentication * @param string $args[1] The password for authentication * @param integer|string $args[2] The unique id of the forum to be deleted * * XML-RPC request to delete a forum with the slug "naughty-forum" * * bb.deleteForum * * joeblow * 123password * naughty-forum * * */ function bb_deleteForum( $args ) { do_action( 'bb_xmlrpc_call', 'bb.deleteForum' ); // Escape args $this->escape( $args ); // Get the login credentials $username = $args[0]; $password = (string) $args[1]; // Check the user is valid $user = $this->authenticate( $username, $password, 'delete_forums', __( 'You do not have permission to delete forums.' ) ); do_action( 'bb_xmlrpc_call_authenticated', 'bb.deleteForum' ); // If an error was raised by authentication or by an action then return it if ( $this->error ) { return $this->error; } // Can be numeric id or slug $forum_id = isset( $args[2] ) ? $args[2] : false; // Check for bad data if ( !$forum_id || ( !is_string( $forum_id ) && !is_integer( $forum_id ) ) ) { $this->error = new IXR_Error( 400, __( 'The forum id is invalid.' ) ); return $this->error; } // Check the requested forum exists if ( !$forum = bb_get_forum( $forum_id ) ) { $this->error = new IXR_Error( 400, __( 'No forum found.' ) ); return $this->error; } // Cast the forum object as an array $forum = (array) $forum; // The forum id may have been a slug, so make sure it's an integer here $forum_id = (int) $forum['forum_id']; // Make sure they are allowed to delete this forum specifically if ( !bb_current_user_can( 'delete_forum', $forum_id ) ) { $this->error = new IXR_Error( 403, __( 'You do not have permission to delete this forum.' ) ); return $this->error; } // Leave the require until the very end require_once( BB_PATH . 'bb-admin/includes/functions.bb-admin.php' ); // Delete the forum if ( !bb_delete_forum( $forum_id ) ) { $this->error = new IXR_Error( 500, __( 'The forum could not be deleted.' ) ); return $this->error; } $result = 1; do_action( 'bb_xmlrpc_call_return', 'bb.deleteForum' ); return $result; } /** * bbPress publishing API - Topic XML-RPC methods */ /** * Returns a numerical count of topics * * @since 1.0 * @return integer|object The number of topics when successfully executed or an IXR_Error object on failure * @param array $args Arguments passed by the XML-RPC call * @param string $args[0] The username for authentication * @param string $args[1] The password for authentication * @param integer|string $args[2] The forum id or slug (optional) * * XML-RPC request to get a count of all topics in the bbPress instance * * bb.getTopicCount * * joeblow * 123password * * * * XML-RPC request to get a count of all topics in the forum with id number 34 * * bb.getTopicCount * * joeblow * 123password * 34 * * * * XML-RPC request to get a count of all topics in the forum with slug "first-forum" * * bb.getTopicCount * * joeblow * 123password * first-forum * * */ function bb_getTopicCount( $args ) { do_action( 'bb_xmlrpc_call', 'bb.getTopicCount' ); // Escape args $this->escape( $args ); // Get the login credentials $username = $args[0]; $password = (string) $args[1]; // Check the user is valid if ( $this->auth_readonly ) { $user = $this->authenticate( $username, $password ); } do_action( 'bb_xmlrpc_call_authenticated', 'bb.getTopicCount' ); // If an error was raised by authentication or by an action then return it if ( $this->error ) { return $this->error; } // Can be numeric id or slug if ( isset( $args[2] ) && $forum_id = $args[2] ) { // Check for bad data if ( !is_string( $forum_id ) && !is_integer( $forum_id ) ) { $this->error = new IXR_Error( 400, __( 'The forum id is invalid.' ) ); return $this->error; } // Check the requested forum exists if ( !$forum = bb_get_forum( $forum_id ) ) { $this->error = new IXR_Error( 400, __( 'The forum does not exist.' ) ); return $this->error; } // OK, let's trust the count in the forum table $count = (int) $forum->topics; } else { // Get all forums $forums = bb_get_forums(); // Return an error when no forums exist if ( !$forums ) { $this->error = new IXR_Error( 400, __( 'No forums found.' ) ); return $this->error; } // Count the topics $count = 0; foreach ( $forums as $forum ) { $count += (int) $forum->topics; } } do_action( 'bb_xmlrpc_call_return', 'bb.getTopicCount' ); // Return the count of topics return $count; } /** * Returns details of the latest topics * * @since 1.0 * @return array|object The topics when successfully executed or an IXR_Error object on failure * @param array $args Arguments passed by the XML-RPC call * @param string $args[0] The username for authentication * @param string $args[1] The password for authentication * @param integer|string $args[2] The forum id or slug (optional) * @param integer $args[3] The number of topics to return (optional) * @param integer $args[4] The number of the page to return (optional) * * XML-RPC request to get all topics in the bbPress instance * * bb.getTopics * * joeblow * 123password * * * * XML-RPC request to get all topics in the forum with id number 34 * * bb.getTopics * * joeblow * 123password * 34 * * * * XML-RPC request to get topics 6 to 10 in the forum with slug "first-forum" * * bb.getTopics * * joeblow * 123password * first-forum * 5 * 2 * * */ function bb_getTopics( $args ) { do_action( 'bb_xmlrpc_call', 'bb.getTopics' ); // Escape args $this->escape( $args ); // Get the login credentials $username = $args[0]; $password = (string) $args[1]; // Check the user is valid if ( $this->auth_readonly ) { $user = $this->authenticate( $username, $password ); } do_action( 'bb_xmlrpc_call_authenticated', 'bb.getTopics' ); // If an error was raised by authentication or by an action then return it if ( $this->error ) { return $this->error; } // Setup an array to store arguments to pass to get_topics() function $get_topics_args = array( 'forum' => false, 'number' => false, 'page' => false ); // Can be numeric id or slug if ( isset( $args[2] ) && $forum_id = $args[2] ) { // Check for bad data if ( !is_string( $forum_id ) && !is_integer( $forum_id ) ) { $this->error = new IXR_Error( 400, __( 'The forum id is invalid.' ) ); return $this->error; } // Check the requested forum exists if ( !$forum = bb_get_forum( $forum_id ) ) { $this->error = new IXR_Error( 400, __( 'The forum does not exist.' ) ); return $this->error; } // The forum id may have been a slug, so make sure it's an integer here $get_topics_args['forum'] = (int) $forum->forum_id; } // Can only be an integer if ( isset( $args[3] ) && $number = (int) $args[3] ) { $get_topics_args['number'] = $number; } // Can only be an integer if ( isset( $args[4] ) && $page = (int) $args[4] ) { $get_topics_args['page'] = $page; } // Get the topics if ( !$topics = get_latest_topics( $get_topics_args ) ) { $this->error = new IXR_Error( 400, __( 'No topics found.' ) ); return $this->error; } // Only include "safe" data in the array $_topics = array(); foreach ( $topics as $topic ) { $_topics[] = $this->prepare_topic( $topic ); } do_action( 'bb_xmlrpc_call_return', 'bb.getTopics' ); // Return the topics return $_topics; } /** * Returns details of a topic * * @since 1.0 * @return array|object An array containing details of the returned topic when successfully executed or an IXR_Error object on failure * @param string $args[0] The username for authentication * @param string $args[1] The password for authentication * @param integer|string $args[2] The topic's id or slug * * XML-RPC request to get the topic with id number 105 * * bb.getTopic * * joeblow * 123password * 105 * * * * XML-RPC request to get the topic with slug "cheesy-biscuits" * * bb.getTopic * * joeblow * 123password * cheesy-biscuits * * */ function bb_getTopic( $args ) { do_action( 'bb_xmlrpc_call', 'bb.getTopic' ); // Escape args $this->escape( $args ); // Get the login credentials $username = $args[0]; $password = (string) $args[1]; // Check the user is valid if ( $this->auth_readonly ) { $user = $this->authenticate( $username, $password ); } do_action( 'bb_xmlrpc_call_authenticated', 'bb.getTopic' ); // If an error was raised by authentication or by an action then return it if ( $this->error ) { return $this->error; } // Can be numeric id or slug $topic_id = isset( $args[2] ) ? $args[2] : false; // Check for bad data if ( !$topic_id || ( !is_string( $topic_id ) && !is_integer( $topic_id ) ) ) { $this->error = new IXR_Error( 400, __( 'The topic id is invalid.' ) ); return $this->error; } // Check the requested topic exists if ( !$topic = get_topic( $topic_id ) ) { $this->error = new IXR_Error( 400, __( 'No topic found.' ) ); return $this->error; } // Only include "safe" data in the array $topic = $this->prepare_topic( $topic ); do_action( 'bb_xmlrpc_call_return', 'bb.getTopic' ); // Return the topic return $topic; } /** * Creates a new topic * * @since 1.0 * @return array|object The topic data when successfully created or an IXR_Error object on failure * @param array $args Arguments passed by the XML-RPC call * @param string $args[0] The username for authentication * @param string $args[1] The password for authentication * @param array $args[2] The values for the various parameters in the new topic * @param string $args[2]['title'] The title of the topic * @param string $args[2]['text'] The text of the topic * @param integer|string $args[2]['forum_id'] The unique id of the forum which will contain this topic, slugs are OK to use too * @param string|array $args[2]['tags'] A comma delimited string or an array of tags to add to the topic (optional) * * XML-RPC request to create a new topic called "Insane monkeys" inside the forum with id 2 * * bb.newTopic * * joeblow * 123password * * * title * Insane monkeys * * * text * I just saw some insane monkeys eating bananas, did anyone else see that? * * * forum_id * 2 * * * tags * monkeys, bananas * * * * */ function bb_newTopic( $args ) { do_action( 'bb_xmlrpc_call', 'bb.newTopic' ); // Escape args $this->escape( $args ); // Get the login credentials $username = $args[0]; $password = (string) $args[1]; // Check the user is valid $user = $this->authenticate( $username, $password, 'write_topics', __( 'You do not have permission to write topics.' ) ); // Additionally they need to be able to write posts if ( !$this->error && !bb_current_user_can( 'write_posts' ) ) { $this->error = new IXR_Error( 403, __( 'You do not have permission to write posts.' ) ); } do_action( 'bb_xmlrpc_call_authenticated', 'bb.newTopic' ); // If an error was raised by authentication or by an action then return it if ( $this->error ) { return $this->error; } // Make sure there is something for us to do if ( !$args[2] || !is_array( $args[2] ) || !count( $args[2] ) ) { $this->error = new IXR_Error( 400, __( 'The topic data is invalid.' ) ); return $this->error; } $structure = (array) $args[2]; // Can be numeric id or slug $forum_id = isset( $structure['forum_id'] ) ? $structure['forum_id'] : false; // Check for bad data if ( !$forum_id || ( !is_string( $forum_id ) && !is_integer( $forum_id ) ) ) { $this->error = new IXR_Error( 400, __( 'The forum id is invalid.' ) ); return $this->error; } // Check the requested forum exists if ( !$forum = bb_get_forum( $forum_id ) ) { $this->error = new IXR_Error( 400, __( 'No forum found.' ) ); return $this->error; } // The forum id may have been a slug, so make sure it's an integer here $forum_id = (int) $forum->forum_id; // Make sure they are allowed to write topics to this forum if ( !bb_current_user_can( 'write_topic', $forum_id ) ) { $this->error = new IXR_Error( 403, __( 'You do not have permission to write topics to this forum.' ) ); return $this->error; } // The topic requires a title if ( !isset( $structure['title'] ) || !$structure['title'] ) { $this->error = new IXR_Error( 400, __( 'The topic title is invalid.' ) ); return $this->error; } // The topic requires text if ( !isset( $structure['text'] ) || !$structure['text'] ) { $this->error = new IXR_Error( 400, __( 'The topic text is invalid.' ) ); return $this->error; } // Inject structure into an array suitable for bb_insert_topic() $bb_insert_topic_args = array( 'topic_title' => (string) $structure['title'], 'forum_id' => $forum_id, 'tags' => (string) trim( $structure['tags'] ) ); // Remove empty settings so that changes to the defaults in bb_insert_topic() are honoured $bb_insert_topic_args = array_filter( $bb_insert_topic_args ); // Create the topic if ( !$topic_id = bb_insert_topic( $bb_insert_topic_args ) ) { $this->error = new IXR_Error( 500, __( 'The topic could not be created.' ) ); return $this->error; } // Inject structure into an array suitable for bb_insert_post() $bb_insert_post_args = array( 'topic_id' => (int) $topic_id, 'post_text' => (string) $structure['text'] ); // Create the post if ( !$post_id = bb_insert_post( $bb_insert_post_args ) ) { $this->error = new IXR_Error( 500, __( 'The post could not be created.' ) ); return $this->error; } // Only include "safe" data in the array $topic = $this->prepare_topic( get_topic( $topic_id ) ); do_action( 'bb_xmlrpc_call_return', 'bb.newTopic' ); return $topic; } /** * Edits an existing topic * * @since 1.0 * @return array|object The topic data when successfully edited or an IXR_Error object on failure * @param array $args Arguments passed by the XML-RPC call * @param string $args[0] The username for authentication * @param string $args[1] The password for authentication * @param array $args[2] The values for the various parameters in the edited topic * @param integer|string $args[2]['topic_id'] The topic's id or slug * @param string $args[2]['title'] The title of the topic * @param string $args[2]['text'] The text of the topic * * XML-RPC request to edit the title of a topic with the slug "insane-monkeys" * * bb.editTopic * * joeblow * 123password * * * topic_id * insane-monkeys * * * title * Very insane monkeys * * * * */ function bb_editTopic( $args ) { do_action( 'bb_xmlrpc_call', 'bb.editTopic' ); // Escape args $this->escape( $args ); // Get the login credentials $username = $args[0]; $password = (string) $args[1]; // Check the user is valid $user = $this->authenticate( $username, $password, 'edit_topics', __( 'You do not have permission to edit topics.' ) ); // Additionally they need to be able to edit posts if ( !$this->error && !bb_current_user_can( 'edit_posts' ) ) { $this->error = new IXR_Error( 403, __( 'You do not have permission to edit posts.' ) ); } do_action( 'bb_xmlrpc_call_authenticated', 'bb.editTopic' ); // If an error was raised by authentication or by an action then return it if ( $this->error ) { return $this->error; } // Make sure there is something for us to do if ( !$args[2] || !is_array( $args[2] ) || !count( $args[2] ) ) { $this->error = new IXR_Error( 400, __( 'The topic data is invalid.' ) ); return $this->error; } $structure = (array) $args[2]; // Can be numeric id or slug $topic_id = isset( $structure['topic_id'] ) ? $structure['topic_id'] : false; // Check for bad data if ( !$topic_id || ( !is_string( $topic_id ) && !is_integer( $topic_id ) ) ) { $this->error = new IXR_Error( 400, __( 'The topic id is invalid.' ) ); return $this->error; } // Check the requested topic exists if ( !$topic = get_topic( $topic_id ) ) { $this->error = new IXR_Error( 400, __( 'No topic found.' ) ); return $this->error; } // The topic id may have been a slug, so make sure it's an integer here $topic_id = (int) $topic->topic_id; // Make sure they are allowed to edit this topic if ( !bb_current_user_can( 'edit_topic', $topic_id ) ) { $this->error = new IXR_Error( 403, __( 'You do not have permission to edit this topic.' ) ); return $this->error; } // Get the first post in the topic (that's where the content is) if ( !$post = bb_get_first_post( $topic_id ) ) { $this->error = new IXR_Error( 400, __( 'No posts found.' ) ); return $this->error; } $post_id = (int) $post->post_id; // Make sure they are allowed to edit this post if ( !bb_current_user_can( 'edit_post', $post_id ) ) { $this->error = new IXR_Error( 403, __( 'You do not have permission to edit this post.' ) ); return $this->error; } // The topic requires a title if ( isset( $structure['title'] ) && !$structure['title'] ) { $this->error = new IXR_Error( 400, __( 'The topic title is invalid.' ) ); return $this->error; } // The topic requires text if ( isset( $structure['text'] ) && !$structure['text'] ) { $this->error = new IXR_Error( 400, __( 'The topic text is invalid.' ) ); return $this->error; } if ( $structure['title'] ) { if ( !bb_insert_topic( array( 'topic_title' => (string) $structure['title'], 'topic_id' => $topic_id ) ) ) { $this->error = new IXR_Error( 500, __( 'The topic could not be edited.' ) ); return $this->error; } } if ( $structure['text'] ) { if ( !bb_insert_post( array( 'post_text' => (string) $structure['text'], 'post_id' => $post_id, 'topic_id'=> $topic_id ) ) ) { $this->error = new IXR_Error( 500, __( 'The post could not be edited.' ) ); return $this->error; } } // Only include "safe" data in the array $topic = $this->prepare_topic( get_topic( $topic_id ) ); do_action( 'bb_xmlrpc_call_return', 'bb.editTopic' ); return $topic; } /** * Deletes a topic * * @since 1.0 * @return integer|object 0 if already changed, 1 when successfully changed or an IXR_Error object on failure * @param array $args Arguments passed by the XML-RPC call * @param string $args[0] The username for authentication * @param string $args[1] The password for authentication * @param integer|string $args[2] The unique id of the topic to be deleted * @param integer $args[3] 1 deletes the topic, 0 undeletes the topic * * XML-RPC request to delete a topic with id of 34 * * bb.deleteTopic * * joeblow * 123password * 34 * * */ function bb_deleteTopic( $args ) { do_action( 'bb_xmlrpc_call', 'bb.deleteTopic' ); // Escape args $this->escape( $args ); // Get the login credentials $username = $args[0]; $password = (string) $args[1]; // Check the user is valid $user = $this->authenticate( $username, $password, 'delete_topics', __( 'You do not have permission to delete topics.' ) ); do_action( 'bb_xmlrpc_call_authenticated', 'bb.deleteTopic' ); // If an error was raised by authentication or by an action then return it if ( $this->error ) { return $this->error; } // Can be numeric id or slug $topic_id = isset( $args[2] ) ? $args[2] : false; // Check for bad data if ( !$topic_id || ( !is_string( $topic_id ) && !is_integer( $topic_id ) ) ) { $this->error = new IXR_Error( 400, __( 'The topic id is invalid.' ) ); return $this->error; } // Check the requested topic exists if ( !$topic = get_topic( $topic_id ) ) { $this->error = new IXR_Error( 400, __( 'No topic found.' ) ); return $this->error; } // The topic id may have been a slug, so make sure it's an integer here $topic_id = (int) $topic->topic_id; $delete = isset( $args[3] ) ? (int) $args[3] : 1; // Don't do anything if already set that way if ( $delete === (int) $topic->topic_status ) { return 0; } // Make sure they are allowed to delete this topic if ( !bb_current_user_can( 'delete_topic', $topic_id ) ) { $this->error = new IXR_Error( 403, __( 'You do not have permission to delete this topic.' ) ); return $this->error; } // Delete the topic if ( !bb_delete_topic( $topic_id, $delete ) ) { $this->error = new IXR_Error( 500, __( 'The topic could not be deleted.' ) ); return $this->error; } $result = 1; do_action( 'bb_xmlrpc_call_return', 'bb.deleteTopic' ); return $result; } /** * Moves a topic to a different forum * * @since 1.0 * @return integer|object the forum id where the topic lives after the method is called or an IXR_Error object on failure * @param array $args Arguments passed by the XML-RPC call * @param string $args[0] The username for authentication * @param string $args[1] The password for authentication * @param integer|string $args[2] The unique id of the topic to be moved * @param integer|string $args[3] The unique id of the forum to be moved to * * XML-RPC request to move the topic with id of 34 to forum with slug of "better-forum" * * bb.moveTopic * * joeblow * 123password * 34 * better-forum * * */ function bb_moveTopic( $args ) { do_action( 'bb_xmlrpc_call', 'bb.moveTopic' ); // Escape args $this->escape( $args ); // Get the login credentials $username = $args[0]; $password = (string) $args[1]; // Check the user is valid $user = $this->authenticate( $username, $password, 'move_topics', __( 'You do not have permission to move topics.' ) ); do_action( 'bb_xmlrpc_call_authenticated', 'bb.moveTopic' ); // If an error was raised by authentication or by an action then return it if ( $this->error ) { return $this->error; } // Can be numeric id or slug $topic_id = isset( $args[2] ) ? $args[2] : false; // Check for bad data if ( !$topic_id || ( !is_string( $topic_id ) && !is_integer( $topic_id ) ) ) { $this->error = new IXR_Error( 400, __( 'The topic id is invalid.' ) ); return $this->error; } // Check the requested topic exists if ( !$topic = get_topic( $topic_id ) ) { $this->error = new IXR_Error( 400, __( 'No topic found.' ) ); return $this->error; } // The topic id may have been a slug, so make sure it's an integer here $topic_id = (int) $topic->topic_id; // Can be numeric id or slug $forum_id = isset( $args[3] ) ? $args[3] : false; // Check for bad data if ( !$forum_id || ( !is_string( $forum_id ) && !is_integer( $forum_id ) ) ) { $this->error = new IXR_Error( 400, __( 'The forum id is invalid.' ) ); return $this->error; } // Check the requested topic exists if ( !$forum = bb_get_forum( $forum_id ) ) { $this->error = new IXR_Error( 400, __( 'No forum found.' ) ); return $this->error; } // The forum id may have been a slug, so make sure it's an integer here $forum_id = (int) $forum->forum_id; // Only move it if it isn't already there if ( $forum_id !== (int) $topic->forum_id ) { // Make sure they are allowed to move this topic specifically to this forum if ( !bb_current_user_can( 'move_topic', $topic_id, $forum_id ) ) { $this->error = new IXR_Error( 403, __( 'You are not allowed to move this topic to this forum.' ) ); return $this->error; } // Move the topic if ( !bb_move_topic( $topic_id, $forum_id ) ) { $this->error = new IXR_Error( 500, __( 'The topic could not be moved.' ) ); return $this->error; } } do_action( 'bb_xmlrpc_call_return', 'bb.moveTopic' ); return $forum_id; } /** * Sticks a topic to the top of a forum or the front page * * @since 1.0 * @return integer|object 0 if it is already stuck to the desired location, 1 when successfully stuck or an IXR_Error object on failure * @param array $args Arguments passed by the XML-RPC call * @param string $args[0] The username for authentication * @param string $args[1] The password for authentication * @param integer|string $args[2] The unique id of the topic to be stuck * @param integer $args[3] 0 unsticks, 1 sticks, 2 sticks to front (optional) * * XML-RPC request to stick the topic with id of 34 to the front page * * bb.stickTopic * * joeblow * 123password * 34 * 1 * * */ function bb_stickTopic( $args ) { do_action( 'bb_xmlrpc_call', 'bb.stickTopic' ); // Escape args $this->escape( $args ); // Get the login credentials $username = $args[0]; $password = (string) $args[1]; // Check the user is valid $user = $this->authenticate( $username, $password, 'stick_topics', __( 'You do not have permission to stick topics.' ) ); do_action( 'bb_xmlrpc_call_authenticated', 'bb.stickTopic' ); // If an error was raised by authentication or by an action then return it if ( $this->error ) { return $this->error; } // Can be numeric id or slug $topic_id = isset( $args[2] ) ? $args[2] : false; // Check for bad data if ( !$topic_id || ( !is_string( $topic_id ) && !is_integer( $topic_id ) ) ) { $this->error = new IXR_Error( 400, __( 'The topic id is invalid.' ) ); return $this->error; } // Check the requested topic exists if ( !$topic = get_topic( $topic_id ) ) { $this->error = new IXR_Error( 400, __( 'No topic found.' ) ); return $this->error; } // The topic id may have been a slug, so make sure it's an integer here $topic_id = (int) $topic->topic_id; // Make sure they are allowed to stick this topic if ( !bb_current_user_can( 'stick_topic', $topic_id ) ) { $this->error = new IXR_Error( 403, __( 'You do not have permission to stick this topic.' ) ); return $this->error; } // Stick to where? $where = isset( $args[3] ) ? (int) $args[3] : 1; // Forget it if it's already there if ( $where === (int) $topic->topic_sticky ) { return 0; } // Stick the topic if ( !bb_stick_topic( $topic_id, $where ) ) { $this->error = new IXR_Error( 500, __( 'The topic could not be stuck.' ) ); return $this->error; } $result = 1; do_action( 'bb_xmlrpc_call_return', 'bb.stickTopic' ); return $result; } /** * Closes a topic * * @since 1.0 * @return integer|object 0 when already changed, 1 when successfully changed or an IXR_Error object on failure * @param array $args Arguments passed by the XML-RPC call * @param string $args[0] The username for authentication * @param string $args[1] The password for authentication * @param integer|string $args[2] The unique id of the topic to be closed * @param integer $args[2] 0 closes, 1 opens (optional) * * XML-RPC request to close the topic with slug of "really-old-topic" * * bb.closeTopic * * joeblow * 123password * really-old-topic * * * * XML-RPC request to open the topic with slug of "really-old-topic" * * bb.closeTopic * * joeblow * 123password * really-old-topic * 1 * * */ function bb_closeTopic( $args ) { do_action( 'bb_xmlrpc_call', 'bb.closeTopic' ); // Escape args $this->escape( $args ); // Get the login credentials $username = $args[0]; $password = (string) $args[1]; // Check the user is valid $user = $this->authenticate( $username, $password, 'close_topics', __( 'You do not have permission to close topics.' ) ); do_action( 'bb_xmlrpc_call_authenticated', 'bb.closeTopic' ); // If an error was raised by authentication or by an action then return it if ( $this->error ) { return $this->error; } // Can be numeric id or slug $topic_id = isset( $args[2] ) ? $args[2] : false; // Check for bad data if ( !$topic_id || ( !is_string( $topic_id ) && !is_integer( $topic_id ) ) ) { $this->error = new IXR_Error( 400, __( 'The topic id is invalid.' ) ); return $this->error; } // Check the requested topic exists if ( !$topic = get_topic( $topic_id ) ) { $this->error = new IXR_Error( 400, __( 'No topic found.' ) ); return $this->error; } // The topic id may have been a slug, so make sure it's an integer here $topic_id = (int) $topic->topic_id; // Make sure they are allowed to close this topic if ( !bb_current_user_can( 'close_topic', $topic_id ) ) { $this->error = new IXR_Error( 403, __( 'You do not have permission to close this topic.' ) ); return $this->error; } // Open or close? $close = isset( $args[3] ) ? (int) $args[3] : 0; // Forget it if it's already matching if ( $close === (int) $topic->topic_open ) { return 0; } // Close the topic if ( !$close && !bb_close_topic( $topic_id ) ) { $this->error = new IXR_Error( 500, __( 'The topic could not be closed.' ) ); return $this->error; } // Open the topic if ( $close && !bb_open_topic( $topic_id ) ) { $this->error = new IXR_Error( 500, __( 'The topic could not be opened.' ) ); return $this->error; } $result = 1; do_action( 'bb_xmlrpc_call_return', 'bb.closeTopic' ); return $result; } /** * bbPress publishing API - Post XML-RPC methods */ /** * Returns a numerical count of posts * * @since 1.0 * @return integer|object The number of topics when successfully executed or an IXR_Error object on failure * @param array $args Arguments passed by the XML-RPC call * @param string $args[0] The username for authentication * @param string $args[1] The password for authentication * @param integer|string $args[2] The topic id or slug * * XML-RPC request to get a count of all posts in the topic with slug "countable-topic" * * bb.getPostCount * * joeblow * 123password * countable-topic * * */ function bb_getPostCount( $args ) { do_action( 'bb_xmlrpc_call', 'bb.getPostCount' ); // Escape args $this->escape( $args ); // Get the login credentials $username = $args[0]; $password = (string) $args[1]; // Check the user is valid if ( $this->auth_readonly ) { $user = $this->authenticate( $username, $password ); } do_action( 'bb_xmlrpc_call_authenticated', 'bb.getPostCount' ); // If an error was raised by authentication or by an action then return it if ( $this->error ) { return $this->error; } // Can be numeric id or slug $topic_id = isset( $args[2] ) ? $args[2] : false; // Check for bad data if ( !$topic_id || ( !is_string( $topic_id ) && !is_integer( $topic_id ) ) ) { $this->error = new IXR_Error( 400, __( 'The topic id is invalid.' ) ); return $this->error; } // Check the requested topic exists if ( !$topic = get_topic( $topic_id ) ) { $this->error = new IXR_Error( 400, __( 'No topic found.' ) ); return $this->error; } // OK, let's trust the count in the topic table $count = $topic->topic_posts; do_action( 'bb_xmlrpc_call_return', 'bb.getPostCount' ); // Return the count of posts return $count; } /** * Returns details of the posts in a given topic * * @since 1.0 * @return array|object The posts when successfully executed or an IXR_Error object on failure * @param array $args Arguments passed by the XML-RPC call * @param string $args[0] The username for authentication * @param string $args[1] The password for authentication * @param integer|string $args[2] The topic id or slug * @param integer $args[3] The number of posts to return (optional) * @param integer $args[4] The number of the page to return (optional) * * XML-RPC request to get all posts in the topic with id number 53 * * bb.getPosts * * joeblow * 123password * 53 * * * * XML-RPC request to get the latest 5 posts in the topic with id number 341 * * bb.getPosts * * joeblow * 123password * 341 * 5 * * * * XML-RPC request to get posts 11 to 20 in the topic with slug "long-topic" * * bb.getPosts * * joeblow * 123password * long-topic * 10 * 2 * * */ function bb_getPosts( $args ) { do_action( 'bb_xmlrpc_call', 'bb.getPosts' ); // Escape args $this->escape( $args ); // Get the login credentials $username = $args[0]; $password = (string) $args[1]; // Check the user is valid if ( $this->auth_readonly ) { $user = $this->authenticate( $username, $password ); } do_action( 'bb_xmlrpc_call_authenticated', 'bb.getPosts' ); // If an error was raised by authentication or by an action then return it if ( $this->error ) { return $this->error; } // Can be numeric id or slug $topic_id = isset( $args[2] ) ? $args[2] : false; // Check for bad data if ( !$topic_id || ( !is_string( $topic_id ) && !is_integer( $topic_id ) ) ) { $this->error = new IXR_Error( 400, __( 'The topic id is invalid.' ) ); return $this->error; } // Check the requested topic exists if ( !$topic = get_topic( $topic_id ) ) { $this->error = new IXR_Error( 400, __( 'No topic found.' ) ); return $this->error; } // The topic id may have been a slug, so make sure it's an integer here $topic_id = (int) $topic->topic_id; // Setup an array to store arguments to pass to get_thread() function $get_thread_args = array(); // Can only be an integer if ( isset( $args[3] ) && $per_page = (int) $args[3] ) { $get_thread_args['per_page'] = $per_page; } // Can only be an integer if ( isset( $args[4] ) && $page = (int) $args[4] ) { $get_thread_args['page'] = $page; } // Get the posts if ( !$posts = get_thread( $topic_id, $get_thread_args ) ) { $this->error = new IXR_Error( 500, __( 'No posts found.' ) ); return $this->error; } // Only include "safe" data in the array $_posts = array(); foreach ( $posts as $post ) { $_posts[] = $this->prepare_post( $post ); } do_action( 'bb_xmlrpc_call_return', 'bb.getPosts' ); // Return the posts return $_posts; } /** * Returns details of a post * * @since 1.0 * @return array|object An array containing details of the returned post when successfully executed or an IXR_Error object on failure * @param array $args Arguments passed by the XML-RPC call * @param string $args[0] The username for authentication * @param string $args[1] The password for authentication * @param integer $args[2] The post's id * * XML-RPC request to get the post with id number 32 * * bb.getPost * * joeblow * 123password * 32 * * */ function bb_getPost( $args ) { do_action( 'bb_xmlrpc_call', 'bb.getPost' ); // Escape args $this->escape( $args ); // Get the login credentials $username = $args[0]; $password = (string) $args[1]; // Check the user is valid if ( $this->auth_readonly ) { $user = $this->authenticate( $username, $password ); } do_action( 'bb_xmlrpc_call_authenticated', 'bb.getPost' ); // If an error was raised by authentication or by an action then return it if ( $this->error ) { return $this->error; } // Can be numeric id or slug $post_id = isset( $args[2] ) ? (int) $args[2] : false; // Check for bad data if ( !$post_id ) { $this->error = new IXR_Error( 400, __( 'The post id is invalid.' ) ); return $this->error; } // Check the requested post exists if ( !$post = bb_get_post( $post_id ) ) { $this->error = new IXR_Error( 400, __( 'No post found.' ) ); return $this->error; } // Only include "safe" data in the array $_post = $this->prepare_post( $post ); do_action( 'bb_xmlrpc_call_return', 'bb.getPost' ); // Return the post return $_post; } /** * Creates a new post in a given topic * * @since 1.0 * @return array|object The post data when successfully created or an IXR_Error object on failure * @param array $args Arguments passed by the XML-RPC call * @param string $args[0] The username for authentication * @param string $args[1] The password for authentication * @param array $args[2] The values for the various parameters in the new topic * @param string $args[2]['text'] The text of the topic * @param integer|string $args[2]['topic_id'] The unique id of the topic which will contain this topic, slugs are OK to use too * * XML-RPC request to create a new post in the topic with slug "totally-worth-it" * * bb.newPost * * joeblow * 123password * * * text * I agree, it is totally worth it. * * * topic_id * totally-worth-it * * * * */ function bb_newPost( $args ) { do_action( 'bb_xmlrpc_call', 'bb.newPost' ); // Escape args $this->escape( $args ); // Get the login credentials $username = $args[0]; $password = (string) $args[1]; // Check the user is valid $user = $this->authenticate( $username, $password, 'write_posts', __( 'You do not have permission to write posts.' ) ); do_action( 'bb_xmlrpc_call_authenticated', 'bb.newPost' ); // If an error was raised by authentication or by an action then return it if ( $this->error ) { return $this->error; } // Make sure there is something for us to do if ( !$args[2] || !is_array( $args[2] ) || !count( $args[2] ) ) { $this->error = new IXR_Error( 400, __( 'The post data is invalid.' ) ); return $this->error; } $structure = (array) $args[2]; // Can be numeric id or slug $topic_id = isset( $structure['topic_id'] ) ? $structure['topic_id'] : false; // Check for bad data if ( !$topic_id || ( !is_string( $topic_id ) && !is_integer( $topic_id ) ) ) { $this->error = new IXR_Error( 400, __( 'The topic id is invalid.' ) ); return $this->error; } // Check the requested topic exists if ( !$topic = get_topic( $topic_id ) ) { $this->error = new IXR_Error( 400, __( 'No topic found.' ) ); return $this->error; } // The topic id may have been a slug, so make sure it's an integer here $topic_id = (int) $topic->topic_id; // Make sure they are allowed to write posts to this topic if ( !bb_current_user_can( 'write_post', $topic_id ) ) { $this->error = new IXR_Error( 403, __( 'You do not have permission to write posts to this topic.' ) ); return $this->error; } // The post requires text if ( !isset( $structure['text'] ) || !$structure['text'] ) { $this->error = new IXR_Error( 400, __( 'The post text is invalid.' ) ); return $this->error; } // Inject structure into an array suitable for bb_insert_post() $bb_insert_post_args = array( 'topic_id' => $topic_id, 'post_text' => (string) $structure['text'] ); // Create the post if ( !$post_id = bb_insert_post( $bb_insert_post_args ) ) { $this->error = new IXR_Error( 500, __( 'The post could not be created.' ) ); return $this->error; } // Only include "safe" data in the array $post = $this->prepare_forum( bb_get_post( $post_id ) ); do_action( 'bb_xmlrpc_call_return', 'bb.newPost' ); return $post; } /** * Edits an existing post * * @since 1.0 * @return array|object The post data when successfully edited or an IXR_Error object on failure * @param array $args Arguments passed by the XML-RPC call * @param string $args[0] The username for authentication * @param string $args[1] The password for authentication * @param array $args[2] The values for the various parameters in the new topic * @param integer $args[2]['post_id'] The unique id of the post * @param string $args[2]['text'] The text of the topic * * XML-RPC request to edit the text of the post with an id of 452 * * bb.editPost * * joeblow * 123password * * * post_id * 452 * * * text * For now I will withhold my opinion. * * * * */ function bb_editPost( $args ) { do_action( 'bb_xmlrpc_call', 'bb.editPost' ); // Escape args $this->escape( $args ); // Get the login credentials $username = $args[0]; $password = (string) $args[1]; // Check the user is valid $user = $this->authenticate( $username, $password, 'edit_posts', __( 'You do not have permission to edit posts.' ) ); do_action( 'bb_xmlrpc_call_authenticated', 'bb.editPost' ); // If an error was raised by authentication or by an action then return it if ( $this->error ) { return $this->error; } // Make sure there is something for us to do if ( !$args[2] || !is_array( $args[2] ) || !count( $args[2] ) ) { $this->error = new IXR_Error( 400, __( 'The post data is invalid.' ) ); return $this->error; } $structure = (array) $args[2]; // Can be numeric id or slug $post_id = isset( $structure['post_id'] ) ? (int) $structure['post_id'] : false; // Check for bad data if ( !$post_id ) { $this->error = new IXR_Error( 400, __( 'The post id is invalid.' ) ); return $this->error; } // Check the requested topic exists if ( !$post = bb_get_post( $post_id ) ) { $this->error = new IXR_Error( 400, __( 'No post found.' ) ); return $this->error; } // Re-assign the post id $post_id = (int) $post->post_id; // Make sure they are allowed to edit this post if ( !bb_current_user_can( 'edit_post', $post_id ) ) { $this->error = new IXR_Error( 403, __( 'You do not have permission to edit this post.' ) ); return $this->error; } // The post requires text if ( !isset( $structure['text'] ) || !$structure['text'] ) { $this->error = new IXR_Error( 400, __( 'The post text is invalid.' ) ); return $this->error; } // Inject structure into an array suitable for bb_insert_post() $bb_insert_post_args = array( 'post_id' => $post_id, 'post_text' => (string) $structure['text'] ); // Create the post if ( !$post_id = bb_insert_post( $bb_insert_post_args ) ) { $this->error = new IXR_Error( 500, __( 'The post could not be edited.' ) ); return $this->error; } // Only include "safe" data in the array $post = $this->prepare_forum( bb_get_post( $post_id ) ); do_action( 'bb_xmlrpc_call_return', 'bb.editPost' ); return $post; } /** * Deletes an existing post * * @since 1.0 * @return integer|object 1 when successfully deleted, 0 when already deleted or an IXR_Error object on failure * @param array $args Arguments passed by the XML-RPC call * @param string $args[0] The username for authentication * @param string $args[1] The password for authentication * @param array $args[2] The unique id of the post * @param array $args[3] 1 deletes the post, 0 undeletes the post (optional) * * XML-RPC request to delete the post with an id of 4301 * * bb.editPost * * joeblow * 123password * 4301 * * */ function bb_deletePost( $args ) { do_action( 'bb_xmlrpc_call', 'bb.deletePost' ); // Escape args $this->escape( $args ); // Get the login credentials $username = $args[0]; $password = (string) $args[1]; // Check the user is valid $user = $this->authenticate( $username, $password, 'delete_posts', __( 'You do not have permission to delete posts.' ) ); do_action( 'bb_xmlrpc_call_authenticated', 'bb.deletePost' ); // If an error was raised by authentication or by an action then return it if ( $this->error ) { return $this->error; } // Can be numeric id or slug $post_id = isset( $args[2] ) ? (int) $args[2] : false; // Check for bad data if ( !$post_id ) { $this->error = new IXR_Error( 400, __( 'The post id is invalid.' ) ); return $this->error; } // Check the requested topic exists if ( !$post = bb_get_post( $post_id ) ) { $this->error = new IXR_Error( 400, __( 'No post found.' ) ); return $this->error; } // Re-assign the post id $post_id = (int) $post->post_id; // Make sure they are allowed to delete this post if ( !bb_current_user_can( 'delete_post', $post_id ) ) { $this->error = new IXR_Error( 403, __( 'You do not have permission to delete this post.' ) ); return $this->error; } $status = isset( $args[3] ) ? (int) $args[3] : 1; if ( $status === (int) $post->post_status ) { return 0; } // Delete the post if ( !$post_id = bb_delete_post( $post_id, $status ) ) { $this->error = new IXR_Error( 500, __( 'The post could not be edited.' ) ); return $this->error; } $result = 1; do_action( 'bb_xmlrpc_call_return', 'bb.deletePost' ); return $result; } /** * bbPress publishing API - Topic Tag XML-RPC methods */ /** * Returns the hot tags in order of hotness in a given forum or all hot tags * * @since 1.0 * @return integer|object The tag data when successfully executed or an IXR_Error object on failure * @param array $args Arguments passed by the XML-RPC call * @param string $args[0] The username for authentication * @param string $args[1] The password for authentication * @param integer $args[2] The number of tags to return (optional) * @param integer|string $args[3] The forum id or slug (optional) * * XML-RPC request to get the 20 hottest tags in the forum with slug "hawtness" * * bb.getTopicTags * * joeblow * 123password * 20 * hawtness * * */ function bb_getHotTopicTags( $args ) { do_action( 'bb_xmlrpc_call', 'bb.getHotTopicTags' ); // Escape args $this->escape( $args ); // Get the login credentials $username = $args[0]; $password = (string) $args[1]; // Check the user is valid if ( $this->auth_readonly ) { $user = $this->authenticate( $username, $password ); } do_action( 'bb_xmlrpc_call_authenticated', 'bb.getHotTopicTags' ); // If an error was raised by authentication or by an action then return it if ( $this->error ) { return $this->error; } // Must be a number $per_page = isset( $args[2] ) ? (integer) $args[2] : false; // Can be numeric id or slug $forum_id = isset( $args[3] ) ? $args[3] : false; if ( $forum_id ) { // Check for bad data if ( !is_string( $forum_id ) && !is_integer( $forum_id ) ) { $this->error = new IXR_Error( 400, __( 'The forum id is invalid.' ) ); return $this->error; } // Check the requested forum exists if ( !$forum = bb_get_forum( $forum_id ) ) { $this->error = new IXR_Error( 404, __( 'No forum found.' ) ); return $this->error; } global $bbdb; $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 ) ); if ( !count( $topic_ids ) ) { $this->error = new IXR_Error( 400, __( 'No topics found.' ) ); return $this->error; } global $wp_taxonomy_object; $tags = $wp_taxonomy_object->get_object_terms( $topic_ids, 'bb_topic_tag', array( 'fields' => 'all_with_object_id', 'orderby' => 'count', 'order' => 'DESC' ) ); if ( !$tags || is_wp_error( $tags ) ) { $this->error = new IXR_Error( 500, __( 'Could not retrieve hot topic tags.' ) ); return $this->error; } if ( !count( $tags ) ) { $this->error = new IXR_Error( 500, __( 'No hot topic tags found.' ) ); return $this->error; } global $bb_log; $bb_log->debug($tags); for ( $i = 0; isset( $tags[$i] ); $i++ ) { _bb_make_tag_compat( $tags[$i] ); } $bb_log->debug($tags); // Only include "safe" data in the array $_tags = array(); foreach ( $tags as $tag ) { $_tag = $this->prepare_topic_tag( $tag ); if ( !in_array( $_tag, $_tags ) ) { $_tags[] = $_tag; } } if ( $per_page ) { $_tags = array_slice( $_tags, 0, $per_page ); } } else { if ( !$tags = bb_get_top_tags( array( 'get' => 'all', 'number' => $per_page ) ) ) { $this->error = new IXR_Error( 500, __( 'No hot topic tags found.' ) ); return $this->error; } // Only include "safe" data in the array $_tags = array(); foreach ( $tags as $tag ) { $_tags[] = $this->prepare_topic_tag( $tag ); } } do_action( 'bb_xmlrpc_call', 'bb.getHotTopicTags' ); return $_tags; } /** * Returns a numerical count of tags in a given topic or all tags * * @since 1.0 * @return integer|object The number of topics when successfully executed or an IXR_Error object on failure * @param array $args Arguments passed by the XML-RPC call * @param string $args[0] The username for authentication * @param string $args[1] The password for authentication * @param integer|string $args[2] The topic id or slug (optional) * * XML-RPC request to get a count of all tags in the topic with slug "woot-frist-topic" * * bb.getTopicTagCount * * joeblow * 123password * woot-frist-topic * * */ function bb_getTopicTagCount( $args ) { do_action( 'bb_xmlrpc_call', 'bb.getTopicTagCount' ); // Escape args $this->escape( $args ); // Get the login credentials $username = $args[0]; $password = (string) $args[1]; // Check the user is valid if ( $this->auth_readonly ) { $user = $this->authenticate( $username, $password ); } do_action( 'bb_xmlrpc_call_authenticated', 'bb.getTopicTagCount' ); // If an error was raised by authentication or by an action then return it if ( $this->error ) { return $this->error; } // Can be numeric id or slug $topic_id = isset( $args[2] ) ? $args[2] : false; // Check for bad data if ( $topic_id ) { if ( !is_string( $topic_id ) && !is_integer( $topic_id ) ) { $this->error = new IXR_Error( 400, __( 'The topic id is invalid.' ) ); return $this->error; } // Check the requested topic exists if ( !$topic = get_topic( $topic_id ) ) { $this->error = new IXR_Error( 400, __( 'No topic found.' ) ); return $this->error; } // The topic id may have been a slug, so make sure it's an integer here $topic_id = (int) $topic->topic_id; // Now get the tags if ( !$tags = bb_get_topic_tags( $topic_id ) ) { $tags = array(); } // Count the tags $count = count( $tags ); } else { global $wp_taxonomy_object; $count = $wp_taxonomy_object->count_terms( 'bb_topic_tag' ); if ( is_wp_error( $count ) ) { $this->error = new IXR_Error( 500, __( 'Could not get a count of all topic tags.' ) ); return $this->error; } } do_action( 'bb_xmlrpc_call_return', 'bb.getTopicTagCount' ); // Return the count of tags return $count; } /** * Returns the tags in a given topic or all tags * * @since 1.0 * @return integer|object The tag data when successfully executed or an IXR_Error object on failure * @param array $args Arguments passed by the XML-RPC call * @param string $args[0] The username for authentication * @param string $args[1] The password for authentication * @param integer|string $args[2] The topic id or slug (optional) * * XML-RPC request to get all tags in the topic with slug "woot-frist-topic" * * bb.getTopicTags * * joeblow * 123password * woot-frist-topic * * */ function bb_getTopicTags( $args ) { do_action( 'bb_xmlrpc_call', 'bb.getTopicTags' ); // Escape args $this->escape( $args ); // Get the login credentials $username = $args[0]; $password = (string) $args[1]; // Check the user is valid if ( $this->auth_readonly ) { $user = $this->authenticate( $username, $password ); } do_action( 'bb_xmlrpc_call_authenticated', 'bb.getTopicTags' ); // If an error was raised by authentication or by an action then return it if ( $this->error ) { return $this->error; } // Can be numeric id or slug $topic_id = isset( $args[2] ) ? $args[2] : false; // Check for bad data if ( $topic_id ) { if ( !is_string( $topic_id ) && !is_integer( $topic_id ) ) { $this->error = new IXR_Error( 400, __( 'The topic id is invalid.' ) ); return $this->error; } // Check the requested topic exists if ( !$topic = get_topic( $topic_id ) ) { $this->error = new IXR_Error( 400, __( 'No topic found.' ) ); return $this->error; } // The topic id may have been a slug, so make sure it's an integer here $topic_id = (int) $topic->topic_id; // Now get the tags if ( !$tags = bb_get_topic_tags( $topic_id ) ) { $this->error = new IXR_Error( 500, __( 'No topic tags found.' ) ); return $this->error; } } else { global $wp_taxonomy_object; $tags = $wp_taxonomy_object->get_terms( 'bb_topic_tag', array( 'get' => 'all' ) ); if ( is_wp_error( $tags ) ) { $this->error = new IXR_Error( 500, __( 'Could not retrieve all topic tags.' ) ); return $this->error; } for ( $i = 0; isset( $tags[$i] ); $i++ ) { _bb_make_tag_compat( $tags[$i] ); } } // Only include "safe" data in the array $_tags = array(); foreach ( $tags as $tag ) { $_tags[] = $this->prepare_topic_tag( $tag ); } do_action( 'bb_xmlrpc_call_return', 'bb.getTopicTags' ); // Return the tags return $_tags; } /** * Returns the topics which are tagged with the given tag * * @since 1.0 * @return integer|object The topic data when successfully executed or an IXR_Error object on failure * @param array $args Arguments passed by the XML-RPC call * @param string $args[0] The username for authentication * @param string $args[1] The password for authentication * @param string $args[2] The tag name or slug * @param integer $args[3] The number of topics to return (optional) * @param integer $args[4] The number of the page to return (optional) * * XML-RPC request to get the latest 10 topics tagged with the tag "apples" * * bb.getTopicTag * * joeblow * 123password * apples * 10 * * */ function bb_getTopicTag( $args ) { do_action( 'bb_xmlrpc_call', 'bb.getTopicTag' ); // Escape args $this->escape( $args ); // Get the login credentials $username = $args[0]; $password = (string) $args[1]; // Check the user is valid if ( $this->auth_readonly ) { $user = $this->authenticate( $username, $password ); } do_action( 'bb_xmlrpc_call_authenticated', 'bb.getTopicTag' ); // If an error was raised by authentication or by an action then return it if ( $this->error ) { return $this->error; } // Can only be a string $tag_id = isset( $args[2] ) ? (string) $args[2] : false; // Check for bad data if ( !$tag_id ) { $this->error = new IXR_Error( 400, __( 'The tag id is invalid.' ) ); return $this->error; } // Check the requested topic exists if ( !$tag = bb_get_tag( $tag_id ) ) { $this->error = new IXR_Error( 400, __( 'No tag found.' ) ); return $this->error; } // Get the numeric tag id $tag_id = (int) $tag->tag_id; // Setup an array to store arguments to pass to get_tagged_topics() function $get_topics_args = array( 'tag_id' => false, 'number' => false, 'page' => false ); // Can only be an integer if ( isset( $args[3] ) && $number = (int) $args[3] ) { $get_topics_args['number'] = $number; } // Can only be an integer if ( isset( $args[4] ) && $page = (int) $args[4] ) { $get_topics_args['page'] = $page; } // Now get the topics if ( !$topics = get_tagged_topics( $tag_id ) ) { $this->error = new IXR_Error( 500, __( 'No topics found.' ) ); return $this->error; } // Only include "safe" data in the array $_topics = array(); foreach ( $topics as $topic ) { $_topics[] = $this->prepare_topic( $topic ); } do_action( 'bb_xmlrpc_call_return', 'bb.getTopicTag' ); // Return the topics return $_topics; } /** * Adds the specified tags to the specified topic * * @since 1.0 * @return array|object The tags which were added when successfully executed or an IXR_Error object on failure * @param array $args Arguments passed by the XML-RPC call * @param string $args[0] The username for authentication * @param string $args[1] The password for authentication * @param string|integer $args[2] The topic id or slug * @param string|array $args[3] The tags to add to the topic * * XML-RPC request to add the tag "banana" to the topic with id 219 * * bb.addTopicTags * * joeblow * 123password * 219 * banana * * * * XML-RPC request to add the tags "banana" and "man" to the topic with id 219 * * bb.addTopicTags * * joeblow * 123password * 219 * banana, man * * * * XML-RPC request to add the tags "banana" and "man" to the topic with id 219 using an array * * bb.addTopicTags * * joeblow * 123password * 219 * * banana * man * * * */ function bb_addTopicTags( $args ) { do_action( 'bb_xmlrpc_call', 'bb.addTopicTags' ); // Escape args $this->escape( $args ); // Get the login credentials $username = $args[0]; $password = (string) $args[1]; // Check the user is valid $user = $this->authenticate( $username, $password, 'edit_tags', __( 'You do not have permission to edit tags.' ) ); do_action( 'bb_xmlrpc_call_authenticated', 'bb.addTopicTags' ); // If an error was raised by authentication or by an action then return it if ( $this->error ) { return $this->error; } // Can be numeric id or slug $topic_id = isset( $args[2] ) ? $args[2] : false; // Check for bad data if ( !$topic_id || ( !is_string( $topic_id ) && !is_integer( $topic_id ) ) ) { $this->error = new IXR_Error( 400, __( 'The topic id is invalid.' ) ); return $this->error; } // Check the requested topic exists if ( !$topic = get_topic( $topic_id ) ) { $this->error = new IXR_Error( 400, __( 'No topic found.' ) ); return $this->error; } // The topic id may have been a slug, so make sure it's an integer here $topic_id = (int) $topic->topic_id; // Make sure they are allowed to add tags to this topic if ( !bb_current_user_can( 'add_tag_to', $topic_id ) ) { $this->error = new IXR_Error( 403, __( 'You do not have permission to add tags to this topic.' ) ); return $this->error; } $tags = isset( $args[3] ) ? $args[3] : false; // Check for bad data if ( !$tags || ( !is_string( $tags ) && !is_array( $tags ) ) ) { $this->error = new IXR_Error( 400, __( 'The tag data is invalid.' ) ); return $this->error; } // Add the tags if ( !$tag_ids = bb_add_topic_tags( $topic_id, $tags ) ) { $this->error = new IXR_Error( 500, __( 'The tags could not be added.' ) ); return $this->error; } // Only include "safe" data in the array $_tags = array(); foreach ( $tag_ids as $tag_id ) { $_tags[] = $this->prepare_topic_tag( bb_get_tag( $tag_id ) ); } do_action( 'bb_xmlrpc_call_return', 'bb.addTopicTags' ); // Return the tags which were added as an array return $_tags; } /** * Removes the specified tags from the specified topic * * @since 1.0 * @return integer|object 1 when successfully executed or an IXR_Error object on failure * @param array $args Arguments passed by the XML-RPC call * @param string $args[0] The username for authentication * @param string $args[1] The password for authentication * @param string|integer $args[2] The topic id or slug * @param string|array $args[3] The tags to remove from the topic * * XML-RPC request to remove the tag "banana" to the topic with id 219 * * bb.removeTopicTags * * joeblow * 123password * 219 * banana * * * * XML-RPC request to remove the tags "banana" and "man" to the topic with id 219 * * bb.removeTopicTags * * joeblow * 123password * 219 * banana, man * * * * XML-RPC request to remove the tags "banana" and "man" to the topic with id 219 using an array * * bb.removeTopicTags * * joeblow * 123password * 219 * * banana * man * * * */ function bb_removeTopicTags( $args ) { do_action( 'bb_xmlrpc_call', 'bb.removeTopicTags' ); // Escape args $this->escape( $args ); // Get the login credentials $username = $args[0]; $password = (string) $args[1]; // Check the user is valid $user = $this->authenticate( $username, $password, 'edit_tags', __( 'You do not have permission to edit tags.' ) ); do_action( 'bb_xmlrpc_call_authenticated', 'bb.removeTopicTags' ); // If an error was raised by authentication or by an action then return it if ( $this->error ) { return $this->error; } // Can be numeric id or slug $topic_id = isset( $args[2] ) ? $args[2] : false; // Check for bad data if ( !$topic_id || ( !is_string( $topic_id ) && !is_integer( $topic_id ) ) ) { $this->error = new IXR_Error( 400, __( 'The topic id is invalid.' ) ); return $this->error; } // Check the requested topic exists if ( !$topic = get_topic( $topic_id ) ) { $this->error = new IXR_Error( 400, __( 'No topic found.' ) ); return $this->error; } // The topic id may have been a slug, so make sure it's an integer here $topic_id = (int) $topic->topic_id; // Make sure they are allowed to add tags to this topic if ( !bb_current_user_can( 'add_tag_to', $topic_id ) ) { $this->error = new IXR_Error( 403, __( 'You do not have permission to remove tags from this topic.' ) ); return $this->error; } $tags = isset( $args[3] ) ? $args[3] : false; // Check for bad data if ( !$tags || ( !is_string( $tags ) && !is_array( $tags ) ) ) { $this->error = new IXR_Error( 400, __( 'The tag data is invalid.' ) ); return $this->error; } // Add the tags if ( !bb_remove_topic_tags( $topic_id, $tags ) ) { $this->error = new IXR_Error( 500, __( 'The tags could not be removed.' ) ); return $this->error; } $result = 1; do_action( 'bb_xmlrpc_call_return', 'bb.removeTopicTags' ); // Return the result return $result; } /** * Renames the specified tag to a new tag name * * @since 1.0 * @return array|object The tag data when successfully renamed or an IXR_Error object on failure * @param array $args Arguments passed by the XML-RPC call * @param string $args[0] The username for authentication * @param string $args[1] The password for authentication * @param string $args[2] The tag name or slug * @param string $args[3] The new tag name (slug is auto-generated) * * XML-RPC request to rename the tag "banana" to "bananas" * * bb.renameTopicTag * * joeblow * 123password * banana * bananas * * */ function bb_renameTopicTag( $args ) { do_action( 'bb_xmlrpc_call', 'bb.renameTopicTag' ); // Escape args $this->escape( $args ); // Get the login credentials $username = $args[0]; $password = (string) $args[1]; // Check the user is valid $user = $this->authenticate( $username, $password, 'manage_tags', __( 'You do not have permission to manage tags.' ) ); do_action( 'bb_xmlrpc_call_authenticated', 'bb.renameTopicTag' ); // If an error was raised by authentication or by an action then return it if ( $this->error ) { return $this->error; } // Can only be a string $tag_id = isset( $args[2] ) ? (string) $args[2] : false; // Check for bad data if ( !$tag_id ) { $this->error = new IXR_Error( 400, __( 'The tag id is invalid.' ) ); return $this->error; } // Check the requested tag exists if ( !$tag = bb_get_tag( $tag_id ) ) { $this->error = new IXR_Error( 400, __( 'No tag found.' ) ); return $this->error; } // Get the numeric tag id $tag_id = (int) $tag->tag_id; // Can only be a string $tag_name = isset( $args[3] ) ? (string) $args[3] : false; // Check for bad data if ( !$tag_name || $tag_name == $tag->tag_name ) { $this->error = new IXR_Error( 400, __( 'The tag name is invalid.' ) ); return $this->error; } // Rename the tag if ( !$new_tag = bb_rename_tag( $tag_id, $tag_name ) ) { $this->error = new IXR_Error( 500, __( 'The tag could not be renamed.' ) ); return $this->error; } // Only include "safe" data in the array $new_tag = $this->prepare_topic_tag( $new_tag ); do_action( 'bb_xmlrpc_call_return', 'bb.renameTopicTag' ); // Return the tag return $new_tag; } /** * Merges the specified tags * * @since 1.0 * @return array|object The tag data when successfully merged or an IXR_Error object on failure * @param array $args Arguments passed by the XML-RPC call * @param string $args[0] The username for authentication * @param string $args[1] The password for authentication * @param string $args[2] The old tag name or slug to be destroyed * @param string $args[3] The new tag name or slug where the old tag will be merged to * * XML-RPC request to merge the tag "banana" into the tag "apple" * * bb.mergeTopicTags * * joeblow * 123password * banana * apple * * */ function bb_mergeTopicTags( $args ) { do_action( 'bb_xmlrpc_call', 'bb.mergeTopicTags' ); // Escape args $this->escape( $args ); // Get the login credentials $username = $args[0]; $password = (string) $args[1]; // Check the user is valid $user = $this->authenticate( $username, $password, 'manage_tags', __( 'You do not have permission to manage tags.' ) ); do_action( 'bb_xmlrpc_call_authenticated', 'bb.mergeTopicTags' ); // If an error was raised by authentication or by an action then return it if ( $this->error ) { return $this->error; } // Can only be strings $old_tag_id = isset( $args[2] ) ? (string) $args[2] : false; $new_tag_id = isset( $args[3] ) ? (string) $args[3] : false; // Check for bad data if ( !$old_tag_id ) { $this->error = new IXR_Error( 400, __( 'The old tag id is invalid.' ) ); return $this->error; } if ( !$new_tag_id ) { $this->error = new IXR_Error( 400, __( 'The new tag id is invalid.' ) ); return $this->error; } // Check the requested tags exist if ( !$old_tag = bb_get_tag( $old_tag_id ) ) { $this->error = new IXR_Error( 400, __( 'No old tag found.' ) ); return $this->error; } if ( !$new_tag = bb_get_tag( $new_tag_id ) ) { $this->error = new IXR_Error( 400, __( 'No new tag found.' ) ); return $this->error; } // Get the numeric tag ids $old_tag_id = (int) $old_tag->tag_id; $new_tag_id = (int) $new_tag->tag_id; // Rename the tag if ( !$result = bb_rename_tag( $old_tag_id, $new_tag_id ) ) { $this->error = new IXR_Error( 500, __( 'The tags could not be merged.' ) ); return $this->error; } // Get the merged tag $new_tag = bb_get_tag( $new_tag_id ); // Only include "safe" data in the array $new_tag = $this->prepare_topic_tag( $new_tag ); do_action( 'bb_xmlrpc_call_return', 'bb.mergeTopicTags' ); // Return the tag return $new_tag; } /** * Destroys the specified tag * * @since 1.0 * @return integer|object 1 when successfully deleted or an IXR_Error object on failure * @param array $args Arguments passed by the XML-RPC call * @param string $args[0] The username for authentication * @param string $args[1] The password for authentication * @param string $args[2] The tag name or slug to be destroyed * * XML-RPC request to destroy the tag "banana" * * bb.destroyTopicTag * * joeblow * 123password * banana * * */ function bb_destroyTopicTag( $args ) { do_action( 'bb_xmlrpc_call', 'bb.destroyTopicTag' ); // Escape args $this->escape( $args ); // Get the login credentials $username = $args[0]; $password = (string) $args[1]; // Check the user is valid $user = $this->authenticate( $username, $password, 'manage_tags', __( 'You do not have permission to manage tags.' ) ); do_action( 'bb_xmlrpc_call_authenticated', 'bb.destroyTopicTag' ); // If an error was raised by authentication or by an action then return it if ( $this->error ) { return $this->error; } // Can only be a string $tag_id = isset( $args[2] ) ? (string) $args[2] : false; // Check for bad data if ( !$tag_id ) { $this->error = new IXR_Error( 400, __( 'The tag id is invalid.' ) ); return $this->error; } // Check the requested tag exists if ( !$tag = bb_get_tag( $tag_id ) ) { $this->error = new IXR_Error( 400, __( 'No tag found.' ) ); return $this->error; } // Get the numeric tag id $tag_id = (int) $tag->tag_id; // Destroy the tag if ( !$result = bb_destroy_tag( $tag_id ) ) { $this->error = new IXR_Error( 500, __( 'The tag could not be destroyed.' ) ); return $this->error; } $result = 1; do_action( 'bb_xmlrpc_call_return', 'bb.destroyTopicTag' ); // Return the tag return $result; } /** * bbPress publishing API - Options XML-RPC methods */ /** * Initialises site options which can be manipulated using XML-RPC * * @since 1.0 * @return void */ function initialise_site_option_info() { $this->site_options = array( // Read only options 'software_name' => array( 'desc' => __( 'Software Name' ), 'readonly' => true, 'value' => 'bbPress' ), 'software_version' => array( 'desc' => __( 'Software Version' ), 'readonly' => true, 'option' => 'version' ), 'site_url' => array( 'desc' => __( 'Site URL' ), 'readonly' => true, 'option' => 'uri' ), // Updatable options 'site_name' => array( 'desc' => __( 'Site Name' ), 'readonly' => false, 'option' => 'name' ), 'site_description' => array( 'desc' => __( 'Site Description' ), 'readonly' => false, 'option' => 'description' ), 'time_zone' => array( 'desc' => __( 'Time Zone' ), 'readonly' => false, 'option' => 'gmt_offset' ), 'datetime_format' => array( 'desc' => __( 'Date/Time Format' ), 'readonly' => false, 'option' => 'datetime_format' ), 'date_format' => array( 'desc' => __( 'Date Format' ), 'readonly' => false, 'option' => 'date_format' ) ); $this->site_options = apply_filters( 'xmlrpc_site_options', $this->site_options ); } /** * Compiles site options into an array suitable to be passed back through the XML-RPC server * * @since 1.0 * @return array The site options in an array * @param array $options An array of options to fetch and return */ function _getOptions( $options ) { $data = array(); foreach ( $options as $option ) { if ( array_key_exists( $option, $this->site_options ) ) { $data[$option] = $this->site_options[$option]; // Is the value static or dynamic? if ( isset( $data[$option]['option'] ) ) { $data[$option]['value'] = bb_get_option( $data[$option]['option'] ); unset( $data[$option]['option'] ); } } } return $data; } /** * Gets the specified site options * * @since 1.0 * @return array|object An array containing the specified options when successfully executed or an IXR_Error object on failure * @param array $args Arguments passed by the XML-RPC call * @param string $args[0] The username for authentication * @param string $args[1] The password for authentication * @param array $args[2] The options to be retrieved, when omitted the method returns all options (optional) * * XML-RPC request to get all site options * * bb.getOptions * * joeblow * 123password * * * * XML-RPC request to get the site name and site description * * bb.getOptions * * joeblow * 123password * * site_name * site_description * * * */ function bb_getOptions( $args ) { do_action( 'bb_xmlrpc_call', 'bb.getOptions' ); // Escape args $this->escape( $args ); // Get the login credentials $username = $args[0]; $password = (string) $args[1]; // Check the user is valid if ( $this->auth_readonly ) { $user = $this->authenticate( $username, $password ); } do_action( 'bb_xmlrpc_call_authenticated', 'bb.getOptions' ); // If an error was raised by authentication or by an action then return it if ( $this->error ) { return $this->error; } // If there are parameters supplied then make sure they are in an array $options = isset( $args[2] ) ? (array) $args[2] : false; // If no specific options where asked for, return all of them if ( !$options || !count( $options ) ) { $options = array_keys( $this->site_options ); } do_action( 'bb_xmlrpc_call_return', 'bb.getOptions' ); return $this->_getOptions( $options ); } /** * Sets the specified site options to the specified values * * @since 1.0 * @return array|object An array containing the specified options when successfully executed or an IXR_Error object on failure * @param array $args Arguments passed by the XML-RPC call * @param string $args[0] The username for authentication * @param string $args[1] The password for authentication * @param array $args[2] The options to be updated along with the new value of the option * * XML-RPC request to set the site name and site description * * bb.setOptions * * joeblow * 123password * * * site_name * Awesome forums * * * site_description * My totally awesome forums will kick your butt * * * * */ function bb_setOptions( $args ) { do_action( 'bb_xmlrpc_call', 'bb.setOptions' ); // Escape args $this->escape( $args ); // Get the login credentials $username = $args[0]; $password = (string) $args[1]; // Check the user is valid $user = $this->authenticate( $username, $password, 'manage_options', __( 'You are not allowed to manage options.' ) ); do_action( 'bb_xmlrpc_call_authenticated', 'bb.setOptions' ); // If an error was raised by authentication or by an action then return it if ( $this->error ) { return $this->error; } // Make sure there is something for us to do if ( !$args[2] || !is_array( $args[2] ) || !count( $args[2] ) ) { $this->error = new IXR_Error( 400, __( 'The options data is invalid.' ) ); return $this->error; } $options = (array) $args[2]; // Update the requested options foreach( $options as $o_name => $o_value ) { $option_names[] = $o_name; // If there is no value set skip it if ( empty( $o_value ) ) { continue; } // If the option doesn't exist skip it if ( !array_key_exists( $o_name, $this->site_options ) ) { continue; } // If the option is readonly skip it if ( $this->site_options[$o_name]['readonly'] == true ) { continue; } // Everything is good, update the option bb_update_option( $this->site_options[$o_name]['option'], $o_value ); } $_options = $this->_getOptions( $option_names ); do_action( 'bb_xmlrpc_call_return', 'bb.setOptions' ); // Now return the updated values return $_options; } /** * Pingback XML-RPC methods */ /** * Processes pingback requests * * @since 1.0 * @link http://www.hixie.ch/specs/pingback/pingback * @return string|object A message of success or an IXR_Error object on failure * @param array $args Arguments passed by the XML-RPC call * @param string $args[0] The full URI of the post where the pingback is being sent from * @param string $args[1] The full URI of the post where the pingback is being sent to * * XML-RPC request to register a pingback * * pingback.ping * * http://example.org/2008/09/post-containing-a-link/ * http://example.com/2008/08/post-being-linked-to/ * * */ function pingback_ping( $args ) { do_action( 'bb_xmlrpc_call', 'pingback.ping' ); $this->escape( $args ); // No particular need to sanitise $link_from = (string) $args[0]; $link_to = (string) $args[1]; // Tidy up ampersands in the URLs $link_from = str_replace( '&', '&', $link_from ); $link_to = str_replace( '&', '&', $link_to ); $link_to = str_replace( '&', '&', $link_to ); // Check if the topic linked to is in our site - a little more strict than WordPress, doesn't pull out the www if added if ( !bb_match_domains( $link_to, bb_get_uri() ) ) { // These are not the droids you are looking for $this->error = new IXR_Error( 0, __( 'This is not the site you are trying to pingback.' ) ); return $this->error; } // Get the topic if ( $topic_to = bb_get_topic_from_uri( $link_to ) ) { // Topics shouldn't ping themselves if ( $topic_from = bb_get_topic_from_uri( $link_from ) ) { if ( $topic_from->topic_id === $topic_to->topic_id ) { $this->error = new IXR_Error( 0, __( 'The source URL and the target URL cannot both point to the same resource.' ) ); return $this->error; } } } else { $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.' ) ); return $this->error; } // Let's check that the remote site didn't already pingback this entry $query = new BB_Query( 'post', array( 'topic_id' => $topic_to->topic_id, 'append_meta' => true ), 'get_thread' ); $posts_to = $query->results; unset( $query ); // Make sure we have some posts in the topic, this error should never happen really if ( !$posts_to || !is_array( $posts_to ) || !count( $posts_to ) ) { $this->error = new IXR_Error( 0, __( 'The specified target topic does not contain any posts.' ) ); return $this->error; } // Check if we already have a pingback from this URL foreach ( $posts_to as $post ) { if ( isset( $post->pingback_uri ) && trim( $post->pingback_uri ) === trim( $link_from ) ) { $this->error = new IXR_Error( 48, __( 'The pingback has already been registered.' ) ); return $this->error; } } unset( $posts_to, $post ); // Give time for the server sending the pingback to finish publishing it's post sleep(1); // Let's check the remote site for valid URL and content $link_from_source = wp_remote_fopen( $link_from ); if ( !$link_from_source ) { $this->error = new IXR_Error( 16, __( 'The source URL does not exist.' ) ); return $this->error; } // Allow plugins to filter here $link_from_source = apply_filters( 'bb_pre_remote_source', $link_from_source, $link_to ); // Work around bug in strip_tags() $link_from_source = str_replace( ']*>/", "\n\n", $link_from_source ); // Find the title of the page preg_match( '|([^<]*?)|is', $link_from_source, $link_from_title ); $link_from_title = $link_from_title[1]; if ( empty( $link_from_title ) ) { $this->error = new IXR_Error( 32, __( 'We cannot find a title on that page.' ) ); return $this->error; } // Strip out all tags except anchors $link_from_source = strip_tags( $link_from_source, '' ); // just keep the tag we need // Split the source into paragraphs $link_from_paragraphs = explode( "\n\n", $link_from_source ); // Prepare the link to search for in preg_match() once here $preg_target = preg_quote( $link_to ); // Loop through the paragraphs looking for the context for the url foreach ( $link_from_paragraphs as $link_from_paragraph ) { // The url exists if ( strpos( $link_from_paragraph, $link_to ) !== false ) { // But is it in an anchor tag preg_match( "|]+?" . $preg_target . "[^>]*>([^>]+?)|", $link_from_paragraph, $context ); // If the URL isn't in an anchor tag, keep looking if ( empty( $context ) ) { continue; } // We're going to use this fake tag to mark the context in a bit // the marker is needed in case the link text appears more than once in the paragraph $excerpt = preg_replace( '|\|', '', $link_from_paragraph ); // Prevent really long link text if ( strlen( $context[1] ) > 100 ) { $context[1] = substr( $context[1], 0, 100 ) . '...'; } // Set up the marker around the context $marker = '' . $context[1] . ''; // Swap out the link for our marker $excerpt = str_replace( $context[0], $marker, $excerpt ); // Strip all tags except for our context marker $excerpt = trim( strip_tags( $excerpt, '' ) ); // Make the marker safe for use in regexp $preg_marker = preg_quote( $marker ); // Reduce the excerpt to only include 100 characters on either side of the link $excerpt = preg_replace( "|.*?\s(.{0,100}" . $preg_marker . "{0,100})\s.*|s", '$1', $excerpt ); // Strip tags again, to remove the marker wrapper $excerpt = strip_tags( $excerpt ); break; } } // Make sure the link to the target was found in the excerpt if ( empty( $context ) ) { $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.' ) ); return $this->error; } // Add whacky prefix and suffix to the excerpt and sanitize $excerpt = '[...] ' . esc_html( $excerpt ) . ' [...]'; $this->escape( $excerpt ); // Build an array of post data to insert then insert a new post $postdata = array( 'topic_id' => $topic_to->topic_id, 'post_text' => $excerpt, 'poster_id' => 0, ); if ( !$post_ID = bb_insert_post( $postdata ) ) { $this->error = new IXR_Error( 0, __( 'The pingback could not be added.' ) ); return $this->error; } // Add meta to let us know where the pingback came from $link_from = str_replace( '&', '&', $link_from ); $this->escape( $link_from ); bb_update_postmeta( $post_ID, 'pingback_uri', $link_from ); // Add the title to meta $this->escape( $link_from_title ); bb_update_postmeta( $post_ID, 'pingback_title', $link_from_title ); // Action for plugins and what not do_action( 'bb_pingback_post', $post_ID ); // Return success message, complete with emoticon return sprintf( __( 'Pingback from %1$s to %2$s registered. Keep the web talking! :-)' ), $link_from, $link_to ); } /** * Returns an array of URLs that pingbacked the given URL * * @since 1.0 * @link http://www.aquarionics.com/misc/archives/blogite/0198.html * @return array The array of URLs that pingbacked the given topic * @param array $args Arguments passed by the XML-RPC call * @param string $args[0] The full URI of the post where the pingback is being sent from * @param string $args[1] The full URI of the post where the pingback is being sent to * * XML-RPC request to get all pingbacks on a topic * * pingback.ping * * http://example.com/2008/08/post-tobe-queried/ * * */ function pingback_extensions_getPingbacks( $args ) { do_action( 'bb_xmlrpc_call', 'pingback.extensions.getPingbacks' ); $this->escape( $args ); // Don't accept arrays of arguments if ( is_array( $args ) ) { $this->error = new IXR_Error( 404, __( 'The requested method only accepts one parameter.' ) ); return $this->error; } else { $url = (string) $args; } // Tidy up ampersands in the URI $url = str_replace( '&', '&', $url ); $url = str_replace( '&', '&', $url ); // Check if the URI is in our site if ( !bb_match_domains( $url, bb_get_uri() ) ) { // These are not the droids you are looking for $this->error = new IXR_Error( 0, __( 'The specified target URL is not on this domain.' ) ); return $this->error; } // Make sure the specified URI is in fact associated with a topic if ( !$topic = bb_get_topic_from_uri( $url ) ) { $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.' ) ); return $this->error; } // Grab the posts from the topic $query = new BB_Query( 'post', array( 'topic_id' => $topic_to->topic_id, 'append_meta' => true ), 'get_thread' ); $posts_to = $query->results; unset( $query ); // Check for pingbacks in the post meta data $pingbacks = array(); foreach ( $posts_to as $post ) { if ( isset( $post->pingback_uri ) ) { $pingbacks[] = $post->pingback_uri; } } unset( $post ); // This will return an empty array on failure return $pingbacks; } } /** * Initialises the XML-RPC server * * @since 1.0 * @var object The instance of the XML-RPC server class */ $bb_xmlrpc_server = new BB_XMLRPC_Server();