Link to home
Start Free TrialLog in
Avatar of Netty Admin
Netty AdminFlag for United States of America

asked on

Wordpress - Javascript - JQuery - AJAX - PHP - need assitance with scripts

Need assistance pulling the whole user object from WordPress and also have a question about where I should put my last JavaScript for this process.
Avatar of Netty Admin
Netty Admin
Flag of United States of America image

ASKER

Currently I have a script that is pulling particular user data from a WordPress user's profile with the following function

 
    function get_user_data() : array
{
    $user = wp_get_current_user();

    $data = [
        'UserId' => $user->ID,
        'Email' => $user->user_email,
        'Username' => $user->user_login,
    ];

    return $data;
}

Open in new window

{

     "id": 438,

     "date_created": "2020-06-25T09:53:56",

     "date_created_gmt": "2020-06-25T13:53:56",

     "date_modified": "2020-06-25T09:53:56",

     "date_modified_gmt": "2020-06-25T13:53:56",

     "email": "testingwebhook@email.com",

     "first_name": "testing",

     "last_name": "newwebhookdata",

     "role": "subscriber",

     "username": "customer1593093203",

     "billing": {

         "first_name": "testing",

         "last_name": "newwebhookdata",

         "company": "",

         "address_1": "4015 Starfish Lane",

         "address_2": "",

         "city": "Tampa",

         "postcode": "33615",

         "country": "",

         "state": "Florida",

         "email": "testingwebhook@email.com",

         "phone": "(111) 444-7777"

     },

     "shipping": {

         "first_name": "",

         "last_name": "",

         "company": "",

         "address_1": "",

         "address_2": "",

         "city": "",

         "postcode": "",

         "country": "",

         "state": ""

     },

     "is_paying_customer": false,

     "avatar_url": "https://secure.gravatar.com/avatar/f2d79",

     "meta_data": [

         {

             "id": 19605,

             "key": "entry_id",

             "value": "1228"

         },

         {

             "id": 19606,

             "key": "_gform-entry-id",

             "value": "1228"

         },

         {

             "id": 19615,

             "key": "gfID",

             "value": "3"

         },

         {

             "id": 19616,

             "key": "ServiceRequested",

             "value": "Bundle"

         },

         {

             "id": 19617,

             "key": "twitter",

             "value": ""

         },

         {

             "id": 19618,

             "key": "facebook",

             "value": ""

         },

         {

             "id": 19619,

             "key": "linkedin",

             "value": ""

         },

         {

             "id": 19620,

             "key": "gplus",

             "value": ""

         },

         {

             "id": 19622,

             "key": "wc_last_active",

             "value": "1593043200"

         }

     ],

     "_links": {

         "self": [

             {

                 "href": "https://blabla/wp-json/wc/v3/customers/438"

             }

         ],

         "collection": [

             {

                 "href": "https://blabla.com//wp-json/wc/v3/customers"

             }

         ]

     }

 }


Open in new window

^^^This is all the data he wants and in JSON form
or he specifically needs the following but would rather have it all if I can give it to him


  • firstname    
  • lastname    
  • billing address (just address, unless there is address_2 [ste.# apt.#], )    
  • zipcode


Avatar of Chris Stanyon
Hi Netty,

That data looks like a WooCommerce Customer, not a WordPress User - they're 2 different objects.

And as for your Javascript, based on our previous conversations, it makes sense to put Javascript in your JS file (the one in your theme folder), and any PHP in your function.php file.
Ok so put the final function that validates the iframe postmessages via the event listener in the same JScript file that I have in the child theme folder?
Yes I meant the woocommerce customer data that is pulled with:
wp_get_current_user()

Open in new window

ASKER CERTIFIED SOLUTION
Avatar of Chris Stanyon
Chris Stanyon
Flag of United Kingdom of Great Britain and Northern Ireland image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Chris,

this is the listener we setup before. It does a couple other things that we need to validate and unhide the Place Order button, going to put it in the JScript file we put in the child theme


 window.addEventListener("message", (event) => {
    if (event.origin !== "https://api-east.pestpac.com")
        return;
  
    let ccInfo = JSON.parse(event.data)
    
 if (ccInfo.BillToID) {
 
    jQuery(document).ready(function($) {
    $('#cc_frame').hide().after(`<br><br><br><p>Credit Card Saved Successfully<br><br><br></p>`)
 $("#payment #place_order.button.alt").fadeIn('slow')
});
 
 } else if (ccInfo.Error) { 
 
  jQuery(document).ready(function($) {
    $('#cc_frame').hide().after(`<br><br><br><hr class="redrule"><p style="color:red">Credit card not saved. Blablabla.</p><hr class="redrule"><br><br><br>`)
 
});
  
 }
  
}, false);

Open in new window

He is asking if I can send it all or if not send just
  • firstname    
  • lastname    
  • billing address (just address, unless there is address_2 [ste.# apt.#], )    
  • zipcode


It would be nice if I had the ability to do either in case he wants to switch back, vice versa
Hi Netty,

For your listener, you'd want something like this:

/**
 * Listen for the window.message event
 */
$(window).on('message', function(e) {
    if (e.originalEvent.origin !== 'https://api-east.pestpac.com') return;

    let ccInfo = e.originalEvent.data

    if (ccInfo.BillToID) {
        $('#cc_frame').hide().after(`<br><br><br><p>Credit Card Saved Successfully<br><br><br></p>`)
        $("#payment #place_order.button.alt").fadeIn('slow')
    } else if (ccInfo.Error) {
        $('#cc_frame').hide().after(`<br><br><br><hr class="redrule"><p style="color:red">Credit card not saved. Blablabla.</p><hr class="redrule"><br><br><br>`)
    }
})

Open in new window

Because we're in jQuery here, you'll want to use originalEvent.data, rather than just event.data
Hey Netty,

How you get your customer info will depend on how your site is setup. Judging by the data you posted earlier, you're dealing with registered customers here, so you can grab their details as long as they're logged into your site.

As for what data you want to send - I would highly recommend you only send the data that is needed for any given operation. The full JSON data you posted ealier contains a lot of information, and most of it is actually useless. If the endpoint just needs firstname, lastname and billing address (including zip code), then just send that. Have a look at this:

/**
 * Get the User data
 */
function get_user_data() : array
{
    $userId = get_current_user_id();
    $customer = new WC_Customer($userId);

    $data = [
        'FirstName' => $customer->get_first_name(),
        'LastName' => $customer->get_last_name(),
        'Billing' => $customer->get_billing(),
    ];

    return $data;
}

Open in new window

is this line supposed to have a space because "new" is doing something or does it also need an underscore

$customer = new WC_Customer($userId);

Open in new window

That's right as it is. In Object Oriented Programming, we instantiate a class by calling new ClassName(). WP_Customer is the class. The constructor for the class (the ctor) takes the ID as an argument, so we need:

new WC_Customer($userId);
ok thank you for explaining it......I am still learning....hopefully by the next month or so I will understand the basics of programming language because I am watching videos and going to follow Harvard's online CS50 class as well so forgive me for not knowing how it works yet and I really appreciate the explanations.  
No worries Netty - you're doing great. Stick at it - you'll have plenty of Eureka! moments where something that you've been struggling with will suddenly make perfect sense :)

To be fair - WordPress is not a great example to use when learning development - it does a lot of things in a really weird, non-standard way. As well as that, you're having to figure out programming in PHP (including some OOP) at the same time as learning Javascript, HTML and CSS, so it can be quite a challenge.
for some reason the billing info comes back with nothing in the fields
the current user works with wp though and gets the user info but not pulling the billing.
all the billing fields come back but with no data in fields

this works with the top results
User generated imagethis gives the second result

User generated image
have it this way and still all the billing comes back with nothing in the fields

User generated image
this one works though

User generated image
with this result:

User generated image

I tried replacing this

$userId = get_current_user_id();

Open in new window

with this

$userId = get_current_user();

Open in new window

If I cannot figure this out soon then I am going to revert to the first solution that give this result and he is going to have to pull the rest of the needed data with another call on the backend because today is the deadline on this part and we are having a meeting about it soon....I haven't even got a valid test url to test the listener yet either so I am hoping the event listener will work as we have it


I really appreciate your help....lmk if there is a way we can figure out why the billing data is not getting pulled

also, I had him put a test valid URL in the response and the event listener does not seem to be working
you sure we would set ccInfo to e.originalEvent.data ??
 

We do not get that info back from the third party until after the CC in inputted. 
OK.

Couple of points - if you're getting Cannot read property 'secureUrl' of undefined, then the Curl request is not returning any valid data. You'll need to log that and see what's coming back from your Curl request. I'm guessing something has changed, because you had this part working previously.

As for the WooCommerce customer data - are you using the standard WooCommerce checkout for this. The way it works is that a user registered on your site is logged in and they work there way through the WooCommerce checkout process. This creates a Customer record linked to their User account. By grabbing the UserId of the currently logged in user, we can use that to get at their Customer record. It seems from the data you're dumping that the User doesn't have a standard WooCommerce Customer record, which is why the data is coming back empty. If you're not using the standard WooCommerce process (or the currently logged in user is not the Customer, then you may need to grab the data from the user_meta instead, but that will depend on your setup.
We do not get that info back from the third party until after the CC in inputted.  

Your event listener (message) is only set up to listen for the postMessage event which fires AFTER the CC info has been input, so I'm not sure what you're referring to here.
Ok how would I get the zipcode from the user meta? and also the reason I was getting the "cannot read property" error was because he wasn't handing me the response the same way as before.....fixed that and now I have a manual test URL that we are using but the listener is not working and displaying the "Credit Card Saved Successfully" message or the "Credit card not saved" message
as for now my concern is to get the listener working.. Any suggestions on how to debug this part or try something else
Something else to check on - make sure you've removed the original event listener that you'd added in your snippets plugin. By putting it in the JS file, you should no longer include it in the snippets plugin
yes it has been disabled from the snippets
For debugging the event listener, just dump the response get and see what that contains:

/**
 * Listen for the window.message event
 */
$(window).on('message', function(e) {
    console.log("MESSAGE DATA", e)
    if (e.originalEvent.origin !== 'https://api-east.pestpac.com') return;

    ...
}

Open in new window

Look at your console and see what comes after the MESSAGE DATE bit.
In particular, pay attention to either data.origin or originalEvent.origin and make sure the remote server URL hasn't change. If it's not exactly as your if() statement, then the function will just quit before handling the data.
it is not logging anything for that

anything wrong here
User generated image
jQuery( function( $ ) {
    $(document).ready( function() {

        /**
         * AJAX Call to grab the Order URL from the server via the custom url created in Azure logics
         */
        $( document.body ).on( "click", "#payment #get_cc_order_url.get_cc_order_url", function(e) {
            e.preventDefault();
            $.ajax({
                url  : ccOrderParams.url,
                data : {
                  action : 'get_order_url',
                  security : ccOrderParams.nonce,
               },
               type : 'post',
               }).done(function(response) {
                  $('#cc_card_iframe').prop('src', response.data.secureURL)
               }).fail(function(error) {
                  console.log("ERROR", error)
               })        
            });
    
            $(window).on('message', function(e) {
               if (e.originalEvent.origin !== 'https://api-east.pestpac.com') return;
               console.log("MESSAGE DATA", e)
               let ccInfo = e.originalEvent.data
           
               if (ccInfo.BillToID) {
                   $('#cc_card_iframe').hide().after(`<br><br><br><p>Credit Card Saved Successfully<br><br><br></p>`)
                   $("#payment #place_order.button.alt").fadeIn('slow')
               } else if (ccInfo.Error) {
                   $('#cc_card_iframe').hide().after(`<br><br><br><hr class="redrule"><p style="color:red">Credit card not saved. blabla.</p><hr class="redrule"><br><br><br>`)
               }
           })
    
    
    
         });
})



Open in new window

SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
And put your console.log BEFORE the if() statement. If for some reason the origin doesn't match, then you function will exit before ever running the consol.e.log() line so you'll be left with no output:

$(window).on('message', function(e) {
    // see what's coming in first!
    console.log("MESSAGE DATA", e)

    if (e.originalEvent.origin !== 'https://api-east.pestpac.com') return;

Open in new window

ok also I need to add a third condition....when the link times out it displays this and this is what is shown...….does not appear to have a post message like the other events


User generated image

we do not need to addEventListener?

User generated image

I need to create that third condition as well.....now that the link is not giving me a postmessage event as I put above because it is timed out it looks much different......so this is def an issue for testing as of now, I am asking him for a new URL now

^^^this is why I am not getting anything in the console.log even before the "if" because this third condition seems not to give a postMessage like the other two conditions
We are adding an Event Listener - we're just doing it the jQuery way:

$(window).on('message', function(e) {
    ...
})

Open in new window

When we originally discussed this, you said there was a message sent when the window timed out - if that doesn't happen then you can't use a listener - there's no event to listen to.
ok I got it.....Ok its working now!!!
after I added antoher document ready and put the function under that it worked.


Now two final things......need to add the one more condition and also need to display a small spinning icon  a message that says" Retreiving Secure URL" for the time between when the button is clicked and the iframe is displayed
And is there any way to get the zip code from the user meta?? I have been googling and can not seem to find it
Right - you don't need a second document ready - you should ony have one, and both your functions go inside that:

jQuery( function( $ ) {
    $(document).ready( function() {

        /**
         * AJAX Call to grab the Order URL from the server via the custom url created in Azure logics
         */
        $( document.body ).on( "click", "#payment #get_cc_order_url.get_cc_order_url", function(e) {
            ...
        });


        /**
         * Message listener
         */
        $(window).on('message', function(e) {
            ...    
         });


    })
})

Open in new window

How you get the ZipCode will depend on how your data i sstored in the database. Like I said ealier, it seems that you're not using the standard WooCommerce customer process, so I don't know how you're storing that data. Generally, to get a Users meta data, you do this:

$data = get_user_meta( $userId, $key );

Open in new window

But you'd need to know the key (could be zipcode ???) . That is entirely dependent on your own system and how it's set up. I don't know that so I can't give you a specific answer on that.

As for the spinner - the jQuery AJAX method has an beforeSend property that allows you to run some code just before the AJAX call is made - that would be the best place to add some code to insert your spinner:

$.ajax({
    url  : ccOrderParams.url,
    type : 'post',
    data : {
        action: 'get_order_url',
        security: ccOrderParams.nonce,
    },
    beforeSend: function() {
        // add in your spinner and please wait code here
    },
}).done(function(response) {
    // hide your spinner and please wait message here
    $("#cc_card_iframe").prop('src', response.data.secureUrl)
}).fail(function(error) {
    console.log("ERROR", error)
})

Open in new window

cool been trying to find out how to get the zip code......I am going to try this other code and get report back...much appreciated. 
Success!
no need for the zip code anymore.....we got brand new URLs being returned every time now with the current config......only issue is for some odd reason when the postMessage gives the "Error" attribute for when the customer clicks cancel the "Credit Card Not Saved" message does not appear...…but when a card is entered correctly and postMessage has a "BillToID" attribute the script works fine and displays the "Credit Card Saved Successfully" message

User generated image^^^Will not display the Card not saved message

User generated image
^^^^Does display the "Credit Card Saved Successfully" message correctly

User generated image

This is really getting to me as it seems to be coded the same as the first message and it is listening for the same postMessage event
Ok, I know why one was working and the other wasn't, It is because I had turned back on the snippet and only had one of the iframe ids changed to match the new id and that was the success message.....so it appears using the snippet works but the function inside the child theme jscript is not working at all.
Got it working! I know you said that it should not need another jquery document ready but the only way that the console.log dumps data from the postMessage is only if I wrap the function in its own doc ready wrapper...
also had to add the json parse
User generated image
All good on this!!! thank you. I am going to make a new question about the "message while waiting" and spinning icon.….