Hi, first of all thanks for your work, I'm really enjoying the platform you built and its miles better than WP frontend.
So i wanted to discuss a couple of changes that I made to the codebase to fix some issues I encountered, keep in mind that im not an SE neither a developer for that matter. I solved the issues with the help of Claude and really thinking about what it was doing.
so 1st of all, related to this issue I still found problems regarding the variations when adding items to the cart with the following error
Error adding to cart: [attribute_name] is not a valid attribute of the product: [Product] at line 75 of useCart
note that [attribute_name] here CAN contain spaces since its the displayed name!
The fix was to actually do not use this field for querying the DB but the databseId instead, hence:
--- woonuxt_base/app/pages/product/[slug].vue
+++ woonuxt_base/app/pages/product/[slug].vue
@@ -85,7 +85,7 @@ const updateSelectedVariations = (variations: VariationAttribute[]): void => {
activeVariation.value = getActiveVariation?.[0] || null;
selectProductInput.value.variationId = activeVariation.value?.databaseId ?? null;
- selectProductInput.value.variation = activeVariation.value ? attrValues.value : null;
+ // selectProductInput.value.variation = activeVariation.value ? attrValues.value : null;
variation.value = variations;
2nd issue i run into was related to some misconfiguration in Stripe that ended up in popup errors, some Floating point math error and some issues with woocommerce "not recognizing the order" because the amount changed due to multiple shipping options:
--- a/woonuxt_base/app/components/shopElements/StripeElement.vue
+++ b/woonuxt_base/app/components/shopElements/StripeElement.vue
@@ -4,7 +4,7 @@ const { stripe } = defineProps(['stripe']);
const appConfig = useAppConfig();
const runtimeConfig = useRuntimeConfig();
-const rawCartTotal = computed(() => cart.value && parseFloat(cart.value.rawTotal as string) * 100);
+const rawCartTotal = computed(() => cart.value && Math.round(parseFloat(cart.value.rawTotal as string) * 100));
const emit = defineEmits(['updateElement']);
let elements = null as any;
let paymentElement = null as any;
@@ -39,13 +39,14 @@ const createStripeElements = async () => {
billingDetails: {
name: 'auto',
email: 'auto',
- phone: 'never',
- address: 'never',
+ phone: 'auto',
+ address: 'auto',
},
},
wallets: {
applePay: 'auto',
googlePay: 'auto',
},
});
paymentElement.mount('#payment-element');
--- a/woonuxt_base/app/pages/checkout.vue
+++ b/woonuxt_base/app/pages/checkout.vue
@@ -94,7 +94,17 @@ const payNow = async () => {
const paymentMethodType = appConfig.stripePaymentMethod || 'payment';
if (paymentMethodType === 'payment') {
- // Modern Payment Element - use confirmPayment
+ // Always fetch a fresh payment intent right before confirming to ensure
+ // it reflects the current cart total (e.g. after shipping method changes)
+ try {
+ const { stripePaymentIntent } = await GqlGetStripePaymentIntent({
+ stripePaymentMethod: 'PAYMENT' as any,
+ });
+ stripeClientSecret.value = stripePaymentIntent?.clientSecret || '';
+ } catch (e) {
+ throw new Error('Could not initialize payment. Please try again.');
+ }
+
if (!stripeClientSecret.value) {
throw new Error('Payment intent not available. Please refresh and try again.');
}
@@ -249,21 +259,13 @@ const checkEmailOnInput = (email?: string | null): void => {
if (email && isInvalidEmail.value) isInvalidEmail.value = false;
};
-// Watch for Stripe payment method selection to get client secret for Payment Element
+// Clear the client secret when switching away from Stripe.
+// The fresh intent is now fetched inside payNow() right before confirming,
+// so we no longer eagerly fetch here (which could become stale if the cart changes).
watch(
() => orderInput.value.paymentMethod?.id,
- async (paymentMethodId) => {
- if (paymentMethodId === 'stripe' && appConfig.stripePaymentMethod === 'payment') {
- try {
- const { stripePaymentIntent } = await GqlGetStripePaymentIntent({
- stripePaymentMethod: 'PAYMENT' as any,
- });
- stripeClientSecret.value = stripePaymentIntent?.clientSecret || '';
- } catch (error) {
- console.error('Failed to get client secret for Payment Element:', error);
- stripeClientSecret.value = '';
- }
- } else {
+ (paymentMethodId) => {
+ if (paymentMethodId !== 'stripe') {
stripeClientSecret.value = '';
}
},
Lastly if a customer is not signed in (i.e. guest customer) order-summary.vue does not work, because the query fails to recover the necessary info, looking though the DB there is no easy way to actually do this, even if it would be really cool to be able to see the status of ones order by browsing a webpage with a databaseID and a key.
From my understanding this is because a guest user is not authorized to gather said data even if he has both the correct key and databaseID. This could be a possible avenue of improvement!
For now I have used a simple workaround to guarantee a consistent user experience:
--- a/woonuxt_base/app/pages/order-summary.vue
+++ b/woonuxt_base/app/pages/order-summary.vue
@@ -6,6 +6,7 @@ const { customer } = useAuth();
const { formatDate, formatPrice } = useHelpers();
const { t } = useI18n();
const { cart, emptyCart, refreshCart } = useCart();
+const { completedOrder } = useCheckout();
const order = ref<Order | null>(null);
const fetchDelay = ref<boolean>(query.fetch_delay === 'true');
@@ -53,18 +54,30 @@ onMounted(async () => {
});
async function getOrder() {
+ // Always try GQL first (works for logged-in users and guests with active session)
try {
const { customer } = await GqlGetOrder({ id: params.orderId as string });
const fetchedOrder = customer?.orders?.nodes?.[0];
-
if (fetchedOrder) {
order.value = fetchedOrder;
- } else {
- errorMessage.value = 'Could not find order';
+ completedOrder.value = null; // clear stashed data, we got fresh data
+ isLoaded.value = true;
+ return;
}
} catch (err: any) {
- errorMessage.value = err?.gqlErrors?.[0].message || 'Could not find order';
+ // GQL failed, will fall through to completedOrder below
+ }
+
+ // Fallback: guest checkout where GQL session is lost after redirect.
+ // useCheckout stashes the order data in completedOrder right after GqlCheckout succeeds.
+ if (completedOrder.value) {
+ order.value = completedOrder.value;
+ completedOrder.value = null; // clear so navigating away and back doesn't reuse stale data
+ isLoaded.value = true;
+ return;
}
+
+ errorMessage.value = 'Could not find order';
isLoaded.value = true;
}
I really hope these changes are useful and do not introduce any security issue, if you find better solutions let me know!
Cheers!
Hi, first of all thanks for your work, I'm really enjoying the platform you built and its miles better than WP frontend.
So i wanted to discuss a couple of changes that I made to the codebase to fix some issues I encountered, keep in mind that im not an SE neither a developer for that matter. I solved the issues with the help of Claude and really thinking about what it was doing.
so 1st of all, related to this issue I still found problems regarding the variations when adding items to the cart with the following error
Error adding to cart: [attribute_name] is not a valid attribute of the product: [Product] at line 75 of useCartnote that
[attribute_name]here CAN contain spaces since its the displayed name!The fix was to actually do not use this field for querying the DB but the
databseIdinstead, hence:2nd issue i run into was related to some misconfiguration in Stripe that ended up in popup errors, some Floating point math error and some issues with woocommerce "not recognizing the order" because the amount changed due to multiple shipping options:
Lastly if a customer is not signed in (i.e. guest customer)
order-summary.vuedoes not work, because the query fails to recover the necessary info, looking though the DB there is no easy way to actually do this, even if it would be really cool to be able to see the status of ones order by browsing a webpage with adatabaseIDand akey.From my understanding this is because a guest user is not authorized to gather said data even if he has both the correct
keyanddatabaseID. This could be a possible avenue of improvement!For now I have used a simple workaround to guarantee a consistent user experience:
I really hope these changes are useful and do not introduce any security issue, if you find better solutions let me know!
Cheers!