manual sync trigger

I am successfully using User Sync between shop.solari.com and home.solari.com, with the former as the master. On shop.solari.com, we sell subscriptions on home.solari.com. Our store is from a company called "FoxyCart (https://www.foxy.io/). They have a WordPress plugin called FoxyShop. A new subscriber buys a subscription via FoxyCart, and then FoxyCart creates a WordPress subscriber account, and password, on the master. That part works great, but the password does not sync to the slave. All other aspects of the new subscriber account do sync to the slave, except for the password. I can go back to the master, create a news password in WordPress, and then the sync is immediate to the slave. The FoxyCart developer says he can fix this but has a question, "We need to know if it’s possible to manually trigger a sync for a single user from PHP, as it appears that because a plugin you’re using is updating a users password with an SQL query, that it’s being missed as part of the sync." I hope this makes some sense to you. I am not a developer, so I have only a rudimentary understanding. Thank you for your help. Please let me know if you need any further information.

  • Predrag Dubajic

    Hey Mark,

    Hope you're doing well.

    Could you please provide me with some more details about your setup, is this issue specific to the way that FoxyCart creates new users?
    Does it use it's own registration form/method or those users are registered as regular WordPress users?

    On my test site I tried creating three different accounts, one from frontend, and two from the backend, one with and one without the password set during the registration, and all of those three were properly synced to my destination site.

    We need to know if it’s possible to manually trigger a sync for a single user from PHP, as it appears that because a plugin you’re using is updating a users password with an SQL query, that it’s being missed as part of the sync

    User Sync plugin offers a manual sync directly from User Sync panel, are they looking to fire this automatically when new user is created via FoxyCart plugin?

    Best regards,
    Predrag

  • Mark Gilmore

    Predrag,

    Thank you for your quick response.

    Before I get into details, let me first start with a comment about your last sentence. I am familiar with the manual sync button. It works well. Perhaps the easiest solution would be to trigger that from the FoxyCart plugin. Is there a relatively easy method to do that?

    Now on to the notes from the FoxyCart developer. I hope they can help you. Again, I am not a programmer, but I know enough to be dangerous. Here's what Adam, from FoxyCart had to say:

    1) remove_action('user_register', 'foxyshop_profile_add', 5);
    $new_user_id = wp_insert_user(array(
    'user_login' => $customer_email,
    'user_email' => $customer_email,
    'first_name' => $customer_first_name,
    'last_name' => $customer_last_name,
    'user_email' => $customer_email,
    'user_pass' => wp_generate_password(),
    'user_nicename' => $customer_first_name . ' ' . $customer_last_name,
    'display_name' => $customer_first_name . ' ' . $customer_last_name,
    'nickname' => $customer_first_name . ' ' . $customer_last_name,
    'role' => apply_filters('foxyshop_default_user_role', 'subscriber'),
    ));
    add_user_meta($new_user_id, 'foxycart_customer_id', $customer_id, true);

    //Set Password In WordPress Database
    $wpdb->query("UPDATE $wpdb->users SET user_pass = '" . esc_sql($customer_password) . "' WHERE ID = $new_user_id");

    2) At a guess, I’d say what’s happening is that the plugin is syncing right after the wp_insert_user() function is called, but not after the SQL query happens
    Does User Sync support manually triggering a sync via code?
    If so, you could add a hook into a FoxyShop event that happens right after that SQL query to trigger it to sync then

    I hope this makes some sense and helps our discussion. Thank you for your help.

    Best regards,

    Mark

  • Predrag Dubajic

    Hi Mark,

    Thanks for the additional info, it appears that User Sync doesn't have an easy way of firing up the sync process from external sources, or at least nothing that I could find :slight_frown:

    It seems that this will require custom development but that goes a bit beyond my head so I will pass this ticket to our dev guys and they will see how it could be integrated with a third-party plugin based on the above information.
    Please note that developer response might be slower than usual staff response, so we appreciate your patience on this.

    Best regards,
    Predrag

  • Ivan

    Hi Mark Gilmore !

    Don't get me wrong but they don't recommend to update a user's password with an SQL query. You can change wp_generate_password() to $customer_password into wp_insert_user function and not to run your SQL at all or at least use wp_insert_user function instead of the SQL query.
    Anyway, if you really have a good reason not to change it, you can use it for syncing an individual user:
    do_action( 'profile_update', $user_id );

    Best,
    Ivan.

  • Mark Gilmore

    Predrag,

    Our FoxyCart developer was convinced that he had what he needed to know to make his plugin talk to yous. After two attempts, he now needs to take this to the next level. He is willing to talk directly to your developer, so that everybody can speak the same language and take non-developers like me out of the middle-man job. Our developer's name is Adam Judd ans he is also located in Australia. Hopefully this will make the transaction much easier, especially since I'm based in California. Please let me know the next steps to get this process in place. Meanwhile, I've cut & pasted Adam's latest at the end of this message.

    Best regards,

    Mark

    1. The datafeed is sent to your FoxyShop endpoint which calls the foxyshop_datafeed_user_update() function
    2. The function performs either a wp_insert_user or wp_update_user call, depending on if the user exists already or not.
    3. That function triggers WP’s profile_update action because a user has been updated.
    4. After that call, FoxyShop then performs the direct SQL to updated the hashed password for the user
    5. It then triggers a custom WP action called either foxyshop_datafeed_add_wp_user or foxyshop_datafeed_update_wp_user
    6. The custom code you added then hooks into those events, manually triggering profile_update again to allow any functions dependant on that event to receive the updated user record
    The custom code outputs a line of text to a file whenever profile_update is triggered, and whenever the foxyshop add_wp_user or update_wp_user actions are triggered. As you can tell based on the steps above, that should result in three lines for each action. Once for step 3, once for step 5 and then again for step 6.
    That’s exactly what I’m seeing in the log file:
    `adam_profile_update: 1697
    solari_datafeed_modify_wp_user: 1697
    adam_profile_update: 1697`

    adam [11:15 PM]
    All of that to say, based on what the WPMU dev said - that should be triggering their user sync to occur. I’m guessing they have a custom function that is run on the profile_update action being triggered too. If our custom event is being triggered, so should theirs.
    FYI: I’ve commented out the custom logging code I provided earlier, but the original action code is still present.
    If you want, you can delete the file called adam_log.txt from within your child theme folder

    adam [11:33 PM]
    It looks like the user sync plugin has some form of debug mode where it logs the different calls it makes - I don’t see a way to enable that debug mode within their plugin though. That could be a good next step to try see if the user synchronisation is being called within their plugin when it should.

  • Mark Gilmore

    Hi Predrag Dubajic and Ivan,

    As Mark mentioned - my name is Adam and I'm a part of the team at FoxyCart.

    For some additional context - the specific reason the password is needed to be updated via SQL is because we don't have access to the customers raw password at that stage. Instead, our system sends on the already hashed password so that customer passwords aren't being sent anywhere in the clear. Unfortunately (at least as best we can tell) Wordpress doesn't support passing a hashed password through to their default user insert/update functions - so the SQL needs to be used instead.

    From your earlier suggestion Ivan, we helped Mark add in a customisation to trigger the profile update event like this:

    do_action('profile_update', $user_id );

    We added in some quick logging around that function call, and also adding an extra hook into the profile update action - and based on those logs we are seeing that the profile update action is being triggered when we're expecting it to.

    As your user sync plugin also hooks into the profile update action - I assumed that this would result in the sync function being triggered successfully. Unfortunately from Mark's tests - that's not what he's seeing.

    Can you think of any particular reason why that wouldn't be working for them? Is there some logging specific to the user sync plugin we could utilise for further debugging for this? And if yes - how can that be enabled?

    Thanks in advance!
    Adam

  • Ivan

    Hi Mark Gilmore !

    You can debug this process in the following way. Please, add the following snippet in a MU plugin ( more info about MU plugins is here )

    <?php
    function wpmu_user_sync_temp() {
    	$change = filter_input( INPUT_GET, 'user_sync_change_debug_mode' );
    	if ( $change && class_exists( 'User_Sync' ) ) {
    		$user_sync = new User_Sync();
    		$user_sync->set_options( 'debug_mode', '1' );
    	}
    }
    add_action( 'plugins_loaded', 'wpmu_user_sync_temp' );

    After than, you can enable plugin debug just visiting {your_domain}/wp-admin/?user_sync_change_debug_mode=1 page. Please, make sure that you enabled debug log for that you can visit the {your_domain}/wp-admin?page=user-sync page and you'll see this notice

    Note: after tests you can change '1' to '0' for disabling debug mode and remove this MU plugin.

    After enabling Debug mode - it'll create two files: {wordpress_folder}/wp-content/plugins/user-sync/log/errors_m.log for main site and {wordpress_folder}/wp-content/plugins/user-sync/log/errors_s.log for sub sites.

    Also, user synchronizations run into sync_user function into {wordpress_folder}/wp-content/plugins/user-sync/user-sync.php file (approximately line 475). In addition, you can add some information to those log-files just add this line anywhere in this function
    $this->write_log( "ADDITIONAL INFORMATION" );

    If it doesn't help you - please, provide me with login credentials, I can look into it more.

    https://premium.wpmudev.org/contact/#i-have-a-different-question
    Please visit our private Contact page and complete the form with the following information:

    Subject: "Attn: Ivan Svyrskyi"

    In the Message box, please provide the following:

    link back to this thread for reference
    instruction STEP BY STEP how can I replicate on your site running your direct SQL
    any other relevant urls

    Admin login:
    Admin username
    Admin password
    Login url

    FTP/SFTP credentials
    host
    username
    password
    (and port if required)

    Note: Don't send any credentials via this forum because it's public forum.

    Best,
    Ivan.

  • Mark Gilmore

    Ivan,

    If I understand correctly, you want me to put the User Sync Master in debug mode. I'm hesitant to do this because of the behavior described here: https://premium.wpmudev.org/forums/topic/user-sync-error-i-am-getting-a-connection-error#post-1313382 The master is communicating well with one client, and only one client. Both the master and client (shop.solari.com and home.solari.com respectively) are both mission critical. The user sync can not fail between shop and home. Now to make a long story short, I can't add any other sync clients. So that you could debug, I set up a test site called vanilla.solari.com, with full access for you, so that you can figure out why I can't add any more sync clients.

    The second issue, this one, is that when FoxyCart creates a user account on the master (shop), that password is not synced on the working client (home). This is where I would like you and Adam Judd from ForyCart to communicate. Adam reached out to you two posts back. Please communicate directly with him and start a discussion. I'll be here to facilitate anything you might need from a sysadmin standpoint. Adam does have limited access to the master and you to to, via a restricted admin account. Please see https://premium.wpmudev.org/forums/topic/user-sync-error-i-am-getting-a-connection-error#post-1313382 for access information.

    It is my since hope that you can you can work with Adam from FoxyCart in a manner that does not require me to put the Master in debug mode. If there is a way that you can proved to me that I won't lose user sync between two production installations, I'll listen.

    I hope this makes sense. Than you for your help.

    Best regards,

    Mark

  • Ivan

    Hi Mark Gilmore !

    Thank you, I've got credentials for both sites.
    I've already replied to that thread. So, first of all, you should solve that issue, because it doesn't sync users at all. After that, Adam Judd from ForyCart, I need an instruction STEP BY STEP how can I replicate on your site running your direct SQL. I mean, what do you do for checking that

    Unfortunately from Mark's tests - that's not what he's seeing.

    Best,
    Ivan.

  • Mark Gilmore

    Just an update... The only way we can test this process, is to buy a subscription, using FoxyShop, just like anyone else. Then, with the password generated while buying the subscription, we go to our sync client (home.solari.com) and then attempt to log in. When you and FoxyShop communicated in the past, Adam at Foxy wrote some code and asked us to try again. Our password on the sync client still didn't work. If we go to the user sync master (shop.solari.com) and change/request a new password, then we have no problems logging into the user sync client. I hope this helps.

  • Mark Gilmore

    Ivan,

    I heard back from the FoxyCart developer. The text is shown below. I hope this help and will get us back making progress with this issue.

    Best regards,

    Mark

    "To reproduce your tests, that’s pretty much exactly what they’d need to do. In order to properly reproduce it, FoxyShop needs to get the datafeed from FoxyCart, which requires a transaction is completed on the store.
    They could potentially also try just using the SQL that the FoxyShop integration uses, which is this:
    $wpdb->query("UPDATE $wpdb->users SET user_pass = '" . esc_sql($customer_password) . "' WHERE ID = $user_id");
    and we’re basically triggering do_action('profile_update', $user_id ); after that has run
    They may be able to just rig something up on their side to use the same call and test manually"

  • Mark Gilmore

    Ivan,

    We were not successful. Here's the latest from the FoxyShop developer. Any ideas?

    Best regards,

    Mark

    adam [4:52 PM]
    That’s a shame. I made changes just as the WPMU devs recommended:
    `// Begin added by FoxyCart - 2018-05-14
    $old_user_data = get_userdata( $new_user_id );
    // End added by FoxyCart - 2018-05-14

    //Set Password In WordPress Database
    $wpdb->query("UPDATE $wpdb->users SET user_pass = '" . esc_sql($customer_password) . "' WHERE ID = $new_user_id");

    // Begin added by FoxyCart - 2018-05-14
    remove_action('profile_update', 'foxyshop_profile_update', 5);
    do_action('profile_update', $new_user_id, $old_user_data );
    // End added by FoxyCart - 2018-05-14`
    the remove_action there is just for preventing FoxyShops normal profile update callback function from running

  • Ivan

    Hi Mark Gilmore !

    Probably, they run their code too early. They should do it at least after plugins_loaded hook. Also, as I mentioned, I tested this code and it works fine. Moreover, you can check it following the next instructions.
    You could try adding the following snippet in a MU plugin ( more info about MU plugins is here )

    <?php
    
    function wpmu_user_sync_update_password() {
    	global $wpdb;
    	$user_id = 1;
    	$old_user_data = get_userdata( $user_id );
    	$wpdb->query("UPDATE $wpdb->users SET user_pass = '" . md5( 'aaaaa' ) . "' WHERE ID = $user_id");
    	do_action('profile_update', $user_id, $old_user_data );
    }
    
    add_action( 'plugins_loaded', 'wpmu_user_sync_update_password' );

    'aaaaa' - is a new password.
    Please, add this MU plugin to your master site, refresh a page on the master site, and then try to login using the new password on a subsite.

    Note: don't forget to remove this MU plugin after the test.

    Best,
    Ivan.

Thank NAME, for their help.

Let NAME know exactly why they deserved these points.

Gift a custom amount of points.