Forum
Shop return_url not working on a view (MVC app)
I've been integrating perch with a site which has an MVC framework. The original site allows people to post classified adverts and the perch integration is intended to make use of the members and shop features so that users must log in before posting ads and can pay for upgrading their ads.
Everything has been going fine and everything seems to have integrated well but the only issue I seem to have is that, after the user submits their ad and comes to the payment page, the stripe payment goes through fine but the return_url is not working. After the stripe popup disappears with the green tick it just seems to reload the same page instead of going to the return_url that's been set.
I wonder if it has something to do with the fact the page where they enter their card details is not a physical page, it's a page I guess generated on the fly by the app and includes a token, in the form:
mywebsite.com/ads/0001/publish/ede46bf0f4b226ab33ef8c7bbf04ad23
The return_url works fine if I create a new, separate page away from the MVC app so I think that code itself is sound. Here are some of the files in question:
ad.publish.php view:
<?php
// pass to stripe basics
$customer_firstname = perch_member_get('first_name');
$customer_surname = perch_member_get('last_name');
$customer_name = $customer_firstname . ' ' . $customer_surname;
$customer_email = perch_member_get('email');
// pass to stripe cart titles, skus
$cart = perch_shop_cart(['skip-template'=>true]);
$cart_items = $cart['items'];
foreach($cart_items as $item) {
$product_titles[] = $item['title'];
$product_skus[] = $item['sku'];
}
$product_title = implode(', ', $product_titles);
$product_sku = implode(', ', $product_skus);
// stripe urls
if (perch_member_logged_in() && perch_post('stripeToken')) {
$return_url = '/dashboard';
$cancel_url = '/cancel';
// stripe data
perch_shop_checkout('stripe', [
'return_url' => $return_url,
'cancel_url' => $cancel_url,
'token' => perch_post('stripeToken'),
'receipt_email' => $customer_email,
'metadata' => [
'email' => $customer_email,
'name' => $customer_name,
'product(s)' => $product_title,
'sku(s)' => $product_sku,
],
]);
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Test</title>
</head>
<body>
<div>
<div>
<h1>Pay here</h1>
<?php
perch_shop_empty_cart();
perch_shop_add_to_cart(1);
// Show the cart with a non-interactive template
perch_shop_cart([
'template'=>'cart/cart_static.html'
]);
// Show the order addresses
perch_shop_order_addresses();
// Show the payment form
perch_shop_payment_form('stripe');
?>
</div>
</div>
</body>
</html>
the controller for the page:
// get publish ad details
$app->get('/:id/publish/:token', 'isAdPostAllowed', 'isBanned', function ($id, $token) use ($app) {
global $lang;
$j = new Ads($id);
$ad = $j->getAdFromToken($token);
$city = $j->getAdCity($ad->city);
$category = $j->getAdCategory($ad->category);
$amount = 0;
if (!$ad->status) {
$amount += AMOUNT_JOB;
}
if ($ad->is_featured < 0) {
$amount += AMOUNT_FEATURED;
}
if (isset($ad) && $ad->id) {
$seo_title = clean($ad->title) .' - '. APP_NAME;
$seo_desc = excerpt($ad->description);
$seo_url = BASE_URL ."ads/{$id}";
$app->render(THEME_PATH . 'ad.publish.php',
array('lang' => $lang,
'seo_url'=>$seo_url,
'seo_title'=>$seo_title,
'seo_desc'=>$seo_desc,
'ad'=>$ad,
'slug'=>$j->getSlugTitle(),
'city'=>$city,
'category'=>$category,
'amount'=>$amount));
} else {
$app->flash('danger', $lang->t('alert|error_encountered'));
$app->redirect(BASE_URL . "ads/{$id}");
}
});
The perch runtime is being called in the main index.php file of the app, like so:
<?php
/*
* Load the configuration file
*/
require 'config.php';
include('members/runtime.php'); // include perch
/*
* Load category and city values
*/
$categories = Categories::findCategories();
$cities = Cities::findCities();
$perch_email = (perch_member_logged_in())? perch_member_get('email'):'';
/*
* Load all existing controllers
*/
foreach (glob(CONTROLLER_PATH . "*.php") as $controller) {
require_once $controller;
}
/*
* Homepage
* Front page controller
*/
$app->get('/(:page)', function ($page=null) use ($app) {
global $categories;
global $lang;
if (isset($page) && $page != '') {
$content = R::findOne('pages', ' url=:url ', array(':url'=>$page));
if ($content && $content->id) {
// show page information
$seo_title = $content->name .' | '. APP_NAME;
$seo_desc = excerpt($content->description);
$seo_url = BASE_URL . $page;
$app->render(THEME_PATH . 'page.php',
array('lang' => $lang,
'seo_url'=>$seo_url,
'seo_title'=>$seo_title,
'seo_desc'=>$seo_desc,
'content'=>$content));
} else {
$app->redirect(BASE_URL, 404);
}
} else {
// show list of ad
$seo_title = APP_NAME;
$seo_desc = APP_DESC;
$seo_url = BASE_URL;
$j = new Ads();
$ads = $j->getAdsAllCategories(ACTIVE, 0, HOME_LIMIT);
$app->render(THEME_PATH . 'home.php',
array('lang' => $lang,
'seo_url'=>$seo_url,
'seo_title'=>$seo_title,
'seo_desc'=>$seo_desc,
'ads'=>$ads));
}
});
// Run app
$app->run();
Any ideas how I can get that return_url to fire as expected within this environment?
Thanks!
Have you turned on debug to see what's happening?
This is the debug. Once you put the card details in and confirm, the page reloads and the debug is exactly the same (other than the cartID number increasing)
So you're getting a new cart?
Yes. Page reloads, get new cart, doesn't go to return_url. The stripe payment goes through fine though.
Also, I tried to see if it would help to set the page as outlined here:
https://docs.grabaperch.com/perch/building/working-with-front-controllers/
...but made no difference.
What's going on with this?
The nature of the page means you can go back to it and pay for your advert upgrade whenever you want (rather than a typical checkout process) therefore because I'm adding the product programatically I needed to empty the cart before adding the product on each page load, otherwise it just keeps multiplying the product each time you visit the page in the same session.
If I comment out the empty cart bit it still doesn't help with the redirect.
Ok. Have you isolated the issue on a test page without all the rest of the unrelated code?
If I detach the perch code from the other app and put the cart on a standard 'my-cart.php' page then everything works fine.
As soon as I put the cart in a "view" within the app I get this return_url problem. All other perch functions are working fine within this same app.
I think you need to look to what the rest of your code is doing, as this doesn't sound like a Perch issue.
Ok thanks. One thing that may or may not help me is that, if I put a perch form on the cart page, that submits and redirects to the redirect URL set for it in the admin with no problem at all. So I'm wondering what the difference is between the way the standard perch forms redirect and the way the redirect from a stripe transaction works, in the hope that narrows down what I should be looking for?
I guess one difference would be the point at which the redirect occurs. For redirects should happen at the point the runtime is included. Shop redirects happen when you call the associated function.
So you might want to check your HTTP state.
How does one check their HTTP state?
That depends on the rest of your application. Just check that you know what headers have already been sent, and if any body output has begun etc before you issue the checkout redirect.
For anyone in future, I solved my redirect issue by moving the perch shop related php from the view in to the controller for the page where the cart appears :)