wp-graphql-woocommerce icon indicating copy to clipboard operation
wp-graphql-woocommerce copied to clipboard

Order properties empty with guest checkout

Open wcoppens opened this issue 3 years ago • 9 comments

Describe the bug When checking out a cart as a guest the orders and lastOrder property is empty, even though the billing_email is set with the updateCustomer mutation and the same billing_email is submitted with the checkout.

To Reproduce Steps to reproduce the behavior:

First of all, i took a clean clone of this repo and spun up the docker-compose file as described in the development guidelines. As second i've made a small adjustment to the docker-compose.yml to allow access to port 80 from outside and mapped port 9002 to port 80 for the testable_app service. This way i can interact with the service from my Docker host. Also i've added 2 defines to the wp-config.php:

define('WP_SITEURL', 'http://localhost:9002');
define('WP_HOME', 'http://localhost:9002');

Then the steps i've taken in order to come to this result:

  1. I added a dummy simple product to the woocommerce store.
  2. I've enabled the pay on delivery method and added free shipping worldwide in the Woocommerce store settings.
  3. I opened Postman and first ran the getCart query:
query GetCart {
  cart {
    total
  }
}

I get a 200 response with a JSON payload telling me the cart value is 0, which is correct. Also a woocommerce-session header is returned with a JWT payload. From now i use this header on each following request!

  1. I update my customer details with the updateCustomer mutation:
mutation UpdateCustomer {
  __typename
  updateCustomer(
    input: {
      billing: {
        email: "[email protected]"
        firstName: "John"
        lastName: "Doe"
        address1: "221 Bakerstreet"
        country: GB
        city: "London"
      }
      shippingSameAsBilling: true
    }
  ) {
    customer {
      billing {
        email
        firstName
        lastName
        address1
        city
        country
      }
      shipping {
        email
        firstName
        lastName
        address1
        city
        country
      }
    }
  }
}

Here i also get a 200 response with the expected payload, telling me the billing and shipping address is setup.

  1. I add a product to my cart using the addToCart mutation:
mutation AddToCart {
  addToCart(input: { productId: 10, quantity: 1 }) {
    cart {
      total
    }
  }
}
  1. I run the checkout mutation as following:
mutation Checkout {
  checkout(
    input: {
      paymentMethod: "cod"
      billing: {
        email: "[email protected]"
        firstName: "John"
        lastName: "Doe"
      }
    }
  ) {
    clientMutationId
    order {
      id
      orderNumber
      orderKey
      status
      billing {
        email
      }
    }
    result
    redirect
  }
}

And the response i get:

{
    "data": {
        "checkout": {
            "clientMutationId": null,
            "order": {
                "id": "c2hvcF9vcmRlcjoxMQ==",
                "orderNumber": "11",
                "orderKey": "wc_order_ghCw1AlrSaru0",
                "status": "PROCESSING",
                "billing": {
                    "email": "[email protected]"
                }
            },
            "result": "success",
            "redirect": "http://localhost:9002/checkout/order-received/11/?key=wc_order_ghCw1AlrSaru0"
        }
    },
    "extensions": {
        "debug": []
    }
}
  1. Finally with still the same wc-session i try to fetch the latest order details using the customer query:
query GetCustomer {
  customer {
    id
    orderCount
    email
    shipping {
      address1
      city
      company
      country
      email
      firstName
      lastName
      phone
    }
    billing {
      address1
      city
      company
      country
      email
      firstName
      lastName
      phone
    }
    sessionToken
    lastOrder {
      id
    }
    orders {
      nodes {
        id
      }
    }
  }
}

Now i would expect that the response i get on the lastOrder, orders and orderCount property would be something different then 0, null or {}. However i get the following response:

{
    "data": {
        "customer": {
            "id": "guest",
            "orderCount": 0,
            "email": null,
            "shipping": {
                "address1": null,
                "city": null,
                "company": null,
                "country": "GB",
                "email": null,
                "firstName": "John",
                "lastName": "Doe",
                "phone": null,
            },
            "billing": {
                "address1": "221 Bakerstreet",
                "city": "London",
                "company": null,
                "country": "GB",
                "email": "[email protected]",
                "firstName": "John",
                "lastName": "Doe",
                "phone": null,
            },
            "sessionToken": null,
            "lastOrder": null,
            "orders": {
                "nodes": []
            }
        }
    },
    "extensions": {
        "debug": []
    }
}

Expected behavior I would expect that the orderCount, lastOrder and orders property of the customer query at step 7 would be filled with data.

Plugin Versions

  • WooGraphQL Version: Dev branch and 0.8.1.
  • WPGraphQL Version: 1.3.4
  • WordPress Version: 5.7
  • WooCommerce Version: 5.1.0

wcoppens avatar Apr 06 '21 11:04 wcoppens

I have the same issue! Help appreciated

sidyes avatar May 10 '21 19:05 sidyes

@wcoppens @sidyes Have you tried setting the guest user's email to the session using the updateCustomer mutation. This will give the guest user access to the order data.

kidunot89 avatar Jul 05 '21 22:07 kidunot89

@kidunot89 I think i am doing that at step 4 in the "steps to reproduce" content, or am i doing it the wrong way?

wcoppens avatar Jul 07 '21 06:07 wcoppens

I have the same issue!

It seems like when the customer is a guest woocommerce use WC_Customer_Data_Store_Session which return false by default for get_last_order().

It also return 0 for get_order_count() and get_total_spent() as well.

in class-wc-customer-data-store-session.php.

...
public function get_last_order( &$customer ) {
	return false;
}

public function get_order_count( &$customer ) {
	return 0;
}

public function get_total_spent( &$customer ) {
	return 0;
}
...

I was able to fix this issue by modifying includes/model/class-customer.php file to something like this.

...
'last_order_id'         => function() {
	$last_order = apply_filters(
		'woocommerce_customer_get_last_order',
		get_user_meta( $customer->get_id(), '_last_order', true ),
		$customer
	);
	if ( '' === $last_order ) {
		global $wpdb;

		$meta_key   = ! empty( $this->data->get_billing_email() ) ? '_billing_email' : '_customer_user';
		$meta_value = ! empty( $this->data->get_billing_email() )
			? $this->data->get_billing_email()
			: $this->data->get_id();

		$last_order = $wpdb->get_var(
			"SELECT posts.ID
			FROM $wpdb->posts AS posts
			LEFT JOIN {$wpdb->postmeta} AS meta on posts.ID = meta.post_id
			WHERE meta.meta_key = '".$meta_key."'
			AND   meta.meta_value = '" . $meta_value . "'
			AND   posts.post_type = 'shop_order'
			AND   posts.post_status IN ( '" . implode( "','", array_map( 'esc_sql', array_keys( wc_get_order_statuses() ) ) ) . "' )
			ORDER BY posts.ID DESC"
		);
		update_user_meta( $customer->get_id(), '_last_order', $last_order );
	}

	if ( ! $last_order ) {
		return null;
	}

	return absint( $last_order );
},
...

I used some code from here class-wc-customer-data-store.php.

I'm not sure if this is a related issue but also using order query after checkout with the same order ID returns null for guest customer.

mahmods avatar Jul 09 '21 13:07 mahmods

I experience the same issue. When trying to load the data for a guest account, even if the customer object returns the proper e-mail, I cannot get the order from the order query, it always returns null.

Marco-Daniel avatar Feb 21 '22 15:02 Marco-Daniel

I experience the same issue. I used woocommerce-session correctly. image @kidunot89 we can see that this issue is marked as resolved. But This query query { customer { orders { ... } } } only works correctly in the Graphql IDE from the backend admin page.

FullstackWEB-developer avatar May 02 '23 06:05 FullstackWEB-developer

@wcoppens @sidyes Have you tried setting the guest user's email to the session using the updateCustomer mutation. This will give the guest user access to the order data.

@kidunot89 But how can I use this mutation without user.accessToken?

  mutation UPDATE_CUSTOMER_MUTATION($input: UpdateCustomerInput!) {
    updateCustomer(input: $input) {
      clientMutationId
      customer {
        email
        billing {
          country
          state
          postcode
          email
        }
        shipping {
          country
          state
          postcode
          email
        }
        calculatedShipping
        hasCalculatedShipping
      }
    }
  }```

FullstackWEB-developer avatar May 02 '23 08:05 FullstackWEB-developer

Hey.

I had the same problem, and after looking inside the code (class-order.php), we can see that the visibility of the order fields depend on the user being either the owner of the order, or the guest customer being the current user (and thus the order's owner). See owner_matches_current_user().

This is checked by matching the email field in the billing address with the customer's email. If neither of those fields are set or if they don't match, you won't be able to get values other than null for most of the order object.

You can set the email addresses with the updateCustomer mutation. You don't need an access token for that operation, just a session token set in the request's cookies, which you should be using to identify a guest customer anyway.

Hope this helps!

jb0b-zdar avatar Feb 23 '24 22:02 jb0b-zdar