Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 63 additions & 11 deletions src/wp-content/themes/tuleva/helpers/extras.php
Original file line number Diff line number Diff line change
Expand Up @@ -314,21 +314,73 @@ function get_app_url($path)
}

/*
* Get Tuleva member count
* Get the number of people saving in Tuleva index funds.
*
* Source: onboarding-service, backed by the same analytics.mv_kpi_new figure as the
* Metabase "kogujate arv". That view only moves once a month, so the value is cached
* for a day: the count changes about monthly, and we are never more than a day behind
* when it does.
*
* The last count the API returned successfully is also kept in an option. A failed
* refresh then keeps showing yesterday's real number instead of dropping back to the
* hand-entered members_count ACF field, which can be months out of date.
*
* Returns 0 only when there is nothing better to show, so callers can fall back to
* the ACF field.
*/
function get_member_count()
function get_investor_count()
{
stream_context_set_default(
array(
'http' => array(
'method' => 'HEAD'
)
)
// Same guard as the fund templates: never call the production API from local dev.
if (isset($_SERVER['SERVER_NAME']) && $_SERVER['SERVER_NAME'] === 'localhost') {
return 0;
}

$cached = get_transient('tuleva_investor_count');
if ($cached !== false) {
$cached = (int) $cached;

// A cached 0 is the failure sentinel, not a real count.
return $cached > 0 ? $cached : get_last_good_investor_count();
}

$context = stream_context_create(
[
'http' => [
'method' => 'GET',
'timeout' => 1,
]
]
);
$headers = get_headers('https://onboarding-service.tuleva.ee/v1/members', 1);
$memberCount = empty($headers['X-Total-Count']) ? 0 : $headers['X-Total-Count'];
$json = @file_get_contents(
'https://onboarding-service.tuleva.ee/v1/statistics/investor-count',
false,
$context
);
$data = json_decode($json, true);
// is_numeric, so that a malformed "70000abc" is rejected rather than cast to 70000.
$count = isset($data['count']) && is_numeric($data['count']) ? (int) $data['count'] : 0;

// Mirrors the sanity bounds the endpoint already applies in SQL.
if ($count < 50000 || $count > 500000) {
// Unreachable, malformed or implausible. Cache the failure briefly so an
// outage costs one slow request per five minutes, not one per visitor.
set_transient('tuleva_investor_count', 0, 5 * MINUTE_IN_SECONDS);

return get_last_good_investor_count();
}

set_transient('tuleva_investor_count', $count, DAY_IN_SECONDS);
update_option('tuleva_investor_count_last_good', $count, false);

return $memberCount;
return $count;
}

/*
* The last count the API returned successfully, or 0 if it has never answered.
*/
function get_last_good_investor_count()
{
return (int) get_option('tuleva_investor_count_last_good', 0);
}

function print_funds_js()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?php
$members_count = get_field('members_count', 'option');
$members_count = get_investor_count() ?: get_field('members_count', 'option');
$members_count_description = get_sub_field('members_count_description');
$security_text = get_sub_field('security_text');
$security_link_text = get_sub_field('security_link_text');
Expand Down