/bp-forums/bp-forums-functions.php

  1. <?php 
  2. /** 
  3. * BuddyPress Forums Functions. 
  4. * 
  5. * @package BuddyPress 
  6. * @subpackage ForumsFunctions 
  7. * @since 1.5.0 
  8. */ 
  9.  
  10. // Exit if accessed directly. 
  11. defined( 'ABSPATH' ) || exit; 
  12.  
  13. /** bbPress 2.x ***************************************************************/ 
  14.  
  15. /** 
  16. * Is see bbPress 2.x is installed and active? 
  17. * 
  18. * @since 1.6.0 
  19. * 
  20. * @return boolean True if bbPress 2.x is active, false if not. 
  21. */ 
  22. function bp_forums_is_bbpress_active() { 
  23.  
  24. // Single site. 
  25. if ( is_plugin_active( 'bbpress/bbpress.php' ) ) 
  26. return true; 
  27.  
  28. // Network active. 
  29. if ( is_plugin_active_for_network( 'bbpress/bbpress.php' ) ) 
  30. return true; 
  31.  
  32. // Nope. 
  33. return false; 
  34.  
  35. /** bbPress 1.x ***************************************************************/ 
  36.  
  37. /** 
  38. * See if bbPress 1.x is installed correctly. 
  39. * 
  40. * "Installed correctly" means that the bb-config-location option is set, and 
  41. * the referenced file exists. 
  42. * 
  43. * @since 1.2.0 
  44. * 
  45. * @return boolean True if option exists, false if not. 
  46. */ 
  47. function bp_forums_is_installed_correctly() { 
  48. $bp = buddypress(); 
  49.  
  50. if ( isset( $bp->forums->bbconfig ) && is_file( $bp->forums->bbconfig ) ) 
  51. return true; 
  52.  
  53. return false; 
  54.  
  55. /** 
  56. * Does the forums component have a directory page registered? 
  57. * 
  58. * Checks $bp pages global and looks for directory page. 
  59. * 
  60. * @since 1.5.0 
  61. * 
  62. * @global BuddyPress $bp The one true BuddyPress instance. 
  63. * 
  64. * @return bool True if set, False if empty. 
  65. */ 
  66. function bp_forums_has_directory() { 
  67. return (bool) !empty( buddypress()->pages->forums->id ); 
  68.  
  69. /** Forum Functions ***********************************************************/ 
  70.  
  71. /** 
  72. * Get a forum by ID. 
  73. * 
  74. * Wrapper for {@link bb_get_forum()}. 
  75. * 
  76. * @since 1.0.0 
  77. * 
  78. * @param int $forum_id ID of the forum being fetched. 
  79. * @return object bbPress forum object. 
  80. */ 
  81. function bp_forums_get_forum( $forum_id ) { 
  82.  
  83. /** This action is documented in bp-forums/bp-forums-screens.php */ 
  84. do_action( 'bbpress_init' ); 
  85. return bb_get_forum( $forum_id ); 
  86.  
  87. /** 
  88. * Create a forum. 
  89. * 
  90. * Wrapper for {@link bb_new_forum()}. 
  91. * 
  92. * @since 1.0.0 
  93. * 
  94. * @param array|string $args { 
  95. * Forum setup arguments. 
  96. * @type string $forum_name Name of the forum. 
  97. * @type string $forum_desc Description of the forum. 
  98. * @type int $forum_parent_id ID of the forum parent. Default: value of 
  99. * {@link bp_forums_parent_forums_id()}. 
  100. * @type bool $forum_order Order. 
  101. * @type int $forum_is_category Whether the forum is a category. Default: 0. 
  102. * } 
  103. * @return int ID of the newly created forum. 
  104. */ 
  105. function bp_forums_new_forum( $args = '' ) { 
  106.  
  107. /** This action is documented in bp-forums/bp-forums-screens.php */ 
  108. do_action( 'bbpress_init' ); 
  109.  
  110. $r = wp_parse_args( $args, array( 
  111. 'forum_name' => '',  
  112. 'forum_desc' => '',  
  113. 'forum_parent_id' => bp_forums_parent_forum_id(),  
  114. 'forum_order' => false,  
  115. 'forum_is_category' => 0 
  116. ) ); 
  117. extract( $r, EXTR_SKIP ); 
  118.  
  119. return bb_new_forum( array( 'forum_name' => stripslashes( $forum_name ), 'forum_desc' => stripslashes( $forum_desc ), 'forum_parent' => $forum_parent_id, 'forum_order' => $forum_order, 'forum_is_category' => $forum_is_category ) ); 
  120.  
  121. /** 
  122. * Update a forum. 
  123. * 
  124. * Wrapper for {@link bb_update_forum(}. 
  125. * 
  126. * @since 1.2.5 
  127. * 
  128. * @param array|string $args { 
  129. * Forum setup arguments. 
  130. * @type int $forum_id ID of the forum to be updated. 
  131. * @type string $forum_name Name of the forum. 
  132. * @type string $forum_desc Description of the forum. 
  133. * @type int $forum_parent_id ID of the forum parent. Default: value of 
  134. * {@link bp_forums_parent_forums_id()}. 
  135. * @type bool $forum_order Order. 
  136. * @type int $forum_is_category Whether the forum is a category. Default: 0. 
  137. * } 
  138. * @return bool True on success, false on failure. 
  139. */ 
  140. function bp_forums_update_forum( $args = '' ) { 
  141.  
  142. /** This action is documented in bp-forums/bp-forums-screens.php */ 
  143. do_action( 'bbpress_init' ); 
  144.  
  145. $r = wp_parse_args( $args, array( 
  146. 'forum_id' => '',  
  147. 'forum_name' => '',  
  148. 'forum_desc' => '',  
  149. 'forum_slug' => '',  
  150. 'forum_parent_id' => bp_forums_parent_forum_id(),  
  151. 'forum_order' => false,  
  152. 'forum_is_category' => 0 
  153. ) ); 
  154. extract( $r, EXTR_SKIP ); 
  155.  
  156. return bb_update_forum( array( 'forum_id' => (int) $forum_id, 'forum_name' => stripslashes( $forum_name ), 'forum_desc' => stripslashes( $forum_desc ), 'forum_slug' => stripslashes( $forum_slug ), 'forum_parent' => $forum_parent_id, 'forum_order' => $forum_order, 'forum_is_category' => $forum_is_category ) ); 
  157.  
  158. /** 
  159. * Delete a group forum by the group id. 
  160. * 
  161. * @since 1.6.0 
  162. * 
  163. * @param int $group_id ID of the group whose forum is to be deleted. 
  164. */ 
  165. function bp_forums_delete_group_forum( $group_id ) { 
  166. $forum_id = groups_get_groupmeta( $group_id, 'forum_id' ); 
  167.  
  168. if ( !empty( $forum_id ) && is_int( $forum_id ) ) { 
  169.  
  170. /** This action is documented in bp-forums/bp-forums-screens.php */ 
  171. do_action( 'bbpress_init' ); 
  172. bb_delete_forum( $forum_id ); 
  173. add_action( 'groups_delete_group', 'bp_forums_delete_group_forum' ); 
  174.  
  175. /** Topic Functions ***********************************************************/ 
  176.  
  177. /** 
  178. * Fetch a set of forum topics. 
  179. * 
  180. * @since 1.1.0 
  181. * 
  182. * @param array|string $args { 
  183. * @type string $type Order or filter type. Default: 'newest'. 
  184. * @type int $forum_id Optional. Pass a forum ID to limit results to topics 
  185. * associated with that forum. 
  186. * @type int $user_id Optional. Pass a user ID to limit results to topics 
  187. * belonging to that user. 
  188. * @type int $page Optional. Number of the results page to return. 
  189. * Default: 1. 
  190. * @type int $per_page Optional. Number of results to return per page. 
  191. * Default: 15. 
  192. * @type int $offset Optional. Numeric offset for results. 
  193. * @type int $number Amount to query for. 
  194. * @type array $exclude Optional. Topic IDs to exclude. 
  195. * @type string $show_stickies Whether to show sticky topics. 
  196. * @type mixed $filter If $type = 'tag', filter is the tag name. Otherwise,  
  197. * $filter is terms to search on. 
  198. * } 
  199. * @return array Found topics. 
  200. */ 
  201. function bp_forums_get_forum_topics( $args = '' ) { 
  202.  
  203. /** This action is documented in bp-forums/bp-forums-screens.php */ 
  204. do_action( 'bbpress_init' ); 
  205.  
  206. $r = wp_parse_args( $args, array( 
  207. 'type' => 'newest',  
  208. 'forum_id' => false,  
  209. 'user_id' => false,  
  210. 'page' => 1,  
  211. 'per_page' => 15,  
  212. 'offset' => false,  
  213. 'number' => false,  
  214. 'exclude' => false,  
  215. 'show_stickies' => 'all',  
  216. 'filter' => false // If $type = tag then filter is the tag name, otherwise it's terms to search on. 
  217. ) ); 
  218. extract( $r, EXTR_SKIP ); 
  219.  
  220. if ( class_exists( 'BB_Query' ) ) { 
  221. switch ( $type ) { 
  222. case 'newest': 
  223. $query = new BB_Query( 'topic', array( 'forum_id' => $forum_id, 'topic_author_id' => $user_id, 'per_page' => $per_page, 'page' => $page, 'number' => $per_page, 'exclude' => $exclude, 'topic_title' => $filter, 'sticky' => $show_stickies, 'offset' => $offset, 'number' => $number ), 'get_latest_topics' ); 
  224. $topics =& $query->results; 
  225. break; 
  226.  
  227. case 'popular': 
  228. $query = new BB_Query( 'topic', array( 'forum_id' => $forum_id, 'topic_author_id' => $user_id, 'per_page' => $per_page, 'page' => $page, 'order_by' => 't.topic_posts', 'topic_title' => $filter, 'sticky' => $show_stickies, 'offset' => $offset, 'number' => $number ) ); 
  229. $topics =& $query->results; 
  230. break; 
  231.  
  232. case 'unreplied': 
  233. $query = new BB_Query( 'topic', array( 'forum_id' => $forum_id, 'topic_author_id' => $user_id, 'post_count' => 1, 'per_page' => $per_page, 'page' => $page, 'order_by' => 't.topic_time', 'topic_title' => $filter, 'sticky' => $show_stickies, 'offset' => $offset, 'number' => $number ) ); 
  234. $topics =& $query->results; 
  235. break; 
  236.  
  237. case 'tags': 
  238. $query = new BB_Query( 'topic', array( 'forum_id' => $forum_id, 'topic_author_id' => $user_id, 'tag' => $filter, 'per_page' => $per_page, 'page' => $page, 'order_by' => 't.topic_time', 'sticky' => $show_stickies, 'offset' => $offset, 'number' => $number ) ); 
  239. $topics =& $query->results; 
  240. break; 
  241. } else { 
  242. $topics = array(); 
  243.  
  244. /** 
  245. * Filters the found forum topics for provided arguments. 
  246. * 
  247. * @since 1.1.0 
  248. * 
  249. * @param array $topics Array of found topics. Passed by reference. 
  250. * @param array $r Array of parsed arguments for query. Passed by reference. 
  251. */ 
  252. return apply_filters_ref_array( 'bp_forums_get_forum_topics', array( &$topics, &$r ) ); 
  253.  
  254. /** 
  255. * Get additional details about a given forum topic. 
  256. * 
  257. * @since 1.0.0 
  258. * 
  259. * @param int $topic_id ID of the topic for which you're fetching details. 
  260. * @return object Details about the topic. 
  261. */ 
  262. function bp_forums_get_topic_details( $topic_id ) { 
  263.  
  264. /** This action is documented in bp-forums/bp-forums-screens.php */ 
  265. do_action( 'bbpress_init' ); 
  266.  
  267. $query = new BB_Query( 'topic', 'topic_id=' . $topic_id . '&page=1' /** Page override so bbPress doesn't use the URI */ ); 
  268.  
  269. return $query->results[0]; 
  270.  
  271. /** 
  272. * Get the numeric ID of a topic from the topic slug. 
  273. * 
  274. * Wrapper for {@link bb_get_id_from_slug()}. 
  275. * 
  276. * @since 1.1.0 
  277. * 
  278. * @param string $topic_slug Slug of the topic. 
  279. * @return int|bool ID of the topic (if found), false on failure. 
  280. */ 
  281. function bp_forums_get_topic_id_from_slug( $topic_slug ) { 
  282.  
  283. /** This action is documented in bp-forums/bp-forums-screens.php */ 
  284. do_action( 'bbpress_init' ); 
  285.  
  286. if ( empty( $topic_slug ) ) 
  287. return false; 
  288.  
  289. return bb_get_id_from_slug( 'topic', $topic_slug ); 
  290.  
  291. /** 
  292. * Create a new forum topic. 
  293. * 
  294. * @since 1.0.0 
  295. * 
  296. * @param array|string $args { 
  297. * @type string $topic_title Title of the new topic. 
  298. * @type string $topic_slug Slug of the new topic. 
  299. * @type string $topic_text Text of the new topic. 
  300. * @type int $topic_poster ID of the user posting the topic. Default: ID of 
  301. * the logged-in user. 
  302. * @type string $topic_poster_name Display name of the user posting the 
  303. * topic. Default: 'fullname' of the logged-in user. 
  304. * @type int $topic_last_poster ID of the user who last posted to the topic. 
  305. * Default: ID of the logged-in user. 
  306. * @type string $topic_last_poster_name Display name of the user who last 
  307. * posted to the topic. Default: 'fullname' of the logged-in user. 
  308. * @type string $topic_start_time Date/time when the topic was created. 
  309. * Default: the current time, as reported by bp_core_current_time(). 
  310. * @type string $topic_time Date/time when the topic was created. 
  311. * Default: the current time, as reported by bp_core_current_time(). 
  312. * @type int $topic_open Whether the topic is open. Default: 1 (open). 
  313. * @type array|string|bool $topic_tags Array or comma-separated list of 
  314. * topic tags. False to leave empty. Default: false. 
  315. * @type int $forum_id ID of the forum to which the topic belongs. 
  316. * Default: 0. 
  317. * } 
  318. * @return object Details about the new topic, as returned by 
  319. * {@link bp_forums_get_topic_details()}. 
  320. */ 
  321. function bp_forums_new_topic( $args = '' ) { 
  322. $bp = buddypress(); 
  323.  
  324. /** This action is documented in bp-forums/bp-forums-screens.php */ 
  325. do_action( 'bbpress_init' ); 
  326.  
  327. $r = wp_parse_args( $args, array( 
  328. 'topic_title' => '',  
  329. 'topic_slug' => '',  
  330. 'topic_text' => '',  
  331. 'topic_poster' => bp_loggedin_user_id(), // Accepts ids. 
  332. 'topic_poster_name' => $bp->loggedin_user->fullname, // Accept names. 
  333. 'topic_last_poster' => bp_loggedin_user_id(), // Accepts ids. 
  334. 'topic_last_poster_name' => $bp->loggedin_user->fullname, // Accept names. 
  335. 'topic_start_time' => bp_core_current_time(),  
  336. 'topic_time' => bp_core_current_time(),  
  337. 'topic_open' => 1,  
  338. 'topic_tags' => false, // Accepts array or comma delimited. 
  339. 'forum_id' => 0 // Accepts ids or slugs. 
  340. ) ); 
  341. extract( $r, EXTR_SKIP ); 
  342.  
  343. $topic_title = strip_tags( $topic_title ); 
  344.  
  345. if ( empty( $topic_title ) || !strlen( trim( $topic_title ) ) ) 
  346. return false; 
  347.  
  348. if ( empty( $topic_poster ) ) 
  349. return false; 
  350.  
  351. if ( bp_is_user_inactive( $topic_poster ) ) 
  352. return false; 
  353.  
  354. if ( empty( $topic_slug ) ) 
  355. $topic_slug = sanitize_title( $topic_title ); 
  356.  
  357. if ( !$topic_id = bb_insert_topic( array( 'topic_title' => stripslashes( $topic_title ), 'topic_slug' => $topic_slug, 'topic_poster' => $topic_poster, 'topic_poster_name' => $topic_poster_name, 'topic_last_poster' => $topic_last_poster, 'topic_last_poster_name' => $topic_last_poster_name, 'topic_start_time' => $topic_start_time, 'topic_time' => $topic_time, 'topic_open' => $topic_open, 'forum_id' => (int) $forum_id, 'tags' => $topic_tags ) ) ) 
  358. return false; 
  359.  
  360. // Now insert the first post. 
  361. if ( !bp_forums_insert_post( array( 'topic_id' => $topic_id, 'post_text' => $topic_text, 'post_time' => $topic_time, 'poster_id' => $topic_poster ) ) ) 
  362. return false; 
  363.  
  364. /** 
  365. * Fires after a new forum topic has been created. 
  366. * 
  367. * @since 1.0.0 
  368. * 
  369. * @param int $topic_id ID of the newly created topic post. 
  370. */ 
  371. do_action( 'bp_forums_new_topic', $topic_id ); 
  372.  
  373. return $topic_id; 
  374.  
  375. /** 
  376. * Update a topic's details. 
  377. * 
  378. * @since 1.1.0 
  379. * 
  380. * @param array|string $args { 
  381. * Array of arguments. 
  382. * @type int $topic_id ID of the topic being updated. 
  383. * @type string $topic_title Updated title of the topic. 
  384. * @type string $topic_text Updated text of the topic. 
  385. * @type array|string|bool $topic_tags Array or comma-separated list of 
  386. * topic tags. False to leave empty. 
  387. * Default false. 
  388. * } 
  389. * @return object Details about the new topic, as returned by 
  390. * {@link bp_forums_get_topic_details()}. 
  391. */ 
  392. function bp_forums_update_topic( $args = '' ) { 
  393.  
  394. /** This action is documented in bp-forums/bp-forums-screens.php */ 
  395. do_action( 'bbpress_init' ); 
  396.  
  397. $r = wp_parse_args( $args, array( 
  398. 'topic_id' => false,  
  399. 'topic_title' => '',  
  400. 'topic_text' => '',  
  401. 'topic_tags' => false 
  402. ) ); 
  403. extract( $r, EXTR_SKIP ); 
  404.  
  405. // Check if the user is a spammer. 
  406. if ( bp_is_user_inactive( bp_loggedin_user_id() ) ) 
  407. return false; 
  408.  
  409. // The bb_insert_topic() function will append tags, but not remove them. So we remove all existing tags. 
  410. bb_remove_topic_tags( $topic_id ); 
  411.  
  412. if ( !$topic_id = bb_insert_topic( array( 'topic_id' => $topic_id, 'topic_title' => stripslashes( $topic_title ), 'tags' => $topic_tags ) ) ) 
  413. return false; 
  414.  
  415. if ( !$post = bb_get_first_post( $topic_id ) ) 
  416. return false; 
  417.  
  418. // Update the first post. 
  419. if ( !$post = bp_forums_insert_post( array( 'post_id' => $post->post_id, 'topic_id' => $topic_id, 'post_text' => $topic_text, 'post_time' => $post->post_time, 'poster_id' => $post->poster_id, 'poster_ip' => $post->poster_ip, 'post_status' => $post->post_status, 'post_position' => $post->post_position ) ) ) 
  420. return false; 
  421.  
  422. return bp_forums_get_topic_details( $topic_id ); 
  423.  
  424. /** 
  425. * Set a topic as sticky/unsticky. 
  426. * 
  427. * @since 1.1.0 
  428. * 
  429. * @param string $args Array of arguments for sticky topic. 
  430. * @return bool 
  431. */ 
  432. function bp_forums_sticky_topic( $args = '' ) { 
  433.  
  434. /** This action is documented in bp-forums/bp-forums-screens.php */ 
  435. do_action( 'bbpress_init' ); 
  436.  
  437. $r = wp_parse_args( $args, array( 
  438. 'topic_id' => false,  
  439. 'mode' => 'stick' // Stick/unstick. 
  440. ) ); 
  441. extract( $r, EXTR_SKIP ); 
  442.  
  443. if ( 'stick' == $mode ) 
  444. return bb_stick_topic( $topic_id ); 
  445. else if ( 'unstick' == $mode ) 
  446. return bb_unstick_topic( $topic_id ); 
  447.  
  448. return false; 
  449.  
  450. /** 
  451. * Set a topic's open/closed status. 
  452. * 
  453. * @since 1.1.0 
  454. * 
  455. * @param array|string $args { 
  456. * @type int $topic_id ID of the topic whose status is being changed. 
  457. * @type string $mode New status of the topic. 'open' or 'close'. 
  458. * Default: 'close'. 
  459. * } 
  460. * @return bool True on success, false on failure. 
  461. */ 
  462. function bp_forums_openclose_topic( $args = '' ) { 
  463.  
  464. /** This action is documented in bp-forums/bp-forums-screens.php */ 
  465. do_action( 'bbpress_init' ); 
  466.  
  467. $r = wp_parse_args( $args, array( 
  468. 'topic_id' => false,  
  469. 'mode' => 'close' // Stick/unstick. 
  470. ) ); 
  471. extract( $r, EXTR_SKIP ); 
  472.  
  473. if ( 'close' == $mode ) 
  474. return bb_close_topic( $topic_id ); 
  475. else if ( 'open' == $mode ) 
  476. return bb_open_topic( $topic_id ); 
  477.  
  478. return false; 
  479.  
  480. /** 
  481. * Delete a topic. 
  482. * 
  483. * @since 1.1.0 
  484. * 
  485. * @param array|string $args { 
  486. * @type int $topic_id ID of the topic being deleted. 
  487. * } 
  488. * @return bool True on success, false on failure. 
  489. */ 
  490. function bp_forums_delete_topic( $args = '' ) { 
  491.  
  492. /** This action is documented in bp-forums/bp-forums-screens.php */ 
  493. do_action( 'bbpress_init' ); 
  494.  
  495. $r = wp_parse_args( $args, array( 
  496. 'topic_id' => false 
  497. ) ); 
  498. extract( $r, EXTR_SKIP ); 
  499.  
  500. return bb_delete_topic( $topic_id, 1 ); 
  501.  
  502. /** 
  503. * Get a count of the total topics on the site. 
  504. * 
  505. * @since 1.2.0 
  506. * 
  507. * @return int $count Total topic count. 
  508. */ 
  509. function bp_forums_total_topic_count() { 
  510. global $bbdb; 
  511.  
  512. /** This action is documented in bp-forums/bp-forums-screens.php */ 
  513. do_action( 'bbpress_init' ); 
  514.  
  515. if ( isset( $bbdb ) ) { 
  516. if ( bp_is_active( 'groups' ) ) { 
  517. $groups_table_sql = groups_add_forum_tables_sql(); 
  518. $groups_where_sql = groups_add_forum_where_sql( "t.topic_status = 0" ); 
  519. } else { 
  520. $groups_table_sql = ''; 
  521. $groups_where_sql = "t.topic_status = 0"; 
  522. $count = $bbdb->get_results( "SELECT t.topic_id FROM {$bbdb->topics} AS t {$groups_table_sql} WHERE {$groups_where_sql}" ); 
  523. $count = count( (array) $count ); 
  524. } else { 
  525. $count = 0; 
  526.  
  527. /** 
  528. * Filters the total topic count for the site. 
  529. * 
  530. * @since 1.5.0 
  531. * 
  532. * @param int $count Total topic count. 
  533. */ 
  534. return apply_filters( 'bp_forums_total_topic_count', $count ); 
  535.  
  536. /** 
  537. * Check to see whether a user has already left this particular reply on a given post. 
  538. * 
  539. * Used to prevent dupes. 
  540. * 
  541. * @since 1.6.0 
  542. * 
  543. * @param string $text The text of the comment. 
  544. * @param int $topic_id The topic id. 
  545. * @param int $user_id The user id. 
  546. * @return bool True if a duplicate reply exists, otherwise false. 
  547. */ 
  548. function bp_forums_reply_exists( $text = '', $topic_id = 0, $user_id = 0 ) { 
  549.  
  550. $reply_exists = false; 
  551.  
  552. if ( $text && $topic_id && $user_id ) { 
  553.  
  554. /** This action is documented in bp-forums/bp-forums-screens.php */ 
  555. do_action( 'bbpress_init' ); 
  556.  
  557. $args = array( 
  558. 'post_author_id' => $user_id,  
  559. 'topic_id' => $topic_id 
  560. ); 
  561.  
  562. // Set the reply_exists_text so we can check it in the filter below. 
  563. buddypress()->forums->reply_exists_text = $text; 
  564.  
  565. // BB_Query's post_text parameter does a MATCH, while we need exact matches. 
  566. add_filter( 'get_posts_where', '_bp_forums_reply_exists_posts_where' ); 
  567. $query = new BB_Query( 'post', $args ); 
  568. remove_filter( 'get_posts_where', '_bp_forums_reply_exists_posts_where' ); 
  569.  
  570. // Cleanup. 
  571. unset( buddypress()->forums->reply_exists_text ); 
  572.  
  573. $reply_exists = (bool) !empty( $query->results ); 
  574.  
  575. /** 
  576. * Filters whether a user has already left this particular reply on a given post. 
  577. * 
  578. * @since 1.6.0 
  579. * 
  580. * @param bool $reply_exists Whether or not a reply exists. 
  581. * @param string $text The text of the comment. 
  582. * @param int $topic_id The topic ID. 
  583. * @param int $user_id The user ID. 
  584. */ 
  585. return (bool) apply_filters( 'bp_forums_reply_exists', $reply_exists, $text, $topic_id, $user_id ); 
  586. /** 
  587. * Private one-time-use function used in conjunction with bp_forums_reply_exists(). 
  588. * 
  589. * @access private 
  590. * @since 1.7.0 
  591. * 
  592. * @global WPDB $wpdb WordPress database access object. 
  593. * 
  594. * @param string $where SQL fragment. 
  595. * @return string SQL fragment. 
  596. */ 
  597. function _bp_forums_reply_exists_posts_where( $where = '' ) { 
  598. return $where . " AND p.post_text = '" . buddypress()->forums->reply_exists_text . "'"; 
  599.  
  600. /** 
  601. * Get a total "Topics Started" count for a given user. 
  602. * 
  603. * @since 1.2.0 
  604. * 
  605. * @param int $user_id ID of the user being queried. Falls back on displayed 
  606. * user, then loggedin. 
  607. * @param string $type The current filter/sort type. 'active', 'popular',  
  608. * 'unreplied'. 
  609. * @return int $count The topic count. 
  610. */ 
  611. function bp_forums_total_topic_count_for_user( $user_id = 0, $type = 'active' ) { 
  612.  
  613. /** This action is documented in bp-forums/bp-forums-screens.php */ 
  614. do_action( 'bbpress_init' ); 
  615.  
  616. if ( !$user_id ) 
  617. $user_id = ( bp_displayed_user_id() ) ? bp_displayed_user_id() : bp_loggedin_user_id(); 
  618.  
  619. if ( class_exists( 'BB_Query' ) ) { 
  620. $args = array( 
  621. 'topic_author_id' => $user_id,  
  622. 'page' => 1,  
  623. 'per_page' => -1,  
  624. 'count' => true 
  625. ); 
  626.  
  627. if ( 'unreplied' == $type ) 
  628. $args['post_count'] = 1; 
  629.  
  630. $query = new BB_Query( 'topic', $args ); 
  631. $count = $query->count; 
  632. $query = null; 
  633. } else { 
  634. $count = 0; 
  635.  
  636. return $count; 
  637.  
  638. /** 
  639. * Return the total number of topics replied to by a given user. 
  640. * 
  641. * Uses an unfortunate technique to count unique topics, due to limitations in 
  642. * BB_Query. 
  643. * 
  644. * @since 1.5.0 
  645. * 
  646. * @param int $user_id ID of the user whose replied topics are being counted. 
  647. * Defaults to displayed user, then to logged-in user. 
  648. * @param string $type Forum thread type. 
  649. * @return int $count Topic count. 
  650. */ 
  651. function bp_forums_total_replied_count_for_user( $user_id = 0, $type = 'active' ) { 
  652.  
  653. /** This action is documented in bp-forums/bp-forums-screens.php */ 
  654. do_action( 'bbpress_init' ); 
  655.  
  656. if ( !$user_id ) 
  657. $user_id = ( bp_displayed_user_id() ) ? bp_displayed_user_id() : bp_loggedin_user_id(); 
  658.  
  659. if ( !$user_id ) 
  660. return 0; 
  661.  
  662. if ( class_exists( 'BB_Query' ) ) { 
  663. $query = new BB_Query( 'post', array( 'post_author_id' => $user_id, 'page' => 1, 'per_page' => -1, 'count' => true ) ); 
  664.  
  665. // Count the unique topics. No better way to do this in the bbPress query API. 
  666. $topics = array(); 
  667. foreach( $query->results as $result ) { 
  668. if ( !in_array( $result->topic_id, $topics ) ) 
  669. $topics[] = $result->topic_id; 
  670.  
  671. // Even more unfortunate. If this is filtered by 'unreplied', we have to requery. 
  672. if ( 'unreplied' == $type ) { 
  673. $topic_ids = implode( ', ', $topics ); 
  674. $topics_query = new BB_Query( 'topic', array( 'topic_id' => $topic_ids, 'page' => 1, 'per_page' => -1, 'post_count' => 1 ) ); 
  675. $count = count( $topics_query->results ); 
  676. } else { 
  677. $count = count( $topics ); 
  678. $query = null; 
  679. } else { 
  680. $count = 0; 
  681.  
  682. /** 
  683. * Filters the total number of topics replied to by a given user. 
  684. * 
  685. * @since 1.5.0 
  686. * 
  687. * @param int $count Total number of topics replied to by a given user. 
  688. * @param int $user_id The user ID. 
  689. */ 
  690. return apply_filters( 'bp_forums_total_replied_count_for_user', $count, $user_id ); 
  691.  
  692. /** 
  693. * Fetch BP-specific details for an array of topics. 
  694. * 
  695. * Done in one fell swoop to reduce query overhead. Currently determines the 
  696. * following: 
  697. * - details about the last poster 
  698. * - information about topic users that may have been deleted/spammed 
  699. * 
  700. * @since 1.2.0 
  701. * 
  702. * @param array $topics Array of topics. 
  703. * @return array $topics Topics with BP details added. 
  704. */ 
  705. function bp_forums_get_topic_extras( $topics ) { 
  706. global $wpdb, $bbdb; 
  707.  
  708. if ( empty( $topics ) ) 
  709. return $topics; 
  710.  
  711. $bp = buddypress(); 
  712.  
  713. // Get the topic ids. 
  714. foreach ( (array) $topics as $topic ) $topic_ids[] = $topic->topic_id; 
  715. $topic_ids = implode( ', ', wp_parse_id_list( $topic_ids ) ); 
  716.  
  717. // Fetch the topic's last poster details. 
  718. $poster_details = $wpdb->get_results( "SELECT t.topic_id, t.topic_last_poster, u.user_login, u.user_nicename, u.user_email, u.display_name FROM {$wpdb->users} u, {$bbdb->topics} t WHERE u.ID = t.topic_last_poster AND t.topic_id IN ( {$topic_ids} )" ); 
  719. for ( $i = 0, $count = count( $topics ); $i < $count; ++$i ) { 
  720. foreach ( (array) $poster_details as $poster ) { 
  721. if ( $poster->topic_id == $topics[$i]->topic_id ) { 
  722. $topics[$i]->topic_last_poster_email = $poster->user_email; 
  723. $topics[$i]->topic_last_poster_nicename = $poster->user_nicename; 
  724. $topics[$i]->topic_last_poster_login = $poster->user_login; 
  725. $topics[$i]->topic_last_poster_displayname = $poster->display_name; 
  726.  
  727. // Fetch fullname for the topic's last poster. 
  728. if ( bp_is_active( 'xprofile' ) ) { 
  729. $poster_names = $wpdb->get_results( "SELECT t.topic_id, pd.value FROM {$bp->profile->table_name_data} pd, {$bbdb->topics} t WHERE pd.user_id = t.topic_last_poster AND pd.field_id = 1 AND t.topic_id IN ( {$topic_ids} )" ); 
  730. for ( $i = 0, $count = count( $topics ); $i < $count; ++$i ) { 
  731. foreach ( (array) $poster_names as $name ) { 
  732. if ( $name->topic_id == $topics[$i]->topic_id ) 
  733. $topics[$i]->topic_last_poster_displayname = $name->value; 
  734.  
  735. // Loop through to make sure that each topic has the proper values set. This covers the 
  736. // case of deleted users. 
  737. foreach ( (array) $topics as $key => $topic ) { 
  738. if ( !isset( $topic->topic_last_poster_email ) ) 
  739. $topics[$key]->topic_last_poster_email = ''; 
  740.  
  741. if ( !isset( $topic->topic_last_poster_nicename ) ) 
  742. $topics[$key]->topic_last_poster_nicename = ''; 
  743.  
  744. if ( !isset( $topic->topic_last_poster_login ) ) 
  745. $topics[$key]->topic_last_poster_login = ''; 
  746.  
  747. if ( !isset( $topic->topic_last_poster_displayname ) ) 
  748. $topics[$key]->topic_last_poster_displayname = ''; 
  749.  
  750. return $topics; 
  751.  
  752. /** Post Functions ************************************************************/ 
  753.  
  754. /** 
  755. * Get the posts belonging to a topic. 
  756. * 
  757. * @since 1.1.0 
  758. * 
  759. * @param array|string $args { 
  760. * @type int $topic_id ID of the topic for which posts are being fetched. 
  761. * @type int $page Optional. Page of results to return. Default: 1. 
  762. * @type int $page Optional. Number of results to return per page. 
  763. * Default: 15. 
  764. * @type string $order 'ASC' or 'DESC'. Default: 'ASC'. 
  765. * } 
  766. * @return array List of posts. 
  767. */ 
  768. function bp_forums_get_topic_posts( $args = '' ) { 
  769.  
  770. /** This action is documented in bp-forums/bp-forums-screens.php */ 
  771. do_action( 'bbpress_init' ); 
  772.  
  773. $defaults = array( 
  774. 'topic_id' => false,  
  775. 'page' => 1,  
  776. 'per_page' => 15,  
  777. 'order' => 'ASC' 
  778. ); 
  779.  
  780. $args = wp_parse_args( $args, $defaults ); 
  781. $query = new BB_Query( 'post', $args, 'get_thread' ); 
  782.  
  783. return bp_forums_get_post_extras( $query->results ); 
  784.  
  785. /** 
  786. * Get a single post object by ID. 
  787. * 
  788. * Wrapper for {@link bb_get_post()}. 
  789. * 
  790. * @since 1.0.0 
  791. * 
  792. * @param int $post_id ID of the post being fetched. 
  793. * @return object Post object. 
  794. */ 
  795. function bp_forums_get_post( $post_id ) { 
  796.  
  797. /** This action is documented in bp-forums/bp-forums-screens.php */ 
  798. do_action( 'bbpress_init' ); 
  799. return bb_get_post( $post_id ); 
  800.  
  801. /** 
  802. * Delete a post. 
  803. * 
  804. * Wrapper for {@link bb_delete_post()}. 
  805. * 
  806. * @since 1.1.0 
  807. * 
  808. * @param array|string $args { 
  809. * @type int $post_id ID of the post being deleted. 
  810. * } 
  811. * @return bool True on success, false on failure. 
  812. */ 
  813. function bp_forums_delete_post( $args = '' ) { 
  814.  
  815. /** This action is documented in bp-forums/bp-forums-screens.php */ 
  816. do_action( 'bbpress_init' ); 
  817.  
  818. $r = wp_parse_args( $args, array( 
  819. 'post_id' => false 
  820. ) ); 
  821.  
  822. extract( $r, EXTR_SKIP ); 
  823.  
  824. return bb_delete_post( $post_id, 1 ); 
  825.  
  826. /** 
  827. * Create a new post. 
  828. * 
  829. * @since 1.1.0 
  830. * 
  831. * @param array|string $args { 
  832. * @type int $post_id Optional. ID of an existing post, if you want to 
  833. * update rather than create. Default: false. 
  834. * @type int $topic_id ID of the topic to which the post belongs. 
  835. * @type string $post_text Contents of the post. 
  836. * @type string $post_time Optional. Time when the post was recorded. 
  837. * Default: current time, as reported by {@link bp_core_current_time()}. 
  838. * @type int $poster_id Optional. ID of the user creating the post. 
  839. * Default: ID of the logged-in user. 
  840. * @type string $poster_ip Optional. IP address of the user creating the 
  841. * post. Default: the IP address found in $_SERVER['REMOTE_ADDR']. 
  842. * @type int $post_status Post status. Default: 0. 
  843. * @type int $post_position Optional. Default: false (auto). 
  844. * } 
  845. * @return int|bool ID of the new post on success, false on failure. 
  846. */ 
  847. function bp_forums_insert_post( $args = '' ) { 
  848.  
  849. /** This action is documented in bp-forums/bp-forums-screens.php */ 
  850. do_action( 'bbpress_init' ); 
  851.  
  852. $defaults = array( 
  853. 'post_id' => false,  
  854. 'topic_id' => false,  
  855. 'post_text' => '',  
  856. 'post_time' => bp_core_current_time(),  
  857. 'poster_id' => bp_loggedin_user_id(), // Accepts ids or names. 
  858. 'poster_ip' => $_SERVER['REMOTE_ADDR'],  
  859. 'post_status' => 0, // Use bb_delete_post() instead. 
  860. 'post_position' => false 
  861. ); 
  862.  
  863. $r = wp_parse_args( $args, $defaults ); 
  864. extract( $r, EXTR_SKIP ); 
  865.  
  866. if ( !$post = bp_forums_get_post( $post_id ) ) 
  867. $post_id = false; 
  868.  
  869. if ( !isset( $topic_id ) ) 
  870. $topic_id = $post->topic_id; 
  871.  
  872. if ( empty( $post_text ) ) 
  873. $post_text = $post->post_text; 
  874.  
  875. if ( !isset( $post_time ) ) 
  876. $post_time = $post->post_time; 
  877.  
  878. if ( !isset( $post_position ) ) 
  879. $post_position = $post->post_position; 
  880.  
  881. if ( empty( $poster_id ) ) 
  882. return false; 
  883.  
  884. if ( bp_is_user_inactive( bp_loggedin_user_id() ) ) 
  885. return false; 
  886.  
  887. $post_id = bb_insert_post( array( 'post_id' => $post_id, 'topic_id' => $topic_id, 'post_text' => stripslashes( trim( $post_text ) ), 'post_time' => $post_time, 'poster_id' => $poster_id, 'poster_ip' => $poster_ip, 'post_status' => $post_status, 'post_position' => $post_position ) ); 
  888.  
  889. if ( !empty( $post_id ) ) { 
  890.  
  891. /** 
  892. * Fires if there was a new post created. 
  893. * 
  894. * @since 1.0.0 
  895. * 
  896. * @param int $post_id ID of the newly created forum post. 
  897. */ 
  898. do_action( 'bp_forums_new_post', $post_id ); 
  899.  
  900. return $post_id; 
  901.  
  902. /** 
  903. * Get BP-specific details about a set of posts. 
  904. * 
  905. * Currently fetches the following: 
  906. * - WP userdata for each poster 
  907. * - BP fullname for each poster 
  908. * 
  909. * @since 1.2.0 
  910. * 
  911. * @param array $posts List of posts. 
  912. * @return array Posts with BP-data added. 
  913. */ 
  914. function bp_forums_get_post_extras( $posts ) { 
  915. global $wpdb; 
  916.  
  917. if ( empty( $posts ) ) 
  918. return $posts; 
  919.  
  920. $bp = buddypress(); 
  921.  
  922. // Get the user ids. 
  923. foreach ( (array) $posts as $post ) $user_ids[] = $post->poster_id; 
  924. $user_ids = implode( ', ', wp_parse_id_list( $user_ids ) ); 
  925.  
  926. // Fetch the poster's user_email, user_nicename and user_login. 
  927. $poster_details = $wpdb->get_results( "SELECT u.ID as user_id, u.user_login, u.user_nicename, u.user_email, u.display_name FROM {$wpdb->users} u WHERE u.ID IN ( {$user_ids} )" ); 
  928.  
  929. for ( $i = 0, $count = count( $posts ); $i < $count; ++$i ) { 
  930. foreach ( (array) $poster_details as $poster ) { 
  931. if ( $poster->user_id == $posts[$i]->poster_id ) { 
  932. $posts[$i]->poster_email = $poster->user_email; 
  933. $posts[$i]->poster_login = $poster->user_login; 
  934. $posts[$i]->poster_nicename = $poster->user_nicename; 
  935. $posts[$i]->poster_name = $poster->display_name; 
  936.  
  937. // Fetch fullname for each poster. 
  938. if ( bp_is_active( 'xprofile' ) ) { 
  939. $poster_names = $wpdb->get_results( "SELECT pd.user_id, pd.value FROM {$bp->profile->table_name_data} pd WHERE pd.user_id IN ( {$user_ids} )" ); 
  940. for ( $i = 0, $count = count( $posts ); $i < $count; ++$i ) { 
  941. foreach ( (array) $poster_names as $name ) { 
  942. if ( isset( $topics[$i] ) && $name->user_id == $topics[$i]->user_id ) 
  943. $posts[$i]->poster_name = $poster->value; 
  944.  
  945. /** 
  946. * Filters BP-specific details about a set of posts. 
  947. * 
  948. * @since 1.5.0 
  949. * 
  950. * @param array $posts Array of posts holding BP-specific details. 
  951. */ 
  952. return apply_filters( 'bp_forums_get_post_extras', $posts ); 
  953.  
  954. /** 
  955. * Get topic and post counts for a given forum. 
  956. * 
  957. * @since 1.1.0 
  958. * 
  959. * @param int $forum_id ID of the forum. 
  960. * @return object Object with properties $topics (topic count) and $posts 
  961. * (post count). 
  962. */ 
  963. function bp_forums_get_forum_topicpost_count( $forum_id ) { 
  964. global $wpdb, $bbdb; 
  965.  
  966. /** This action is documented in bp-forums/bp-forums-screens.php */ 
  967. do_action( 'bbpress_init' ); 
  968.  
  969. // Need to find a bbPress function that does this. 
  970. return $wpdb->get_results( $wpdb->prepare( "SELECT topics, posts from {$bbdb->forums} WHERE forum_id = %d", $forum_id ) ); 
  971.  
  972. /** 
  973. * Map WordPress caps onto bbPress users, to ensure that they can post. 
  974. * 
  975. * @since 1.1.0 
  976. * 
  977. * @param array $allcaps Array of capabilities. 
  978. * @return array Caps array with bbPress caps added. 
  979. */ 
  980. function bp_forums_filter_caps( $allcaps ) { 
  981. global $wp_roles, $bb_table_prefix; 
  982.  
  983. if ( !bp_loggedin_user_id() ) 
  984. return $allcaps; 
  985.  
  986. $bb_cap = bp_get_user_meta( bp_loggedin_user_id(), $bb_table_prefix . 'capabilities', true ); 
  987.  
  988. if ( empty( $bb_cap ) ) 
  989. return $allcaps; 
  990.  
  991. $bb_cap = array_keys($bb_cap); 
  992. $bb_cap = $wp_roles->get_role( $bb_cap[0] ); 
  993. $bb_cap = $bb_cap->capabilities; 
  994.  
  995. return array_merge( (array) $allcaps, (array) $bb_cap ); 
  996. add_filter( 'user_has_cap', 'bp_forums_filter_caps' ); 
  997.  
  998. /** 
  999. * Return the parent forum ID for the bbPress abstraction layer. 
  1000. * 
  1001. * @since 1.5.0 
  1002. * 
  1003. * @return int Forum ID. 
  1004. */ 
  1005. function bp_forums_parent_forum_id() { 
  1006.  
  1007. /** 
  1008. * Filters the parent forum ID for the bbPress abstraction layer. 
  1009. * 
  1010. * @since 1.5.0 
  1011. * 
  1012. * @param int BP_FORUMS_PARENT_FORUM_ID The Parent forum ID constant. 
  1013. */ 
  1014. return apply_filters( 'bp_forums_parent_forum_id', BP_FORUMS_PARENT_FORUM_ID ); 
  1015.  
  1016. /** 
  1017. * Should sticky topics be broken out of regular topic order on forum directories? 
  1018. * 
  1019. * Defaults to false. Define BP_FORUMS_ENABLE_GLOBAL_DIRECTORY_STICKIES, or 
  1020. * filter 'bp_forums_enable_global_directory_stickies', to change this behavior. 
  1021. * 
  1022. * @since 1.5.0 
  1023. * 
  1024. * @return bool True if stickies should be displayed at the top of the global 
  1025. * directory, otherwise false. 
  1026. */ 
  1027. function bp_forums_enable_global_directory_stickies() { 
  1028.  
  1029. /** 
  1030. * Filters whether or not sticky topics should be broken out of regular topic order. 
  1031. * 
  1032. * @since 1.5.0 
  1033. * 
  1034. * @param bool $value Whether or not to break out of topic order. 
  1035. */ 
  1036. return apply_filters( 'bp_forums_enable_global_directory_stickies', defined( 'BP_FORUMS_ENABLE_GLOBAL_DIRECTORY_STICKIES' ) && BP_FORUMS_ENABLE_GLOBAL_DIRECTORY_STICKIES ); 
  1037.  
  1038.  
  1039. /** Caching ******************************************************************/ 
  1040.  
  1041. /** 
  1042. * Caching functions handle the clearing of cached objects and pages on specific 
  1043. * actions throughout BuddyPress. 
  1044. */ 
  1045.  
  1046. // List actions to clear super cached pages on, if super cache is installed. 
  1047. add_action( 'bp_forums_new_forum', 'bp_core_clear_cache' ); 
  1048. add_action( 'bp_forums_new_topic', 'bp_core_clear_cache' ); 
  1049. add_action( 'bp_forums_new_post', 'bp_core_clear_cache' ); 
  1050.  
  1051.  
  1052. /** Embeds *******************************************************************/ 
  1053.  
  1054. /** 
  1055. * Attempt to retrieve the oEmbed cache for a forum topic. 
  1056. * 
  1057. * Grabs the topic post ID and attempts to retrieve the oEmbed cache (if it exists) 
  1058. * during the forum topic loop. If no cache and link is embeddable, cache it. 
  1059. * 
  1060. * @since 1.5.0 
  1061. * 
  1062. * @see BP_Embed 
  1063. * @see bp_embed_forum_cache() 
  1064. * @see bp_embed_forum_save_cache() 
  1065. */ 
  1066. function bp_forums_embed() { 
  1067. add_filter( 'embed_post_id', 'bp_get_the_topic_post_id' ); 
  1068. add_filter( 'bp_embed_get_cache', 'bp_embed_forum_cache', 10, 3 ); 
  1069. add_action( 'bp_embed_update_cache', 'bp_embed_forum_save_cache', 10, 3 ); 
  1070. add_action( 'topic_loop_start', 'bp_forums_embed' ); 
  1071.  
  1072. /** 
  1073. * Used during {@link BP_Embed::parse_oembed()} via {@link bp_forums_embed()}. 
  1074. * 
  1075. * Wrapper function for {@link bb_get_postmeta()}. 
  1076. * 
  1077. * @since 1.5.0 
  1078. * 
  1079. * @param object $cache Cache object. 
  1080. * @param int $id ID of the forum being cached. 
  1081. * @param string $cachekey Key to use with forum embed cache. 
  1082. */ 
  1083. function bp_embed_forum_cache( $cache, $id, $cachekey ) { 
  1084. return bb_get_postmeta( $id, $cachekey ); 
  1085.  
  1086. /** 
  1087. * Used during {@link BP_Embed::parse_oembed()} via {@link bp_forums_embed()}. 
  1088. * 
  1089. * Wrapper function for {@link bb_update_postmeta()}. 
  1090. * 
  1091. * @since 1.5.0 
  1092. * 
  1093. * @param object $cache Cache object. 
  1094. * @param string $cachekey Key to use with forum embed cache. 
  1095. * @param int $id ID of the forum being cached. 
  1096. */ 
  1097. function bp_embed_forum_save_cache( $cache, $cachekey, $id ) { 
  1098. bb_update_postmeta( $id, $cachekey, $cache ); 
.