WordPress.org

Make WordPress Core

Opened 3 years ago

Last modified 3 years ago

#39223 closed enhancement

Add a filter to edit $meta array in wpmu_signup_user — at Version 7

Reported by: Mista-Flo Owned by: Mista-Flo
Milestone: 4.8 Priority: normal
Severity: normal Version: 3.0
Component: Users Keywords: has-patch
Focuses: multisite Cc:

Description (last modified by SergeyBiryukov)

Hello,

Here's the situation.

In a multisite context, on a new user form in a site of the network, it creates a new signup entry in the signups database table with user informations, and a meta array containing by default 'add_to_blog' => $wpdb->blogid, 'new_role' => $_REQUEST['role'] , so when the user is finnaly activated (with email confirmation or not) the wpmu_activate_user function is called and use this $meta array.

Imagine you want to extend this behavior and for example, add some user meta in signup to use it for activation. you have the good hook in wpmu_activate_user wpmu_activate_user where you can use the meta array to do what you want, but you can't filter the $meta array in wpmu_signup_user to add some usefull data.

For example, for my plugin Multiple Roles : https://wordpress.org/plugins/multiple-roles/ which allow admins to add multiple roles for a given user. In order to handle the multisite behavior, I need to edit this $meta array to pass it my multiple roles array.

So according to me, the best approach will be to add a filter for $meta array in wpmu_signup_user function just before the database insert like this :

<?php
$meta = apply_filters( 'signup_user_meta', $meta, $user, $user_email, $key );

With this given filter, In my plugin, I just have to add those lines, so here a real use of case :

<?php
add_filter( 'signup_user_meta', 'mu_add_roles_in_signup', 10, 4 ); // Handle Multisite
add_action( 'wpmu_activate_user', 'mu_add_roles_after_activation', 10, 3 ); // Handle Multisite

        /**
         * Add multiple roles in meta array on multisite signups database table
         *
         * @param $meta
         * @param $user
         * @param $user_email
         * @param $key
         *
         * @return mixed
         */
        function mu_add_roles_in_signup( $meta, $user, $user_email, $key ) {

                $new_roles = ( isset( $_POST['md_multiple_roles'] ) && is_array( $_POST['md_multiple_roles'] ) ) ? $_POST['md_multiple_roles'] : array();
                if ( ! empty( $new_roles ) ) {
                        $meta['md_roles'] = $new_roles;
                }

                return $meta;
        }

        /**
         * Add multiple roles after user activation
         *
         * @param $user_id
         * @param $password
         * @param $meta
         */
        function mu_add_roles_after_activation( $user_id, $password, $meta ) {
                if ( ! empty( $meta['md_roles'] ) ) {
                        $this->model->update_roles( $user_id, $meta['md_roles'] );
                }
        }

By the way, if you're okay with my following patch, I would benefit from this other ticket : #38781 which avoid $meta array to be serialized when passed to hooks, in fact, I'm using its patch to make mine.

Change History (9)

@Mista-Flo
3 years ago

Add signup_user_meta filter to edit meta array in wp_signup_user function

#1 @Mista-Flo
3 years ago

  • Keywords has-patch added

#2 @johnjamesjacoby
3 years ago

This seems fine to me.

Since the meta data couldn't be accessed previously, I don't see harm in serializing it now either.

#3 @Mista-Flo
3 years ago

Without this patch merged in the core, in my plugin, I should do this (code from my last plugin release 24 december) :

<?php
add_action( 'after_signup_user', 'mu_add_roles_in_signup_meta', 10, 4 );
public function mu_add_roles_in_signup_meta( $user, $user_email, $key, $meta ) {
        if ( isset( $_POST['md_multiple_roles_nonce'] ) && ! wp_verify_nonce( $_POST['md_multiple_roles_nonce'], 'update-md-multiple-roles' ) ) {
                return;
        }

        if ( ! $this->model->can_update_roles() ) {
                return;
        }

        $new_roles = ( isset( $_POST['md_multiple_roles'] ) && is_array( $_POST['md_multiple_roles'] ) ) ? $_POST['md_multiple_roles'] : array();
        if ( empty( $new_roles ) ) {
                return;
        }

        global $wpdb;

        // Get user signup
        // Suppress errors in case the table doesn't exist
        $suppress = $wpdb->suppress_errors();
        $signup   = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->signups} WHERE user_email = %s", $user_email ) );
        $wpdb->suppress_errors( $suppress );

        if ( empty( $signup ) || is_wp_error( $signup ) ) {
                return new WP_Error( 'md_get_user_signups_failed' );
        }

        // Add multiple roles to a new array in meta var
        $meta = maybe_unserialize( $meta );
        $meta['md_roles'] = $new_roles;
        $meta = maybe_serialize( $meta );

        // Update user signup with good meta
        $where        = array( 'signup_id' => (int) $signup->signup_id );
        $where_format = array( '%d' );
        $formats      = array( '%s' );
        $fields       = array( 'meta' => $meta );
        $result       = $wpdb->update( $wpdb->signups, $fields, $where, $formats, $where_format );

        // Check for errors
        if ( empty( $result ) && ! empty( $wpdb->last_error ) ) {
                return new WP_Error( 'md_update_user_signups_failed' );
        }
}

That means, get the signup from the database, update the meta array with the data I want to add, update the signup in the database, so it's painfull and not sure (bugs are possible), btw, the code is inspired by the WP signup plugin of @johnjamesjacoby

Last edited 3 years ago by Mista-Flo (previous) (diff)

This ticket was mentioned in Slack in #core-multisite by florian-tiar. View the logs.


3 years ago

#5 @flixos90
3 years ago

  • Milestone changed from Awaiting Review to 4.8
  • Owner set to Mista-Flo
  • Status changed from new to assigned

This looks like a useful enhancement to me as well.

The patch looks good except for a few documentation issues:

  • The filter description should be in 3rd person singular.
  • The filter description should describe what is being filtered and thus should start with "Filters ...", for example "Filters the metadata for a user signup.".
  • The description for the $meta parameter should rather say "Default empty array." instead of a full sentence in the end.
  • The description for the $key parameter is missing a dot.
  • Since the data is serialized, an additional line could possibly included as extended description to indicate this to developers, maybe something like "The metadata will be serialized prior to storing it in the database.".

All kind of nitpicking, but would you update the patch @Mista-Flo? :)

The last thing we might think about is whether signup_user_meta is the best name for the filter. I'm not opposed to it, but just to throw something in the room, user_signup_meta or wpmu_signup_user_meta (the latter would give parity with the function although I don't like the wpmu prefix) would be alternatives. What do you think?

#6 @Mista-Flo
3 years ago

Thanks for your review :)

Totaly agree with your recommendations, I have updated the PHPdoc.

Concerning the filter name, I'm not sure about the best name, I tried to be consistent by looking at the other hook of the function named "after_signup_user" but it's not the best one maybe. I also like the wpmu_signup_user_meta name. Is there any recent multisite hook added that we can compare ?

Last edited 3 years ago by Mista-Flo (previous) (diff)

@Mista-Flo
3 years ago

Fix php doc

#7 @SergeyBiryukov
3 years ago

  • Description modified (diff)
Note: See TracTickets for help on using tickets.