/bp-xprofile/classes/class-bp-xprofile-field.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 fields. 
  15. * 
  16. * @since 1.0.0 
  17. */ 
  18. class BP_XProfile_Field { 
  19.  
  20. /** 
  21. * Field ID. 
  22. * 
  23. * @since 1.0.0 
  24. * @var int ID of field. 
  25. */ 
  26. public $id; 
  27.  
  28. /** 
  29. * Field group ID. 
  30. * 
  31. * @since 1.0.0 
  32. * @var int Field group ID for field. 
  33. */ 
  34. public $group_id; 
  35.  
  36. /** 
  37. * Field parent ID. 
  38. * 
  39. * @since 1.0.0 
  40. * @var int Parent ID of field. 
  41. */ 
  42. public $parent_id; 
  43.  
  44. /** 
  45. * Field type. 
  46. * 
  47. * @since 1.0.0 
  48. * @var string Field type. 
  49. */ 
  50. public $type; 
  51.  
  52. /** 
  53. * Field name. 
  54. * 
  55. * @since 1.0.0 
  56. * @var string Field name. 
  57. */ 
  58. public $name; 
  59.  
  60. /** 
  61. * Field description. 
  62. * 
  63. * @since 1.0.0 
  64. * @var string Field description. 
  65. */ 
  66. public $description; 
  67.  
  68. /** 
  69. * Required field? 
  70. * 
  71. * @since 1.0.0 
  72. * @var bool Is field required to be filled out? 
  73. */ 
  74. public $is_required; 
  75.  
  76. /** 
  77. * Deletable field? 
  78. * 
  79. * @since 1.0.0 
  80. * @var int Can field be deleted? 
  81. */ 
  82. public $can_delete = '1'; 
  83.  
  84. /** 
  85. * Field position. 
  86. * 
  87. * @since 1.0.0 
  88. * @var int Field position. 
  89. */ 
  90. public $field_order; 
  91.  
  92. /** 
  93. * Option order. 
  94. * 
  95. * @since 1.0.0 
  96. * @var int Option order. 
  97. */ 
  98. public $option_order; 
  99.  
  100. /** 
  101. * Order child fields. 
  102. * 
  103. * @since 1.0.0 
  104. * @var string Order child fields by. 
  105. */ 
  106. public $order_by; 
  107.  
  108. /** 
  109. * Is this the default option? 
  110. * 
  111. * @since 1.0.0 
  112. * @var bool Is this the default option for this field? 
  113. */ 
  114. public $is_default_option; 
  115.  
  116. /** 
  117. * Field data visibility. 
  118. * 
  119. * @since 1.9.0 
  120. * @since 2.4.0 Property marked protected. Now accessible by magic method or by `get_default_visibility()`. 
  121. * @var string Default field data visibility. 
  122. */ 
  123. protected $default_visibility; 
  124.  
  125. /** 
  126. * Is the visibility able to be modified? 
  127. * 
  128. * @since 2.3.0 
  129. * @since 2.4.0 Property marked protected. Now accessible by magic method or by `get_allow_custom_visibility()`. 
  130. * @var string Members are allowed/disallowed to modify data visibility. 
  131. */ 
  132. protected $allow_custom_visibility; 
  133.  
  134. /** 
  135. * Whether values from this field are autolinked to directory searches. 
  136. * 
  137. * @since 2.5.0 
  138. * @var bool 
  139. */ 
  140. public $do_autolink; 
  141.  
  142. /** 
  143. * Field type option. 
  144. * 
  145. * @since 2.0.0 
  146. * @var BP_XProfile_Field_Type Field type object used for validation. 
  147. */ 
  148. public $type_obj = null; 
  149.  
  150. /** 
  151. * Field data for user ID. 
  152. * 
  153. * @since 2.0.0 
  154. * @var BP_XProfile_ProfileData Field data for user ID. 
  155. */ 
  156. public $data; 
  157.  
  158. /** 
  159. * Member types to which the profile field should be applied. 
  160. * 
  161. * @since 2.4.0 
  162. * @var array Array of member types. 
  163. */ 
  164. protected $member_types; 
  165.  
  166. /** 
  167. * Initialize and/or populate profile field. 
  168. * 
  169. * @since 1.1.0 
  170. * 
  171. * @param int|null $id Field ID. 
  172. * @param int|null $user_id User ID. 
  173. * @param bool $get_data Get data. 
  174. */ 
  175. public function __construct( $id = null, $user_id = null, $get_data = true ) { 
  176.  
  177. if ( ! empty( $id ) ) { 
  178. $this->populate( $id, $user_id, $get_data ); 
  179.  
  180. // Initialise the type obj to prevent fatals when creating new profile fields. 
  181. } else { 
  182. $this->type_obj = bp_xprofile_create_field_type( 'textbox' ); 
  183. $this->type_obj->field_obj = $this; 
  184.  
  185. /** 
  186. * Populate a profile field object. 
  187. * 
  188. * @since 1.1.0 
  189. * 
  190. * @global object $wpdb 
  191. * @global object $userdata 
  192. * 
  193. * @param int $id Field ID. 
  194. * @param int|null $user_id User ID. 
  195. * @param bool $get_data Get data. 
  196. */ 
  197. public function populate( $id, $user_id = null, $get_data = true ) { 
  198. global $wpdb, $userdata; 
  199.  
  200. if ( empty( $user_id ) ) { 
  201. $user_id = isset( $userdata->ID ) ? $userdata->ID : 0; 
  202.  
  203. $field = wp_cache_get( $id, 'bp_xprofile_fields' ); 
  204. if ( false === $field ) { 
  205. $bp = buddypress(); 
  206.  
  207. $field = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$bp->profile->table_name_fields} WHERE id = %d", $id ) ); 
  208.  
  209. if ( ! $field ) { 
  210. return false; 
  211.  
  212. wp_cache_add( $id, $field, 'bp_xprofile_fields' ); 
  213.  
  214. $this->fill_data( $field ); 
  215.  
  216. if ( ! empty( $get_data ) && ! empty( $user_id ) ) { 
  217. $this->data = $this->get_field_data( $user_id ); 
  218.  
  219. /** 
  220. * Retrieve a `BP_XProfile_Field` instance. 
  221. * 
  222. * @since 2.4.0 
  223. * @since 2.8.0 Added `$user_id` and `$get_data` parameters. 
  224. * 
  225. * @static 
  226. * 
  227. * @param int $field_id ID of the field. 
  228. * @param int $user_id Optional. ID of the user associated with the field. 
  229. * Ignored if `$get_data` is false. If `$get_data` is 
  230. * true, but no `$user_id` is provided, defaults to 
  231. * logged-in user ID. 
  232. * @param bool $get_data Whether to fetch data for the specified `$user_id`. 
  233. * @return BP_XProfile_Field|false Field object if found, otherwise false. 
  234. */ 
  235. public static function get_instance( $field_id, $user_id = null, $get_data = true ) { 
  236. global $wpdb; 
  237.  
  238. $field_id = (int) $field_id; 
  239. if ( ! $field_id ) { 
  240. return false; 
  241.  
  242. return new self( $field_id, $user_id, $get_data ); 
  243.  
  244. /** 
  245. * Fill object vars based on data passed to the method. 
  246. * 
  247. * @since 2.4.0 
  248. * 
  249. * @param array|object $args Array or object representing the `BP_XProfile_Field` properties. 
  250. * Generally, this is a row from the fields database table. 
  251. */ 
  252. public function fill_data( $args ) { 
  253. if ( is_object( $args ) ) { 
  254. $args = (array) $args; 
  255.  
  256. $int_fields = array( 
  257. 'id', 'is_required', 'group_id', 'parent_id', 'is_default_option',  
  258. 'field_order', 'option_order', 'can_delete' 
  259. ); 
  260.  
  261. foreach ( $args as $k => $v ) { 
  262. if ( 'name' === $k || 'description' === $k ) { 
  263. $v = stripslashes( $v ); 
  264.  
  265. // Cast numeric strings as integers. 
  266. if ( true === in_array( $k, $int_fields ) ) { 
  267. $v = (int) $v; 
  268.  
  269. $this->{$k} = $v; 
  270.  
  271. // Create the field type and store a reference back to this object. 
  272. $this->type_obj = bp_xprofile_create_field_type( $this->type ); 
  273. $this->type_obj->field_obj = $this; 
  274.  
  275. /** 
  276. * Magic getter. 
  277. * 
  278. * @since 2.4.0 
  279. * 
  280. * @param string $key Property name. 
  281. * @return mixed 
  282. */ 
  283. public function __get( $key ) { 
  284. switch ( $key ) { 
  285. case 'default_visibility' : 
  286. return $this->get_default_visibility(); 
  287. break; 
  288.  
  289. case 'allow_custom_visibility' : 
  290. return $this->get_allow_custom_visibility(); 
  291. break; 
  292.  
  293. /** 
  294. * Magic issetter. 
  295. * 
  296. * @since 2.4.0 
  297. * 
  298. * @param string $key Property name. 
  299. * @return bool 
  300. */ 
  301. public function __isset( $key ) { 
  302. switch ( $key ) { 
  303. // Backward compatibility for when these were public methods. 
  304. case 'allow_custom_visibility' : 
  305. case 'default_visibility' : 
  306. return true; 
  307. break; 
  308.  
  309. /** 
  310. * Delete a profile field. 
  311. * 
  312. * @since 1.1.0 
  313. * 
  314. * @global object $wpdb 
  315. * 
  316. * @param boolean $delete_data Whether or not to delete data. 
  317. * @return boolean 
  318. */ 
  319. public function delete( $delete_data = false ) { 
  320. global $wpdb; 
  321.  
  322. // Prevent deletion if no ID is present. 
  323. // Prevent deletion by url when can_delete is false. 
  324. // Prevent deletion of option 1 since this invalidates fields with options. 
  325. if ( empty( $this->id ) || empty( $this->can_delete ) || ( $this->parent_id && $this->option_order == 1 ) ) { 
  326. return false; 
  327.  
  328. $bp = buddypress(); 
  329. $sql = $wpdb->prepare( "DELETE FROM {$bp->profile->table_name_fields} WHERE id = %d OR parent_id = %d", $this->id, $this->id ); 
  330.  
  331. if ( ! $wpdb->query( $sql ) ) { 
  332. return false; 
  333.  
  334. // Delete the data in the DB for this field. 
  335. if ( true === $delete_data ) { 
  336. BP_XProfile_ProfileData::delete_for_field( $this->id ); 
  337.  
  338. return true; 
  339.  
  340. /** 
  341. * Save a profile field. 
  342. * 
  343. * @since 1.1.0 
  344. * 
  345. * @global object $wpdb 
  346. * 
  347. * @return boolean 
  348. */ 
  349. public function save() { 
  350. global $wpdb; 
  351.  
  352. $bp = buddypress(); 
  353.  
  354. $this->group_id = apply_filters( 'xprofile_field_group_id_before_save', $this->group_id, $this->id ); 
  355. $this->parent_id = apply_filters( 'xprofile_field_parent_id_before_save', $this->parent_id, $this->id ); 
  356. $this->type = apply_filters( 'xprofile_field_type_before_save', $this->type, $this->id ); 
  357. $this->name = apply_filters( 'xprofile_field_name_before_save', $this->name, $this->id ); 
  358. $this->description = apply_filters( 'xprofile_field_description_before_save', $this->description, $this->id ); 
  359. $this->is_required = apply_filters( 'xprofile_field_is_required_before_save', $this->is_required, $this->id ); 
  360. $this->order_by = apply_filters( 'xprofile_field_order_by_before_save', $this->order_by, $this->id ); 
  361. $this->field_order = apply_filters( 'xprofile_field_field_order_before_save', $this->field_order, $this->id ); 
  362. $this->option_order = apply_filters( 'xprofile_field_option_order_before_save', $this->option_order, $this->id ); 
  363. $this->can_delete = apply_filters( 'xprofile_field_can_delete_before_save', $this->can_delete, $this->id ); 
  364. $this->type_obj = bp_xprofile_create_field_type( $this->type ); 
  365.  
  366. /** 
  367. * Fires before the current field instance gets saved. 
  368. * 
  369. * Please use this hook to filter the properties above. Each part will be passed in. 
  370. * 
  371. * @since 1.0.0 
  372. * 
  373. * @param BP_XProfile_Field $this Current instance of the field being saved. 
  374. */ 
  375. do_action_ref_array( 'xprofile_field_before_save', array( $this ) ); 
  376.  
  377. $is_new_field = is_null( $this->id ); 
  378.  
  379. if ( ! $is_new_field ) { 
  380. $sql = $wpdb->prepare( "UPDATE {$bp->profile->table_name_fields} SET group_id = %d, parent_id = 0, type = %s, name = %s, description = %s, is_required = %d, order_by = %s, field_order = %d, option_order = %d, can_delete = %d, is_default_option = %d WHERE id = %d", $this->group_id, $this->type, $this->name, $this->description, $this->is_required, $this->order_by, $this->field_order, $this->option_order, $this->can_delete, $this->is_default_option, $this->id ); 
  381. } else { 
  382. $sql = $wpdb->prepare( "INSERT INTO {$bp->profile->table_name_fields} (group_id, parent_id, type, name, description, is_required, order_by, field_order, option_order, can_delete, is_default_option ) VALUES ( %d, %d, %s, %s, %s, %d, %s, %d, %d, %d, %d )", $this->group_id, $this->parent_id, $this->type, $this->name, $this->description, $this->is_required, $this->order_by, $this->field_order, $this->option_order, $this->can_delete, $this->is_default_option ); 
  383.  
  384. /** 
  385. * Check for null so field options can be changed without changing any 
  386. * other part of the field. The described situation will return 0 here. 
  387. */ 
  388. if ( $wpdb->query( $sql ) !== null ) { 
  389.  
  390. if ( $is_new_field ) { 
  391. $this->id = $wpdb->insert_id; 
  392.  
  393. // Only do this if we are editing an existing field. 
  394. if ( ! $is_new_field ) { 
  395.  
  396. /** 
  397. * Remove any radio or dropdown options for this 
  398. * field. They will be re-added if needed. 
  399. * This stops orphan options if the user changes a 
  400. * field from a radio button field to a text box. 
  401. */ 
  402. $this->delete_children(); 
  403.  
  404. /** 
  405. * Check to see if this is a field with child options. 
  406. * We need to add the options to the db, if it is. 
  407. */ 
  408. if ( $this->type_obj->supports_options ) { 
  409.  
  410. $parent_id = $this->id; 
  411.  
  412. // Allow plugins to filter the field's child options (i.e. the items in a selectbox). 
  413. $post_option = ! empty( $_POST["{$this->type}_option"] ) ? $_POST["{$this->type}_option"] : ''; 
  414. $post_default = ! empty( $_POST["isDefault_{$this->type}_option"] ) ? $_POST["isDefault_{$this->type}_option"] : ''; 
  415.  
  416. /** 
  417. * Filters the submitted field option value before saved. 
  418. * 
  419. * @since 1.5.0 
  420. * 
  421. * @param string $post_option Submitted option value. 
  422. * @param BP_XProfile_Field $type Current field type being saved for. 
  423. */ 
  424. $options = apply_filters( 'xprofile_field_options_before_save', $post_option, $this->type ); 
  425.  
  426. /** 
  427. * Filters the default field option value before saved. 
  428. * 
  429. * @since 1.5.0 
  430. * 
  431. * @param string $post_default Default option value. 
  432. * @param BP_XProfile_Field $type Current field type being saved for. 
  433. */ 
  434. $defaults = apply_filters( 'xprofile_field_default_before_save', $post_default, $this->type ); 
  435.  
  436. $counter = 1; 
  437. if ( !empty( $options ) ) { 
  438. foreach ( (array) $options as $option_key => $option_value ) { 
  439. $is_default = 0; 
  440.  
  441. if ( is_array( $defaults ) ) { 
  442. if ( isset( $defaults[ $option_key ] ) ) { 
  443. $is_default = 1; 
  444. } else { 
  445. if ( (int) $defaults == $option_key ) { 
  446. $is_default = 1; 
  447.  
  448. if ( '' != $option_value ) { 
  449. $sql = $wpdb->prepare( "INSERT INTO {$bp->profile->table_name_fields} (group_id, parent_id, type, name, description, is_required, option_order, is_default_option) VALUES (%d, %d, 'option', %s, '', 0, %d, %d)", $this->group_id, $parent_id, $option_value, $counter, $is_default ); 
  450. if ( ! $wpdb->query( $sql ) ) { 
  451. return false; 
  452.  
  453. $counter++; 
  454.  
  455. /** 
  456. * Fires after the current field instance gets saved. 
  457. * 
  458. * @since 1.0.0 
  459. * 
  460. * @param BP_XProfile_Field $this Current instance of the field being saved. 
  461. */ 
  462. do_action_ref_array( 'xprofile_field_after_save', array( $this ) ); 
  463.  
  464. // Recreate type_obj in case someone changed $this->type via a filter. 
  465. $this->type_obj = bp_xprofile_create_field_type( $this->type ); 
  466. $this->type_obj->field_obj = $this; 
  467.  
  468. return $this->id; 
  469. } else { 
  470. return false; 
  471.  
  472. /** 
  473. * Get field data for a user ID. 
  474. * 
  475. * @since 1.2.0 
  476. * 
  477. * @param int $user_id ID of the user to get field data for. 
  478. * @return BP_XProfile_ProfileData 
  479. */ 
  480. public function get_field_data( $user_id = 0 ) { 
  481. return new BP_XProfile_ProfileData( $this->id, $user_id ); 
  482.  
  483. /** 
  484. * Get all child fields for this field ID. 
  485. * 
  486. * @since 1.2.0 
  487. * 
  488. * @global object $wpdb 
  489. * 
  490. * @param bool $for_editing Whether or not the field is for editing. 
  491. * @return array 
  492. */ 
  493. public function get_children( $for_editing = false ) { 
  494. global $wpdb; 
  495.  
  496. // This is done here so we don't have problems with sql injection. 
  497. if ( empty( $for_editing ) && ( 'asc' === $this->order_by ) ) { 
  498. $sort_sql = 'ORDER BY name ASC'; 
  499. } elseif ( empty( $for_editing ) && ( 'desc' === $this->order_by ) ) { 
  500. $sort_sql = 'ORDER BY name DESC'; 
  501. } else { 
  502. $sort_sql = 'ORDER BY option_order ASC'; 
  503.  
  504. // This eliminates a problem with getting all fields when there is no 
  505. // id for the object. 
  506. if ( empty( $this->id ) ) { 
  507. $parent_id = -1; 
  508. } else { 
  509. $parent_id = $this->id; 
  510.  
  511. $bp = buddypress(); 
  512. $sql = $wpdb->prepare( "SELECT * FROM {$bp->profile->table_name_fields} WHERE parent_id = %d AND group_id = %d {$sort_sql}", $parent_id, $this->group_id ); 
  513.  
  514. $children = $wpdb->get_results( $sql ); 
  515.  
  516. /** 
  517. * Filters the found children for a field. 
  518. * 
  519. * @since 1.2.5 
  520. * 
  521. * @param object $children Found children for a field. 
  522. * @param bool $for_editing Whether or not the field is for editing. 
  523. */ 
  524. return apply_filters( 'bp_xprofile_field_get_children', $children, $for_editing ); 
  525.  
  526. /** 
  527. * Delete all field children for this field. 
  528. * 
  529. * @since 1.2.0 
  530. * 
  531. * @global object $wpdb 
  532. */ 
  533. public function delete_children() { 
  534. global $wpdb; 
  535.  
  536. $bp = buddypress(); 
  537. $sql = $wpdb->prepare( "DELETE FROM {$bp->profile->table_name_fields} WHERE parent_id = %d", $this->id ); 
  538.  
  539. $wpdb->query( $sql ); 
  540.  
  541. /** 
  542. * Gets the member types to which this field should be available. 
  543. * 
  544. * Will not return inactive member types, even if associated metadata is found. 
  545. * 
  546. * 'null' is a special pseudo-type, which represents users that do not have a member type. 
  547. * 
  548. * @since 2.4.0 
  549. * 
  550. * @return array Array of member type names. 
  551. */ 
  552. public function get_member_types() { 
  553. if ( ! is_null( $this->member_types ) ) { 
  554. return $this->member_types; 
  555.  
  556. $raw_types = bp_xprofile_get_meta( $this->id, 'field', 'member_type', false ); 
  557.  
  558. // If `$raw_types` is not an array, it probably means this is a new field (id=0). 
  559. if ( ! is_array( $raw_types ) ) { 
  560. $raw_types = array(); 
  561.  
  562. // If '_none' is found in the array, it overrides all types. 
  563. $types = array(); 
  564. if ( ! in_array( '_none', $raw_types ) ) { 
  565. $registered_types = bp_get_member_types(); 
  566.  
  567. // Eliminate invalid member types saved in the database. 
  568. foreach ( $raw_types as $raw_type ) { 
  569. // 'null' is a special case - it represents users without a type. 
  570. if ( 'null' === $raw_type || isset( $registered_types[ $raw_type ] ) ) { 
  571. $types[] = $raw_type; 
  572.  
  573. // If no member types have been saved, intepret as *all* member types. 
  574. if ( empty( $types ) ) { 
  575. $types = array_values( $registered_types ); 
  576.  
  577. // + the "null" type, ie users without a type. 
  578. $types[] = 'null'; 
  579.  
  580. /** 
  581. * Filters the member types to which an XProfile object should be applied. 
  582. * 
  583. * @since 2.4.0 
  584. * 
  585. * @param array $types Member types. 
  586. * @param BP_XProfile_Field $field Field object. 
  587. */ 
  588. $this->member_types = apply_filters( 'bp_xprofile_field_member_types', $types, $this ); 
  589.  
  590. return $this->member_types; 
  591.  
  592. /** 
  593. * Sets the member types for this field. 
  594. * 
  595. * @since 2.4.0 
  596. * 
  597. * @param array $member_types Array of member types. Can include 'null' (users with no type) in addition to any 
  598. * registered types. 
  599. * @param bool $append Whether to append to existing member types. If false, all existing member type 
  600. * associations will be deleted before adding your `$member_types`. Default false. 
  601. * @return array Member types for the current field, after being saved. 
  602. */ 
  603. public function set_member_types( $member_types, $append = false ) { 
  604. // Unset invalid member types. 
  605. $types = array(); 
  606. foreach ( $member_types as $member_type ) { 
  607. // 'null' is a special case - it represents users without a type. 
  608. if ( 'null' === $member_type || bp_get_member_type_object( $member_type ) ) { 
  609. $types[] = $member_type; 
  610.  
  611. // When `$append` is false, delete all existing types before adding new ones. 
  612. if ( ! $append ) { 
  613. bp_xprofile_delete_meta( $this->id, 'field', 'member_type' ); 
  614.  
  615. /** 
  616. * We interpret an empty array as disassociating the field from all types. This is 
  617. * represented internally with the '_none' flag. 
  618. */ 
  619. if ( empty( $types ) ) { 
  620. bp_xprofile_add_meta( $this->id, 'field', 'member_type', '_none' ); 
  621.  
  622. /** 
  623. * Unrestricted fields are represented in the database as having no 'member_type'. 
  624. * We detect whether a field is being set to unrestricted by checking whether the 
  625. * list of types passed to the method is the same as the list of registered types,  
  626. * plus the 'null' pseudo-type. 
  627. */ 
  628. $_rtypes = bp_get_member_types(); 
  629. $rtypes = array_values( $_rtypes ); 
  630. $rtypes[] = 'null'; 
  631.  
  632. sort( $types ); 
  633. sort( $rtypes ); 
  634.  
  635. // Only save if this is a restricted field. 
  636. if ( $types !== $rtypes ) { 
  637. // Save new types. 
  638. foreach ( $types as $type ) { 
  639. bp_xprofile_add_meta( $this->id, 'field', 'member_type', $type ); 
  640.  
  641. // Reset internal cache of member types. 
  642. $this->member_types = null; 
  643.  
  644. /** 
  645. * Fires after a field's member types have been updated. 
  646. * 
  647. * @since 2.4.0 
  648. * 
  649. * @param BP_XProfile_Field $this Field object. 
  650. */ 
  651. do_action( 'bp_xprofile_field_set_member_type', $this ); 
  652.  
  653. // Refetch fresh items from the database. 
  654. return $this->get_member_types(); 
  655.  
  656. /** 
  657. * Gets a label representing the field's member types. 
  658. * 
  659. * This label is displayed alongside the field's name on the Profile Fields Dashboard panel. 
  660. * 
  661. * @since 2.4.0 
  662. * 
  663. * @return string 
  664. */ 
  665. public function get_member_type_label() { 
  666. // Field 1 is always displayed to everyone, so never gets a label. 
  667. if ( 1 == $this->id ) { 
  668. return ''; 
  669.  
  670. // Return an empty string if no member types are registered. 
  671. $all_types = bp_get_member_types(); 
  672. if ( empty( $all_types ) ) { 
  673. return ''; 
  674.  
  675. $member_types = $this->get_member_types(); 
  676.  
  677. // If the field applies to all member types, show no message. 
  678. $all_types[] = 'null'; 
  679. if ( array_values( $all_types ) == $member_types ) { 
  680. return ''; 
  681.  
  682. $label = ''; 
  683. if ( ! empty( $member_types ) ) { 
  684. $has_null = false; 
  685. $member_type_labels = array(); 
  686. foreach ( $member_types as $member_type ) { 
  687. if ( 'null' === $member_type ) { 
  688. $has_null = true; 
  689. continue; 
  690. } else { 
  691. $mt_obj = bp_get_member_type_object( $member_type ); 
  692. $member_type_labels[] = $mt_obj->labels['name']; 
  693.  
  694. // Alphabetical sort. 
  695. natcasesort( $member_type_labels ); 
  696. $member_type_labels = array_values( $member_type_labels ); 
  697.  
  698. // Add the 'null' option to the end of the list. 
  699. if ( $has_null ) { 
  700. $member_type_labels[] = __( 'Users with no member type', 'buddypress' ); 
  701.  
  702. $label = sprintf( __( '(Member types: %s)', 'buddypress' ), implode( ', ', array_map( 'esc_html', $member_type_labels ) ) ); 
  703. } else { 
  704. $label = '<span class="member-type-none-notice">' . __( '(Unavailable to all members)', 'buddypress' ) . '</span>'; 
  705.  
  706. return $label; 
  707.  
  708. /** 
  709. * Get the field's default visibility setting. 
  710. * 
  711. * Lazy-loaded to reduce overhead. 
  712. * 
  713. * Defaults to 'public' if no visibility setting is found in the database. 
  714. * 
  715. * @since 2.4.0 
  716. * 
  717. * @return string 
  718. */ 
  719. public function get_default_visibility() { 
  720. if ( ! isset( $this->default_visibility ) ) { 
  721. $this->default_visibility = bp_xprofile_get_meta( $this->id, 'field', 'default_visibility' ); 
  722.  
  723. if ( ! $this->default_visibility ) { 
  724. $this->default_visibility = 'public'; 
  725.  
  726. return $this->default_visibility; 
  727.  
  728. /** 
  729. * Get whether the field's default visibility can be overridden by users. 
  730. * 
  731. * Lazy-loaded to reduce overhead. 
  732. * 
  733. * Defaults to 'allowed'. 
  734. * 
  735. * @since 4.4.0 
  736. * 
  737. * @return string 'disabled' or 'allowed'. 
  738. */ 
  739. public function get_allow_custom_visibility() { 
  740. if ( ! isset( $this->allow_custom_visibility ) ) { 
  741. $allow_custom_visibility = bp_xprofile_get_meta( $this->id, 'field', 'allow_custom_visibility' ); 
  742.  
  743. if ( 'disabled' === $allow_custom_visibility ) { 
  744. $this->allow_custom_visibility = 'disabled'; 
  745. } else { 
  746. $this->allow_custom_visibility = 'allowed'; 
  747.  
  748. return $this->allow_custom_visibility; 
  749.  
  750. /** 
  751. * Get whether the field values should be auto-linked to a directory search. 
  752. * 
  753. * Lazy-loaded to reduce overhead. 
  754. * 
  755. * Defaults to true for multi and default fields, false for single fields. 
  756. * 
  757. * @since 2.5.0 
  758. * 
  759. * @return bool 
  760. */ 
  761. public function get_do_autolink() { 
  762. if ( ! isset( $this->do_autolink ) ) { 
  763. $do_autolink = bp_xprofile_get_meta( $this->id, 'field', 'do_autolink' ); 
  764.  
  765. if ( '' === $do_autolink ) { 
  766. $this->do_autolink = $this->type_obj->supports_options; 
  767. } else { 
  768. $this->do_autolink = 'on' === $do_autolink; 
  769.  
  770. return $this->do_autolink; 
  771.  
  772. /** Static Methods ********************************************************/ 
  773.  
  774. /** 
  775. * Get the type for provided field ID. 
  776. * 
  777. * @param int $field_id Field ID to get type of. 
  778. * @return bool|null|string 
  779. */ 
  780. public static function get_type( $field_id = 0 ) { 
  781. global $wpdb; 
  782.  
  783. // Bail if no field ID. 
  784. if ( empty( $field_id ) ) { 
  785. return false; 
  786.  
  787. $bp = buddypress(); 
  788. $sql = $wpdb->prepare( "SELECT type FROM {$bp->profile->table_name_fields} WHERE id = %d", $field_id ); 
  789. $type = $wpdb->get_var( $sql ); 
  790.  
  791. // Return field type. 
  792. if ( ! empty( $type ) ) { 
  793. return $type; 
  794.  
  795. return false; 
  796.  
  797. /** 
  798. * Delete all fields in a field group. 
  799. * 
  800. * @since 1.2.0 
  801. * 
  802. * @global object $wpdb 
  803. * 
  804. * @param int $group_id ID of the field group to delete fields from. 
  805. * @return boolean 
  806. */ 
  807. public static function delete_for_group( $group_id = 0 ) { 
  808. global $wpdb; 
  809.  
  810. // Bail if no group ID. 
  811. if ( empty( $group_id ) ) { 
  812. return false; 
  813.  
  814. $bp = buddypress(); 
  815. $sql = $wpdb->prepare( "DELETE FROM {$bp->profile->table_name_fields} WHERE group_id = %d", $group_id ); 
  816. $deleted = $wpdb->get_var( $sql ); 
  817.  
  818. // Return true if fields were deleted. 
  819. if ( false !== $deleted ) { 
  820. return true; 
  821.  
  822. return false; 
  823.  
  824. /** 
  825. * Get field ID from field name. 
  826. * 
  827. * @since 1.5.0 
  828. * 
  829. * @global object $wpdb 
  830. * 
  831. * @param string $field_name Name of the field to query the ID for. 
  832. * @return int|null Field ID on success; null on failure. 
  833. */ 
  834. public static function get_id_from_name( $field_name = '' ) { 
  835. global $wpdb; 
  836.  
  837. $bp = buddypress(); 
  838.  
  839. if ( empty( $bp->profile->table_name_fields ) || empty( $field_name ) ) { 
  840. return false; 
  841.  
  842. $id = bp_core_get_incremented_cache( $field_name, 'bp_xprofile_fields_by_name' ); 
  843. if ( false === $id ) { 
  844. $sql = $wpdb->prepare( "SELECT id FROM {$bp->profile->table_name_fields} WHERE name = %s AND parent_id = 0", $field_name ); 
  845. $id = $wpdb->get_var( $sql ); 
  846. bp_core_set_incremented_cache( $field_name, 'bp_xprofile_fields_by_name', $id ); 
  847.  
  848. return is_numeric( $id ) ? (int) $id : $id; 
  849.  
  850. /** 
  851. * Update field position and/or field group when relocating. 
  852. * 
  853. * @since 1.5.0 
  854. * 
  855. * @global object $wpdb 
  856. * 
  857. * @param int $field_id ID of the field to update. 
  858. * @param int|null $position Field position to update. 
  859. * @param int|null $field_group_id ID of the field group. 
  860. * @return boolean 
  861. */ 
  862. public static function update_position( $field_id, $position = null, $field_group_id = null ) { 
  863. global $wpdb; 
  864.  
  865. // Bail if invalid position or field group. 
  866. if ( ! is_numeric( $position ) || ! is_numeric( $field_group_id ) ) { 
  867. return false; 
  868.  
  869. // Get table name and field parent. 
  870. $table_name = buddypress()->profile->table_name_fields; 
  871. $sql = $wpdb->prepare( "UPDATE {$table_name} SET field_order = %d, group_id = %d WHERE id = %d", $position, $field_group_id, $field_id ); 
  872. $parent = $wpdb->query( $sql ); 
  873.  
  874. // Update $field_id with new $position and $field_group_id. 
  875. if ( ! empty( $parent ) && ! is_wp_error( $parent ) ) { 
  876.  
  877. // Update any children of this $field_id. 
  878. $sql = $wpdb->prepare( "UPDATE {$table_name} SET group_id = %d WHERE parent_id = %d", $field_group_id, $field_id ); 
  879. $wpdb->query( $sql ); 
  880.  
  881. // Invalidate profile field cache. 
  882. wp_cache_delete( $field_id, 'bp_xprofile_fields' ); 
  883.  
  884. return $parent; 
  885.  
  886. return false; 
  887.  
  888. /** 
  889. * Gets the IDs of fields applicable for a given member type or array of member types. 
  890. * 
  891. * @since 2.4.0 
  892. * 
  893. * @param string|array $member_types Member type or array of member types. Use 'any' to return unrestricted 
  894. * fields (those available for anyone, regardless of member type). 
  895. * @return array Multi-dimensional array, with field IDs as top-level keys, and arrays of member types 
  896. * associated with each field as values. 
  897. */ 
  898. public static function get_fields_for_member_type( $member_types ) { 
  899. global $wpdb; 
  900.  
  901. $fields = array(); 
  902.  
  903. if ( empty( $member_types ) ) { 
  904. $member_types = array( 'any' ); 
  905. } elseif ( ! is_array( $member_types ) ) { 
  906. $member_types = array( $member_types ); 
  907.  
  908. $bp = buddypress(); 
  909.  
  910. // Pull up all recorded field member type data. 
  911. $mt_meta = wp_cache_get( 'field_member_types', 'bp_xprofile' ); 
  912. if ( false === $mt_meta ) { 
  913. $mt_meta = $wpdb->get_results( "SELECT object_id, meta_value FROM {$bp->profile->table_name_meta} WHERE meta_key = 'member_type' AND object_type = 'field'" ); 
  914. wp_cache_set( 'field_member_types', $mt_meta, 'bp_xprofile' ); 
  915.  
  916. // Keep track of all fields with recorded member_type metadata. 
  917. $all_recorded_field_ids = wp_list_pluck( $mt_meta, 'object_id' ); 
  918.  
  919. // Sort member_type matches in arrays, keyed by field_id. 
  920. foreach ( $mt_meta as $_mt_meta ) { 
  921. if ( ! isset( $fields[ $_mt_meta->object_id ] ) ) { 
  922. $fields[ $_mt_meta->object_id ] = array(); 
  923.  
  924. $fields[ $_mt_meta->object_id ][] = $_mt_meta->meta_value; 
  925.  
  926. /** 
  927. * Filter out fields that don't match any passed types, or those marked '_none'. 
  928. * The 'any' type is implicitly handled here: it will match no types. 
  929. */ 
  930. foreach ( $fields as $field_id => $field_types ) { 
  931. if ( ! array_intersect( $field_types, $member_types ) ) { 
  932. unset( $fields[ $field_id ] ); 
  933.  
  934. // Any fields with no member_type metadata are available to all member types. 
  935. if ( ! in_array( '_none', $member_types ) ) { 
  936. if ( ! empty( $all_recorded_field_ids ) ) { 
  937. $all_recorded_field_ids_sql = implode( ', ', array_map( 'absint', $all_recorded_field_ids ) ); 
  938. $unrestricted_field_ids = $wpdb->get_col( "SELECT id FROM {$bp->profile->table_name_fields} WHERE id NOT IN ({$all_recorded_field_ids_sql})" ); 
  939. } else { 
  940. $unrestricted_field_ids = $wpdb->get_col( "SELECT id FROM {$bp->profile->table_name_fields}" ); 
  941.  
  942. // Append the 'null' pseudo-type. 
  943. $all_member_types = bp_get_member_types(); 
  944. $all_member_types = array_values( $all_member_types ); 
  945. $all_member_types[] = 'null'; 
  946.  
  947. foreach ( $unrestricted_field_ids as $unrestricted_field_id ) { 
  948. $fields[ $unrestricted_field_id ] = $all_member_types; 
  949.  
  950. return $fields; 
  951.  
  952. /** 
  953. * Validate form field data on sumbission. 
  954. * 
  955. * @since 2.2.0 
  956. * 
  957. * @global $message 
  958. * 
  959. * @return boolean 
  960. */ 
  961. public static function admin_validate() { 
  962. global $message; 
  963.  
  964. // Check field name. 
  965. if ( ! isset( $_POST['title'] ) || ( '' === $_POST['title'] ) ) { 
  966. $message = esc_html__( 'Profile fields must have a name.', 'buddypress' ); 
  967. return false; 
  968.  
  969. // Check field requirement. 
  970. if ( ! isset( $_POST['required'] ) ) { 
  971. $message = esc_html__( 'Profile field requirement is missing.', 'buddypress' ); 
  972. return false; 
  973.  
  974. // Check field type. 
  975. if ( empty( $_POST['fieldtype'] ) ) { 
  976. $message = esc_html__( 'Profile field type is missing.', 'buddypress' ); 
  977. return false; 
  978.  
  979. // Check that field is of valid type. 
  980. if ( ! in_array( $_POST['fieldtype'], array_keys( bp_xprofile_get_field_types() ), true ) ) { 
  981. $message = sprintf( esc_html__( 'The profile field type %s is not registered.', 'buddypress' ), '<code>' . esc_attr( $_POST['fieldtype'] ) . '</code>' ); 
  982. return false; 
  983.  
  984. // Get field type so we can check for and lavidate any field options. 
  985. $field_type = bp_xprofile_create_field_type( $_POST['fieldtype'] ); 
  986.  
  987. // Field type requires options. 
  988. if ( true === $field_type->supports_options ) { 
  989.  
  990. // Build the field option key. 
  991. $option_name = sanitize_key( $_POST['fieldtype'] ) . '_option'; 
  992.  
  993. // Check for missing or malformed options. 
  994. if ( empty( $_POST[ $option_name ] ) || ! is_array( $_POST[ $option_name ] ) ) { 
  995. $message = esc_html__( 'These field options are invalid.', 'buddypress' ); 
  996. return false; 
  997.  
  998. // Trim out empty field options. 
  999. $field_values = array_values( $_POST[ $option_name ] ); 
  1000. $field_options = array_map( 'sanitize_text_field', $field_values ); 
  1001. $field_count = count( $field_options ); 
  1002.  
  1003. // Check for missing or malformed options. 
  1004. if ( 0 === $field_count ) { 
  1005. $message = sprintf( esc_html__( '%s require at least one option.', 'buddypress' ), $field_type->name ); 
  1006. return false; 
  1007.  
  1008. // If only one option exists, it cannot be an empty string. 
  1009. if ( ( 1 === $field_count ) && ( '' === $field_options[0] ) ) { 
  1010. $message = sprintf( esc_html__( '%s require at least one option.', 'buddypress' ), $field_type->name ); 
  1011. return false; 
  1012.  
  1013. return true; 
  1014.  
  1015. /** 
  1016. * Save miscellaneous settings for this field. 
  1017. * 
  1018. * Some field types have type-specific settings, which are saved here. 
  1019. * 
  1020. * @since 2.7.0 
  1021. * 
  1022. * @param array $settings Array of settings. 
  1023. */ 
  1024. public function admin_save_settings( $settings ) { 
  1025. return $this->type_obj->admin_save_settings( $this->id, $settings ); 
  1026.  
  1027. /** 
  1028. * Populates the items for radio buttons, checkboxes, and dropdown boxes. 
  1029. */ 
  1030. public function render_admin_form_children() { 
  1031. foreach ( array_keys( bp_xprofile_get_field_types() ) as $field_type ) { 
  1032. $type_obj = bp_xprofile_create_field_type( $field_type ); 
  1033. $type_obj->admin_new_field_html( $this ); 
  1034.  
  1035. /** 
  1036. * Oupput the admin form for this field. 
  1037. * 
  1038. * @since 1.9.0 
  1039. * 
  1040. * @param string $message Message to display. 
  1041. */ 
  1042. public function render_admin_form( $message = '' ) { 
  1043. if ( empty( $this->id ) ) { 
  1044. $title = __( 'Add New Field', 'buddypress' ); 
  1045. $action = "users.php?page=bp-profile-setup&group_id=" . $this->group_id . "&mode=add_field#tabs-" . $this->group_id; 
  1046. $button = __( 'Save', 'buddypress' ); 
  1047.  
  1048. if ( !empty( $_POST['saveField'] ) ) { 
  1049. $this->name = $_POST['title']; 
  1050. $this->description = $_POST['description']; 
  1051. $this->is_required = $_POST['required']; 
  1052. $this->type = $_POST['fieldtype']; 
  1053. $this->field_order = $_POST['field_order']; 
  1054.  
  1055. if ( ! empty( $_POST["sort_order_{$this->type}"] ) ) { 
  1056. $this->order_by = $_POST["sort_order_{$this->type}"]; 
  1057. } else { 
  1058. $title = __( 'Edit Field', 'buddypress' ); 
  1059. $action = "users.php?page=bp-profile-setup&mode=edit_field&group_id=" . $this->group_id . "&field_id=" . $this->id . "#tabs-" . $this->group_id; 
  1060. $button = __( 'Update', 'buddypress' ); 
  1061. } ?> 
  1062.  
  1063. <div class="wrap"> 
  1064.  
  1065. <h1><?php echo esc_html( $title ); ?></h1> 
  1066.  
  1067. <?php if ( !empty( $message ) ) : ?> 
  1068.  
  1069. <div id="message" class="error fade"> 
  1070. <p><?php echo esc_html( $message ); ?></p> 
  1071. </div> 
  1072.  
  1073. <?php endif; ?> 
  1074.  
  1075. <form id="bp-xprofile-add-field" action="<?php echo esc_url( $action ); ?>" method="post"> 
  1076. <div id="poststuff"> 
  1077. <div id="post-body" class="metabox-holder columns-<?php echo ( 1 == get_current_screen()->get_columns() ) ? '1' : '2'; ?>"> 
  1078. <div id="post-body-content"> 
  1079.  
  1080. <?php 
  1081.  
  1082. // Output the name & description fields. 
  1083. $this->name_and_description(); ?> 
  1084.  
  1085. </div><!-- #post-body-content --> 
  1086.  
  1087. <div id="postbox-container-1" class="postbox-container"> 
  1088.  
  1089. <?php 
  1090.  
  1091. // Output the sumbit metabox. 
  1092. $this->submit_metabox( $button ); 
  1093.  
  1094. // Output the required metabox. 
  1095. $this->required_metabox(); 
  1096.  
  1097. // Output the Member Types metabox. 
  1098. $this->member_type_metabox(); 
  1099.  
  1100. // Output the field visibility metaboxes. 
  1101. $this->visibility_metabox(); 
  1102.  
  1103. // Output the autolink metabox. 
  1104. $this->autolink_metabox(); 
  1105.  
  1106.  
  1107. /** 
  1108. * Fires after XProfile Field sidebar metabox. 
  1109. * 
  1110. * @since 2.2.0 
  1111. * 
  1112. * @param BP_XProfile_Field $this Current XProfile field. 
  1113. */ 
  1114. do_action( 'xprofile_field_after_sidebarbox', $this ); ?> 
  1115.  
  1116. </div> 
  1117.  
  1118. <div id="postbox-container-2" class="postbox-container"> 
  1119.  
  1120. <?php 
  1121.  
  1122. /** 
  1123. * Fires before XProfile Field content metabox. 
  1124. * 
  1125. * @since 2.3.0 
  1126. * 
  1127. * @param BP_XProfile_Field $this Current XProfile field. 
  1128. */ 
  1129. do_action( 'xprofile_field_before_contentbox', $this ); 
  1130.  
  1131. // Output the field attributes metabox. 
  1132. $this->type_metabox(); 
  1133.  
  1134. // Output hidden inputs for default field. 
  1135. $this->default_field_hidden_inputs(); 
  1136.  
  1137. /** 
  1138. * Fires after XProfile Field content metabox. 
  1139. * 
  1140. * @since 2.2.0 
  1141. * 
  1142. * @param BP_XProfile_Field $this Current XProfile field. 
  1143. */ 
  1144. do_action( 'xprofile_field_after_contentbox', $this ); ?> 
  1145.  
  1146. </div> 
  1147. </div><!-- #post-body --> 
  1148. </div><!-- #poststuff --> 
  1149. </form> 
  1150. </div> 
  1151.  
  1152. <?php 
  1153.  
  1154. /** 
  1155. * Private method used to display the submit metabox. 
  1156. * 
  1157. * @since 2.3.0 
  1158. * 
  1159. * @param string $button_text Text to put on button. 
  1160. */ 
  1161. private function submit_metabox( $button_text = '' ) { 
  1162.  
  1163. /** 
  1164. * Fires before XProfile Field submit metabox. 
  1165. * 
  1166. * @since 2.1.0 
  1167. * 
  1168. * @param BP_XProfile_Field $this Current XProfile field. 
  1169. */ 
  1170. do_action( 'xprofile_field_before_submitbox', $this ); ?> 
  1171.  
  1172. <div id="submitdiv" class="postbox"> 
  1173. <h2><?php esc_html_e( 'Submit', 'buddypress' ); ?></h2> 
  1174. <div class="inside"> 
  1175. <div id="submitcomment" class="submitbox"> 
  1176. <div id="major-publishing-actions"> 
  1177.  
  1178. <?php 
  1179.  
  1180. /** 
  1181. * Fires at the beginning of the XProfile Field publishing actions section. 
  1182. * 
  1183. * @since 2.1.0 
  1184. * 
  1185. * @param BP_XProfile_Field $this Current XProfile field. 
  1186. */ 
  1187. do_action( 'xprofile_field_submitbox_start', $this ); ?> 
  1188.  
  1189. <input type="hidden" name="field_order" id="field_order" value="<?php echo esc_attr( $this->field_order ); ?>" /> 
  1190.  
  1191. <?php if ( ! empty( $button_text ) ) : ?> 
  1192.  
  1193. <div id="publishing-action"> 
  1194. <input type="submit" name="saveField" value="<?php echo esc_attr( $button_text ); ?>" class="button-primary" /> 
  1195. </div> 
  1196.  
  1197. <?php endif; ?> 
  1198.  
  1199. <div id="delete-action"> 
  1200. <a href="users.php?page=bp-profile-setup" class="deletion"><?php esc_html_e( 'Cancel', 'buddypress' ); ?></a> 
  1201. </div> 
  1202.  
  1203. <?php wp_nonce_field( 'xprofile_delete_option' ); ?> 
  1204.  
  1205. <div class="clear"></div> 
  1206. </div> 
  1207. </div> 
  1208. </div> 
  1209. </div> 
  1210.  
  1211. <?php 
  1212.  
  1213. /** 
  1214. * Fires after XProfile Field submit metabox. 
  1215. * 
  1216. * @since 2.1.0 
  1217. * 
  1218. * @param BP_XProfile_Field $this Current XProfile field. 
  1219. */ 
  1220. do_action( 'xprofile_field_after_submitbox', $this ); 
  1221.  
  1222. /** 
  1223. * Private method used to output field name and description fields. 
  1224. * 
  1225. * @since 2.3.0 
  1226. */ 
  1227. private function name_and_description() { 
  1228. ?> 
  1229.  
  1230. <div id="titlediv"> 
  1231. <div class="titlewrap"> 
  1232. <label id="title-prompt-text" for="title"><?php echo esc_html_x( 'Name (required)', 'XProfile admin edit field', 'buddypress' ); ?></label> 
  1233. <input type="text" name="title" id="title" value="<?php echo esc_attr( $this->name ); ?>" autocomplete="off" /> 
  1234. </div> 
  1235. </div> 
  1236.  
  1237. <div class="postbox"> 
  1238. <h2><?php echo esc_html_x( 'Description', 'XProfile admin edit field', 'buddypress' ); ?></h2> 
  1239. <div class="inside"> 
  1240. <label for="description" class="screen-reader-text"><?php 
  1241. /** translators: accessibility text */ 
  1242. esc_html_e( 'Add description', 'buddypress' ); 
  1243. ?></label> 
  1244. <textarea name="description" id="description" rows="8" cols="60"><?php echo esc_textarea( $this->description ); ?></textarea> 
  1245. </div> 
  1246. </div> 
  1247.  
  1248. <?php 
  1249.  
  1250. /** 
  1251. * Private method used to output field Member Type metabox. 
  1252. * 
  1253. * @since 2.4.0 
  1254. */ 
  1255. private function member_type_metabox() { 
  1256.  
  1257. // The primary field is for all, so bail. 
  1258. if ( 1 === (int) $this->id ) { 
  1259. return; 
  1260.  
  1261. // Bail when no member types are registered. 
  1262. if ( ! $member_types = bp_get_member_types( array(), 'objects' ) ) { 
  1263. return; 
  1264.  
  1265. $field_member_types = $this->get_member_types(); 
  1266.  
  1267. ?> 
  1268.  
  1269. <div id="member-types-div" class="postbox"> 
  1270. <h2><?php _e( 'Member Types', 'buddypress' ); ?></h2> 
  1271. <div class="inside"> 
  1272. <p class="description"><?php _e( 'This field should be available to:', 'buddypress' ); ?></p> 
  1273.  
  1274. <ul> 
  1275. <?php foreach ( $member_types as $member_type ) : ?> 
  1276. <li> 
  1277. <label for="member-type-<?php echo $member_type->labels['name']; ?>"> 
  1278. <input name="member-types[]" id="member-type-<?php echo $member_type->labels['name']; ?>" class="member-type-selector" type="checkbox" value="<?php echo $member_type->name; ?>" <?php checked( in_array( $member_type->name, $field_member_types ) ); ?>/> 
  1279. <?php echo $member_type->labels['name']; ?> 
  1280. </label> 
  1281. </li> 
  1282. <?php endforeach; ?> 
  1283.  
  1284. <li> 
  1285. <label for="member-type-none"> 
  1286. <input name="member-types[]" id="member-type-none" class="member-type-selector" type="checkbox" value="null" <?php checked( in_array( 'null', $field_member_types ) ); ?>/> 
  1287. <?php _e( 'Users with no member type', 'buddypress' ); ?> 
  1288. </label> 
  1289. </li> 
  1290.  
  1291. </ul> 
  1292. <p class="description member-type-none-notice<?php if ( ! empty( $field_member_types ) ) : ?> hide<?php endif; ?>"><?php _e( 'Unavailable to all members.', 'buddypress' ) ?></p> 
  1293. </div> 
  1294.  
  1295. <input type="hidden" name="has-member-types" value="1" /> 
  1296. </div> 
  1297.  
  1298. <?php 
  1299.  
  1300. /** 
  1301. * Private method used to output field visibility metaboxes. 
  1302. * 
  1303. * @since 2.3.0 
  1304. * 
  1305. * @return void If default field id 1. 
  1306. */ 
  1307. private function visibility_metabox() { 
  1308.  
  1309. // Default field cannot have custom visibility. 
  1310. if ( true === $this->is_default_field() ) { 
  1311. return; 
  1312. } ?> 
  1313.  
  1314. <div class="postbox"> 
  1315. <h2><label for="default-visibility"><?php esc_html_e( 'Visibility', 'buddypress' ); ?></label></h2> 
  1316. <div class="inside"> 
  1317. <div> 
  1318. <select name="default-visibility" id="default-visibility"> 
  1319.  
  1320. <?php foreach( bp_xprofile_get_visibility_levels() as $level ) : ?> 
  1321.  
  1322. <option value="<?php echo esc_attr( $level['id'] ); ?>" <?php selected( $this->get_default_visibility(), $level['id'] ); ?>> 
  1323. <?php echo esc_html( $level['label'] ); ?> 
  1324. </option> 
  1325.  
  1326. <?php endforeach ?> 
  1327.  
  1328. </select> 
  1329. </div> 
  1330.  
  1331. <div> 
  1332. <ul> 
  1333. <li> 
  1334. <input type="radio" id="allow-custom-visibility-allowed" name="allow-custom-visibility" value="allowed" <?php checked( $this->get_allow_custom_visibility(), 'allowed' ); ?> /> 
  1335. <label for="allow-custom-visibility-allowed"><?php esc_html_e( 'Allow members to override', 'buddypress' ); ?></label> 
  1336. </li> 
  1337. <li> 
  1338. <input type="radio" id="allow-custom-visibility-disabled" name="allow-custom-visibility" value="disabled" <?php checked( $this->get_allow_custom_visibility(), 'disabled' ); ?> /> 
  1339. <label for="allow-custom-visibility-disabled"><?php esc_html_e( 'Enforce field visibility', 'buddypress' ); ?></label> 
  1340. </li> 
  1341. </ul> 
  1342. </div> 
  1343. </div> 
  1344. </div> 
  1345.  
  1346. <?php 
  1347.  
  1348. /** 
  1349. * Output the metabox for setting if field is required or not. 
  1350. * 
  1351. * @since 2.3.0 
  1352. * 
  1353. * @return void If default field. 
  1354. */ 
  1355. private function required_metabox() { 
  1356.  
  1357. // Default field is always required. 
  1358. if ( true === $this->is_default_field() ) { 
  1359. return; 
  1360. } ?> 
  1361.  
  1362. <div class="postbox"> 
  1363. <h2><label for="required"><?php esc_html_e( 'Requirement', 'buddypress' ); ?></label></h2> 
  1364. <div class="inside"> 
  1365. <select name="required" id="required"> 
  1366. <option value="0"<?php selected( $this->is_required, '0' ); ?>><?php esc_html_e( 'Not Required', 'buddypress' ); ?></option> 
  1367. <option value="1"<?php selected( $this->is_required, '1' ); ?>><?php esc_html_e( 'Required', 'buddypress' ); ?></option> 
  1368. </select> 
  1369. </div> 
  1370. </div> 
  1371.  
  1372. <?php 
  1373.  
  1374. /** 
  1375. * Private method used to output autolink metabox. 
  1376. * 
  1377. * @since 2.5.0 
  1378. * 
  1379. * @return void If default field id 1. 
  1380. */ 
  1381. private function autolink_metabox() { 
  1382. ?> 
  1383.  
  1384. <div class="postbox"> 
  1385. <h2><?php esc_html_e( 'Autolink', 'buddypress' ); ?></h2> 
  1386. <div class="inside"> 
  1387. <p class="description"><?php esc_html_e( 'On user profiles, link this field to a search of the Members directory, using the field value as a search term.', 'buddypress' ); ?></p> 
  1388.  
  1389. <p> 
  1390. <label for="do-autolink" class="screen-reader-text"><?php 
  1391. /** translators: accessibility text */ 
  1392. esc_html_e( 'Autolink status for this field', 'buddypress' ); 
  1393. ?></label> 
  1394. <select name="do_autolink" id="do-autolink"> 
  1395. <option value="on" <?php selected( $this->get_do_autolink() ); ?>><?php esc_html_e( 'Enabled', 'buddypress' ); ?></option> 
  1396. <option value="" <?php selected( $this->get_do_autolink(), false ); ?>><?php esc_html_e( 'Disabled', 'buddypress' ); ?></option> 
  1397. </select> 
  1398. </p> 
  1399. </div> 
  1400. </div> 
  1401.  
  1402. <?php 
  1403.  
  1404. /** 
  1405. * Output the metabox for setting what type of field this is. 
  1406. * 
  1407. * @since 2.3.0 
  1408. * 
  1409. * @return void If default field. 
  1410. */ 
  1411. private function type_metabox() { 
  1412.  
  1413. // Default field cannot change type. 
  1414. if ( true === $this->is_default_field() ) { 
  1415. return; 
  1416. } ?> 
  1417.  
  1418. <div class="postbox"> 
  1419. <h2><label for="fieldtype"><?php esc_html_e( 'Type', 'buddypress'); ?></label></h2> 
  1420. <div class="inside" aria-live="polite" aria-atomic="true" aria-relevant="all"> 
  1421. <select name="fieldtype" id="fieldtype" onchange="show_options(this.value)"> 
  1422.  
  1423. <?php bp_xprofile_admin_form_field_types( $this->type ); ?> 
  1424.  
  1425. </select> 
  1426.  
  1427. <?php 
  1428.  
  1429. // Deprecated filter, don't use. Go look at {@link BP_XProfile_Field_Type::admin_new_field_html()}. 
  1430. do_action( 'xprofile_field_additional_options', $this ); 
  1431.  
  1432. $this->render_admin_form_children(); ?> 
  1433.  
  1434. </div> 
  1435. </div> 
  1436.  
  1437. <?php 
  1438.  
  1439. /** 
  1440. * Output hidden fields used by default field. 
  1441. * 
  1442. * @since 2.3.0 
  1443. * 
  1444. * @return void If not default field. 
  1445. */ 
  1446. private function default_field_hidden_inputs() { 
  1447.  
  1448. // Field 1 is the fullname field, which cannot have custom visibility. 
  1449. if ( false === $this->is_default_field() ) { 
  1450. return; 
  1451. } ?> 
  1452.  
  1453. <input type="hidden" name="required" id="required" value="1" /> 
  1454. <input type="hidden" name="fieldtype" id="fieldtype" value="textbox" /> 
  1455.  
  1456. <?php 
  1457.  
  1458. /** 
  1459. * Return if a field ID is the default field. 
  1460. * 
  1461. * @since 2.3.0 
  1462. * 
  1463. * @param int $field_id ID of field to check. 
  1464. * @return bool 
  1465. */ 
  1466. private function is_default_field( $field_id = 0 ) { 
  1467.  
  1468. // Fallback to current field ID if none passed. 
  1469. if ( empty( $field_id ) ) { 
  1470. $field_id = $this->id; 
  1471.  
  1472. // Compare & return. 
  1473. return (bool) ( 1 === (int) $field_id ); 
.