parent = $redux; $this->add_field( 'users' ); $this->parent->extensions['users'] = $this; $this->pagenows = array( 'user-new.php', 'profile.php', 'user-edit.php' ); require_once __DIR__ . '/redux-users-helpers.php'; add_action( 'admin_notices', array( $this, 'meta_profiles_show_errors' ), 0 ); add_action( 'admin_enqueue_scripts', array( $this, 'enqueue' ), 20 ); if ( is_admin() && in_array( $pagenow, $this->pagenows, true ) ) { $this->init(); add_action( 'personal_options_update', array( $this, 'user_meta_save' ) ); add_action( 'edit_user_profile_update', array( $this, 'user_meta_save' ) ); } } /** * Add term classes. * * @param array $classes Classes. * * @return array */ public function add_term_classes( array $classes ): array { $classes[] = 'redux-users'; $classes[] = 'redux-' . $this->parent->args['opt_name']; if ( '' !== $this->parent->args['class'] ) { $classes[] = $this->parent->args['class']; } return $classes; } /** * Add hide term class. * * @param array $classes Classes. * * @return array */ public function add_term_hide_class( array $classes ): array { $classes[] = 'hide'; return $classes; } /** * Init. */ public function init() { global $pagenow; // phpcs:ignore WordPress.Security.NonceVerification $user = isset( $_GET['user_id'] ) ? sanitize_text_field( wp_unslash( $_GET['user_id'] ) ) : get_current_user_id(); $this->meta = Redux_Users::get_user_meta( array( 'user' => $user ) ); $this->parent->options = $this->meta; // phpcs:ignore WordPress.NamingConventions.ValidHookName $this->profiles = apply_filters( 'redux/users/' . $this->parent->args['opt_name'] . '/profiles', $this->profiles, $this->parent->args['opt_name'] ); if ( empty( $this->profiles ) && class_exists( 'Redux_Users' ) ) { $this->profiles = Redux_Users::construct_profiles( $this->parent->args['opt_name'] ); } if ( empty( $this->profiles ) || ! is_array( $this->profiles ) ) { return; } $this->base_url = ( is_ssl() ? 'https://' : 'http://' ) . Redux_Core::$server['HTTP_HOST'] . Redux_Core::$server['REQUEST_URI']; foreach ( $this->profiles as $bk => $profile ) { $profile['roles'] = isset( $profile['roles'] ) ? (array) $profile['roles'] : array( 'read' ); if ( ! empty( $profile['sections'] ) ) { $this->sections = $profile['sections']; $this->users_roles = wp_parse_args( $this->users_roles, $profile['roles'] ); // Checking to override the parent variables. $add_field = false; foreach ( $profile['roles'] as $role ) { if ( $this->users_role === $role ) { $add_field = true; } } // Replacing all the fields. if ( $add_field || ( ( is_admin() && in_array( $pagenow, $this->pagenows, true ) ) || ( ! is_admin() ) ) ) { $profile_id = 'redux-' . $this->parent->args['opt_name'] . '-metaterm-' . $profile['id']; if ( isset( $profile['page_template'] ) && 'page' === $this->users_role ) { if ( ! is_array( $profile['page_template'] ) ) { $profile['page_template'] = array( $profile['page_template'] ); } $this->wp_links[ $profile_id ]['page_template'] = isset( $this->wp_links[ $profile_id ]['page_template'] ) ? wp_parse_args( $this->wp_links[ $profile_id ]['page_template'], $profile['page_template'] ) : $profile['page_template']; } if ( isset( $profile['post_format'] ) && ( in_array( $this->users_role, $this->users_roles, true ) || '' === $this->users_role ) ) { if ( ! is_array( $profile['post_format'] ) ) { $profile['post_format'] = array( $profile['post_format'] ); } $this->wp_links[ $profile_id ]['post_format'] = isset( $this->wp_links[ $profile_id ]['post_format'] ) ? wp_parse_args( $this->wp_links[ $profile_id ]['post_format'], $profile['post_format'] ) : $profile['post_format']; } foreach ( $profile['sections'] as $sk => $section ) { if ( ! empty( $section['fields'] ) ) { foreach ( $section['fields'] as $fk => $field ) { if ( ! isset( $field['class'] ) ) { $field['class'] = ''; $this->profiles[ $bk ]['sections'][ $sk ]['fields'][ $fk ] = $field; } $this->parent->required_class->check_dependencies( $field ); /** phpcs:ignore * if ( stripos( $field['class'], 'redux-field-init' ) === 0 ) { * $field['class'] = trim( $field['class'] . ' redux-field-init' ); * } */ if ( $add_field || ( ( is_admin() && in_array( $pagenow, $this->pagenows, true ) ) || ( ! is_admin() ) ) ) { if ( empty( $field['id'] ) ) { continue; } if ( isset( $field['default'] ) ) { $this->options_defaults[ $field['id'] ] = $field['default']; } else { $this->options_defaults[ $field['id'] ] = $this->field_default( $field ); } foreach ( $profile['roles'] as $type ) { $this->profile_fields[ $type ][ $field['id'] ] = 1; } if ( ! empty( $field['output'] ) ) { $this->output[ $field['id'] ] = isset( $this->output[ $field['id'] ] ) ? array_merge( $field['output'], $this->output[ $field['id'] ] ) : $field['output']; } // Detect what field types are being used. if ( ! isset( $this->parent->fields[ $field['type'] ][ $field['id'] ] ) ) { $this->parent->fields[ $field['type'] ][ $field['id'] ] = 1; } else { $this->parent->fields[ $field['type'] ] = array( $field['id'] => 1 ); } if ( isset( $this->options_defaults[ $field['id'] ] ) ) { $this->to_replace[ $field['id'] ] = $field; } } if ( ! isset( $this->parent->options[ $field['id'] ] ) ) { $this->parent->sections[ ( count( $this->parent->sections ) - 1 ) ]['fields'][] = $field; } if ( ! isset( $this->meta[ $field['id'] ] ) ) { $this->meta[ $field['id'] ] = $this->options_defaults[ $field['id'] ]; } // Only override if it exists, and it's not the default. /** If ( isset( $this->meta[ $field['id'] ] ) && isset( $field['default'] ) && $this->meta[ $field['id'] ] === $field['default'] ) { * // unset($this->meta[$this->tag_id][$field['id']]); * } */ } } } } } } $this->parent_options = ''; if ( ! empty( $this->to_replace ) ) { foreach ( $this->to_replace as $id => $field ) { add_filter( "redux/options/{$this->parent->args['opt_name']}/field/$id/register", array( $this, 'replace_field' ) ); } } add_filter( "redux/options/{$this->parent->args['opt_name']}/options", array( $this, 'override_options' ) ); if ( is_admin() && in_array( $pagenow, $this->pagenows, true ) ) { $priority = $this->parent->args['user_priority'] ?? 3; add_action( 'show_user_profile', array( $this, 'add_profiles' ), $priority ); add_action( 'edit_user_profile', array( $this, 'add_profiles' ), $priority ); add_action( 'user_new_form', array( $this, 'add_profiles' ), $priority ); } } /** * Replace field. * * @param array $field Field array. * * @return mixed */ public function replace_field( array $field ) { if ( isset( $this->to_replace[ $field['id'] ] ) ) { $field = $this->to_replace[ $field['id'] ]; } return $field; } /** * Output CSS. * * @param array $field Field array. * * @return array */ public function output_css( array $field ): array { if ( isset( $this->output[ $field['id'] ] ) ) { $field['output'] = $this->output[ $field['id'] ]; } return $field; } /** * Make sure the defaults are the defaults * * @param array $options Option array. * * @return array */ public function override_options( array $options ): array { $this->parent->options_class->default_values(); $this->parent_defaults = $this->parent->options_defaults; if ( empty( $this->meta ) ) { // phpcs:ignore WordPress.Security.NonceVerification $user = isset( $_GET['user_id'] ) ? sanitize_text_field( wp_unslash( $_GET['user_id'] ) ) : get_current_user_id(); $this->meta = Redux_Users::get_user_meta( array( 'user' => $user ) ); } $data = wp_parse_args( $this->meta, $this->options_defaults ); foreach ( $data as $key => $value ) { if ( isset( $meta[ $key ] ) && '' !== $meta[ $key ] ) { $data[ $key ] = $meta[ $key ]; continue; } if ( isset( $options[ $key ] ) ) { $data[ $key ] = $options[ $key ]; } } $this->parent->options_defaults = wp_parse_args( $this->options_defaults, $this->parent->options_defaults ); return wp_parse_args( $data, $options ); } /** * Sanitize Query. * * @param array $queries Queries. * * @return array */ public function sanitize_query( array $queries ): array { $clean_queries = array(); foreach ( $queries as $key => $query ) { if ( 'relation' === $key ) { $relation = $query; } elseif ( ! is_array( $query ) ) { $clean_queries[ $key ]['values'] = array( $query ); // First-order clause. } elseif ( $this->is_first_order_clause( $query ) ) { print( 'h3' ); if ( isset( $query['value'] ) && array() === $query['value'] ) { unset( $query['value'] ); } $clean_queries[ $key ] = $query; // Otherwise, it's a nested query, so we recurse. } else { print( 'h4' ); $cleaned_query = $this->sanitize_query( $query ); if ( ! empty( $cleaned_query ) ) { $clean_queries[ $key ] = $cleaned_query; } } } if ( empty( $clean_queries ) ) { return $clean_queries; } // Sanitize the 'relation' key provided in the query. if ( isset( $relation ) && 'OR' === strtoupper( $relation ) ) { $clean_queries['relation'] = 'OR'; /* * If there is only a single clause, call the relation 'OR'. * This value will not actually be used to join clauses, but it * simplifies the logic around combining key-only queries. */ } elseif ( 1 === count( $clean_queries ) ) { $clean_queries['relation'] = 'OR'; // Default to AND. } else { $clean_queries['relation'] = 'AND'; } return $clean_queries; } /** * Is first order clause. * * @param array $query Query array. * * @return bool */ protected function is_first_order_clause( array $query ): bool { return isset( $query['key'] ) || isset( $query['value'] ); } /** * Support file and field enqueue. */ public function enqueue() { global $pagenow; if ( in_array( $pagenow, $this->pagenows, true ) ) { if ( 'user-new.php' === $pagenow ) { $this->parent->args['disable_save_warn'] = true; } $this->parent->transients = get_transient( $this->parent->args['opt_name'] . '-transients-users' ); $this->parent->transients_check = $this->parent->transients; if ( isset( $this->parent->transients['notices'] ) ) { $this->notices = $this->parent->transients['notices']; $this->parent->transients['last_save_mode'] = 'users'; } delete_transient( $this->parent->args['opt_name'] . '-transients-users' ); $this->parent->enqueue_class->init(); // phpcs:ignore WordPress.NamingConventions.ValidHookName do_action( "redux/users/{$this->parent->args['opt_name']}/enqueue" ); /** * Redux users CSS * filter 'redux/page/{opt_name}/enqueue/redux-extension-users-css' */ if ( true === $this->parent->args['dev_mode'] ) { wp_enqueue_style( 'redux-extension-users', // phpcs:ignore WordPress.NamingConventions.ValidHookName apply_filters( "redux/users/{$this->parent->args['opt_name']}/enqueue/redux-extension-users-css", $this->extension_url . 'redux-extension-users.css' ), array(), self::$version ); } /** * Redux users JS * filter 'redux/page/{opt_name}/enqueue/redux-extension-users-js */ wp_enqueue_script( 'redux-extension-users', // phpcs:ignore WordPress.NamingConventions.ValidHookName apply_filters( "redux/users/{$this->parent->args['opt_name']}/enqueue/redux-extension-users-js", $this->extension_url . 'redux-extension-users' . Redux_Functions::is_min() . '.js' ), array( 'jquery', 'redux-js' ), self::$version, true ); // Values used by the javascript. wp_localize_script( 'redux-extension-users', 'reduxUsers', $this->users_roles ); } } /** * DEPRECATED */ public function default_values() { if ( ! empty( $this->profiles ) && empty( $this->options_defaults ) ) { foreach ( $this->profiles as $key => $profile ) { if ( empty( $profile['sections'] ) ) { continue; } // fill the cache. foreach ( $profile['sections'] as $sk => $section ) { if ( ! isset( $section['id'] ) ) { if ( ! is_numeric( $sk ) || ! isset( $section['title'] ) ) { $section['id'] = $sk; } else { $section['id'] = sanitize_title( $section['title'], $sk ); } $this->profiles[ $key ]['sections'][ $sk ] = $section; } if ( isset( $section['fields'] ) ) { foreach ( $section['fields'] as $k => $field ) { if ( empty( $field['id'] ) && empty( $field['type'] ) ) { continue; } if ( 'ace_editor' === $field['type'] && isset( $field['options'] ) ) { $this->profiles[ $key ]['sections'][ $sk ]['fields'][ $k ]['args'] = $field['options']; unset( $this->profiles[ $key ]['sections'][ $sk ]['fields'][ $k ]['options'] ); } if ( 'section' === $field['type'] && isset( $field['indent'] ) && true === $field['indent'] ) { $field['class'] = $field['class'] ?? ''; $field['class'] .= 'redux-section-indent-start'; $this->profiles[ $key ]['sections'][ $sk ]['fields'][ $k ] = $field; } $this->parent->options_defaults_class->field_default_values( $this->parent->args['opt_name'], $field ); } } } } } if ( empty( $this->meta ) ) { // phpcs:ignore WordPress.Security.NonceVerification $user = isset( $_GET['user_id'] ) ? sanitize_text_field( wp_unslash( $_GET['user_id'] ) ) : get_current_user_id(); $this->meta = Redux_Users::get_user_meta( array( 'user' => $user ) ); } } /** * Add Profiles. */ public function add_profiles() { if ( empty( $this->profiles ) || ! is_array( $this->profiles ) ) { return; } foreach ( $this->profiles as $key => $profile ) { if ( empty( $profile['sections'] ) ) { continue; } $defaults = array( 'id' => "$key", 'section_id' => $key, 'profiles' => array(), ); $profile = wp_parse_args( $profile, $defaults ); // Override the parent args on a meta-term level. if ( empty( $this->orig_args ) ) { $this->orig_args = $this->parent->args; } if ( isset( $profile['args'] ) ) { $this->parent->args = wp_parse_args( $profile['args'], $this->orig_args ); } elseif ( $this->parent->args !== $this->orig_args ) { $this->parent->args = $this->orig_args; } if ( ! isset( $profile['class'] ) ) { $profile['class'] = array(); } if ( ! empty( $profile['class'] ) ) { if ( ! is_array( $profile['class'] ) ) { $profile['class'] = array( $profile['class'] ); } } $profile['class'] = $this->add_term_classes( $profile['class'] ); if ( isset( $profile['post_format'] ) ) { $profile['class'] = $this->add_term_hide_class( $profile['class'] ); } global $pagenow; if ( strpos( $pagenow, 'edit-' ) !== false ) { $profile['style'] = 'wp'; $profile['class'][] = ' edit-page'; $profile['class'][] = ' redux-wp-style'; } $this->generate_profiles( array( 'args' => $profile ) ); if ( ! empty( $profile['roles'] ) ) { foreach ( $profile['roles'] as $profiletype ) { if ( sanitize_text_field( wp_unslash( $_GET['users'] ) ) !== $profiletype ) { // phpcs:ignore WordPress.Security.NonceVerification continue; } } } } } /** * Field Default. * * @param array $field_id ID. * * @return mixed|string */ public function field_default( array $field_id ) { if ( ! isset( $this->parent->options_defaults ) ) { $this->parent->options_defaults = $this->parent->default_values(); } if ( ! isset( $this->parent->options ) || empty( $this->parent->options ) ) { $this->parent->get_options(); } $this->options = $this->parent->options; if ( isset( $this->parent->options[ $field_id['id'] ] ) && isset( $this->parent->options_defaults[ $field_id['id'] ] ) && $this->parent->options[ $field_id['id'] ] !== $this->parent->options_defaults[ $field_id['id'] ] ) { return $this->parent->options[ $field_id['id'] ]; } else { if ( empty( $this->options_defaults ) ) { $this->default_values(); // fill cache. } $data = ''; if ( ! empty( $this->options_defaults ) ) { $data = $this->options_defaults[ $field_id['id'] ] ?? ''; } if ( empty( $data ) && isset( $this->parent->options_defaults[ $field_id['id'] ] ) ) { $data = $this->parent->options_defaults[ $field_id['id'] ] ?? ''; } return $data; } } /** * Function to get and cache the post meta. * * @param string $id ID. * * @return array */ private function get_meta( string $id ): array { if ( ! isset( $this->meta[ $id ] ) ) { $this->meta[ $id ] = array(); $o_data = get_post_meta( $id ); // phpcs:ignore WordPress.NamingConventions.ValidHookName $o_data = apply_filters( "redux/users/{$this->parent->args['opt_name']}/get_meta", $o_data ); if ( ! empty( $o_data ) ) { foreach ( $o_data as $key => $value ) { if ( count( $value ) === 1 ) { $this->meta[ $id ][ $key ] = maybe_unserialize( $value[0] ); } else { $new_value = array_map( 'maybe_unserialize', $value ); $this->meta[ $id ][ $key ] = $new_value[0]; } } } if ( isset( $this->meta[ $id ][ $this->parent->args['opt_name'] ] ) ) { $data = maybe_unserialize( $this->meta[ $id ][ $this->parent->args['opt_name'] ] ); foreach ( $data as $key => $value ) { $this->meta[ $id ][ $key ] = $value; update_post_meta( $id, $key, $value ); } unset( $this->meta[ $id ][ $this->parent->args['opt_name'] ] ); delete_post_meta( $id, $this->parent->args['opt_name'] ); } } return $this->meta[ $id ]; } /** * Get values. * * @param mixed $the_post Post array. * @param string $meta_key Meta key. * @param string $def_val Default value. * * @return mixed|string */ public function get_values( $the_post, string $meta_key = '', string $def_val = '' ) { // Override these values if they differ from the admin panel defaults. ;). if ( isset( $the_post->users_role ) && in_array( $the_post->users_role, $this->users_roles, true ) ) { if ( isset( $this->users_role_values[ $the_post->users_role ] ) ) { $meta = $this->profile_fields[ $the_post->users_role ]; } else { $defaults = array(); if ( ! empty( $this->profile_fields[ $the_post->users_role ] ) ) { foreach ( $this->profile_fields[ $the_post->users_role ] as $key => $null ) { if ( isset( $this->options_defaults[ $key ] ) ) { $defaults[ $key ] = $this->options_defaults[ $key ]; } } } $meta = wp_parse_args( $this->get_meta( $the_post->ID ), $defaults ); $this->profile_fields[ $the_post->users_role ] = $meta; } if ( ! empty( $meta_key ) ) { if ( ! isset( $meta[ $meta_key ] ) ) { $meta[ $meta_key ] = $def_val; } return $meta[ $meta_key ]; } else { return $meta; } } return $def_val; } /** * Check Edit Visibility. * * @param array $params Array. * * @return bool */ private function check_edit_visibility( array $params = array() ): bool { global $pagenow; // Edit page visibility. if ( strpos( $pagenow, 'edit-' ) !== false ) { if ( isset( $params['fields'] ) ) { foreach ( $params['fields'] as $field ) { if ( in_array( $field['id'], $this->parent->fields_hidden, true ) ) { // Not visible. } elseif ( isset( $field['add_visibility'] ) && $field['add_visibility'] ) { return true; } } return false; } if ( isset( $params['add_visibility'] ) && $params['add_visibility'] ) { return true; } return false; } return true; } /** * Generate Profiles. * * @param array $metaterm Meta term. */ private function generate_profiles( array $metaterm ) { if ( ! empty( $metaterm['args']['permissions'] ) && ! Redux_Helpers::current_user_can( $metaterm['args']['permissions'] ) ) { return; } if ( isset( $metaterm['args']['style'] ) && in_array( $metaterm['args']['style'], array( 'wp', 'wordpress' ), true ) ) { $container_class = 'redux-wp-style'; $metaterm['args']['sidebar'] = false; } elseif ( isset( $metaterm['args']['sidebar'] ) && ! $metaterm['args']['sidebar'] ) { $container_class = 'redux-no-sections'; } else { $container_class = 'redux-has-sections'; } $class = implode( ' ', $metaterm['args']['class'] ); echo '
| '; if ( ! empty( $th ) ) { echo $th; //phpcs:ignore WordPress.Security.EscapeOutput } echo ' | '; echo ''; } } else { echo ' | ' . $th; //phpcs:ignore WordPress.Security.EscapeOutput } if ( 'section' === $field['type'] && true === $field['indent'] ) { $field['class'] = $field['class'] ?? ''; $field['class'] .= 'redux-section-indent-start'; } if ( ! isset( $this->meta[ $field['id'] ] ) ) { $this->meta[ $field['id'] ] = ''; } $this->parent->render_class->field_input( $field, $this->meta[ $field['id'] ] ); echo ' |
|---|
' . count( $this->notices['errors'] ) . ' ' . esc_html__( 'error(s) were found!', 'redux-framework' ) . '
'; echo '' . count( $this->notices['warnings'] ) . ' ' . esc_html__( 'warnings(s) were found!', 'redux-framework' ) . '
'; echo '