Skip to content

Commit e13d6e9

Browse files
lewisgoddardcassidyjames
authored andcommitted
Indicate shipping costs on product pages. (elementary#1879)
* Add API endpoint to approximate location * Add estimated shipping API * Update shipping estimate function * Whitespace and if * Fix code style * Fix store modal close button alignment * Add printful_id to products list * Trigger on product modal launch * Remove IP override * Happy linter * Spaces everywhere * Update text style * fix root url for shipping estimates * Move requires around, use a try instead of an if * Remove redundant bit * Better checks, local IP catch * Fix price change on size change overriding shipping
1 parent 0ac1e0e commit e13d6e9

File tree

9 files changed

+171
-39
lines changed

9 files changed

+171
-39
lines changed

_backend/classify.current.php

+3-14
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,11 @@
11
<?php
22

33
require_once 'classify.functions.php';
4+
require_once 'classify.get_ip.php';
45

5-
if (!empty($_SERVER['HTTP_CF_CONNECTING_IP'])) {
6-
$ip = $_SERVER['HTTP_CF_CONNECTING_IP'];
7-
} else if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
8-
$ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
9-
} else if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
10-
$ip = $_SERVER['HTTP_CLIENT_IP'];
11-
} else if (!empty($_SERVER['REMOTE_ADDR'])) {
12-
$ip = $_SERVER['REMOTE_ADDR'];
13-
} else {
14-
$ip = false;
15-
}
16-
17-
$region = ipCheck($ip);
6+
$region = getDownloadRegion($ip);
187
if ( is_array($region) ) {
19-
$hash = ipHash($ip);
8+
$hash = getIPHash($ip);
209
$region = $region[$hash];
2110
}
2211

_backend/classify.functions.php

+58-22
Original file line numberDiff line numberDiff line change
@@ -13,31 +13,25 @@
1313
require_once __DIR__.'/geoip2.phar';
1414
use GeoIp2\Database\Reader;
1515

16-
//// ipCheck
16+
//// getDownloadRegion
1717
// Lookup the IP, and classify it by:
1818
// - Continent
1919
// - Country
2020
// - Timezone
2121
// Returns either a string of the selected region,
2222
// or an array of two regions.
23-
function ipCheck($hostname, $debug = false) {
23+
function getDownloadRegion($hostname, $debug = false) {
2424

2525
try {
26-
if ( $debug ) {
27-
echo $hostname."\n";
28-
}
2926
if (!class_exists('GeoIp2\Database\Reader')) {
3027
throw new \Exception('Class GeoIp2\Database\Reader not found');
3128
}
3229
$reader = new Reader(__DIR__.'/GeoLite2-City.mmdb');
3330
$record = $reader->city($hostname);
34-
if ( $debug ) {
35-
var_dump($record);
36-
echo "\n";
37-
}
31+
3832
$continent = $record->continent->code;
3933
$country = $record->country->isoCode;
40-
$longitude = $record->location->longitude;
34+
$longitude = $record->location->longitude;
4135

4236
} catch (\Exception $e) {
4337
if ( $debug ) {
@@ -48,12 +42,12 @@ function ipCheck($hostname, $debug = false) {
4842

4943
$continent = false;
5044
$country = false;
51-
$longitude = false;
45+
$longitude = false;
5246
}
5347

5448
if ( $debug ) {
5549
echo 'Continent: "'.$continent.'"'."\n";
56-
echo 'Country: "'.$country.'"'."\n";
50+
echo 'Country: "' .$country .'"'."\n";
5751
echo 'Longitude: "'.$longitude.'"'."\n";
5852
}
5953

@@ -118,10 +112,10 @@ function ipCheck($hostname, $debug = false) {
118112

119113
}
120114

121-
//// ipHash
115+
//// getIPHash
122116
// Hashes the given IP to return either a 0 or a 1 consistently for the same IP.
123-
// Used when balancing between two regions returned by ipCheck.
124-
function ipHash($hostname, $debug = false) {
117+
// Used when balancing between two regions returned by getDownloadRegion.
118+
function getIPHash($hostname, $debug = false) {
125119
$hash = array_sum(str_split($hostname));
126120
if ( $debug ) {
127121
echo 'Hash: "'.$hash.'"'."\n";
@@ -140,18 +134,12 @@ function ipHash($hostname, $debug = false) {
140134
function getCurrentCountry($hostname, $debug = false) {
141135

142136
try {
143-
if ( $debug ) {
144-
echo $hostname."\n";
145-
}
146137
if (!class_exists('GeoIp2\Database\Reader')) {
147138
throw new \Exception('Class GeoIp2\Database\Reader not found');
148139
}
149140
$reader = new Reader(__DIR__.'/GeoLite2-City.mmdb');
150141
$record = $reader->city($hostname);
151-
if ( $debug ) {
152-
var_dump($record);
153-
}
154-
$country = $record->country->isoCode;
142+
$country = $record->country->isoCode;
155143

156144
} catch (\Exception $e) {
157145
if ( $debug ) {
@@ -168,3 +156,51 @@ function getCurrentCountry($hostname, $debug = false) {
168156

169157
return $country;
170158
}
159+
160+
161+
function getCurrentLocation($hostname, $debug = false) {
162+
163+
try {
164+
if ( $debug ) {
165+
echo $hostname."\n";
166+
}
167+
if (!class_exists('GeoIp2\Database\Reader')) {
168+
throw new \Exception('Class GeoIp2\Database\Reader not found');
169+
}
170+
$reader = new Reader(__DIR__.'/GeoLite2-City.mmdb');
171+
$record = $reader->city($hostname);
172+
173+
$city = $record->city->name; // 'Minneapolis'
174+
$state = $record->mostSpecificSubdivision->name ; // 'Minnesota'
175+
$stateCode = $record->mostSpecificSubdivision->isoCode; // 'MN'
176+
$country = $record->country->name; // 'United States'
177+
$countryCode = $record->country->isoCode; // 'US'
178+
$postcode = $record->postal->code; // '55455'
179+
$continent = $record->continent->code;
180+
181+
} catch (\Exception $e) {
182+
if ( $debug ) {
183+
echo $e->getMessage();
184+
} else {
185+
error_log($e->getMessage());
186+
}
187+
188+
$city = false;
189+
$state = false;
190+
$stateCode = false;
191+
$country = false;
192+
$countryCode = false;
193+
$postcode = false;
194+
$continent = false;
195+
}
196+
197+
return array(
198+
'city' => $city,
199+
'state' => $state,
200+
'stateCode' => $stateCode,
201+
'country' => $country,
202+
'countryCode' => $countryCode,
203+
'postcode' => $postcode,
204+
'continent' => $continent,
205+
);
206+
}

_backend/classify.get_ip.php

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
3+
if (!empty($_SERVER['HTTP_CF_CONNECTING_IP'])) {
4+
$ip = $_SERVER['HTTP_CF_CONNECTING_IP'];
5+
} else if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
6+
$ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
7+
} else if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
8+
$ip = $_SERVER['HTTP_CLIENT_IP'];
9+
} else if (!empty($_SERVER['REMOTE_ADDR'])) {
10+
$ip = $_SERVER['REMOTE_ADDR'];
11+
} else {
12+
$ip = false;
13+
}
14+
15+
// DEVELOPER OVERRIDE
16+
// Override IP here
17+
if ( !$ip || $ip = '127.0.0.1' ) {
18+
$ip = '78.148.208.61';
19+
}

_backend/store/api.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ function get_varients (string $i) {
9494
* Returns a list of shipping rates from Printful api
9595
*
9696
* @param \Store\Address\Address $s shipping address
97-
* @param Arrray $i list of items to buy
97+
* @param Array $i list of items to buy
9898
*
9999
* @return Array list of shipping rates
100100
*/

_backend/store/product.php

+2
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ function get_products () {
3939

4040
$product['size'] = [];
4141
$product['color'] = [];
42+
$product['printful_id'] = [];
4243

4344
foreach ($product['variants'] as $variant) {
4445
if ($product['price_max'] == null || $variant['price'] > $product['price_max']) {
@@ -51,6 +52,7 @@ function get_products () {
5152

5253
if (!in_array($variant['size'], $product['size'])) $product['size'][] = $variant['size'];
5354
if (!in_array($variant['color'], $product['color'])) $product['color'][] = $variant['color'];
55+
if (!in_array($variant['printful_id'], $product['printful_id'])) $product['printful_id'][] = $variant['printful_id'];
5456
}
5557
}
5658

_scripts/pages/store/index.js

+28
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,35 @@ Promise.all([jQuery, modal]).then(([$]) => {
4747
$trigger.click()
4848

4949
ga('send', 'event', 'Store', 'View Product', $item.data('product-name'))
50+
51+
updateShippingEstimate($item.attr('data-printful-id'))
5052
})
5153

54+
/**
55+
* updateShippingEstimate
56+
* Fetches a psudeo shipping estimate
57+
*
58+
* @param {String} printfulId - the variant printful_id
59+
*
60+
* @return {Void}
61+
*/
62+
var updateShippingEstimate = function (printfulId) {
63+
var $m = $('.js-leanmodal-active .modal__shipping')
64+
// GET /api/gelocate
65+
// with the parameters "shipping" and "item" (printful variant id)
66+
$.getJSON(baseUrl + 'api/geolocate?shipping&item=' + printfulId, function (data) {
67+
// Update price information
68+
try {
69+
const cost = data['shipping']['estimates'][0]['cost']
70+
if (cost != null) {
71+
$m.text('+ $' + cost + ' estimated shipping')
72+
}
73+
} catch (e) {
74+
console.log(e)
75+
}
76+
})
77+
}
78+
5279
/**
5380
* updateVariant
5481
* Updates a modal with new variant data
@@ -166,6 +193,7 @@ Promise.all([jQuery, modal]).then(([$]) => {
166193
if (color != null && variant['color'] !== color) continue
167194

168195
updateVariant($f, p, variant)
196+
updateShippingEstimate(variant['printful_id'])
169197

170198
$('.alert--error', $f).text('')
171199
$('input[type="submit"]', $f).prop('disabled', false)

_styles/store.css

+1
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ i.fa.fa-times.close-modal {
108108
border-radius: 50%;
109109
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24);
110110
color: #fff;
111+
float: left;
111112
height: 32px;
112113
margin-left: -10px;
113114
margin-top: -10px;

api/geolocate.php

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<?php
2+
3+
require_once __DIR__.'/../_backend/classify.functions.php';
4+
require_once __DIR__.'/../_backend/classify.get_ip.php';
5+
require_once __DIR__.'/../_backend/store/address.php';
6+
require_once __DIR__.'/../_backend/store/api.php';
7+
8+
//// API for Geolocating Shipping
9+
// Parameters:
10+
// - shipping [no value]
11+
// - item (printful variant id of 1 product)
12+
// Outputs:
13+
// {
14+
// "ip": "92.26.51.149",
15+
// "shipping": {
16+
// "address": ...,
17+
// "estimates": ...
18+
// }
19+
// }
20+
21+
if ( isset($_GET['shipping']) && !empty($_GET['item']) ) {
22+
$estimatedAddress = getCurrentLocation($ip);
23+
24+
$result = array(
25+
'ip' => $ip,
26+
'shipping' => array(
27+
'address' => $estimatedAddress,
28+
),
29+
);
30+
31+
if (
32+
!empty($estimatedAddress['countryCode']) &&
33+
!empty($estimatedAddress['stateCode']) &&
34+
!empty($estimatedAddress['city']) &&
35+
!empty($estimatedAddress['postcode'])
36+
) {
37+
$address = new \Store\Address\Address();
38+
$address->set_line1('');
39+
$address->set_country($estimatedAddress['countryCode']);
40+
$address->set_state($estimatedAddress['stateCode']);
41+
$address->set_city($estimatedAddress['city']);
42+
$address->set_postal($estimatedAddress['postcode']);
43+
$items = array(
44+
array (
45+
'quantity' => 1,
46+
'variant_id' => $_GET['item'],
47+
),
48+
);
49+
$result['shipping']['estimates'] = Store\Api\get_shipping($address, $items);
50+
}
51+
52+
echo json_encode($result, JSON_PRETTY_PRINT);
53+
54+
} else {
55+
$result = array ('error' => 'No parameters were supplied, but some were expected.');
56+
echo json_encode($result, JSON_PRETTY_PRINT);
57+
}

store/index.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@
7272

7373
<?php foreach ($products as $product) { ?>
7474

75-
<div class="grid__item" id="product-<?php echo $product['id'] ?>" data-product-name="<?php echo $product['name']; ?>">
75+
<div class="grid__item" id="product-<?php echo $product['id'] ?>" data-product-name="<?php echo $product['name']; ?>" data-printful-id="<?php echo $product['printful_id'][0] ?>">
7676
<img src="<?php echo $product['image'] ?>"/>
7777
<h4><?php echo $product['name'] ?></h4>
7878
<?php if ($product['price_min'] !== $product['price_max']) { ?>
@@ -99,7 +99,7 @@
9999
</div>
100100
<form action="<?php echo $page['lang-root'] ?>store/inventory" class="half">
101101
<h2><?php echo $product['name'] ?></h2>
102-
<h4 class="modal__price" data-l10n-off="1">$<?php echo number_format($product['price_min'], 2) ?></h4>
102+
<h4 data-l10n-off="1"><strong class="modal__price">$<?php echo number_format($product['price_min'], 2) ?></strong> <span class="modal__shipping" data-l10n-off="1"></span></h4>
103103
<p><?php echo $product['description'] ?></p>
104104

105105
<input type="hidden" name="id" value="<?php echo $product['id'] ?>">

0 commit comments

Comments
 (0)