/bp-xprofile/classes/class-bp-xprofile-group.php

  1. <?php 
  2. /** 
  3. * BuddyPress XProfile Classes. 
  4. * 
  5. * @package BuddyPress 
  6. * @subpackage XProfileClasses 
  7. * @since 1.0.0 
  8. */ 
  9.  
  10. // Exit if accessed directly. 
  11. defined( 'ABSPATH' ) || exit; 
  12.  
  13. /** 
  14. * Class to help set up XProfile Groups. 
  15. * 
  16. * @since 1.0.0 
  17. */ 
  18. class BP_XProfile_Group { 
  19.  
  20. /** 
  21. * Field group ID. 
  22. * 
  23. * @since 1.1.0 
  24. * @var int ID of field group. 
  25. */ 
  26. public $id = null; 
  27.  
  28. /** 
  29. * Field group name. 
  30. * 
  31. * @since 1.1.0 
  32. * @var string Name of field group. 
  33. */ 
  34. public $name; 
  35.  
  36. /** 
  37. * Field group Description. 
  38. * 
  39. * @since 1.1.0 
  40. * @var string Description of field group. 
  41. */ 
  42. public $description; 
  43.  
  44. /** 
  45. * Group deletion boolean. 
  46. * 
  47. * @since 1.1.0 
  48. * @var bool Can this group be deleted? 
  49. */ 
  50. public $can_delete; 
  51.  
  52. /** 
  53. * Group order. 
  54. * 
  55. * @since 1.1.0 
  56. * @var int Group order relative to other groups. 
  57. */ 
  58. public $group_order; 
  59.  
  60. /** 
  61. * Group fields. 
  62. * 
  63. * @since 1.1.0 
  64. * @var array Fields of group. 
  65. */ 
  66. public $fields; 
  67.  
  68. /** 
  69. * Initialize and/or populate profile field group. 
  70. * 
  71. * @since 1.1.0 
  72. * 
  73. * @param int|null $id Field group ID. 
  74. */ 
  75. public function __construct( $id = null ) { 
  76. if ( ! empty( $id ) ) { 
  77. $this->populate( $id ); 
  78.  
  79. /** 
  80. * Populate a profile field group. 
  81. * 
  82. * @since 1.0.0 
  83. * 
  84. * @global $wpdb $wpdb 
  85. * 
  86. * @param int $id Field group ID. 
  87. * @return boolean 
  88. */ 
  89. public function populate( $id ) { 
  90.  
  91. // Get this group. 
  92. $group = self::get( array( 
  93. 'profile_group_id' => $id 
  94. ) ); 
  95.  
  96. // Bail if group not found. 
  97. if ( empty( $group ) ) { 
  98. return false; 
  99.  
  100. // Get the first array element. 
  101. $group = reset( $group ); 
  102.  
  103. // Set object properties. 
  104. $this->id = $group->id; 
  105. $this->name = $group->name; 
  106. $this->description = $group->description; 
  107. $this->can_delete = $group->can_delete; 
  108. $this->group_order = $group->group_order; 
  109.  
  110. /** 
  111. * Save a profile field group. 
  112. * 
  113. * @since 1.1.0 
  114. * 
  115. * @global object $wpdb 
  116. * 
  117. * @return boolean 
  118. */ 
  119. public function save() { 
  120. global $wpdb; 
  121.  
  122. // Filter the field group attributes. 
  123. $this->name = apply_filters( 'xprofile_group_name_before_save', $this->name, $this->id ); 
  124. $this->description = apply_filters( 'xprofile_group_description_before_save', $this->description, $this->id ); 
  125.  
  126. /** 
  127. * Fires before the current group instance gets saved. 
  128. * 
  129. * Please use this hook to filter the properties above. Each part will be passed in. 
  130. * 
  131. * @since 1.0.0 
  132. * 
  133. * @param BP_XProfile_Group $this Current instance of the group being saved. Passed by reference. 
  134. */ 
  135. do_action_ref_array( 'xprofile_group_before_save', array( &$this ) ); 
  136.  
  137. $bp = buddypress(); 
  138.  
  139. // Update or insert. 
  140. if ( ! empty( $this->id ) ) { 
  141. $sql = $wpdb->prepare( "UPDATE {$bp->profile->table_name_groups} SET name = %s, description = %s WHERE id = %d", $this->name, $this->description, $this->id ); 
  142. } else { 
  143. $sql = $wpdb->prepare( "INSERT INTO {$bp->profile->table_name_groups} (name, description, can_delete) VALUES (%s, %s, 1)", $this->name, $this->description ); 
  144.  
  145. // Attempt to insert or update. 
  146. $query = $wpdb->query( $sql ); 
  147.  
  148. // Bail if query fails. If `$query` is 0, it means the save was successful, but no fields were updated. 
  149. if ( false === $query || is_wp_error( $query ) ) { 
  150. return false; 
  151.  
  152. // If not set, update the ID in the group object. 
  153. if ( empty( $this->id ) ) { 
  154. $this->id = $wpdb->insert_id; 
  155.  
  156. /** 
  157. * Fires after the current group instance gets saved. 
  158. * 
  159. * @since 1.0.0 
  160. * 
  161. * @param BP_XProfile_Group $this Current instance of the group being saved. Passed by reference. 
  162. */ 
  163. do_action_ref_array( 'xprofile_group_after_save', array( &$this ) ); 
  164.  
  165. return $this->id; 
  166.  
  167. /** 
  168. * Delete a profile field group 
  169. * 
  170. * @since 1.1.0 
  171. * 
  172. * @global object $wpdb 
  173. * 
  174. * @return boolean 
  175. */ 
  176. public function delete() { 
  177. global $wpdb; 
  178.  
  179. // Bail if field group cannot be deleted. 
  180. if ( empty( $this->can_delete ) ) { 
  181. return false; 
  182.  
  183. /** 
  184. * Fires before the current group instance gets deleted. 
  185. * 
  186. * @since 2.0.0 
  187. * 
  188. * @param BP_XProfile_Group $this Current instance of the group being deleted. Passed by reference. 
  189. */ 
  190. do_action_ref_array( 'xprofile_group_before_delete', array( &$this ) ); 
  191.  
  192. $bp = buddypress(); 
  193. $sql = $wpdb->prepare( "DELETE FROM {$bp->profile->table_name_groups} WHERE id = %d", $this->id ); 
  194. $deleted = $wpdb->query( $sql ); 
  195.  
  196. // Delete field group. 
  197. if ( empty( $deleted ) || is_wp_error( $deleted ) ) { 
  198. return false; 
  199.  
  200. // Remove the group's fields. 
  201. if ( BP_XProfile_Field::delete_for_group( $this->id ) ) { 
  202.  
  203. // Remove profile data for the groups fields. 
  204. for ( $i = 0, $count = count( $this->fields ); $i < $count; ++$i ) { 
  205. BP_XProfile_ProfileData::delete_for_field( $this->fields[$i]->id ); 
  206.  
  207. /** 
  208. * Fires after the current group instance gets deleted. 
  209. * 
  210. * @since 2.0.0 
  211. * 
  212. * @param BP_XProfile_Group $this Current instance of the group being deleted. Passed by reference. 
  213. */ 
  214. do_action_ref_array( 'xprofile_group_after_delete', array( &$this ) ); 
  215.  
  216. return true; 
  217.  
  218. /** Static Methods ********************************************************/ 
  219.  
  220. /** 
  221. * Populates the BP_XProfile_Group object with profile field groups, fields,  
  222. * and field data. 
  223. * 
  224. * @since 1.2.0 
  225. * 
  226. * @global object $wpdb WordPress DB access object. 
  227. * 
  228. * @param array $args { 
  229. * Array of optional arguments: 
  230. * @type int $profile_group_id Limit results to a single profile group. 
  231. * @type int $user_id Required if you want to load a specific user's data. 
  232. * Default: displayed user's ID. 
  233. * @type array|string $member_type Limit fields by those restricted to a given member type, or array of 
  234. * member types. If `$user_id` is provided, the value of `$member_type` 
  235. * will be overridden by the member types of the provided user. The 
  236. * special value of 'any' will return only those fields that are 
  237. * unrestricted by member type - i.e., those applicable to any type. 
  238. * @type bool $hide_empty_groups True to hide groups that don't have any fields. Default: false. 
  239. * @type bool $hide_empty_fields True to hide fields where the user has not provided data. 
  240. * Default: false. 
  241. * @type bool $fetch_fields Whether to fetch each group's fields. Default: false. 
  242. * @type bool $fetch_field_data Whether to fetch data for each field. Requires a $user_id. 
  243. * Default: false. 
  244. * @type array $exclude_groups Comma-separated list or array of group IDs to exclude. 
  245. * @type array $exclude_fields Comma-separated list or array of field IDs to exclude. 
  246. * @type bool $update_meta_cache Whether to pre-fetch xprofilemeta for all retrieved groups, fields,  
  247. * and data. Default: true. 
  248. * } 
  249. * @return array $groups 
  250. */ 
  251. public static function get( $args = array() ) { 
  252. global $wpdb; 
  253.  
  254. // Parse arguments. 
  255. $r = wp_parse_args( $args, array( 
  256. 'profile_group_id' => false,  
  257. 'user_id' => bp_displayed_user_id(),  
  258. 'member_type' => false,  
  259. 'hide_empty_groups' => false,  
  260. 'hide_empty_fields' => false,  
  261. 'fetch_fields' => false,  
  262. 'fetch_field_data' => false,  
  263. 'fetch_visibility_level' => false,  
  264. 'exclude_groups' => false,  
  265. 'exclude_fields' => false,  
  266. 'update_meta_cache' => true,  
  267. ) ); 
  268.  
  269. // Keep track of object IDs for cache-priming. 
  270. $object_ids = array( 
  271. 'group' => array(),  
  272. 'field' => array(),  
  273. 'data' => array(),  
  274. ); 
  275.  
  276. // WHERE. 
  277. if ( ! empty( $r['profile_group_id'] ) ) { 
  278. $where_sql = $wpdb->prepare( 'WHERE g.id = %d', $r['profile_group_id'] ); 
  279. } elseif ( $r['exclude_groups'] ) { 
  280. $exclude = join( ', ', wp_parse_id_list( $r['exclude_groups'] ) ); 
  281. $where_sql = "WHERE g.id NOT IN ({$exclude})"; 
  282. } else { 
  283. $where_sql = ''; 
  284.  
  285. $bp = buddypress(); 
  286.  
  287. // Include or exclude empty groups. 
  288. if ( ! empty( $r['hide_empty_groups'] ) ) { 
  289. $group_ids = $wpdb->get_col( "SELECT DISTINCT g.id FROM {$bp->profile->table_name_groups} g INNER JOIN {$bp->profile->table_name_fields} f ON g.id = f.group_id {$where_sql} ORDER BY g.group_order ASC" ); 
  290. } else { 
  291. $group_ids = $wpdb->get_col( "SELECT DISTINCT g.id FROM {$bp->profile->table_name_groups} g {$where_sql} ORDER BY g.group_order ASC" ); 
  292.  
  293. // Get all group data. 
  294. $groups = self::get_group_data( $group_ids ); 
  295.  
  296. // Bail if not also getting fields. 
  297. if ( empty( $r['fetch_fields'] ) ) { 
  298. return $groups; 
  299.  
  300. // Get the group ids from the groups we found. 
  301. $group_ids = wp_list_pluck( $groups, 'id' ); 
  302.  
  303. // Store for meta cache priming. 
  304. $object_ids['group'] = $group_ids; 
  305.  
  306. // Bail if no groups found. 
  307. if ( empty( $group_ids ) ) { 
  308. return $groups; 
  309.  
  310. // Setup IN query from group IDs. 
  311. $group_ids_in = implode( ', ', (array) $group_ids ); 
  312.  
  313. // Support arrays and comma-separated strings. 
  314. $exclude_fields_cs = wp_parse_id_list( $r['exclude_fields'] ); 
  315.  
  316. // Visibility - Handled here so as not to be overridden by sloppy use of the 
  317. // exclude_fields parameter. See bp_xprofile_get_hidden_fields_for_user(). 
  318. $hidden_user_fields = bp_xprofile_get_hidden_fields_for_user( $r['user_id'] ); 
  319. $exclude_fields_cs = array_merge( $exclude_fields_cs, $hidden_user_fields ); 
  320. $exclude_fields_cs = implode( ', ', $exclude_fields_cs ); 
  321.  
  322. // Set up NOT IN query for excluded field IDs. 
  323. if ( ! empty( $exclude_fields_cs ) ) { 
  324. $exclude_fields_sql = "AND id NOT IN ({$exclude_fields_cs})"; 
  325. } else { 
  326. $exclude_fields_sql = ''; 
  327.  
  328. // Set up IN query for included field IDs. 
  329. $include_field_ids = array(); 
  330.  
  331. // Member-type restrictions. 
  332. if ( bp_get_member_types() ) { 
  333. if ( $r['user_id'] || false !== $r['member_type'] ) { 
  334. $member_types = $r['member_type']; 
  335. if ( $r['user_id'] ) { 
  336. $member_types = bp_get_member_type( $r['user_id'], false ); 
  337. if ( empty( $member_types ) ) { 
  338. $member_types = array( 'null' ); 
  339.  
  340. $member_types_fields = BP_XProfile_Field::get_fields_for_member_type( $member_types ); 
  341. $include_field_ids += array_keys( $member_types_fields ); 
  342.  
  343. $in_sql = ''; 
  344. if ( ! empty( $include_field_ids ) ) { 
  345. $include_field_ids_cs = implode( ', ', array_map( 'intval', $include_field_ids ) ); 
  346. $in_sql = " AND id IN ({$include_field_ids_cs}) "; 
  347.  
  348. // Fetch the fields. 
  349. $field_ids = $wpdb->get_col( "SELECT id FROM {$bp->profile->table_name_fields} WHERE group_id IN ( {$group_ids_in} ) AND parent_id = 0 {$exclude_fields_sql} {$in_sql} ORDER BY field_order" ); 
  350.  
  351. foreach( $groups as $group ) { 
  352. $group->fields = array(); 
  353.  
  354. // Bail if no fields. 
  355. if ( empty( $field_ids ) ) { 
  356. return $groups; 
  357.  
  358. $field_ids = array_map( 'intval', $field_ids ); 
  359.  
  360. // Prime the field cache. 
  361. $uncached_field_ids = bp_get_non_cached_ids( $field_ids, 'bp_xprofile_fields' ); 
  362. if ( ! empty( $uncached_field_ids ) ) { 
  363. $_uncached_field_ids = implode( ', ', array_map( 'intval', $uncached_field_ids ) ); 
  364. $uncached_fields = $wpdb->get_results( "SELECT * FROM {$bp->profile->table_name_fields} WHERE id IN ({$_uncached_field_ids})" ); 
  365. foreach ( $uncached_fields as $uncached_field ) { 
  366. $fid = intval( $uncached_field->id ); 
  367. wp_cache_set( $fid, $uncached_field, 'bp_xprofile_fields' ); 
  368.  
  369. // Pull field objects from the cache. 
  370. $fields = array(); 
  371. foreach ( $field_ids as $field_id ) { 
  372. $fields[] = xprofile_get_field( $field_id, null, false ); 
  373.  
  374. // Store field IDs for meta cache priming. 
  375. $object_ids['field'] = $field_ids; 
  376.  
  377. // Maybe fetch field data. 
  378. if ( ! empty( $r['fetch_field_data'] ) ) { 
  379.  
  380. // Get field data for user ID. 
  381. if ( ! empty( $field_ids ) && ! empty( $r['user_id'] ) ) { 
  382. $field_data = BP_XProfile_ProfileData::get_data_for_user( $r['user_id'], $field_ids ); 
  383.  
  384. // Remove data-less fields, if necessary. 
  385. if ( ! empty( $r['hide_empty_fields'] ) && ! empty( $field_ids ) && ! empty( $field_data ) ) { 
  386.  
  387. // Loop through the results and find the fields that have data. 
  388. foreach( (array) $field_data as $data ) { 
  389.  
  390. // Empty fields may contain a serialized empty array. 
  391. $maybe_value = maybe_unserialize( $data->value ); 
  392.  
  393. // Valid field values of 0 or '0' get caught by empty(), so we have an extra check for these. See #BP5731. 
  394. if ( ( ! empty( $maybe_value ) || '0' == $maybe_value ) && false !== $key = array_search( $data->field_id, $field_ids ) ) { 
  395.  
  396. // Fields that have data get removed from the list. 
  397. unset( $field_ids[ $key ] ); 
  398.  
  399. // The remaining members of $field_ids are empty. Remove them. 
  400. foreach( $fields as $field_key => $field ) { 
  401. if ( in_array( $field->id, $field_ids ) ) { 
  402. unset( $fields[ $field_key ] ); 
  403.  
  404. // Reset indexes. 
  405. $fields = array_values( $fields ); 
  406.  
  407. // Field data was found. 
  408. if ( ! empty( $fields ) && ! empty( $field_data ) && ! is_wp_error( $field_data ) ) { 
  409.  
  410. // Loop through fields. 
  411. foreach( (array) $fields as $field_key => $field ) { 
  412.  
  413. // Loop through the data in each field. 
  414. foreach( (array) $field_data as $data ) { 
  415.  
  416. // Assign correct data value to the field. 
  417. if ( $field->id == $data->field_id ) { 
  418. $fields[ $field_key ]->data = new stdClass; 
  419. $fields[ $field_key ]->data->value = $data->value; 
  420. $fields[ $field_key ]->data->id = $data->id; 
  421.  
  422. // Store for meta cache priming. 
  423. $object_ids['data'][] = $data->id; 
  424.  
  425. // Prime the meta cache, if necessary. 
  426. if ( ! empty( $r['update_meta_cache'] ) ) { 
  427. bp_xprofile_update_meta_cache( $object_ids ); 
  428.  
  429. // Maybe fetch visibility levels. 
  430. if ( ! empty( $r['fetch_visibility_level'] ) ) { 
  431. $fields = self::fetch_visibility_level( $r['user_id'], $fields ); 
  432.  
  433. // Merge the field array back in with the group array. 
  434. foreach( (array) $groups as $group ) { 
  435. // Indexes may have been shifted after previous deletions, so we get a 
  436. // fresh one each time through the loop. 
  437. $index = array_search( $group, $groups ); 
  438.  
  439. foreach( (array) $fields as $field ) { 
  440. if ( $group->id === $field->group_id ) { 
  441. $groups[ $index ]->fields[] = $field; 
  442.  
  443. // When we unset fields above, we may have created empty groups. 
  444. // Remove them, if necessary. 
  445. if ( empty( $group->fields ) && ! empty( $r['hide_empty_groups'] ) ) { 
  446. unset( $groups[ $index ] ); 
  447.  
  448. // Reset indexes. 
  449. $groups = array_values( $groups ); 
  450.  
  451. return $groups; 
  452.  
  453. /** 
  454. * Get data about a set of groups, based on IDs. 
  455. * 
  456. * @since 2.0.0 
  457. * 
  458. * @param array $group_ids Array of IDs. 
  459. * @return array 
  460. */ 
  461. protected static function get_group_data( $group_ids ) { 
  462. global $wpdb; 
  463.  
  464. // Bail if no group IDs are passed. 
  465. if ( empty( $group_ids ) ) { 
  466. return array(); 
  467.  
  468. // Setup empty arrays. 
  469. $groups = array(); 
  470. $uncached_gids = array(); 
  471.  
  472. // Loop through groups and look for cached & uncached data. 
  473. foreach ( $group_ids as $group_id ) { 
  474.  
  475. // If cached data is found, use it. 
  476. $group_data = wp_cache_get( $group_id, 'bp_xprofile_groups' ); 
  477. if ( false !== $group_data ) { 
  478. $groups[ $group_id ] = $group_data; 
  479.  
  480. // Otherwise leave a placeholder so we don't lose the order. 
  481. } else { 
  482. $groups[ $group_id ] = ''; 
  483.  
  484. // Add to the list of items to be queried. 
  485. $uncached_gids[] = $group_id; 
  486.  
  487. // Fetch uncached data from the DB if necessary. 
  488. if ( ! empty( $uncached_gids ) ) { 
  489.  
  490. // Setup IN query for uncached group data. 
  491. $uncached_gids_sql = implode( ', ', wp_parse_id_list( $uncached_gids ) ); 
  492.  
  493. // Get table name to query. 
  494. $table_name = buddypress()->profile->table_name_groups; 
  495.  
  496. // Fetch data, preserving order. 
  497. $queried_gdata = $wpdb->get_results( "SELECT * FROM {$table_name} WHERE id IN ({$uncached_gids_sql}) ORDER BY FIELD( id, {$uncached_gids_sql} )"); 
  498.  
  499. // Make sure query returned valid data. 
  500. if ( ! empty( $queried_gdata ) && ! is_wp_error( $queried_gdata ) ) { 
  501.  
  502. // Put queried data into the placeholders created earlier,  
  503. // and add it to the cache. 
  504. foreach ( (array) $queried_gdata as $gdata ) { 
  505.  
  506. // Add group to groups array. 
  507. $groups[ $gdata->id ] = $gdata; 
  508.  
  509. // Cache previously uncached group data. 
  510. wp_cache_set( $gdata->id, $gdata, 'bp_xprofile_groups' ); 
  511.  
  512. // Integer casting. 
  513. foreach ( (array) $groups as $key => $data ) { 
  514. $groups[ $key ]->id = (int) $groups[ $key ]->id; 
  515. $groups[ $key ]->group_order = (int) $groups[ $key ]->group_order; 
  516. $groups[ $key ]->can_delete = (int) $groups[ $key ]->can_delete; 
  517.  
  518. // Reset indexes & return. 
  519. return array_values( $groups ); 
  520.  
  521. /** 
  522. * Validate field group when form submitted. 
  523. * 
  524. * @since 1.0.0 
  525. * 
  526. * @global string $message 
  527. * 
  528. * @return boolean 
  529. */ 
  530. public static function admin_validate() { 
  531. global $message; 
  532.  
  533. // Validate Form. 
  534. if ( empty( $_POST['group_name'] ) ) { 
  535. $message = __( 'Please make sure you give the group a name.', 'buddypress' ); 
  536. return false; 
  537. } else { 
  538. return true; 
  539.  
  540. /** 
  541. * Update field group position. 
  542. * 
  543. * @since 1.5.0 
  544. * 
  545. * @global $wpdb $wpdb 
  546. * 
  547. * @param int $field_group_id ID of the group the field belongs to. 
  548. * @param int $position Field group position. 
  549. * @return boolean 
  550. */ 
  551. public static function update_position( $field_group_id, $position ) { 
  552. global $wpdb; 
  553.  
  554. if ( ! is_numeric( $position ) ) { 
  555. return false; 
  556.  
  557. // Purge profile field group cache. 
  558. wp_cache_delete( 'all', 'bp_xprofile_groups' ); 
  559.  
  560. $bp = buddypress(); 
  561.  
  562. return $wpdb->query( $wpdb->prepare( "UPDATE {$bp->profile->table_name_groups} SET group_order = %d WHERE id = %d", $position, $field_group_id ) ); 
  563.  
  564. /** 
  565. * Fetch the field visibility level for the fields returned by the query. 
  566. * 
  567. * @since 1.6.0 
  568. * 
  569. * @param int $user_id The profile owner's user_id. 
  570. * @param array $fields The database results returned by the get() query. 
  571. * @return array $fields The database results, with field_visibility added 
  572. */ 
  573. public static function fetch_visibility_level( $user_id = 0, $fields = array() ) { 
  574.  
  575. // Get the user's visibility level preferences. 
  576. $visibility_levels = bp_get_user_meta( $user_id, 'bp_xprofile_visibility_levels', true ); 
  577.  
  578. foreach( (array) $fields as $key => $field ) { 
  579.  
  580. // Does the admin allow this field to be customized? 
  581. $visibility = bp_xprofile_get_meta( $field->id, 'field', 'allow_custom_visibility' ); 
  582. $allow_custom = (bool) ( 'disabled' !== $visibility ); 
  583.  
  584. // Look to see if the user has set the visibility for this field. 
  585. if ( ( true === $allow_custom ) && isset( $visibility_levels[ $field->id ] ) ) { 
  586. $field_visibility = $visibility_levels[ $field->id ]; 
  587.  
  588. // If no admin-set default is saved, fall back on a global default. 
  589. } else { 
  590. $fallback_visibility = bp_xprofile_get_meta( $field->id, 'field', 'default_visibility' ); 
  591.  
  592. /** 
  593. * Filters the XProfile default visibility level for a field. 
  594. * 
  595. * @since 1.6.0 
  596. * 
  597. * @param string $value Default visibility value. 
  598. */ 
  599. $field_visibility = ! empty( $fallback_visibility ) 
  600. ? $fallback_visibility 
  601. : apply_filters( 'bp_xprofile_default_visibility_level', 'public' ); 
  602.  
  603. $fields[ $key ]->visibility_level = $field_visibility; 
  604.  
  605. return $fields; 
  606.  
  607. /** 
  608. * Fetch the admin-set preferences for all fields. 
  609. * 
  610. * @since 1.6.0 
  611. * 
  612. * @return array $default_visibility_levels An array, keyed by field_id, of default 
  613. * visibility level + allow_custom 
  614. * (whether the admin allows this 
  615. * field to be set by user) 
  616. */ 
  617. public static function fetch_default_visibility_levels() { 
  618. global $wpdb; 
  619.  
  620. $default_visibility_levels = wp_cache_get( 'default_visibility_levels', 'bp_xprofile' ); 
  621.  
  622. if ( false === $default_visibility_levels ) { 
  623. $bp = buddypress(); 
  624.  
  625. $levels = $wpdb->get_results( "SELECT object_id, meta_key, meta_value FROM {$bp->profile->table_name_meta} WHERE object_type = 'field' AND ( meta_key = 'default_visibility' OR meta_key = 'allow_custom_visibility' )" ); 
  626.  
  627. // Arrange so that the field id is the key and the visibility level the value. 
  628. $default_visibility_levels = array(); 
  629. foreach ( $levels as $level ) { 
  630. switch ( $level->meta_key ) { 
  631. case 'default_visibility' : 
  632. $default_visibility_levels[ $level->object_id ]['default'] = $level->meta_value; 
  633. break; 
  634. case 'allow_custom_visibility' : 
  635. $default_visibility_levels[ $level->object_id ]['allow_custom'] = $level->meta_value; 
  636. break; 
  637.  
  638. wp_cache_set( 'default_visibility_levels', $default_visibility_levels, 'bp_xprofile' ); 
  639.  
  640. return $default_visibility_levels; 
  641.  
  642. /** Admin Output **********************************************************/ 
  643.  
  644. /** 
  645. * Output the admin area field group form. 
  646. * 
  647. * @since 1.0.0 
  648. * 
  649. * @global string $message 
  650. */ 
  651. public function render_admin_form() { 
  652. global $message; 
  653.  
  654. // New field group. 
  655. if ( empty( $this->id ) ) { 
  656. $title = __( 'Add New Field Group', 'buddypress' ); 
  657. $action = add_query_arg( array( 'page' => 'bp-profile-setup', 'mode' => 'add_group' ), 'users.php' ); 
  658. $button = __( 'Save', 'buddypress' ); 
  659.  
  660. // Existing field group. 
  661. } else { 
  662. $title = __( 'Edit Field Group', 'buddypress' ); 
  663. $action = add_query_arg( array( 'page' => 'bp-profile-setup', 'mode' => 'edit_group', 'group_id' => $this->id ), 'users.php' ); 
  664. $button = __( 'Update', 'buddypress' ); 
  665. } ?> 
  666.  
  667. <div class="wrap"> 
  668.  
  669. <h1><?php echo esc_html( $title ); ?></h1> 
  670.  
  671. <?php if ( ! empty( $message ) ) : ?> 
  672.  
  673. <div id="message" class="error fade"> 
  674. <p><?php echo esc_html( $message ); ?></p> 
  675. </div> 
  676.  
  677. <?php endif; ?> 
  678.  
  679. <form id="bp-xprofile-add-field-group" action="<?php echo esc_url( $action ); ?>" method="post"> 
  680. <div id="poststuff"> 
  681. <div id="post-body" class="metabox-holder columns-<?php echo ( 1 == get_current_screen()->get_columns() ) ? '1' : '2'; ?>"> 
  682. <div id="post-body-content"> 
  683. <div id="titlediv"> 
  684. <div class="titlewrap"> 
  685. <label id="title-prompt-text" for="title"><?php esc_html_e( 'Field Group Name (required)', 'buddypress') ?></label> 
  686. <input type="text" name="group_name" id="title" value="<?php echo esc_attr( $this->name ); ?>" autocomplete="off" /> 
  687. </div> 
  688. </div> 
  689. <div class="postbox"> 
  690. <h2><?php esc_html_e( 'Field Group Description', 'buddypress' ); ?></h2> 
  691. <div class="inside"> 
  692. <label for="group_description" class="screen-reader-text"><?php 
  693. /** translators: accessibility text */ 
  694. esc_html_e( 'Add description', 'buddypress' ); 
  695. ?></label> 
  696. <textarea name="group_description" id="group_description" rows="8" cols="60"><?php echo esc_textarea( $this->description ); ?></textarea> 
  697. </div> 
  698. </div> 
  699.  
  700. <?php 
  701.  
  702. /** 
  703. * Fires after the XProfile group description field is rendered in wp-admin. 
  704. * 
  705. * @since 2.6.0 
  706. * 
  707. * @param BP_XProfile_Group $this Current XProfile group. 
  708. */ 
  709. do_action( 'xprofile_group_admin_after_description', $this ); ?> 
  710.  
  711. </div><!-- #post-body-content --> 
  712.  
  713. <div id="postbox-container-1" class="postbox-container"> 
  714.  
  715. <?php 
  716.  
  717. /** 
  718. * Fires before XProfile Group submit metabox. 
  719. * 
  720. * @since 2.1.0 
  721. * 
  722. * @param BP_XProfile_Group $this Current XProfile group. 
  723. */ 
  724. do_action( 'xprofile_group_before_submitbox', $this ); ?> 
  725.  
  726. <div id="submitdiv" class="postbox"> 
  727. <h2><?php _e( 'Submit', 'buddypress' ); ?></h2> 
  728. <div class="inside"> 
  729. <div id="submitcomment" class="submitbox"> 
  730. <div id="major-publishing-actions"> 
  731.  
  732. <?php 
  733.  
  734. // Nonce fields 
  735. wp_nonce_field( 'bp_xprofile_admin_group', 'bp_xprofile_admin_group' ); 
  736.  
  737. /** 
  738. * Fires at the beginning of the XProfile Group publishing actions section. 
  739. * 
  740. * @since 2.1.0 
  741. * 
  742. * @param BP_XProfile_Group $this Current XProfile group. 
  743. */ 
  744. do_action( 'xprofile_group_submitbox_start', $this ); ?> 
  745.  
  746. <input type="hidden" name="group_order" id="group_order" value="<?php echo esc_attr( $this->group_order ); ?>" /> 
  747. <div id="publishing-action"> 
  748. <input type="submit" name="save_group" value="<?php echo esc_attr( $button ); ?>" class="button-primary"/> 
  749. </div> 
  750. <div id="delete-action"> 
  751. <a href="users.php?page=bp-profile-setup" class="deletion"><?php _e( 'Cancel', 'buddypress' ); ?></a> 
  752. </div> 
  753. <div class="clear"></div> 
  754. </div> 
  755. </div> 
  756. </div> 
  757. </div> 
  758.  
  759. <?php 
  760.  
  761. /** 
  762. * Fires after XProfile Group submit metabox. 
  763. * 
  764. * @since 2.1.0 
  765. * 
  766. * @param BP_XProfile_Group $this Current XProfile group. 
  767. */ 
  768. do_action( 'xprofile_group_after_submitbox', $this ); ?> 
  769.  
  770. </div> 
  771. </div> 
  772. </div> 
  773. </form> 
  774. </div> 
  775.  
  776. <?php 
.