Support » Developing with WordPress » Firing hooks on user creation

  • I need to fire a webhook when a user is created. I’m not sure which hook to use, though.

    I need to pass into the hook’s function some meta about the user such as their First Name, Last Name, email, and a custom meta field I created (their mobile number).

    user_register() seems to be the one I want, but the codex does say:

    “Not all user meta data has been stored in the database when this action is triggered. For example, nickname is in the database but first_name and last_name are not (as of v3.9.1). The password has already been encrypted when this action is triggered.”

    So, that leads me to believe that I might not be able to access all of the data I need on the newly created user….

    • This topic was modified 1 month, 2 weeks ago by oguruma.
Viewing 15 replies - 1 through 15 (of 19 total)
  • That is correct, not all data will be available.
    https://developer.wordpress.org/reference/hooks/user_register/

    The question is, do you need that data?
    If not, it is the right hook.

    If you need such data like the first_name or last_name you need to hook into the user_meta actions, as those are user meta data and not user data.
    Thus you might find https://developer.wordpress.org/reference/hooks/insert_user_meta/ useful.
    Note that this is a filter, thus needs to return something, as opposed to the action.

    Moderator bcworkz

    (@bcworkz)

    “insert_user_meta” might be an option, but if you need a conglomerate of meta data to do your function, this filter will only let you access one item at a time.

    You might see if “user_register” will work for you by getting the necessary meta data from $_POST. This will only work for data entered when an admin adds users through the back end. Front end self registration will only yield name and email, unless you use a custom form that collects more data.

    Thread Starter oguruma

    (@oguruma)

    Thanks for the input.

    Unfortunately, I need custom user meta. I do have a form plugin (JetFormBuilder) that I use to create custom registration forms. That plugin does have its own API that lets you fire a hook/filter to catch the form data, but I was hoping to do this without having to rely on that form plugin itself, in case I want to change form plugins in the future.

    @bcworkz – I’m not sure to understand the reason why @oguruma cant use the filter I suggested

    It has a $meta argument with all the meta in an array
    So he can get all meta data – not just one a time

    It’s perhaps unorthodox to do something inside a filter but by what I see it’s the only chance to get user meta when it’s inserted
    And since it’s an array, you can access all of its data and pass it to whatever other code you might have. You could even do another action within this filter, as long you return the array at the end and don’t modify it?

    On the other hand the data might not even be there

    Filters a user’s meta values and keys immediately after the user is created or updated and before any user meta is inserted or updated.

    … so it appears the data would be the defaults, not what you passed when creating the user?
    This useless I guess for this use case?

    • This reply was modified 1 month, 1 week ago by Beda.
    Moderator bcworkz

    (@bcworkz)

    It has a $meta argument with all the meta in an array

    .
    Oh! Right. I completely forgot about that aspect. It’s an extremely rare use case for me. Somehow I had “add_post_meta” in my mind :/

    so it appears the data would be the defaults

    No, it should be entered user data. It fires before the SQL to insert executes. The passed data is valid at that point, but not in the DB. Sorry for causing confusion.

    That said, it’s conceivable performBuilder stores data through some other mechanism. The easiest way to verify one way or another is to hook the filter and dump out the passed data to see what’s there. I think it’s very likely to all be there. This would be a cleaner approach IMO than grabbing data out of $_POST, even though it too ought to work fine.

    Thread Starter oguruma

    (@oguruma)

    @bcworkz I’m having a hard time working with the JetFormBuilder hook/filter.

    From the JetFormBuilder documentation the hook arguments are:

    $result – only for Filter hook. Hook execution result
    $request – array with submitted form data
    $action_handler – action handler object, allows to manage actions and to throws error status “throw new Action_Exception(‘ Failed’ )

    I test the action hook to fire my curl to Twilio, and it works, but the problem is that it fires on form submission, without regard to whether or not the user got registered successfully, so if the submit the form, but the user already exists, it will still fire the hook.

    I think if I filter the form submission, but I have no idea what to return (obviously when I try to filter it without reutrning anything, it breaks the form submission).

    The JetFormBuilder documentation isn’t clear as to how you’re supposed to do this…

    Ultimately what I would like to do, though, is have this operate indepdently of JetFormBuilder (or any plugin, really), which would mean creation of Custom User Meta by modifying the theme or a simple custom plugin.

    Moderator bcworkz

    (@bcworkz)

    How you package your code depends on what your end goals are. If for one specific site, you could add code via a child theme, or a custom plugin that contains all site specific code. If you want others to use your code, it’s best packaged as a stand-alone plugin. Whether it’s dependent on JetForm or not is up to you. If it’s saving data in user meta like most do, using one of the mechanisms Beda and I have discussed should serve your needs. No dependency required since you’re depending on core functionality.

    Filter callbacks should return the equivalent of what ever the second apply_filters() arg is (the first collected by your callback). You can alter this as needed, but maintain the type and structure of what is passed. To collect more than one arg in your callback, be sure to pass all 4 args that are possible in add_filter(). The 4th being the number of args your callback collects.

    When a user registers, their data will be inserted into the DB, whether they’ve confirmed their registration or not. (for single site installations, multisite user registration is different). The only reason for failure is if there is some sort of coding or DB communication error. If it’s critical that your callback’s actions only occur after you’re sure of successful registration, either after insertion or confirmation, then the hooks discussed so far are inappropriate. “user_register” will fire after successful installation, but if the data you need is not in the passed $userdata, don’t try to get it from the DB. Due to race conditions, it’s unlikely to be available yet. The submitted data should still be in $_POST though.

    If you need to wait until the user confirms registration by setting their password, use one of the password reset actions. In that case the user data can be taken from the DB

    Thread Starter oguruma

    (@oguruma)

    In this case, the users set their password when they register via the form.

    What I am trying to do is pass their phone number to Twilio when they (successfully) register. Twilio will use a custom flow to have them verify their phone number (“Please reply CONFIRM” etc).

    The registration form (made with JetFormbBuilder so far) will capture their phone number.

    I experimented with using the JetFormBuilder built-in action hook, but the problem is that the hook fires when the form is submitted, regardless of whether the registration was successful. So, if the username/email is already taken by another user, the registration will fail, but the custom Twilio function will still fire.

    As far as I can tell, none of hooks will work since the user_meta won’t have been written, yet, unless I am misudnerstanding one of the solutions that’s been mentioned.

    • This reply was modified 1 month ago by oguruma.
    • This reply was modified 1 month ago by oguruma.
    Moderator bcworkz

    (@bcworkz)

    If an alternative registration process is involved, where a known password is immediately set, I’m unsure what constitutes a successful registration. (Default WP process does set an unknown password prior to confirmation) What generally happens on a process failure in WP is either some sort of error hook fires, or some sort of error value is returned somewhere such as a WP_Error object. Lacking any precise suggestions on where this happens in your case, you’d need to trace through the code involved. Somewhere there must be a failure branch for error conditions like “name already exists”.

    Easier said than done since plugin code added via hooks is difficult to manually trace unless you have some sort of IDE that steps through and into every code line. Lacking that, you can often determine what callbacks are added by examining the global $wp_filter structure. Because callbacks can be added at the last moment, then removed on execution, dumping out the structure at the wrong time may not reveal all callbacks added. At least with filters you can examine the values returned at different priority levels without knowing what callbacks were used.

    Thread Starter oguruma

    (@oguruma)

    As I think about it, the only thing that could stop the new user from being created (assuming that the form is successful on the front-end), is the username/email address being used already.

    Would it be feasible to parse the submitted-form’s email and username against the existing users, and then fire the necessary code if it’s not taken (and therefore we assume the user registration was successful)?

    Moderator bcworkz

    (@bcworkz)

    It’s feasible as long as you check before the new user is actually inserted 🙂 It seems unnecessary though since surely this check gets done already somewhere else. I’m unsure about your form’s process, but for the default WP process (using register_new_user()), both “register_post” (confusing name IMO) and “registration_errors” fire prior to insertion. They both pass any registration errors in a WP_Error object if any should exist. If there are such errors, that error object will be returned soon afterwards instead of the expected new user ID.

    Using “registration_errors” filter, you can cause custom errors to occur which prevent registration even if WP would normally accept all the submitted user data. But only if your form’s process utilizes register_new_user().

    Thread Starter oguruma

    (@oguruma)

    Looking back at the insert_user_meta filter that @bedas mentioned, it looks like that returns $user object, not just the specified fields.

    Assuming that I have made custom user meta fields, and those fields are added with the registration form, can I use get_user_meta( $user->ID) to get the custom meta?

    Or does that hook only insert the fields as part of the $meta array that are part of its parameters(things like first name, last name, show_admin_bar)?

    I tried to reach out to Crocoblock, the plugin’s author, but they haven’t been profoundly helpful…

    As I test it based on the plugin’s included hook, the hook will fire as long as the front-end/javascript of the form is successful. Since the validation of whether or not the email/username is already used takes place on the back-end, what can happen is the user submits the form with an email address that’s already taken, the Twilio function will fire, and then they will resubmit the form (with a different email, hopefully) and then the function will fire again.

    Obviously, it’s better to only call that function when the registration is successful, so they don’t get spammed with it.

    Moderator bcworkz

    (@bcworkz)

    AFAICT, the “insert_user_meta” would only fire after successful user insertion. Failing due to existing user name or email would occur well before this hook fires.

    That filter should contain any additional meta data submitted at the same time. Be sure to extract your data from the 4th parameter $userdata array, not the 1st $meta array. This filter will also fire when a user updates their profile data, but you can check the 3rd $update parameter if this is so. The filter docs page says $userdata is the raw meta data, so you should validate and sanitize any data you want to use.

    These comments are based on what I see from reviewing source code, I’ve not confirmed any of this, I leave that to you. Hook the filter and dump out the passed data to verify what you need is there. Then re-register again in a way that will fail. The hook ought not to fire.

    Thread Starter oguruma

    (@oguruma)

    Well, the filter worked, but it doesn’t seem to work when with JetForm builder. JetForm Builder will update the custom user meta, but it doesn’t seem to get caught by the insert_user_meta filter when a user registers that way.

    So, when a user registers with the JetForm, the user_mobile meta isn’t sent, but if I update a user on the WordPress dashboard, the user_meta is sent.

    test_sender() is a function I built to send the data to pipedream for testing. It will eventually be sent to a real function.

    add_filter('insert_user_meta', 'twilio_verify_new_user',10,4);
    
    function twilio_verify_new_user($meta, $user, $update, $userdata){
    
      $user_payload = array (
        "is_update" => $update,
        "mobile" => get_user_meta($userdata['ID'],'user_mobile',true),
        "first_name" => $userdata['first_name'],
      );
    test_sender($user_payload);
      
    return $meta;
    return $user;
    return $update;
    return $userdata;
    };
    • This reply was modified 3 weeks, 1 day ago by bcworkz. Reason: code format fixed
    Moderator bcworkz

    (@bcworkz)

    Ugh! That’s what I was afraid of. The form uses some alternative method of adding user meta. Sadly, I know nothing of JetForm. Where does the form submit to? Perhaps you can examine the code at that destination and gain some clue to how it’s saving user meta data.

Viewing 15 replies - 1 through 15 (of 19 total)
  • You must be logged in to reply to this topic.