WordPress.org

Make WordPress Core

Opened 4 months ago

Closed 3 months ago

#39223 closed enhancement (fixed)

Add a filter to edit $meta array in wpmu_signup_user

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.

Attachments (4)

39223.1.diff (1.2 KB) - added by Mista-Flo 4 months ago.
Add signup_user_meta filter to edit meta array in wp_signup_user function
39223.2.patch (4.6 KB) - added by Mista-Flo 4 months ago.
Fix php doc
39223.3.patch (1.9 KB) - added by Mista-Flo 3 months ago.
Refresh patch according to #38781
39223.4.patch (3.7 KB) - added by Mista-Flo 3 months ago.
add signup_site_meta filter to wpmu_signup_blog() and keep consistency with filter names

Download all attachments as: .zip

Change History (16)

@Mista-Flo
4 months ago

Add signup_user_meta filter to edit meta array in wp_signup_user function

#1 @Mista-Flo
4 months ago

  • Keywords has-patch added

#2 @johnjamesjacoby
4 months 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
4 months 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 4 months ago by Mista-Flo (previous) (diff)

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


4 months ago

#5 @flixos90
4 months 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
4 months 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 4 months ago by Mista-Flo (previous) (diff)

@Mista-Flo
4 months ago

Fix php doc

#7 @SergeyBiryukov
3 months ago

  • Description modified (diff)

#8 @SergeyBiryukov
3 months ago

  • Keywords needs-refresh added

Need a refresh after [39886] and [39887].

@Mista-Flo
3 months ago

Refresh patch according to #38781

#9 follow-up: @Mista-Flo
3 months ago

  • Keywords needs-refresh removed

I have refreshed the patch. And I have chosen a new name for the filter, tell me if it's good : "user_signup_meta"

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

#10 in reply to: ↑ 9 @SergeyBiryukov
3 months ago

Replying to Mista-Flo:

And I have chosen a new name for the filter, tell me if it's good : "user_signup_meta"

I think signup_user_meta is more consistent with other filters like after_signup_user or wpmu_signup_user_notification.

While we're at it, let's also add signup_site_meta to wpmu_signup_blog() for consistency between two functions, like after_signup_site mirrors after_signup_user in [34112].

@Mista-Flo
3 months ago

add signup_site_meta filter to wpmu_signup_blog() and keep consistency with filter names

#11 @Mista-Flo
3 months ago

@SergeyBiryukov Thanks for your review. It should be fine now :)

#12 @SergeyBiryukov
3 months ago

  • Resolution set to fixed
  • Status changed from assigned to closed

In 39920:

Users: Introduce signup_site_meta and signup_user_meta for filtering signup metadata in wpmu_signup_blog() and wpmu_signup_user(), respectively.

Props Mista-Flo.
Fixes #39223.

Note: See TracTickets for help on using tickets.