/bp-forums/bp-forums-bbpress-sa.php

  1. <?php 
  2. /** 
  3. * BuddyPress bbPress 1.x integration. 
  4. * 
  5. * @package BuddyPress 
  6. * @subpackage ForumsbbPress 
  7. * @since 1.5.0 
  8. */ 
  9.  
  10. // Exit if accessed directly. 
  11. defined( 'ABSPATH' ) || exit; 
  12.  
  13. /** 
  14. * Bootstrap bbPress 1.x, and manipulate globals to integrate with BuddyPress. 
  15. * 
  16. * @since 1.1.0 
  17. * 
  18. * @return bool|null Returns false on failure. 
  19. */ 
  20. function bp_forums_load_bbpress() { 
  21. global $wpdb, $wp_roles, $current_user, $wp_users_object; 
  22. global $bb, $bbdb, $bb_table_prefix, $bb_current_user; 
  23. global $bb_roles, $wp_taxonomy_object, $bb_queries; 
  24.  
  25. // Return if we've already run this function. 
  26. if ( is_object( $bbdb ) ) 
  27. return; 
  28.  
  29. if ( !bp_forums_is_installed_correctly() ) 
  30. return false; 
  31.  
  32. $bp = buddypress(); 
  33.  
  34. define( 'BB_PATH', $bp->plugin_dir . '/bp-forums/bbpress/' ); 
  35. define( 'BACKPRESS_PATH', $bp->plugin_dir . '/bp-forums/bbpress/bb-includes/backpress/' ); 
  36. define( 'BB_URL', $bp->plugin_url . 'bp-forums/bbpress/' ); 
  37. define( 'BB_INC', 'bb-includes/' ); 
  38.  
  39. require( BB_PATH . BB_INC . 'class.bb-query.php' ); 
  40. require( BB_PATH . BB_INC . 'class.bb-walker.php' ); 
  41.  
  42. require( BB_PATH . BB_INC . 'functions.bb-core.php' ); 
  43. require( BB_PATH . BB_INC . 'functions.bb-forums.php' ); 
  44. require( BB_PATH . BB_INC . 'functions.bb-topics.php' ); 
  45. require( BB_PATH . BB_INC . 'functions.bb-posts.php' ); 
  46. require( BB_PATH . BB_INC . 'functions.bb-topic-tags.php' ); 
  47. require( BB_PATH . BB_INC . 'functions.bb-capabilities.php' ); 
  48. require( BB_PATH . BB_INC . 'functions.bb-meta.php' ); 
  49. require( BB_PATH . BB_INC . 'functions.bb-pluggable.php' ); 
  50. require( BB_PATH . BB_INC . 'functions.bb-formatting.php' ); 
  51. require( BB_PATH . BB_INC . 'functions.bb-template.php' ); 
  52.  
  53. require( BACKPRESS_PATH . 'class.wp-taxonomy.php' ); 
  54. require( BB_PATH . BB_INC . 'class.bb-taxonomy.php' ); 
  55.  
  56. require( BB_PATH . 'bb-admin/includes/functions.bb-admin.php' ); 
  57.  
  58. $bb = new stdClass(); 
  59. require( bp_get_option( 'bb-config-location' ) ); 
  60.  
  61. // Setup the global database connection. 
  62. $bbdb = new BPDB ( BBDB_USER, BBDB_PASSWORD, BBDB_NAME, BBDB_HOST ); 
  63.  
  64. // Set the table names. 
  65. $bbdb->forums = $bb_table_prefix . 'forums'; 
  66. $bbdb->meta = $bb_table_prefix . 'meta'; 
  67. $bbdb->posts = $bb_table_prefix . 'posts'; 
  68. $bbdb->terms = $bb_table_prefix . 'terms'; 
  69. $bbdb->term_relationships = $bb_table_prefix . 'term_relationships'; 
  70. $bbdb->term_taxonomy = $bb_table_prefix . 'term_taxonomy'; 
  71. $bbdb->topics = $bb_table_prefix . 'topics'; 
  72.  
  73. if ( isset( $bb->custom_user_table ) ) 
  74. $bbdb->users = $bb->custom_user_table; 
  75. else 
  76. $bbdb->users = $wpdb->users; 
  77.  
  78. if ( isset( $bb->custom_user_meta_table ) ) 
  79. $bbdb->usermeta = $bb->custom_user_meta_table; 
  80. else 
  81. $bbdb->usermeta = $wpdb->usermeta; 
  82.  
  83. $bbdb->prefix = $bb_table_prefix; 
  84.  
  85. define( 'BB_INSTALLING', false ); 
  86.  
  87. if ( is_object( $wp_roles ) ) { 
  88. $bb_roles = $wp_roles; 
  89. bb_init_roles( $bb_roles ); 
  90.  
  91. /** 
  92. * Fires during the bootstrap setup for bbPress 1.x. 
  93. * 
  94. * @since 1.1.0 
  95. */ 
  96. do_action( 'bb_got_roles' ); 
  97.  
  98. /** 
  99. * Fires during the bootstrap setup for bbPress 1.x. 
  100. * 
  101. * @since 1.1.0 
  102. */ 
  103. do_action( 'bb_init' ); 
  104.  
  105. /** 
  106. * Fires during the bootstrap setup for bbPress 1.x. 
  107. * 
  108. * @since 1.1.0 
  109. */ 
  110. do_action( 'init_roles' ); 
  111.  
  112. $bb_current_user = $current_user; 
  113. $wp_users_object = new BP_Forums_BB_Auth; 
  114.  
  115. if ( !isset( $wp_taxonomy_object ) ) 
  116. $wp_taxonomy_object = new BB_Taxonomy( $bbdb ); 
  117.  
  118. $wp_taxonomy_object->register_taxonomy( 'bb_topic_tag', 'bb_topic' ); 
  119.  
  120. // Set a site id if there isn't one already. 
  121. if ( !isset( $bb->site_id ) ) 
  122. $bb->site_id = bp_get_root_blog_id(); 
  123.  
  124. // Check if the tables are installed, if not, install them. 
  125. if ( !$tables_installed = (boolean) $bbdb->get_results( 'DESCRIBE `' . $bbdb->forums . '`;', ARRAY_A ) ) { 
  126. require( BB_PATH . 'bb-admin/includes/defaults.bb-schema.php' ); 
  127.  
  128. // Backticks and "IF NOT EXISTS" break the dbDelta function. 
  129. bp_bb_dbDelta( str_replace( ' IF NOT EXISTS', '', str_replace( '`', '', $bb_queries ) ) ); 
  130.  
  131. require( BB_PATH . 'bb-admin/includes/functions.bb-upgrade.php' ); 
  132. bb_update_db_version(); 
  133.  
  134. // Set the site admins as the keymasters. 
  135. $site_admins = get_site_option( 'site_admins', array('admin') ); 
  136. foreach ( (array) $site_admins as $site_admin ) 
  137. bp_update_user_meta( bp_core_get_userid( $site_admin ), $bb_table_prefix . 'capabilities', array( 'keymaster' => true ) ); 
  138.  
  139. // Create the first forum. 
  140. bb_new_forum( array( 'forum_name' => 'Default Forum' ) ); 
  141.  
  142. // Set the site URI. 
  143. bb_update_option( 'uri', BB_URL ); 
  144.  
  145. /** 
  146. * Fires inside an anonymous function that is run on bbPress shutdown. 
  147. * 
  148. * @since 1.1.0 
  149. */ 
  150. register_shutdown_function( function() { do_action( 'bb_shutdown' ); } ); 
  151. add_action( 'bbpress_init', 'bp_forums_load_bbpress' ); 
  152.  
  153. /** WP to bbPress wrapper functions ******************************************/ 
  154.  
  155. /** 
  156. * Get the current bbPress user. 
  157. * 
  158. * @since 1.1.0 
  159. * 
  160. * @return object $current_user Current user object from WordPress. 
  161. */ 
  162. function bb_get_current_user() { global $current_user; return $current_user; } 
  163.  
  164. /** 
  165. * Get userdata for a bbPress user. 
  166. * 
  167. * @since 1.1.0 
  168. * 
  169. * @param int $user_id User ID. 
  170. * @return object User data from WordPress. 
  171. */ 
  172. function bb_get_user( $user_id ) { return get_userdata( $user_id ); } 
  173.  
  174. /** 
  175. * Cache users. 
  176. * 
  177. * Noop. 
  178. * 
  179. * @since 1.1.0 
  180. * 
  181. * @param array $users Array of users. 
  182. */ 
  183. function bb_cache_users( $users ) {} 
  184.  
  185. /** 
  186. * The bbPress plugin needs this class for its usermeta manipulation. 
  187. * 
  188. * @since 1.1.0 
  189. */ 
  190. class BP_Forums_BB_Auth { 
  191.  
  192. /** 
  193. * Update usermeta data. 
  194. * 
  195. * @since 1.1.0 
  196. * 
  197. * @param string $args Array of arguments. 
  198. * @return bool 
  199. */ 
  200. function update_meta( $args = '' ) { 
  201. $defaults = array( 'id' => 0, 'meta_key' => null, 'meta_value' => null, 'meta_table' => 'usermeta', 'meta_field' => 'user_id', 'cache_group' => 'users' ); 
  202. $args = wp_parse_args( $args, $defaults ); 
  203. extract( $args, EXTR_SKIP ); 
  204.  
  205. return bp_update_user_meta( $id, $meta_key, $meta_value ); 
  206.  
  207. /** 
  208. * The bbPress plugin needs the DB class to be BPDB, but we want to use WPDB, so we can extend it and use this. 
  209. * 
  210. * The class is pluggable, so that plugins that swap out WPDB with a custom 
  211. * database class (such as HyperDB and ShareDB) can provide their own versions 
  212. * of BPDB which extend the appropriate base class. 
  213. */ 
  214. if ( ! class_exists( 'BPDB' ) ) : 
  215.  
  216. /** 
  217. * WPDB class extension. 
  218. * 
  219. * @since 1.1.0 
  220. */ 
  221. class BPDB extends WPDB { 
  222. var $db_servers = array(); 
  223.  
  224. /** 
  225. * Constructor. 
  226. * 
  227. * @since 1.1.0 
  228. * 
  229. * @see WPDB::__construct() for description of parameters. 
  230. */ 
  231. function __construct( $dbuser, $dbpassword, $dbname, $dbhost ) { 
  232. parent::__construct( $dbuser, $dbpassword, $dbname, $dbhost ); 
  233.  
  234. $args = call_user_func_array( array( &$this, 'init' ), func_get_args() ); 
  235.  
  236. if ( $args['host'] ) 
  237. $this->db_servers['dbh_global'] = $args; 
  238.  
  239. /** 
  240. * Determine if a database supports a particular feature. 
  241. * 
  242. * Overridden here to work around differences between bbPress's 
  243. * and WordPress's implementations. In particular, when 
  244. * BuddyPress tries to run bbPress' SQL installation script,  
  245. * the collation check always failed. The capability is long 
  246. * supported by WordPress' minimum required MySQL version, so 
  247. * this is safe. 
  248. * 
  249. * @since 1.1.0 
  250. * 
  251. * @see WPDB::has_cap() for a description of parameters and 
  252. * return values. 
  253. * 
  254. * @param string $db_cap See {@link WPDB::has_cap()}. 
  255. * @param string $_table_name See {@link WPDB::has_cap()}. 
  256. * @return bool See {@link WPDB::has_cap()}. 
  257. */ 
  258. function has_cap( $db_cap, $_table_name='' ) { 
  259. if ( 'collation' == $db_cap ) 
  260. return true; 
  261.  
  262. return parent::has_cap( $db_cap ); 
  263.  
  264. /** 
  265. * Initialize the class variables based on provided arguments. 
  266. * 
  267. * Based on, and taken from, the BackPress class in turn taken 
  268. * from the 1.0 branch of bbPress. 
  269. * 
  270. * @see BBDB::__construct() for a description of params. 
  271. * 
  272. * @param array $args Array of args to parse. 
  273. * @return array $args. 
  274. */ 
  275. function init( $args ) { 
  276. if ( 4 == func_num_args() ) { 
  277. $args = array( 
  278. 'user' => $args,  
  279. 'password' => func_get_arg( 1 ),  
  280. 'name' => func_get_arg( 2 ),  
  281. 'host' => func_get_arg( 3 ),  
  282. 'charset' => defined( 'BBDB_CHARSET' ) ? BBDB_CHARSET : false,  
  283. 'collate' => defined( 'BBDB_COLLATE' ) ? BBDB_COLLATE : false,  
  284. ); 
  285.  
  286. $defaults = array( 
  287. 'user' => false,  
  288. 'password' => false,  
  289. 'name' => false,  
  290. 'host' => 'localhost',  
  291. 'charset' => false,  
  292. 'collate' => false,  
  293. 'errors' => false 
  294. ); 
  295.  
  296. return wp_parse_args( $args, $defaults ); 
  297.  
  298. /** 
  299. * Stub for escape_deep() compatibility. 
  300. * 
  301. * @since 1.1.0 
  302. * 
  303. * @param mixed $data See {@link WPDB::escape_deep()}. 
  304. * @return mixed $data See {@link WPDB::escape_deep()}. 
  305. */ 
  306. function escape_deep( $data ) { 
  307. return esc_sql( $data ); 
  308. endif; // End class_exists( 'BPDB' ). 
  309.  
  310. /** 
  311. * Convert object to given output format. 
  312. * 
  313. * The bbPress plugin needs this to convert vars. 
  314. * 
  315. * @since 1.1.0 
  316. * 
  317. * @param object $object Object to convert. 
  318. * @param string $output Type of object to return. OBJECT, ARRAY_A, or ARRAY_N. 
  319. */ 
  320. function backpress_convert_object( &$object, $output ) { 
  321. if ( is_array( $object ) ) { 
  322. foreach ( array_keys( $object ) as $key ) 
  323. backpress_convert_object( $object[$key], $output ); 
  324. } else { 
  325. switch ( $output ) { 
  326. case OBJECT : break; 
  327. case ARRAY_A : $object = get_object_vars($object); break; 
  328. case ARRAY_N : $object = array_values(get_object_vars($object)); break; 
  329.  
  330. /** 
  331. * Parse and execute queries for updating a set of database tables. 
  332. * 
  333. * Copied from wp-admin/includes/upgrade.php, this will take care of creating 
  334. * the bbPress stand-alone tables without loading a conflicting WP Admin. 
  335. * 
  336. * @since 1.5.0 
  337. * 
  338. * @see dbDelta() for a description of parameters and return value. 
  339. * 
  340. * @param array $queries See {@link dbDelta()}. 
  341. * @param bool $execute See {@link dbDelta()}. 
  342. * @return array See {@link dbDelta()}. 
  343. */ 
  344. function bp_bb_dbDelta($queries, $execute = true) { 
  345. global $wpdb; 
  346.  
  347. // Separate individual queries into an array. 
  348. if ( !is_array($queries) ) { 
  349. $queries = explode( ';', $queries ); 
  350. if ('' == $queries[count($queries) - 1]) array_pop($queries); 
  351.  
  352. $cqueries = array(); // Creation Queries. 
  353. $iqueries = array(); // Insertion Queries. 
  354. $for_update = array(); 
  355.  
  356. // Create a tablename index for an array ($cqueries) of queries. 
  357. foreach($queries as $qry) { 
  358. if (preg_match("|CREATE TABLE ([^ ]*)|", $qry, $matches)) { 
  359. $cqueries[trim( strtolower($matches[1]), '`' )] = $qry; 
  360. $for_update[$matches[1]] = 'Created table '.$matches[1]; 
  361. } else if (preg_match("|CREATE DATABASE ([^ ]*)|", $qry, $matches)) { 
  362. array_unshift($cqueries, $qry); 
  363. } else if (preg_match("|INSERT INTO ([^ ]*)|", $qry, $matches)) { 
  364. $iqueries[] = $qry; 
  365. } else if (preg_match("|UPDATE ([^ ]*)|", $qry, $matches)) { 
  366. $iqueries[] = $qry; 
  367. } else { 
  368. // Unrecognized query type. 
  369.  
  370. // Check to see which tables and fields exist. 
  371. if ($tables = $wpdb->get_col('SHOW TABLES;')) { 
  372. // For every table in the database. 
  373. foreach ($tables as $table) { 
  374. // Upgrade global tables only for the main site. Don't upgrade at all if DO_NOT_UPGRADE_GLOBAL_TABLES is defined. 
  375. if ( in_array($table, $wpdb->tables('global')) && ( !is_main_site() || defined('DO_NOT_UPGRADE_GLOBAL_TABLES') ) ) 
  376. continue; 
  377.  
  378. // If a table query exists for the database table... 
  379. if ( array_key_exists(strtolower($table), $cqueries) ) { 
  380. // Clear the field and index arrays. 
  381. $cfields = $indices = array(); 
  382. // Get all of the field names in the query from between the parents. 
  383. preg_match("|\((.*)\)|ms", $cqueries[strtolower($table)], $match2); 
  384. $qryline = trim($match2[1]); 
  385.  
  386. // Separate field lines into an array. 
  387. $flds = explode("\n", $qryline); 
  388.  
  389. //echo "<hr/><pre>\n".print_r(strtolower($table), true).":\n".print_r($cqueries, true)."</pre><hr/>"; 
  390.  
  391. // For every field line specified in the query. 
  392. foreach ($flds as $fld) { 
  393. // Extract the field name. 
  394. preg_match("|^([^ ]*)|", trim($fld), $fvals); 
  395. $fieldname = trim( $fvals[1], '`' ); 
  396.  
  397. // Verify the found field name. 
  398. $validfield = true; 
  399. switch (strtolower($fieldname)) { 
  400. case '': 
  401. case 'primary': 
  402. case 'index': 
  403. case 'fulltext': 
  404. case 'unique': 
  405. case 'key': 
  406. $validfield = false; 
  407. $indices[] = trim(trim($fld), ", \n"); 
  408. break; 
  409. $fld = trim($fld); 
  410.  
  411. // If it's a valid field, add it to the field array. 
  412. if ($validfield) { 
  413. $cfields[strtolower($fieldname)] = trim($fld, ", \n"); 
  414.  
  415. // Fetch the table column structure from the database. 
  416. $tablefields = $wpdb->get_results("DESCRIBE {$table};"); 
  417.  
  418. // For every field in the table. 
  419. foreach ($tablefields as $tablefield) { 
  420. // If the table field exists in the field array... 
  421. if (array_key_exists(strtolower($tablefield->Field), $cfields)) { 
  422. // Get the field type from the query. 
  423. preg_match("|".$tablefield->Field." ([^ ]*( unsigned)?)|i", $cfields[strtolower($tablefield->Field)], $matches); 
  424. $fieldtype = $matches[1]; 
  425.  
  426. // Is actual field type different from the field type in query? 
  427. if ($tablefield->Type != $fieldtype) { 
  428. // Add a query to change the column type. 
  429. $cqueries[] = "ALTER TABLE {$table} CHANGE COLUMN {$tablefield->Field} " . $cfields[strtolower($tablefield->Field)]; 
  430. $for_update[$table.'.'.$tablefield->Field] = "Changed type of {$table}.{$tablefield->Field} from {$tablefield->Type} to {$fieldtype}"; 
  431.  
  432. // Get the default value from the array. 
  433. //echo "{$cfields[strtolower($tablefield->Field)]}<br>"; 
  434. if (preg_match("| DEFAULT '(.*)'|i", $cfields[strtolower($tablefield->Field)], $matches)) { 
  435. $default_value = $matches[1]; 
  436. if ($tablefield->Default != $default_value) { 
  437. // Add a query to change the column's default value. 
  438. $cqueries[] = "ALTER TABLE {$table} ALTER COLUMN {$tablefield->Field} SET DEFAULT '{$default_value}'"; 
  439. $for_update[$table.'.'.$tablefield->Field] = "Changed default value of {$table}.{$tablefield->Field} from {$tablefield->Default} to {$default_value}"; 
  440.  
  441. // Remove the field from the array (so it's not added). 
  442. unset($cfields[strtolower($tablefield->Field)]); 
  443. } else { 
  444. // This field exists in the table, but not in the creation queries? 
  445.  
  446. // For every remaining field specified for the table. 
  447. foreach ($cfields as $fieldname => $fielddef) { 
  448. // Push a query line into $cqueries that adds the field to that table. 
  449. $cqueries[] = "ALTER TABLE {$table} ADD COLUMN $fielddef"; 
  450. $for_update[$table.'.'.$fieldname] = 'Added column '.$table.'.'.$fieldname; 
  451.  
  452. // Index stuff goes here 
  453. // Fetch the table index structure from the database. 
  454. $tableindices = $wpdb->get_results("SHOW INDEX FROM {$table};"); 
  455.  
  456. if ($tableindices) { 
  457. // Clear the index array. 
  458. unset($index_ary); 
  459.  
  460. // For every index in the table. 
  461. foreach ($tableindices as $tableindex) { 
  462. // Add the index to the index data array. 
  463. $keyname = $tableindex->Key_name; 
  464. $index_ary[$keyname]['columns'][] = array('fieldname' => $tableindex->Column_name, 'subpart' => $tableindex->Sub_part); 
  465. $index_ary[$keyname]['unique'] = ($tableindex->Non_unique == 0)?true:false; 
  466.  
  467. // For each actual index in the index array. 
  468. foreach ($index_ary as $index_name => $index_data) { 
  469. // Build a create string to compare to the query. 
  470. $index_string = ''; 
  471. if ($index_name == 'PRIMARY') { 
  472. $index_string .= 'PRIMARY '; 
  473. } else if($index_data['unique']) { 
  474. $index_string .= 'UNIQUE '; 
  475. $index_string .= 'KEY '; 
  476. if ($index_name != 'PRIMARY') { 
  477. $index_string .= $index_name; 
  478. $index_columns = ''; 
  479. // For each column in the index. 
  480. foreach ($index_data['columns'] as $column_data) { 
  481. if ($index_columns != '') $index_columns .= ', '; 
  482. // Add the field to the column list string. 
  483. $index_columns .= $column_data['fieldname']; 
  484. if ($column_data['subpart'] != '') { 
  485. $index_columns .= '('.$column_data['subpart'].')'; 
  486. // Add the column list to the index create string. 
  487. $index_string .= ' ('.$index_columns.')'; 
  488. if (!(($aindex = array_search($index_string, $indices)) === false)) { 
  489. unset($indices[$aindex]); 
  490. //echo "<pre style=\"border:1px solid #ccc;margin-top:5px;\">{$table}:<br />Found index:".$index_string."</pre>\n"; 
  491. //else echo "<pre style=\"border:1px solid #ccc;margin-top:5px;\">{$table}:<br /><b>Did not find index:</b>".$index_string."<br />".print_r($indices, true)."</pre>\n"; 
  492.  
  493. // For every remaining index specified for the table. 
  494. foreach ( (array) $indices as $index ) { 
  495. // Push a query line into $cqueries that adds the index to that table. 
  496. $cqueries[] = "ALTER TABLE {$table} ADD $index"; 
  497. $for_update[$table.'.'.$fieldname] = 'Added index '.$table.' '.$index; 
  498.  
  499. // Remove the original table creation query from processing. 
  500. unset($cqueries[strtolower($table)]); 
  501. unset($for_update[strtolower($table)]); 
  502. } else { 
  503. // This table exists in the database, but not in the creation queries? 
  504.  
  505. $allqueries = array_merge($cqueries, $iqueries); 
  506. if ($execute) { 
  507. foreach ($allqueries as $query) { 
  508. //echo "<pre style=\"border:1px solid #ccc;margin-top:5px;\">".print_r($query, true)."</pre>\n"; 
  509. $wpdb->query($query); 
  510.  
  511. return $for_update; 
.