+ name = $name;
+ $this->label = $label;
+ $this->description = $description;
+ }
+
+ /**
+ * Magic getter for read-only properties.
+ *
+ * @param string $name The property name.
+ * @return mixed The property value.
+ */
+ public function __get( $name ) {
+ if ( isset( $this->$name ) ) {
+ return $this->$name;
+ }
+
+ return null;
+ }
+
+ /**
+ * Add a field group.
+ *
+ * @since TBD
+ *
+ * @param string $name The name of the field group.
+ * @param string|null $label The label for the field group. If NULL, a cleaned version of the name will be used.
+ * @param string $description The description for the field group.
+ *
+ * @return PMPro_Field_Group The field group object.
+ */
+ public static function add( $name, $label = NULL, $description = '' ) {
+ global $pmpro_field_groups;
+
+ // If the field group already exists, update the label and description.
+ if ( ! empty( $pmpro_field_groups[ $name ] ) ) { // Looking at global to avoid infinite loop when a group doesn't exist.
+ $existing_field_group = self::get( $name );
+ $existing_field_group->label = $label;
+ $existing_field_group->description = $description;
+
+ return $existing_field_group;
+ }
+
+ // If no label is provided, use the name.
+ if ( empty( $label ) ) {
+ if ( $name === 'checkout_boxes' ) {
+ apply_filters( 'pmpro_default_field_group_label', __( 'More Information','paid-memberships-pro' ) );
+ } else {
+ $label = ucwords( str_replace( '_', ' ', $name ) );
+ }
+ }
+
+ // Create a new field group object.
+ $field_group = new PMPro_Field_Group( $name, $label, $description );
+
+ // Add the field group to the global array.
+ $pmpro_field_groups[ $name ] = $field_group;
+
+ return $field_group;
+ }
+
+ /**
+ * Get all added field groups.
+ *
+ * @since TBD
+ *
+ * @return array An array of PMPro_Field_Group objects.
+ */
+ public static function get_all() {
+ global $pmpro_field_groups;
+
+ if ( empty( $pmpro_field_groups ) ) {
+ $pmpro_field_groups = array();
+ }
+
+ return $pmpro_field_groups;
+ }
+
+ /**
+ * Get an added field group by name.
+ *
+ * @since TBD
+ *
+ * @param string $name The name of the field group.
+ * @return PMPro_Field_Group The field group object.
+ */
+ public static function get( $name ) {
+ // Get all field groups.
+ $field_groups = self::get_all();
+
+ // If we don't yet have the field group, create it.
+ if ( empty( $field_groups[ $name ] ) ) {
+ return self::add( $name );
+ }
+
+ // Return the field group.
+ return $field_groups[ $name ];
+ }
+
+ /**
+ * Get the field group for a field.
+ *
+ * @since TBD
+ *
+ * @param PMPro_Field $field The field object.
+ * @return PMPro_Field_Group|null The field group object, or NULL if the field is not in a group.
+ */
+ public static function get_group_for_field( $field ) {
+ global $pmpro_field_groups;
+
+ if ( empty( $pmpro_field_groups ) ) {
+ $pmpro_field_groups = array();
+ }
+
+ foreach ( $pmpro_field_groups as $field_group ) {
+ $group_fields = $field_group->get_fields();
+ foreach( $group_fields as $group_field ) {
+ if ( $group_field->name === $field->name ) {
+ return $field_group;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Get a field by name.
+ *
+ * @since TBD
+ *
+ * @param string $name The name of the field.
+ * @return PMPro_Field|null The field object, or NULL if the field is not in a group.
+ */
+ public static function get_field( $name ) {
+ global $pmpro_user_fields;
+
+ if ( empty( $pmpro_user_fields ) ) {
+ $pmpro_user_fields = array();
+ }
+
+ foreach ( $pmpro_user_fields as $group_name => $fields ) {
+ if ( isset( $fields[ $name ] ) ) {
+ return $fields[ $name ];
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Add a field to this field group.
+ *
+ * @since TBD
+ *
+ * @param PMPro_Field $field The field object to add.
+ * @return bool True if the field was added, otherwise false.
+ */
+ public function add_field( $field ) {
+ global $pmpro_user_fields;
+ if ( empty( $pmpro_user_fields ) ) {
+ $pmpro_user_fields = array();
+ }
+
+ /**
+ * Filter the field to add.
+ *
+ * @since 2.9.3
+ *
+ * @param PMProField $field The field being added.
+ * @param string $group_name The name of the group to add the field to.
+ */
+ $field = apply_filters( 'pmpro_add_user_field', $field, $this->name );
+
+ // Make sure that we have a valid field.
+ if ( empty( $field ) || ! pmpro_is_field( $field ) ) {
+ return false;
+ }
+
+ // Make sure the group is in the global array of fields.
+ if ( empty( $pmpro_user_fields[ $this->name ] ) ) {
+ $pmpro_user_fields[ $this->name ] = array();
+ }
+
+ // Add the field to the group.
+ $pmpro_user_fields[ $this->name ][ $field->name ] = $field;
+
+ return true;
+ }
+
+ /**
+ * Get all fields in this field group.
+ *
+ * @since TBD
+ *
+ * @return array An array of PMPro_Field objects.
+ */
+ public function get_fields() {
+ global $pmpro_user_fields;
+ if ( empty( $pmpro_user_fields ) ) {
+ $pmpro_user_fields = array();
+ }
+
+ if ( empty( $pmpro_user_fields[ $this->name ] ) ) {
+ $pmpro_user_fields[ $this->name ] = array();
+ }
+
+ return $pmpro_user_fields[ $this->name ];
+ }
+
+ /**
+ * Get all fields to display in a specific context.
+ *
+ * @since TBD
+ *
+ * @param array $args The arguments for getting the fields.
+ */
+ public function get_fields_to_display( $args = array() ) {
+ $default_args = array(
+ 'scope' => 'profile', // The scope of the fields to show. Can be 'profile' or 'checkout'.
+ 'user_id' => NULL, // The user ID to show the users for. If null, we are showing fields for the current user.
+ );
+ $args = wp_parse_args( $args, $default_args );
+
+ // Get all fields in this group.
+ $fields = $this->get_fields();
+
+ // Get the user ID.
+ $user_id = empty( $args['user_id'] ) ? get_current_user_id() : $args['user_id'];
+
+ // Get a list of the fields that should be displayed.
+ $fields_to_display = array();
+ foreach ( $fields as $field ) {
+ // Validate the field for scope.
+ if ( 'checkout' === $args['scope'] ) {
+ // At checkout.
+ // Check if this field should only be shown in the profile.
+ if ( in_array( $field->profile, array( 'only', 'only_admin' ), true ) ) {
+ continue;
+ }
+
+ // Check if this field is for the level being purchased.
+ // Get the checkout level.
+ $checkout_level = pmpro_getLevelAtCheckout();
+ $chekcout_level_id = ! empty( $checkout_level->id ) ? (int)$checkout_level->id : NULL;
+ if ( empty( $chekcout_level_id ) ) {
+ continue;
+ }
+ if ( ! empty( $field->levels ) && ! in_array( (int) $chekcout_level_id, $field->levels, true ) ) {
+ continue;
+ }
+ } else {
+ // In profile.
+ // Check if this field should ever be shown in the profile.
+ if ( empty( $field->profile ) ) {
+ continue;
+ }
+
+ // Check if this field should only be shown to admins.
+ if ( ( ! current_user_can( 'manage_options' ) && ! current_user_can( 'pmpro_membership_manager' ) ) && in_array( $field->profile, array( 'admins', 'admin', 'only_admin' ), true ) ) {
+ continue;
+ }
+
+ // Check if the user has a level required for this field.
+ if ( ! empty( $field->levels ) && ! pmpro_hasMembershipLevel( $field->levels, $user_id ) ) {
+ continue;
+ }
+ }
+
+ // Add the field to the list of fields to display.
+ $fields_to_display[] = $field;
+ }
+
+ return $fields_to_display;
+ }
+
+ /**
+ * Display the field group.
+ *
+ * @since TBD
+ *
+ * @param array $args The arguments for displaying the fields.
+ */
+ public function display( $args = array() ) {
+ $default_args = array(
+ 'markup' => 'card', // The markup to use for the field group. Can be 'card', 'div' or 'table'.
+ 'scope' => 'profile', // The scope of the fields to show. Can be 'profile' or 'checkout'.
+ 'show_group_label' => true, // Whether or not to show the field group.
+ 'prefill_from_request' => false, // Whether or not to prefill the field values from the $_REQUEST array.
+ 'show_required' => false, // Whether or not to show required fields.
+ 'user_id' => NULL, // The user ID to show the users for. If null, we are showing fields for the current user.
+ );
+ $args = wp_parse_args( $args, $default_args );
+
+ // Get the user ID.
+ $user_id = empty( $args['user_id'] ) ? get_current_user_id() : $args['user_id'];
+
+ // Get the fields to display.
+ $fields_to_display = $this->get_fields_to_display( $args );
+
+ // If we don't have any fields to display, don't display the group.
+ if ( empty( $fields_to_display ) ) {
+ return;
+ }
+
+ // Display the field group.
+ if ( empty( $args['show_group_label'] ) ) {
+ $group_header = '';
+ $group_footer = '';
+ } elseif ( $args['markup'] === 'card' ) {
+ // Get the "header" for the field group.
+ ob_start();
+ ?>
+
+
+
+
+
+
label ); ?>
+ description ) ) {
+ ?>
+
description ); ?>
+
+
+
+
+ get_value_from_request() ) {
+ $value = $field->get_value_from_request();
+ } elseif ( ! empty( $user_id ) && metadata_exists( 'user', $user_id, $field->meta_key ) ) {
+ $value = get_user_meta( $user_id, $field->meta_key, true );
+ } elseif ( ! empty( $user_id ) ) {
+ $userdata = get_userdata( $user_id );
+ if ( ! empty( $userdata->{$field->name} ) ) {
+ $value = $userdata->{$field->name};
+ } elseif(isset($field->value)) {
+ $value = $field->value;
+ }
+ } elseif(isset($field->value)) {
+ $value = $field->value;
+ }
+
+ if ( $args['markup'] === 'div' || $args['markup'] === 'card' ) {
+ // Fix divclass.
+ if ( ! empty( $field->divclass ) ) {
+ $field->divclass .= " ";
+ }
+
+ // Add a class to the field based on the type.
+ $field->divclass .= "pmpro_form_field pmpro_form_field-" . $field->type;
+ $field->class .= " pmpro_form_input-" . $field->type;
+
+ // Add the required class to field.
+ if ( ! empty( $args['show_required'] ) && ! empty( $field->required ) ) {
+ $field->divclass .= " pmpro_form_field-required";
+ $field->class .= " pmpro_form_input-required";
+ }
+
+ // Add the class to not show a field is required if set.
+ if ( ! empty( $args['show_required'] ) && ( empty( $field->showrequired ) || is_string( $field->showrequired ) ) ) {
+ $field->divclass .= " pmpro_form_field-hide-required";
+ }
+
+ // Run the class through the filter.
+ $field->divclass = pmpro_get_element_class( $field->divclass );
+ $field->class = pmpro_get_element_class( $field->class );
+
+ ?>
+
+ 'profile', // The scope of the fields to save. Can be 'profile' or 'checkout'.
+ 'user_id' => NULL, // The user ID to save the users for. If null, we are saving fields for the current user.
+ );
+ $args = wp_parse_args( $args, $default_args );
+
+ // Get the user ID if needed.
+ $user_id = empty( $args['user_id'] ) ? get_current_user_id() : $args['user_id'];
+
+ // Make sure the current user can edit this user.
+ if ( 'scope' == 'profile' && ! current_user_can( 'edit_user', $user_id ) ) {
+ return false;
+ }
+
+ // Get the fields to display.
+ $fields_to_display = $this->get_fields_to_display( $args );
+
+ // Save the fields.
+ foreach ( $fields_to_display as $field ) {
+ $field->save_field_for_user( $user_id );
+ }
+
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/classes/class-pmpro-field.php b/classes/class-pmpro-field.php
index b23fa1009..50b0984e7 100755
--- a/classes/class-pmpro-field.php
+++ b/classes/class-pmpro-field.php
@@ -10,7 +10,7 @@ class PMPro_Field {
*
* @var string
*/
- public $name = '';
+ private $name = '';
/**
* The type of field that this is.
@@ -19,7 +19,7 @@ class PMPro_Field {
*
* @var string
*/
- public $type = '';
+ private $type = '';
/**
* The meta key for this field.
@@ -30,7 +30,7 @@ class PMPro_Field {
*
* @var string
*/
- public $meta_key = '';
+ private $meta_key = '';
/**
* The label of the field.
@@ -41,7 +41,7 @@ class PMPro_Field {
*
* @var string
*/
- public $label = '';
+ private $label = '';
/**
* Whether the label should be shown.
@@ -50,7 +50,7 @@ class PMPro_Field {
*
* @var bool
*/
- public $showmainlabel = true;
+ private $showmainlabel = true;
/**
* A hint to be displayed with the field.
@@ -59,7 +59,7 @@ class PMPro_Field {
*
* @var string
*/
- public $hint = '';
+ private $hint = '';
/**
* The membership levels that this field should be displayed for.
@@ -68,7 +68,7 @@ class PMPro_Field {
*
* @var array
*/
- public $levels = array();
+ private $levels = array();
/**
* Whether the field is required.
@@ -77,7 +77,7 @@ class PMPro_Field {
*
* @var bool
*/
- public $required = false;
+ private $required = false;
/**
* Whether the field should be shown as required if $required is set to true.
@@ -86,7 +86,7 @@ class PMPro_Field {
*
* @var bool
*/
- public $showrequired = true;
+ private $showrequired = true;
/**
* Where this field should be shown.
@@ -97,7 +97,7 @@ class PMPro_Field {
*
* @var mixed
*/
- public $profile = true;
+ private $profile = true;
/**
* Whether the field is readonly.
@@ -106,7 +106,7 @@ class PMPro_Field {
*
* @var bool
*/
- public $readonly = false;
+ private $readonly = false;
/**
* Array to define conditions when a field should be shown or hidden.
@@ -115,7 +115,7 @@ class PMPro_Field {
*
* @var array
*/
- public $depends = array();
+ private $depends = array();
/**
* Flag to determine if depends conditions should be ANDed or ORed together.
@@ -124,7 +124,7 @@ class PMPro_Field {
*
* @var bool
*/
- public $depends_or = false;
+ private $depends_or = false;
/**
* Whether the field value should be sanitized before saving.
@@ -133,7 +133,7 @@ class PMPro_Field {
*
* @var bool
*/
- public $sanitize = true;
+ private $sanitize = true;
/**
* The ID to show for the field.
@@ -142,7 +142,7 @@ class PMPro_Field {
*
* @var string
*/
- public $id = '';
+ private $id = '';
/**
* Class for the input field.
@@ -151,7 +151,7 @@ class PMPro_Field {
*
* @var string
*/
- public $class = '';
+ private $class = '';
/**
* Class for the div wrapper for the input field.
@@ -160,7 +160,7 @@ class PMPro_Field {
*
* @var string
*/
- public $divclass = '';
+ private $divclass = '';
/**
* Whether this field should be included in a members list CSV export.
@@ -169,7 +169,7 @@ class PMPro_Field {
*
* @var bool
*/
- public $memberslistcsv = false;
+ private $memberslistcsv = false;
/**
* The save function that should be used for this field.
@@ -180,7 +180,7 @@ class PMPro_Field {
*
* @var callable
*/
- public $save_function = null;
+ private $save_function = null;
/**
* Whether this field should be shown when adding a member using
@@ -190,7 +190,7 @@ class PMPro_Field {
*
* @var bool
*/
- public $addmember = false;
+ private $addmember = false;
/**
* The size attribute when using a text input field type.
@@ -199,7 +199,7 @@ class PMPro_Field {
*
* @var int
*/
- public $size = 30;
+ private $size = 30;
/**
* The number of rows to show when using a textarea field type.
@@ -208,7 +208,7 @@ class PMPro_Field {
*
* @var int
*/
- public $rows = 5;
+ private $rows = 5;
/**
* The number of columns to show when using a textarea field type.
@@ -217,7 +217,7 @@ class PMPro_Field {
*
* @var int
*/
- public $cols = 80;
+ private $cols = 80;
/**
* The options for a select, select2, multiselect, checkbox_grouped, or radio field type.
@@ -226,7 +226,7 @@ class PMPro_Field {
*
* @var array
*/
- public $options = array();
+ private $options = array();
/**
* Whether multiple options should be selectable when using a select, select2, or multiselect field type.
@@ -235,7 +235,7 @@ class PMPro_Field {
*
* @var bool
*/
- public $multiple = false;
+ private $multiple = false;
/**
* The text to show next to a checkbox when using a checkbox field type.
@@ -244,7 +244,7 @@ class PMPro_Field {
*
* @var string
*/
- public $text = '';
+ private $text = '';
/**
* The HTML to show for an HTML field type.
@@ -253,7 +253,7 @@ class PMPro_Field {
*
* @var string
*/
- public $html = '';
+ private $html = '';
/**
* The default value for a field.
@@ -262,7 +262,7 @@ class PMPro_Field {
*
* @var string
*/
- public $default = '';
+ private $default = '';
/**
* File upload types.
@@ -272,7 +272,7 @@ class PMPro_Field {
* @var string
*
*/
- public $allowed_file_types = '';
+ private $allowed_file_types = '';
/**
* File upload limit
@@ -281,7 +281,7 @@ class PMPro_Field {
*
* @var int
*/
- public $max_file_size = '';
+ private $max_file_size = '';
function __construct($name = NULL, $type = NULL, $attr = NULL) {
if ( ! empty( $name ) )
@@ -290,6 +290,137 @@ function __construct($name = NULL, $type = NULL, $attr = NULL) {
return true;
}
+ /**
+ * Magic getter to allow reading private class properties.
+ *
+ * @param string $name The property name.
+ * @return mixed The property value.
+ */
+ function __get( $name ) {
+ if ( isset( $this->$name ) ) {
+ if ( ! $this->is_valid_property( $name ) ) {
+ _doing_it_wrong( __FUNCTION__, sprintf( esc_html__( 'The property %s is not valid for the field type %s.', 'paid-memberships-pro' ), $name, $this->type ), 'TBD' );
+ }
+ return $this->$name;
+ } else {
+ _doing_it_wrong( __FUNCTION__, sprintf( esc_html__( 'The property %s does not exist.', 'paid-memberships-pro' ), $name ), 'TBD' );
+ }
+
+ return null;
+ }
+
+ /**
+ * Magic setter to allow setting private class properties and
+ * throwing warnings when we want to phase out a property.
+ *
+ * @param string $name The property name.
+ * @param mixed $value The property value.
+ */
+ function __set( $name, $value ) {
+ if ( 'type' === $name ) {
+ _doing_it_wrong( __FUNCTION__, esc_html__( 'PMPro_Field properties should not be modified directly and may break in a future version. Instead, create a new PMPro_Field object.', 'paid-memberships-pro' ), 'TBD' );
+ }
+
+ $this->$name = $value;
+ }
+
+ /**
+ * Magic isset to check if a private class property is set.
+ *
+ * @param string $name The property name.
+ * @return bool Whether the property is set.
+ */
+ function __isset( $name ) {
+ return isset( $this->$name );
+ }
+
+ /**
+ * Magic __call to allow calling private class methods and throwing warnings
+ * when we want to phase out a method.
+ */
+ function __call( $name, $arguments ) {
+ switch( $name ) {
+ case 'set':
+ _doing_it_wrong( __FUNCTION__, sprintf( esc_html__( 'The method %s of PMPro_Field has become private and will not be available in a future version. Instead, use the $args property of the constructor when creating a new PMPro_Field object.', 'paid-memberships-pro' ), $name ), 'TBD' );
+ break;
+ case 'saveUsersTable':
+ case 'saveTermRelationshipsTable':
+ case 'saveFile':
+ _doing_it_wrong( __FUNCTION__, sprintf( esc_html__( 'The method %s of PMPro_Field has become private and will not be available in a future version. Instead, use the save_field_for_user method of the PMPro_Field object.', 'paid-memberships-pro' ), $name ), 'TBD' );
+ break;
+ case 'getHTML':
+ case 'getDependenciesJS':
+ _doing_it_wrong( __FUNCTION__, sprintf( esc_html__( 'The method %s of PMPro_Field has become private and will not be available in a future version. Instead, use the display() method of the PMPro_Field object.', 'paid-memberships-pro' ), $name ), 'TBD' );
+ break;
+ default:
+ _doing_it_wrong( __FUNCTION__, sprintf( esc_html__( 'The method %s of PMPro_Field has become private and will not be available in a future version.', 'paid-memberships-pro' ), $name ), 'TBD' );
+ break;
+ }
+ return call_user_func( array( $this, $name ), $arguments );
+ }
+
+ /**
+ * Check if a property should be present for the current field type.
+ *
+ * @since TBD
+ *
+ * @param string $property The property to check.
+ * return bool Whether the property is valid for the field type.
+ */
+ private function is_valid_property( $property ) {
+ switch ( $property ) {
+ case 'name':
+ case 'type':
+ case 'meta_key':
+ case 'label':
+ case 'showmainlabel':
+ case 'hint':
+ case 'levels':
+ case 'required':
+ case 'showrequired':
+ case 'profile':
+ case 'readonly':
+ case 'depends':
+ case 'depends_or':
+ case 'sanitize':
+ case 'id':
+ case 'class':
+ case 'divclass':
+ case 'memberslistcsv':
+ case 'save_function':
+ case 'addmember':
+ case 'default':
+ return true;
+ break;
+ case 'size':
+ return in_array( $this->type, array( 'text', 'number' ) );
+ break;
+ case 'rows':
+ case 'cols':
+ return 'textarea' === $this->type;
+ break;
+ case 'options':
+ return in_array( $this->type, array( 'select', 'multiselect', 'select2', 'radio', 'checkbox_grouped' ) );
+ break;
+ case 'multiple':
+ return in_array( $this->type, array( 'select', 'select2', 'multiselect' ) );
+ break;
+ case 'text':
+ return 'checkbox' === $this->type;
+ break;
+ case 'html':
+ return 'html' === $this->type;
+ break;
+ case 'allowed_file_types':
+ case 'max_file_size':
+ return 'file' === $this->type;
+ break;
+ default:
+ return false;
+ break;
+ }
+ }
+
/*
setup field based on passed values
attr is array of one or more of the following:
@@ -300,7 +431,7 @@ function __construct($name = NULL, $type = NULL, $attr = NULL) {
- just_profile = bool (not required. true means only show field in profile)
- class = string (class to add to html element)
*/
- function set($name, $type, $attr = array())
+ private function set($name, $type, $attr = array())
{
$this->name = $name;
$this->type = $type;
@@ -468,8 +599,86 @@ function set($name, $type, $attr = array())
return true;
}
+ /**
+ * Get the field value from $_REQEUST or $_SESSION.
+ * The value will be sanitized if the field has the sanitize property set to true.
+ *
+ * @since TBD
+ *
+ * @return mixed The value of the field or null if not found.
+ */
+ function get_value_from_request() {
+ if ( isset( $_REQUEST[ $this->name ] ) ) {
+ $value = $_REQUEST[$this->name];
+ } elseif ( isset( $_REQUEST[ $this->name . '_checkbox' ] ) && $this->type == 'checkbox' ) {
+ // Empty checkbox.
+ $value = 0;
+ } elseif ( ! empty( $_REQUEST[ $this->name . '_checkbox' ] ) && in_array( $this->type, array( 'checkbox_grouped', 'select2' ) ) ) {
+ // Empty group checkboxes or select2.
+ $value = array();
+ } elseif ( isset( $_FILES[$this->name] ) && $this->type == 'file' ) {
+ // File field.
+ $value = $_FILES[$this->name]['name'];
+ } elseif ( isset( $_SESSION[$this->name] ) ) {
+ // Value stored in session.
+ if ( is_array( $_SESSION[$this->name] ) && isset( $_SESSION[$this->name]['name'] ) ) {
+ // File field in session.
+ $_FILES[$this->name] = $_SESSION[$this->name];
+ $value = $_SESSION[$this->name]['name'];
+ } else {
+ // Other field in session.
+ $value = $_SESSION[$this->name];
+ }
+
+ // Clean up session.
+ unset($_SESSION[$this->name]);
+ } else {
+ // No value found.
+ return null;
+ }
+
+ // Sanitize the value if needed.
+ if ( ! empty( $field->sanitize ) ) {
+ if ( $this->type == 'textarea' ) {
+ $value = sanitize_textarea_field( $value );
+ } elseif ( is_array( $value ) ) {
+ $value = array_map( 'sanitize_text_field', $value );
+ } else {
+ $value = sanitize_text_field( $value );
+ }
+ }
+
+ return $value;
+ }
+
+ /**
+ * Save the field for a user.
+ *
+ * @since TBD
+ *
+ * @param int $user_id The user ID to save the field for.
+ */
+ function save_field_for_user( int $user_id ) {
+ // Get the value of the field.
+ $value = $this->get_value_from_request();
+
+ // If field was not submitted, bail.
+ if ( null === $value ) {
+ return;
+ }
+
+ // Check if we have a save function.
+ if ( ! empty( $this->save_function ) ) {
+ // Call the save function.
+ call_user_func( $this->save_function, $user_id, $this->name, $value, $this );
+ } else {
+ // Save the value to usermeta.
+ update_user_meta($user_id, $this->meta_key, $value);
+ }
+ }
+
// Save function for users table field.
- function saveUsersTable( $user_id, $name, $value ) {
+ private function saveUsersTable( $user_id, $name, $value ) {
// Special sanitization needed for certain user fields.
if ( $name === 'user_url' ) {
$value = esc_url_raw( $value );
@@ -483,7 +692,7 @@ function saveUsersTable( $user_id, $name, $value ) {
}
// Save function for user taxonomy field.
- function saveTermRelationshipsTable( $user_id, $name, $value ) {
+ private function saveTermRelationshipsTable( $user_id, $name, $value ) {
// Get the taxonomy to save for.
if ( isset( $this->taxonomy ) ) {
$taxonomy = $this->taxonomy;
@@ -512,7 +721,7 @@ function saveTermRelationshipsTable( $user_id, $name, $value ) {
}
//save function for files
- function saveFile($user_id, $name, $value)
+ private function saveFile($user_id, $name, $value)
{
//setup some vars
$user = get_userdata($user_id);
@@ -649,15 +858,17 @@ function saveFile($user_id, $name, $value)
update_user_meta($user_id, $meta_key, $file_meta_value_array );
}
- //echo the HTML for the field
- function display($value = NULL)
- {
- echo $this->getHTML($value); //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
+ /**
+ * Display the field.
+ */
+ function display( $value = NULL ) {
+ echo $this->getHTML( $value ); //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
+ $this->getDependenciesJS();
return;
}
//get HTML for the field
- function getHTML($value = "")
+ private function getHTML($value = "")
{
// Vars to store HTML to be added to the beginning or end.
$r_beginning = '';
@@ -683,7 +894,7 @@ function getHTML($value = "")
if($this->type == "text")
{
- $r = 'size))
$r .= 'size="' . esc_attr( $this->size ) . '" ';
if(!empty($this->class))
@@ -909,7 +1120,7 @@ function getHTML($value = "")
$r .= 'readonly="readonly" ';
if(!empty($this->html_attributes))
$r .= $this->getHTMLAttributes();
- $r .= '>' . esc_textarea(wp_unslash($value)) . '';
+ $r .= '>' . ( ( is_string( $value ) ) ? esc_textarea(wp_unslash($value) ) : '' ) . '';
}
elseif($this->type == "hidden")
{
@@ -934,35 +1145,32 @@ function getHTML($value = "")
{
$r = '';
- //old value
- if(is_user_logged_in())
- {
- global $current_user;
- $old_value = get_user_meta($current_user->ID, $this->meta_key, true);
- if(!empty($old_value))
- $r .= '';
- }
-
// Show the existing file with a preview and allow user to delete or replace.
- if ( ! empty( $value ) ) {
+ if ( ! empty( $value ) && ( is_array( $value ) || ! empty( $this->file ) ) ) {
+ if ( is_array( $value ) ) {
+ $file = $value;
+ } elseif ( ! empty( $this->file ) ) {
+ // Legacy support for $this->file.
+ $file = $this->file;
+ }
// Show a preview of existing file if image type.
- if ( ( ! empty( $this->preview ) ) && ! empty( $this->file['previewurl'] ) ) {
- $filetype = wp_check_filetype( basename( $this->file['previewurl'] ), null );
+ if ( ( ! empty( $this->preview ) ) && ! empty( $file['previewurl'] ) ) {
+ $filetype = wp_check_filetype( basename( $file['previewurl'] ), null );
if ( $filetype && 0 === strpos( $filetype['type'], 'image/' ) ) {
- $r_beginning .= '';
+ $r_beginning .= '';
}
}
- if( ! empty( $this->file['fullurl'] ) ) {
- $r_beginning .= '
';
// Allow user to delete the uploaded file if we know the full location.
- if ( ( ! empty( $this->allow_delete ) ) && ! empty( $this->file['fullurl'] ) ) {
+ if ( ( ! empty( $this->allow_delete ) ) && ! empty( $file['fullurl'] ) ) {
// Check whether the current user can delete the uploaded file based on the field attribute 'allow_delete'.
if ( $this->allow_delete === true ||
( $this->allow_delete === 'admins' || $this->allow_delete === 'only_admin' && current_user_can( 'manage_options' ) )
@@ -977,48 +1185,52 @@ function getHTML($value = "")
$r_beginning .= '';
}
$r_beginning .= '
';
- }
+ //include script to change enctype of the form and allow deletion
+ $r .= '
+
+ ';
+ }
- });
-
- ';
-
- $r .= '
- __( 'More Information', 'paid-memberships-pro' ),
+ 'name' => 'more_information',
+ 'label' => __( 'More Information', 'paid-memberships-pro' ),
'checkout' => 'yes',
'profile' => 'yes',
'description' => '',
@@ -1565,6 +1024,7 @@ function pmpro_get_user_fields_settings() {
// Make sure all expected properties are set for each group.
foreach ( $settings as $group ) {
$group->name = ! empty( $group->name ) ? $group->name : '';
+ $group->label = ! empty( $group->label ) ? $group->label : '';
$group->checkout = ! empty( $group->checkout ) ? $group->checkout : 'yes';
$group->profile = ! empty( $group->profile ) ? $group->profile : 'yes';
$group->description = ! empty( $group->description ) ? $group->description : '';
@@ -1596,11 +1056,10 @@ function pmpro_get_user_fields_settings() {
* Load user field settings into the fields global var.
*/
function pmpro_load_user_fields_from_settings() {
- global $pmpro_user_fields, $pmpro_field_groups;
$settings_groups = pmpro_get_user_fields_settings();
foreach ( $settings_groups as $group ) {
- pmpro_add_field_group( $group->name, $group->name, $group->description );
+ $group_obj = PMPro_field_Group::add( $group->name, $group->label, $group->description );
// Figure out profile value. Change 2 settings values into 1 field value.
if ( $group->checkout === 'yes' ) {
@@ -1678,7 +1137,7 @@ function pmpro_load_user_fields_from_settings() {
'default' => $settings_field->default,
)
);
- pmpro_add_user_field( $group->name, $field );
+ $group_obj->add_field( $field );
}
}
}
@@ -1688,11 +1147,13 @@ function pmpro_load_user_fields_from_settings() {
* Check if user is adding custom user fields with code.
*
* @since 2.9
+ * @deprecated TBD
*
* @return bool True if user is adding custom user fields with code.
*/
function pmpro_has_coded_user_fields() {
- global $pmpro_user_fields, $pmprorh_registration_fields;
+ _deprecated_function( __FUNCTION__, 'TBD' );
+ global $pmprorh_registration_fields;
// Check if coded fields are being added using the PMPro Register Helper Add On active.
if ( ! empty( $pmprorh_registration_fields ) ) {
@@ -1700,15 +1161,16 @@ function pmpro_has_coded_user_fields() {
}
// Check if coded fields are being added using the PMPro Register Helper Add On inactive.
- $num_db_fields = array_sum( array_map( function ($group) { return count( $group->fields ); }, pmpro_get_user_fields_settings() ) ); // Fields from UI settings page.
- $num_global_fields = array_sum( array_map( 'count', $pmpro_user_fields ) ); // Total loaded fields.
- return $num_global_fields > $num_db_fields;
+ $num_fields_from_settings = array_sum( array_map( function ($group) { return count( $group->fields ); }, pmpro_get_user_fields_settings() ) ); // Fields from UI settings page.
+ $total_registered_fields = array_sum( array_map( function ($group) { return count( $group->get_fields() ); }, PMPro_Field_Group::get_all() ) ); // All registered fields.
+ return $total_registered_fields > $num_fields_from_settings;
}
/**
* Gets the label(s) for a passed user field value.
*
* @since 2.11
+ * @deprecated TBD Use PMProField::displayValue instead.
*
* @param string $field_name The name of the field that the value belongs to.
* @param string|array $field_value The value to get the label for.
@@ -1716,9 +1178,14 @@ function pmpro_has_coded_user_fields() {
* @return string|array The label(s) for the passed value. Will be same type as $field_value.
*/
function pmpro_get_label_for_user_field_value( $field_name, $field_value ) {
- global $pmpro_user_fields;
- foreach ( $pmpro_user_fields as $user_field_group ) { // Loop through each user field group.
- foreach ( $user_field_group as $user_field ) { // Loop through each user field in the group.
+ _deprecated_function( __FUNCTION__, 'TBD', 'PMProField::displayValue' );
+
+ // Loop through all the field groups.
+ $field_groups = PMPro_Field_Group::get_all();
+ foreach($field_groups as $group_name => $group) {
+ // Loop through all the fields in the group.
+ $fields = $group->get_fields();
+ foreach( $fields as $user_field ) {
// Check if this is the user field that we are displaying.
if ( $user_field->name !== $field_name ) {
continue;
@@ -1740,42 +1207,21 @@ function pmpro_get_label_for_user_field_value( $field_name, $field_value ) {
}
// Replace meta values with their corresponding labels.
- if ( is_array( $field_value ) ) {
- foreach ( $field_value as $key => $value ) {
- if ( isset( $user_field->options[ $value ] ) ) {
- $field_value[ $key ] = $user_field->options[ $value ];
- }
- }
- } else {
- if ( isset( $user_field->options[ $field_value ] ) ) {
- $field_value = $user_field->options[ $field_value ];
- }
- }
+ $field_value = $user_field->displayValue( $field_value, false );
}
}
return $field_value;
}
/**
- * Get a single field from the global $pmpro_user_fields array.
+ * Get a single user field.
* @since 3.0
+ * @deprecated TBD
* @param string $field_name The name of the field to get.
* @return bool|object The field object if found, false otherwise.
*/
function pmpro_get_user_field( $field_name ) {
- global $pmpro_user_fields;
-
- if ( empty( $pmpro_user_fields ) ) {
- return false;
- }
-
- foreach ( $pmpro_user_fields as $group ) {
- foreach ( $group as $field ) {
- if ( $field->name === $field_name ) {
- return $field;
- }
- }
- }
-
- return false;
+ _deprecated_function( __FUNCTION__, 'TBD', 'PMPro_Field_Group::get_field' );
+ $field = PMPro_Field_Group::get_field( $field_name );
+ return empty( $field ) ? false : $field;
}
diff --git a/includes/functions.php b/includes/functions.php
index 1da6088ee..395710621 100644
--- a/includes/functions.php
+++ b/includes/functions.php
@@ -3809,12 +3809,17 @@ function pmpro_sanitize_with_safelist( $needle, $safelist ) {
* Sanitizes the passed value.
* Default sanitizing for things like user fields.
*
+ * @since TBD Marking the $field argument as deprecated.
+ *
* @param array|int|null|string|stdClass $value The value to sanitize
- * @param PMPro_Field $field (optional) Field to check type.
*
* @return array|int|string|object Sanitized value
*/
function pmpro_sanitize( $value, $field = null ) {
+ if ( null !== $field ) {
+ // This argument is deprecated. User fields now have sanitization logic in the field class.
+ _deprecated_argument( __FUNCTION__, 'TBD', __( 'The $field argument is deprecated. The sanitization logic is now built into the PMPro_Field class.', 'paid-memberships-pro' ) );
+ }
if ( is_array( $value ) ) {
@@ -4759,8 +4764,6 @@ function pmpro_set_expiration_date( $user_id, $level_id, $enddate ) {
* @return true|WP_Error True if the file is allowed, otherwise a WP_Error object.
*/
function pmpro_check_upload( $file_index ) {
- global $pmpro_user_fields;
-
// Check if the file was uploaded.
if ( empty( $_FILES[ $file_index ] ) ) {
return new WP_Error( 'pmpro_upload_error', __( 'No file was uploaded.', 'paid-memberships-pro' ) );
@@ -4781,51 +4784,40 @@ function pmpro_check_upload( $file_index ) {
}
// If this is an upload for a user field, we need to perform additional checks.
- $is_user_field = false;
- if ( ! empty( $pmpro_user_fields ) && is_array( $pmpro_user_fields ) ) {
- foreach ( $pmpro_user_fields as $checkout_box ) {
- foreach ( $checkout_box as $field ) {
- if ( $field->name == $file_index ) {
- // This file is being uploaded for a user field.
- $is_user_field = true;
-
- // First, make sure that this is a 'file' field.
- if ( $field->type !== 'file' ) {
- return new WP_Error( 'pmpro_upload_error', __( 'Invalid field input.', 'paid-memberships-pro' ) );
- }
+ $field = PMPro_Field_Group::get_field( $file_index );
+ if ( ! empty( $field) ) {
+ // First, make sure that this is a 'file' field.
+ if ( $field->type !== 'file' ) {
+ return new WP_Error( 'pmpro_upload_error', __( 'Invalid field input.', 'paid-memberships-pro' ) );
+ }
- // If there are allowed file types, check if the file is an allowed file type.
- // It does not look like the ext property is documented anywhere, but keeping it in case sites are using it.
- if ( ! empty( $field->ext ) && is_array( $field->ext ) && ! in_array( $filetype['ext'], $field->ext ) ) {
- return new WP_Error( 'pmpro_upload_error', __( 'Invalid file type.', 'paid-memberships-pro' ) );
- }
+ // If there are allowed file types, check if the file is an allowed file type.
+ // It does not look like the ext property is documented anywhere, but keeping it in case sites are using it.
+ if ( ! empty( $field->ext ) && is_array( $field->ext ) && ! in_array( $filetype['ext'], $field->ext ) ) {
+ return new WP_Error( 'pmpro_upload_error', __( 'Invalid file type.', 'paid-memberships-pro' ) );
+ }
- // Check the file type against the allowed types.
- $allowed_mime_types = ! empty( $field->allowed_file_types ) ? array_map( 'sanitize_text_field', explode( ',', $field->allowed_file_types ) ) : array();
+ // Check the file type against the allowed types.
+ $allowed_mime_types = ! empty( $field->allowed_file_types ) ? array_map( 'sanitize_text_field', explode( ',', $field->allowed_file_types ) ) : array();
- //Remove fullstops from the beginning of the allowed file types.
- $allowed_mime_types = array_map( function( $type ) {
- return ltrim( $type, '.' );
- }, $allowed_mime_types );
+ //Remove fullstops from the beginning of the allowed file types.
+ $allowed_mime_types = array_map( function( $type ) {
+ return ltrim( $type, '.' );
+ }, $allowed_mime_types );
- // Check the file type against the allowed types. If empty allowed mimes, assume any file upload is okay.
- if ( ! empty( $allowed_mime_types ) && ! in_array( $filetype['ext'], $allowed_mime_types ) ) {
- return new WP_Error( 'pmpro_upload_file_type_error', sprintf( esc_html__( 'Invalid file type. Please try uploading the file type(s): %s', 'paid-memberships-pro' ), implode( ',' ,$allowed_mime_types ) ) );
- }
-
- // Check if the file upload is too big to upload.
- if ( $field->max_file_size > 0 ) {
- $upload_max_file_size_in_bytes = $field->max_file_size * 1024 * 1024;
- if ( $file['size'] > $upload_max_file_size_in_bytes ) {
- return new WP_Error( 'pmpro_upload_file_size_error', sprintf( esc_html__( 'File size is too large for %s. Please upload files smaller than %dMB.', 'paid-memberships-pro' ), $field->label, $field->max_file_size ) );
- }
- }
- }
+ // Check the file type against the allowed types. If empty allowed mimes, assume any file upload is okay.
+ if ( ! empty( $allowed_mime_types ) && ! in_array( $filetype['ext'], $allowed_mime_types ) ) {
+ return new WP_Error( 'pmpro_upload_file_type_error', sprintf( esc_html__( 'Invalid file type. Please try uploading the file type(s): %s', 'paid-memberships-pro' ), implode( ',' ,$allowed_mime_types ) ) );
+ }
+
+ // Check if the file upload is too big to upload.
+ if ( $field->max_file_size > 0 ) {
+ $upload_max_file_size_in_bytes = $field->max_file_size * 1024 * 1024;
+ if ( $file['size'] > $upload_max_file_size_in_bytes ) {
+ return new WP_Error( 'pmpro_upload_file_size_error', sprintf( esc_html__( 'File size is too large for %s. Please upload files smaller than %dMB.', 'paid-memberships-pro' ), $field->label, $field->max_file_size ) );
}
}
- }
-
- if ( ! $is_user_field ) {
+ } else {
/**
* Filter whether a file not associated with a user field can be uploaded.
*
diff --git a/includes/scripts.php b/includes/scripts.php
index 050f88c4c..2098f2149 100644
--- a/includes/scripts.php
+++ b/includes/scripts.php
@@ -137,14 +137,6 @@ function pmpro_admin_enqueue_scripts() {
$level->formatted_expiration = trim( pmpro_no_quotes( pmpro_getLevelExpiration( $level ) ) );
$all_levels_formatted_text[$level->id] = $level;
}
- // Get HTML for empty field group.
- ob_start();
- pmpro_get_field_group_html();
- $empty_field_group_html = ob_get_clean();
- // Get HTML for empty field.
- ob_start();
- pmpro_get_field_html();
- $empty_field_html = ob_get_clean();
wp_localize_script(
'pmpro_admin',
@@ -154,8 +146,6 @@ function pmpro_admin_enqueue_scripts() {
'all_levels_formatted_text' => $all_levels_formatted_text,
'all_level_values_and_labels' => $all_level_values_and_labels,
'checkout_url' => pmpro_url( 'checkout' ),
- 'user_fields_blank_group' => $empty_field_group_html,
- 'user_fields_blank_field' => $empty_field_html,
// We want the core WP translation so we can check for it in JS.
'plugin_updated_successfully_text' => __( 'Plugin updated successfully.' ),
)
diff --git a/includes/services.php b/includes/services.php
index d5045250a..8d9743c4d 100644
--- a/includes/services.php
+++ b/includes/services.php
@@ -197,18 +197,127 @@ function pmpro_update_level_group_order() {
// User fields AJAX.
/**
* Callback to draw a field group.
+ *
+ * @deprecated TBD
*/
-function pmpro_userfields_get_group_ajax() {
- pmpro_get_field_group_html();
+function pmpro_userfields_get_group_ajax() {
+ _deprecated_function( __FUNCTION__, 'TBD' );
exit;
}
add_action( 'wp_ajax_pmpro_userfields_get_group', 'pmpro_userfields_get_group_ajax' );
/**
* Callback to draw a field.
+ *
+ * @deprecated TBD
*/
function pmpro_userfields_get_field_ajax() {
- pmpro_get_field_html();
+ _deprecated_function( __FUNCTION__, 'TBD' );
exit;
}
add_action( 'wp_ajax_pmpro_userfields_get_field', 'pmpro_userfields_get_field_ajax' );
+
+function pmpro_update_field_order() {
+ // only admins can get this
+ if ( ! function_exists( 'current_user_can' ) || ( ! current_user_can( 'manage_options' ) && ! current_user_can( 'pmpro_userfields' ) ) ) {
+ die( esc_html__( 'You do not have permissions to perform this action.', 'paid-memberships-pro' ) );
+ }
+
+ // Check the nonce.
+ if ( ! wp_verify_nonce( sanitize_key( $_REQUEST['nonce'] ), 'pmpro_update_field_order' ) ) {
+ die( esc_html__( 'You do not have permissions to perform this action.', 'paid-memberships-pro' ) );
+ }
+
+ // Get the field group that was reordered and the new order.
+ $field_group = sanitize_text_field( $_REQUEST['group'] );
+ $ordered_fields = array_map( 'sanitize_text_field', $_REQUEST['ordered_fields'] );
+
+ // Get the current user fields settings.
+ $current_settings = pmpro_get_user_fields_settings();
+
+ // Find the group object that we are reordering.
+ $group = null;
+ foreach ( $current_settings as $group_settings ) {
+ if ( $group_settings->name === $field_group ) {
+ $group = $group_settings;
+ break;
+ }
+ }
+ if ( empty( $group ) ) {
+ die( esc_html__( 'Could not find the group to reorder.', 'paid-memberships-pro' ) );
+ }
+
+ // Create an associative version of $group->fields to make it easier to reorder.
+ $group_field_tmp = array();
+ foreach ( $group->fields as $field ) {
+ $group_field_tmp[ $field->name ] = $field;
+ }
+
+ // Create a reordered version of the fields.
+ $reordered_fields = array();
+ foreach ( $ordered_fields as $field_name ) {
+ if ( isset( $group_field_tmp[ $field_name ] ) ) {
+ $reordered_fields[] = $group_field_tmp[ $field_name ];
+ unset( $group_field_tmp[ $field_name ] );
+ }
+ }
+
+ // If there are any fields left in $group_field_tmp, add them to the end of $reordered_fields.
+ if ( ! empty( $group_field_tmp ) ) {
+ $reordered_fields = array_merge( $reordered_fields, $group_field_tmp );
+ }
+
+ // Update the group with the reordered fields.
+ $group->fields = $reordered_fields;
+
+ // Update the settings with the reordered group.
+ update_option( 'pmpro_user_fields_settings', $current_settings );
+
+ exit;
+}
+add_action('wp_ajax_pmpro_update_field_order', 'pmpro_update_field_order');
+
+
+function pmpro_update_field_group_order() {
+ // only admins can get this
+ if ( ! function_exists( 'current_user_can' ) || ( ! current_user_can( 'manage_options' ) && ! current_user_can( 'pmpro_userfields' ) ) ) {
+ die( esc_html__( 'You do not have permissions to perform this action.', 'paid-memberships-pro' ) );
+ }
+
+ // Check the nonce.
+ if ( ! wp_verify_nonce( sanitize_key( $_REQUEST['nonce'] ), 'pmpro_update_field_group_order' ) ) {
+ die( esc_html__( 'You do not have permissions to perform this action.', 'paid-memberships-pro' ) );
+ }
+
+ // Get the new order.
+ $ordered_groups = array_map( 'sanitize_text_field', $_REQUEST['ordered_groups'] );
+
+ // Get the current user fields settings.
+ $current_settings = pmpro_get_user_fields_settings();
+
+ // Create an associative version of $current_settings to make it easier to reorder.
+ $current_settings_tmp = array();
+ foreach ( $current_settings as $group_settings ) {
+ $current_settings_tmp[ $group_settings->name ] = $group_settings;
+ }
+
+ // Create a reordered version of the groups.
+ $reordered_groups = array();
+ foreach ( $ordered_groups as $group_name ) {
+ if ( isset( $current_settings_tmp[ $group_name ] ) ) {
+ $reordered_groups[] = $current_settings_tmp[ $group_name ];
+ unset( $current_settings_tmp[ $group_name ] );
+ }
+ }
+
+ // If there are any groups left in $current_settings_tmp, add them to the end of $reordered_groups.
+ if ( ! empty( $current_settings_tmp ) ) {
+ $reordered_groups = array_merge( $reordered_groups, $current_settings_tmp );
+ }
+
+ // Update the settings with the reordered groups.
+ update_option( 'pmpro_user_fields_settings', $reordered_groups );
+
+ exit;
+}
+add_action('wp_ajax_pmpro_update_field_group_order', 'pmpro_update_field_group_order');
diff --git a/js/pmpro-admin.js b/js/pmpro-admin.js
index 16467385d..49619ecb3 100644
--- a/js/pmpro-admin.js
+++ b/js/pmpro-admin.js
@@ -257,315 +257,39 @@ jQuery(document).ready(function () {
// Function to prep click events.
function pmpro_userfields_prep_click_events() {
- // Whenever we make a change, warn the user if they try to navigate away.
- function pmpro_userfields_made_a_change() {
- window.onbeforeunload = function () {
- return true;
- };
- jQuery('#pmpro_userfields_savesettings').prop("disabled", false);
- }
-
- // Add group button.
- jQuery('#pmpro_userfields_add_group').unbind('click').on('click', function (event) {
- jQuery('#pmpro_userfields_add_group').parent('p').before(pmpro.user_fields_blank_group);
- pmpro_userfields_prep_click_events();
- jQuery('#pmpro_userfields_add_group').parent('p').prev().find('input').focus().select();
- pmpro_userfields_made_a_change();
- });
-
- // Delete group button.
- jQuery('.pmpro_userfield-group-actions button[name=pmpro_userfields_delete_group]').unbind('click').on('click', function (event) {
- var thegroup = jQuery(this).closest('.pmpro_userfield-group');
- var thename = thegroup.find('input[name=pmpro_userfields_group_name]').val();
- var answer;
- if (thename.length > 0) {
- answer = window.confirm('Delete the "' + thename + '" group?');
- } else {
- answer = window.confirm('Delete this group?');
- }
- if (answer) {
- thegroup.remove();
- pmpro_userfields_made_a_change();
- }
- });
+ function update_userfield_type_fields() {
+ // Hide all
elements with the `field_type` class.
+ jQuery('.field_type').hide();
- // Add field button.
- jQuery('button[name="pmpro_userfields_add_field"]').unbind('click').on('click', function (event) {
- var thefields = jQuery(event.target).closest('div.pmpro_userfield-group-actions').siblings('div.pmpro_userfield-group-fields');
- thefields.append(pmpro.user_fields_blank_field);
- pmpro_userfields_prep_click_events();
- thefields.children().last().find('.edit-field').click();
- thefields.children().last().find('input[name="pmpro_userfields_field_label"]').focus().select();
- pmpro_userfields_made_a_change();
- });
+ // Get the selected field type.
+ var field_type = jQuery('.pmpro_admin-pmpro-userfields select[name=type]').val();
- // Delete field button.
- jQuery('.pmpro_userfield-field-options a.delete-field, .pmpro_userfield-field-actions .is-destructive').unbind('click').on('click', function (event) {
- var thefield = jQuery(this).closest('.pmpro_userfield-group-field');
- var thelabel = thefield.find('input[name=pmpro_userfields_field_label]').val();
- var answer;
- if (thelabel.length > 0) {
- answer = window.confirm('Delete the "' + thelabel + '" field?');
- } else {
- answer = window.confirm('Delete this unlabeled field?');
- }
- if (answer) {
- thefield.remove();
- pmpro_userfields_made_a_change();
- }
- });
-
- // Toggle groups.
- jQuery('button.pmpro_userfield-group-buttons-button-toggle-group, div.pmpro_userfield-group-header h3').unbind('click').on('click', function (event) {
- event.preventDefault();
-
- // Ignore if the text field was clicked.
- if (jQuery(event.target).prop('nodeName') === 'INPUT') {
- return;
- }
-
- // Find the toggle button and open or close.
- let thebutton = jQuery(event.target).parents('.pmpro_userfield-group').find('button.pmpro_userfield-group-buttons-button-toggle-group');
- let buttonicon = thebutton.children('.dashicons');
- let groupheader = thebutton.closest('.pmpro_userfield-group-header');
- let groupinside = groupheader.siblings('.pmpro_userfield-inside');
-
- if (buttonicon.hasClass('dashicons-arrow-up')) {
- // closing
- buttonicon.removeClass('dashicons-arrow-up');
- buttonicon.addClass('dashicons-arrow-down');
- groupinside.slideUp();
- } else {
- // opening
- buttonicon.removeClass('dashicons-arrow-down');
- buttonicon.addClass('dashicons-arrow-up');
- groupinside.slideDown();
- }
- });
-
- // Move group up.
- jQuery('.pmpro_userfield-group-buttons-button-move-up').unbind('click').on('click', function (event) {
- var thegroup = jQuery(this).closest('.pmpro_userfield-group');
- var thegroupprev = thegroup.prev('.pmpro_userfield-group');
- if (thegroupprev.length > 0) {
- thegroup.insertBefore(thegroupprev);
- pmpro_userfields_made_a_change();
- }
- });
-
- // Move group down.
- jQuery('.pmpro_userfield-group-buttons-button-move-down').unbind('click').on('click', function (event) {
- var thegroup = jQuery(this).closest('.pmpro_userfield-group');
- var thegroupnext = thegroup.next('.pmpro_userfield-group');
- if (thegroupnext.length > 0) {
- thegroup.insertAfter(thegroupnext);
- pmpro_userfields_made_a_change();
- }
- });
-
- // Open field.
- jQuery('a.edit-field').unbind('click').on('click', function (event) {
- var fieldcontainer = jQuery(this).parents('.pmpro_userfield-group-field');
- var fieldsettings = fieldcontainer.children('.pmpro_userfield-field-settings');
-
- fieldcontainer.removeClass('pmpro_userfield-group-field-collapse');
- fieldcontainer.addClass('pmpro_userfield-group-field-expand');
- fieldsettings.find('select[name=pmpro_userfields_field_type]').change();
- fieldsettings.show();
- });
-
- // Close field.
- jQuery('button.pmpro_userfields_close_field').unbind('click').on('click', function (event) {
- event.preventDefault();
- var fieldcontainer = jQuery(this).parents('.pmpro_userfield-group-field');
- var fieldsettings = fieldcontainer.children('.pmpro_userfield-field-settings');
- var fieldheading = fieldsettings.prev();
- // Update label, name, and type.
- fieldheading.find('span.pmpro_userfield-label').html(fieldsettings.find('input[name=pmpro_userfields_field_label]').val().replace(/(<([^>]+)>)/gi, ''));
- fieldheading.find('li.pmpro_userfield-group-column-name').html(fieldsettings.find('input[name=pmpro_userfields_field_name]').val());
- fieldheading.find('li.pmpro_userfield-group-column-type').html(fieldsettings.find('select[name=pmpro_userfields_field_type]').val());
-
- // Toggle
- fieldcontainer.removeClass('pmpro_userfield-group-field-expand');
- fieldcontainer.addClass('pmpro_userfield-group-field-collapse');
- fieldsettings.hide();
- });
-
- // Move field up.
- jQuery('.pmpro_userfield-field-buttons-button-move-up').unbind('click').on('click', function (event) {
- var thefield = jQuery(this).closest('.pmpro_userfield-group-field');
- var thefieldprev = thefield.prev('.pmpro_userfield-group-field');
- if (thefieldprev.length > 0) {
- thefield.insertBefore(thefieldprev);
- pmpro_userfields_made_a_change();
- }
- });
-
- // Move field down.
- jQuery('.pmpro_userfield-field-buttons-button-move-down').unbind('click').on('click', function (event) {
- var thefield = jQuery(this).closest('.pmpro_userfield-group-field');
- var thefieldnext = thefield.next('.pmpro_userfield-group-field');
- if (thefieldnext.length > 0) {
- thefield.insertAfter(thefieldnext);
- pmpro_userfields_made_a_change();
- }
- });
-
- // Duplicate field.
- jQuery('a.duplicate-field').unbind('click').on('click', function (event) {
- var thefield = jQuery(this).closest('.pmpro_userfield-group-field');
- thefield.clone(true).insertAfter(thefield); // clone( true ) to clone event handlers.
- pmpro_userfields_made_a_change();
- });
+ // Show al the
elements with `field_type_{field_type}` class.
+ jQuery('.field_type_' + field_type).show();
+ }
+ update_userfield_type_fields();
// Toggle field settings based on type.
- jQuery('select[name=pmpro_userfields_field_type]').on('change', function (event) {
- var fieldcontainer = jQuery(this).parents('.pmpro_userfield-group-field');
- var fieldsettings = fieldcontainer.children('.pmpro_userfield-field-settings');
- var fieldtype = jQuery(this).val();
-
- var fieldoptions = fieldsettings.find('textarea[name=pmpro_userfields_field_options]').parents('.pmpro_userfield-field-setting');
- var fieldfiles = fieldsettings.find('input[name=pmpro_userfields_field_max_file_size]').parents('.pmpro_userfield-field-setting');
- var fielddefault = fieldsettings.find('input[name=pmpro_userfields_field_default]').parents('.pmpro_userfield-field-setting');
-
- // Hide all the field settings.
- fieldoptions.hide();
- fieldfiles.hide();
- fielddefault.hide();
-
- // Show the option field if needed.
- var optiontypes = ['checkbox_grouped', 'radio', 'select', 'select2', 'multiselect'];
- if (jQuery.inArray(fieldtype, optiontypes) > -1) {
- fieldoptions.show();
- }
-
- // Show the file field options if needed.
- if (fieldtype === 'file') {
- fieldfiles.show();
- }
-
- // Show the default field if needed.
- var defaulttypes = ['text', 'textarea', 'checkbox', 'radio', 'select', 'date', 'readonly', 'hidden', 'number'];
- if (jQuery.inArray(fieldtype, defaulttypes) > -1) {
- fielddefault.show();
- }
+ jQuery('.pmpro_admin-pmpro-userfields select[name=type]').on('change', function (event) {
+ update_userfield_type_fields();
});
// Suggest name after leaving label field.
- jQuery('input[name=pmpro_userfields_field_label]').on('focusout', function (event) {
- var fieldcontainer = jQuery(this).parents('.pmpro_userfield-group-field');
- var fieldsettings = fieldcontainer.children('.pmpro_userfield-field-settings');
- var fieldname = fieldsettings.find('input[name=pmpro_userfields_field_name]');
- if (!fieldname.val()) {
- fieldname.val(jQuery(this).val().toLowerCase().replace(/[^a-z0-9]/gi, '_').replace(/(^\_+|\_+$)/mg, ''));
+ jQuery('.pmpro_admin-pmpro-userfields input[name=label]').on('focusout', function (event) {
+ // Check if the "name" field is empty and a text field.
+ var name = jQuery('.pmpro_admin-pmpro-userfields input[name=name]').val();
+ var label = jQuery('.pmpro_admin-pmpro-userfields input[name=label]').val();
+ if ( ! name && label ) {
+ // Generate a name based on the label.
+ name = label.toLowerCase().replace(/[^a-z0-9]/gi, '_').replace(/(^\_+|\_+$)/mg, '');
+ jQuery('.pmpro_admin-pmpro-userfields input[name=name]').val(name);
}
});
- // If we change a field, mark it as changed.
- jQuery('.pmpro_userfield-group input, .pmpro_userfield-group textarea, .pmpro_userfield-group select').on('change', function (event) {
- pmpro_userfields_made_a_change();
- });
-
- // Save User Field Settings
- jQuery('#pmpro_userfields_savesettings').unbind('click').on('click', function (event) {
- ///event.preventDefault();
- // We have saved, so we no longer need to warn user if they try to navigate away.
- window.onbeforeunload = null;
-
- let field_groups = [];
- let group_names = [];
- let default_group_name = 'More Information';
-
- jQuery('.pmpro_userfield-group').each(function (index, value) {
- let group_name = jQuery(this).find('input[name=pmpro_userfields_group_name]').val();
-
- // Make sure name is not blank.
- if (group_name.length === 0) {
- group_name = default_group_name;
- }
- // Make sure name is unique.
- let count = 1;
- while (group_names.includes(group_name)) {
- count++;
- group_name = group_name.replace(/\(0-9*\)/, '');
- group_name = group_name + ' (' + String(count) + ')';
- }
- group_names.push(group_name);
-
- let group_checkout = jQuery(this).find('select[name=pmpro_userfields_group_checkout]').val();
- let group_profile = jQuery(this).find('select[name=pmpro_userfields_group_profile]').val();
- let group_description = jQuery(this).find('textarea[name=pmpro_userfields_group_description]').val();
-
- // Get level ids.
- let group_levels = [];
- jQuery(this).find('input[name="pmpro_userfields_group_membership[]"]:checked').each(function () {
- group_levels.push(parseInt(jQuery(this).attr('id').replace('pmpro_userfields_group_membership_', '')));
- });
-
- // Get fields.
- let group_fields = [];
- jQuery(this).find('div.pmpro_userfield-group-fields div.pmpro_userfield-field-settings').each(function () {
- let field_label = jQuery(this).find('input[name=pmpro_userfields_field_label]').val();
- let field_name = jQuery(this).find('input[name=pmpro_userfields_field_name]').val();
- let field_type = jQuery(this).find('select[name=pmpro_userfields_field_type]').val();
- let field_required = jQuery(this).find('select[name=pmpro_userfields_field_required]').val();
- let field_readonly = jQuery(this).find('select[name=pmpro_userfields_field_readonly]').val();
- let field_profile = jQuery(this).find('select[name=pmpro_userfields_field_profile]').val();
- let field_wrapper_class = jQuery(this).find('input[name=pmpro_userfields_field_class]').val();
- let field_element_class = jQuery(this).find('input[name=pmpro_userfields_field_divclass]').val();
- let field_hint = jQuery(this).find('textarea[name=pmpro_userfields_field_hint]').val();
- let field_options = jQuery(this).find('textarea[name=pmpro_userfields_field_options]').val();
- let field_allowed_file_types = jQuery(this).find('input[name=pmpro_userfields_field_allowed_file_types]').val();
- let field_max_file_size = jQuery(this).find('input[name=pmpro_userfields_field_max_file_size]').val();
- let field_default = jQuery(this).find('input[name=pmpro_userfields_field_default]').val();
-
- // Get level ids.
- let field_levels = [];
- jQuery(this).find('input[name="pmpro_userfields_field_levels[]"]:checked').each(function () {
- field_levels.push(parseInt(jQuery(this).attr('id').replace('pmpro_userfields_field_levels_', '')));
- });
-
- let field = {
- 'label': field_label,
- 'name': field_name,
- 'type': field_type,
- 'required': field_required,
- 'readonly': field_readonly,
- 'levels': field_levels,
- 'profile': field_profile,
- 'wrapper_class': field_wrapper_class,
- 'element_class': field_element_class,
- 'hint': field_hint,
- 'options': field_options,
- 'allowed_file_types': field_allowed_file_types,
- 'max_file_size': field_max_file_size,
- 'default': field_default
- };
-
- // Add to array. (Only if it has a label or name.)
- if (field.label.length > 0 || field.name.length > 0) {
- group_fields.push(field);
- }
- });
-
- // Set up the field group object.
- let field_group = {
- 'name': group_name,
- 'checkout': group_checkout,
- 'profile': group_profile,
- 'description': group_description,
- 'levels': group_levels,
- 'fields': group_fields
- };
-
- // Add to array.
- field_groups.push(field_group);
- });
-
- // console.log( field_groups );
- jQuery('#pmpro_user_fields_settings').val(JSON.stringify(field_groups));
-
- return true;
+ jQuery('.pmpro-level-restrictions-preview-button').on('click', function(event) {
+ event.preventDefault();
+ jQuery(this).hide();
+ jQuery(this).next('.pmpro-level-restrictions-preview-list').show();
});
}
diff --git a/paid-memberships-pro.php b/paid-memberships-pro.php
index 38efe602f..59c5ba4a3 100644
--- a/paid-memberships-pro.php
+++ b/paid-memberships-pro.php
@@ -46,6 +46,7 @@
require_once( PMPRO_DIR . '/classes/class.memberorder.php' ); // class to process and save orders
require_once( PMPRO_DIR . '/classes/class.pmproemail.php' ); // setup and filter emails sent by PMPro
require_once( PMPRO_DIR . '/classes/class-pmpro-field.php' );
+require_once( PMPRO_DIR . '/classes/class-pmpro-field-group.php' );
require_once( PMPRO_DIR . '/classes/class-pmpro-levels.php' );
require_once( PMPRO_DIR . '/classes/class-pmpro-subscription.php' );
require_once( PMPRO_DIR . '/classes/class-pmpro-admin-activity-email.php' ); // setup the admin activity email
diff --git a/scheduled/crons.php b/scheduled/crons.php
index ff3720787..6457927c6 100644
--- a/scheduled/crons.php
+++ b/scheduled/crons.php
@@ -377,3 +377,29 @@ function pmpro_cron_recurring_payment_reminders() {
$previous_days = $days;
}
}
+
+/**
+ * Delete old files in wp-content/uploads/pmpro-register-helper/tmp every day.
+ */
+function pmpro_cron_delete_tmp() {
+ $upload_dir = wp_upload_dir();
+ $pmprorh_dir = $upload_dir['basedir'] . "/paid-memberships-pro/tmp/";
+
+ if(file_exists($pmprorh_dir) && $handle = opendir($pmprorh_dir))
+ {
+ while(false !== ($file = readdir($handle)))
+ {
+ $file = $pmprorh_dir . $file;
+ $filelastmodified = filemtime($file);
+ if(is_file($file) && (time() - $filelastmodified) > 3600)
+ {
+ unlink($file);
+ }
+ }
+
+ closedir($handle);
+ }
+
+ exit;
+}
+add_action( 'pmpro_cron_delete_tmp', 'pmpro_cron_delete_tmp' );
diff --git a/shortcodes/pmpro_member.php b/shortcodes/pmpro_member.php
index 07ce3be76..a9c9ea3f7 100644
--- a/shortcodes/pmpro_member.php
+++ b/shortcodes/pmpro_member.php
@@ -185,21 +185,12 @@ function pmpro_member_shortcode( $atts, $content = null, $shortcode_tag = '' ) {
}
}
- // Check for files to reformat them.
- if ( is_array( $r ) && ! empty( $r['fullurl'] ) ) {
- $file_field = pmpro_get_user_field( $field );
- if ( ! empty( $file_field ) ) {
- $file_field->file = $r;
- $file_field->readonly = true;
- $r = $file_field->displayValue( $r['fullurl'], false ); // False to not echo.
- } else {
- $r = '' . esc_html( basename($r['fullurl'] ) ) . '';
- }
+ // If this is a user field, get the display value.
+ $user_field = PMPro_Field_Group::get_field( $field );
+ if ( ! empty( $user_field ) ) {
+ $r = $user_field->displayValue( $r, false );
}
- // If this is a user field with an associative array of options, get the label(s) for the value(s).
- $r = pmpro_get_label_for_user_field_value( $field, $r );
-
// Check for arrays to reformat them.
if ( is_array( $r ) ) {
$r = implode( ', ', $r );