Intervals
1 year ago
Campaign_Statistics.php
2 years ago
City_Statistics.php
2 years ago
Country_Statistics.php
2 years ago
Device_Browser_Statistics.php
2 years ago
Device_OS_Statistics.php
2 years ago
Device_Type_Statistics.php
2 years ago
Page_Statistics.php
2 years ago
Referrer_Statistics.php
2 years ago
Statistic.php
1 year ago
Statistics.php
1 year ago
Statistics.php
305 lines
| 1 | <?php |
| 2 | |
| 3 | namespace IAWP\Statistics; |
| 4 | |
| 5 | use DateInterval; |
| 6 | use DatePeriod; |
| 7 | use DateTime; |
| 8 | use IAWP\Date_Range\Date_Range; |
| 9 | use IAWP\Form_Submissions\Form; |
| 10 | use IAWP\Illuminate_Builder; |
| 11 | use IAWP\Plugin_Group; |
| 12 | use IAWP\Query; |
| 13 | use IAWP\Query_Taps; |
| 14 | use IAWP\Rows\Rows; |
| 15 | use IAWP\Statistics\Intervals\Interval; |
| 16 | use IAWP\Statistics\Intervals\Intervals; |
| 17 | use IAWP\Utils\Calculations; |
| 18 | use IAWPSCOPED\Illuminate\Database\Query\Builder; |
| 19 | use IAWPSCOPED\Illuminate\Database\Query\JoinClause; |
| 20 | use IAWPSCOPED\Illuminate\Support\Collection; |
| 21 | use IAWPSCOPED\Illuminate\Support\Str; |
| 22 | use IAWPSCOPED\Proper\Timezone; |
| 23 | use Throwable; |
| 24 | /** @internal */ |
| 25 | abstract class Statistics |
| 26 | { |
| 27 | protected $date_range; |
| 28 | protected $rows; |
| 29 | protected $chart_interval; |
| 30 | private $statistics; |
| 31 | private $previous_period_statistics; |
| 32 | private $statistics_grouped_by_date_interval; |
| 33 | private $unfiltered_statistics; |
| 34 | private $previous_period_unfiltered_statistic; |
| 35 | private $unfiltered_statistics_grouped_by_date_interval; |
| 36 | private $statistic_instances; |
| 37 | // The biggest flaw here is that it requires two queries for the stats (current and previous) when |
| 38 | // that could be one. I think it would also be possible to reuse the rows query and not limit |
| 39 | // by 50 and just SUM() up all the stats columns for the quick stats. Maybe that would be faster |
| 40 | // even if two queries were still used. Needs testing. |
| 41 | public function __construct(Date_Range $date_range, ?Rows $rows = null, ?Interval $chart_interval = null) |
| 42 | { |
| 43 | $this->date_range = $date_range; |
| 44 | $this->rows = $rows; |
| 45 | $this->chart_interval = $chart_interval ?? Intervals::default_for($date_range->number_of_days()); |
| 46 | if (\is_null($rows)) { |
| 47 | $this->statistics = $this->query($this->date_range); |
| 48 | $this->previous_period_statistics = $this->query($this->date_range->previous_period()); |
| 49 | $this->statistics_grouped_by_date_interval = $this->query($this->date_range, null, \true); |
| 50 | } else { |
| 51 | $this->statistics = $this->query($this->date_range, $rows); |
| 52 | $this->previous_period_statistics = $this->query($this->date_range->previous_period(), $rows); |
| 53 | $this->statistics_grouped_by_date_interval = $this->query($this->date_range, $rows, \true); |
| 54 | $this->unfiltered_statistics = $this->query($this->date_range); |
| 55 | $this->previous_period_unfiltered_statistic = $this->query($this->date_range->previous_period()); |
| 56 | $this->unfiltered_statistics_grouped_by_date_interval = $this->query($this->date_range, null, \true); |
| 57 | } |
| 58 | $this->statistic_instances = $this->make_statistic_instances(); |
| 59 | } |
| 60 | /** |
| 61 | * @return Statistic[] |
| 62 | */ |
| 63 | public function get_statistics() : array |
| 64 | { |
| 65 | return $this->statistic_instances; |
| 66 | } |
| 67 | public function get_grouped_statistics() |
| 68 | { |
| 69 | // This whole thing is a bit of a mess... |
| 70 | return Collection::make($this->statistic_instances)->groupBy(function (\IAWP\Statistics\Statistic $item, int $key) { |
| 71 | return Plugin_Group::get_plugin_group($item->plugin_group())->name(); |
| 72 | })->map(function (Collection $group, $plugin_group) { |
| 73 | $items = $group->map(function (\IAWP\Statistics\Statistic $item) { |
| 74 | if (!$item->is_group_plugin_enabled()) { |
| 75 | return null; |
| 76 | } |
| 77 | return ['id' => $item->id(), 'name' => $item->name()]; |
| 78 | })->filter(); |
| 79 | if ($items->isEmpty()) { |
| 80 | return null; |
| 81 | } |
| 82 | return ['name' => $plugin_group, 'items' => $items->toArray()]; |
| 83 | })->filter()->values()->toArray(); |
| 84 | } |
| 85 | public function get_statistic(string $statistic_id) : ?\IAWP\Statistics\Statistic |
| 86 | { |
| 87 | foreach ($this->statistic_instances as $statistic_instance) { |
| 88 | if ($statistic_instance->id() == $statistic_id) { |
| 89 | return $statistic_instance; |
| 90 | } |
| 91 | } |
| 92 | return null; |
| 93 | } |
| 94 | public function has_filters() : bool |
| 95 | { |
| 96 | return !\is_null($this->rows); |
| 97 | } |
| 98 | public function chart_interval() : Interval |
| 99 | { |
| 100 | return $this->chart_interval; |
| 101 | } |
| 102 | /** |
| 103 | * I'm sure there's more we could do here. If you get a result back where there isn't a full |
| 104 | * page of results or where you're not paginating, then you can just count up the rows... |
| 105 | * |
| 106 | * @return int|null |
| 107 | */ |
| 108 | public function total_number_of_rows() : ?int |
| 109 | { |
| 110 | $sessions_table = Query::get_table_name(Query::SESSIONS); |
| 111 | $views_table = Query::get_table_name(Query::VIEWS); |
| 112 | $column = $this->total_table_rows_column() ?? $this->required_column(); |
| 113 | $query = Illuminate_Builder::get_builder()->selectRaw("COUNT(DISTINCT {$column}) AS total_table_rows")->from("{$sessions_table} AS sessions")->join("{$views_table} AS views", function (JoinClause $join) { |
| 114 | $join->on('sessions.session_id', '=', 'views.session_id'); |
| 115 | })->tap(Query_Taps::tap_authored_content_check(\true))->when(!\is_null($this->rows), function (Builder $query) { |
| 116 | $this->rows->attach_filters($query); |
| 117 | })->whereBetween('sessions.created_at', [$this->date_range->iso_start(), $this->date_range->iso_end()])->whereBetween('views.viewed_at', [$this->date_range->iso_start(), $this->date_range->iso_end()]); |
| 118 | return $query->value('total_table_rows'); |
| 119 | } |
| 120 | /** |
| 121 | * Define which id column to use to count up the total table rows. This is only required |
| 122 | * for classes that don't have a required column and don't override required_column |
| 123 | * |
| 124 | * @return string|null |
| 125 | */ |
| 126 | protected function total_table_rows_column() : ?string |
| 127 | { |
| 128 | return null; |
| 129 | } |
| 130 | /** |
| 131 | * Statistics can require that a column exists in order to be included. As an example, geos |
| 132 | * requires visitors.country_code and campaigns requires sessions.campaign_id |
| 133 | * |
| 134 | * @return string|null |
| 135 | */ |
| 136 | protected function required_column() : ?string |
| 137 | { |
| 138 | return null; |
| 139 | } |
| 140 | /** |
| 141 | * @return Statistic[] |
| 142 | */ |
| 143 | private function make_statistic_instances() : array |
| 144 | { |
| 145 | $statistics = [$this->make_statistic(['id' => 'visitors', 'name' => \__('Visitors', 'independent-analytics'), 'plugin_group' => 'general', 'is_visible_in_dashboard_widget' => \true]), $this->make_statistic(['id' => 'views', 'name' => \__('Views', 'independent-analytics'), 'plugin_group' => 'general', 'is_visible_in_dashboard_widget' => \true]), $this->make_statistic(['id' => 'sessions', 'name' => \__('Sessions', 'independent-analytics'), 'plugin_group' => 'general']), $this->make_statistic(['id' => 'average_session_duration', 'name' => \__('Average Session Duration', 'independent-analytics'), 'plugin_group' => 'general', 'format' => 'time']), $this->make_statistic(['id' => 'bounce_rate', 'name' => \__('Bounce Rate', 'independent-analytics'), 'plugin_group' => 'general', 'format' => 'percent', 'is_growth_good' => \false, 'compute' => function (object $statistics) { |
| 146 | return Calculations::percentage($statistics->bounces, $statistics->sessions); |
| 147 | }]), $this->make_statistic(['id' => 'views_per_session', 'name' => \__('Views Per Session', 'independent-analytics'), 'plugin_group' => 'general', 'format' => 'decimal', 'compute' => function (object $statistics) { |
| 148 | return Calculations::divide($statistics->total_views, $statistics->sessions, 2); |
| 149 | }]), $this->make_statistic(['id' => 'wc_orders', 'name' => \__('Orders', 'independent-analytics'), 'plugin_group' => 'ecommerce', 'icon' => $this->get_ecommerce_icon()]), $this->make_statistic(['id' => 'wc_gross_sales', 'name' => \__('Gross Sales', 'independent-analytics'), 'plugin_group' => 'ecommerce', 'icon' => $this->get_ecommerce_icon(), 'format' => 'rounded-currency']), $this->make_statistic(['id' => 'wc_refunds', 'name' => \__('Refunds', 'independent-analytics'), 'plugin_group' => 'ecommerce', 'icon' => $this->get_ecommerce_icon()]), $this->make_statistic(['id' => 'wc_refunded_amount', 'name' => \__('Refunded Amount', 'independent-analytics'), 'plugin_group' => 'ecommerce', 'icon' => $this->get_ecommerce_icon(), 'format' => 'rounded-currency']), $this->make_statistic(['id' => 'wc_net_sales', 'name' => \__('Total Sales', 'independent-analytics'), 'plugin_group' => 'ecommerce', 'icon' => $this->get_ecommerce_icon(), 'format' => 'rounded-currency']), $this->make_statistic(['id' => 'wc_conversion_rate', 'name' => \__('Conversion Rate', 'independent-analytics'), 'plugin_group' => 'ecommerce', 'icon' => $this->get_ecommerce_icon(), 'format' => 'percent']), $this->make_statistic(['id' => 'wc_earnings_per_visitor', 'name' => \__('Earnings Per Visitor', 'independent-analytics'), 'plugin_group' => 'ecommerce', 'icon' => $this->get_ecommerce_icon(), 'format' => 'currency']), $this->make_statistic(['id' => 'wc_average_order_volume', 'name' => \__('Average Order Volume', 'independent-analytics'), 'plugin_group' => 'ecommerce', 'icon' => $this->get_ecommerce_icon(), 'format' => 'rounded-currency']), $this->make_statistic(['id' => 'form_submissions', 'name' => \__('Form Submissions', 'independent-analytics'), 'plugin_group' => 'forms']), $this->make_statistic(['id' => 'form_conversion_rate', 'name' => \__('Form Conversion Rate', 'independent-analytics'), 'plugin_group' => 'forms', 'format' => 'percent', 'compute' => function (object $statistics) { |
| 150 | return Calculations::percentage($statistics->form_submissions, $statistics->visitors, 2); |
| 151 | }])]; |
| 152 | foreach (Form::get_forms() as $form) { |
| 153 | if (!$form->is_plugin_active()) { |
| 154 | continue; |
| 155 | } |
| 156 | $statistics[] = $this->make_statistic(['id' => 'form_submissions_for_' . $form->id(), 'name' => \sprintf(\_x('%s Submissions', 'Title of the contact form', 'independent-analytics'), $form->title()), 'plugin_group' => 'forms', 'is_subgroup_plugin_active' => $form->is_plugin_active(), 'plugin_group_header' => $form->plugin_name(), 'icon' => $form->icon()]); |
| 157 | $statistics[] = $this->make_statistic(['id' => 'form_conversion_rate_for_' . $form->id(), 'name' => \sprintf(\_x('%s Conversion Rate', 'Title of the contact form', 'independent-analytics'), $form->title()), 'plugin_group' => 'forms', 'is_subgroup_plugin_active' => $form->is_plugin_active(), 'plugin_group_header' => $form->plugin_name(), 'icon' => $form->icon(), 'format' => 'percent', 'compute' => function (object $statistics) use($form) { |
| 158 | $form_submission_id = 'form_submissions_for_' . $form->id(); |
| 159 | return Calculations::percentage($statistics->{$form_submission_id}, $statistics->visitors, 2); |
| 160 | }]); |
| 161 | } |
| 162 | return $statistics; |
| 163 | } |
| 164 | private function make_statistic(array $attributes) : \IAWP\Statistics\Statistic |
| 165 | { |
| 166 | $statistic_id = $attributes['id']; |
| 167 | if (!\array_key_exists('compute', $attributes)) { |
| 168 | $attributes['compute'] = function ($statistics, $statistic_id) { |
| 169 | return $statistics->{$statistic_id}; |
| 170 | }; |
| 171 | } |
| 172 | $attributes['statistic'] = $attributes['compute']($this->statistics, $statistic_id); |
| 173 | $attributes['previous_period_statistic'] = $attributes['compute']($this->previous_period_statistics, $statistic_id); |
| 174 | $attributes['statistic_over_time'] = $this->fill_in_partial_day_range($this->statistics_grouped_by_date_interval, $attributes); |
| 175 | $attributes['unfiltered_statistic'] = $this->has_filters() ? $attributes['compute']($this->unfiltered_statistics, $statistic_id) : null; |
| 176 | return new \IAWP\Statistics\Statistic($attributes); |
| 177 | } |
| 178 | private function query(Date_Range $range, ?Rows $rows = null, bool $is_grouped_by_date_interval = \false) |
| 179 | { |
| 180 | $utc_offset = Timezone::utc_offset(); |
| 181 | $site_offset = Timezone::site_offset(); |
| 182 | $sessions_table = Query::get_table_name(Query::SESSIONS); |
| 183 | $views_table = Query::get_table_name(Query::VIEWS); |
| 184 | $orders_table = Query::get_table_name(Query::ORDERS); |
| 185 | $form_submissions_table = Query::get_table_name(Query::FORM_SUBMISSIONS); |
| 186 | $form_submissions_query = Illuminate_Builder::get_builder()->select(['form_id', 'session_id'])->selectRaw('COUNT(*) AS form_submissions')->from($form_submissions_table, 'form_submissions')->whereBetween('created_at', [$range->iso_start(), $range->iso_end()])->groupBy(['form_id', 'session_id']); |
| 187 | $session_statistics = Illuminate_Builder::get_builder(); |
| 188 | $session_statistics->select('sessions.session_id')->selectRaw('COUNT(DISTINCT views.id) AS views')->selectRaw('COUNT(DISTINCT orders.order_id) AS orders')->selectRaw('IFNULL(CAST(SUM(orders.total) AS UNSIGNED), 0) AS gross_sales')->selectRaw('IFNULL(CAST(SUM(orders.total_refunded) AS UNSIGNED), 0) AS total_refunded')->selectRaw('IFNULL(CAST(SUM(orders.total_refunds) AS UNSIGNED), 0) AS total_refunds')->selectRaw('IFNULL(CAST(SUM(orders.total - orders.total_refunded) AS UNSIGNED), 0) AS net_sales')->from("{$sessions_table} AS sessions")->join("{$views_table} AS views", function (JoinClause $join) { |
| 189 | $join->on('sessions.session_id', '=', 'views.session_id'); |
| 190 | })->leftJoin("{$orders_table} AS orders", function (JoinClause $join) { |
| 191 | $join->on('views.id', '=', 'orders.initial_view_id')->where('orders.is_included_in_analytics', '=', \true); |
| 192 | })->tap(Query_Taps::tap_authored_content_check(\true))->when(!\is_null($rows), function (Builder $query) use($rows) { |
| 193 | $rows->attach_filters($query); |
| 194 | })->whereBetween('sessions.created_at', [$range->iso_start(), $range->iso_end()])->whereBetween('views.viewed_at', [$range->iso_start(), $range->iso_end()])->groupBy('sessions.session_id')->when(!\is_null($this->required_column()), function (Builder $query) { |
| 195 | $query->whereNotNull($this->required_column()); |
| 196 | }); |
| 197 | $statistics = Illuminate_Builder::get_builder(); |
| 198 | $statistics->selectRaw('IFNULL(CAST(SUM(sessions.total_views) AS UNSIGNED), 0) AS total_views')->selectRaw('IFNULL(CAST(SUM(session_statistics.views) AS UNSIGNED), 0) AS views')->selectRaw('COUNT(DISTINCT sessions.visitor_id) AS visitors')->selectRaw('COUNT(DISTINCT sessions.session_id) AS sessions')->selectRaw('IFNULL(CAST(AVG(TIMESTAMPDIFF(SECOND, sessions.created_at, sessions.ended_at)) AS UNSIGNED), 0) AS average_session_duration')->selectRaw('COUNT(DISTINCT IF(sessions.final_view_id IS NULL, sessions.session_id, NULL)) AS bounces')->selectRaw('IFNULL(CAST(SUM(session_statistics.orders) AS UNSIGNED), 0) AS wc_orders')->selectRaw('IFNULL(CAST(SUM(session_statistics.gross_sales) AS UNSIGNED), 0) AS wc_gross_sales')->selectRaw('IFNULL(CAST(SUM(session_statistics.total_refunds) AS UNSIGNED), 0) AS wc_refunds')->selectRaw('IFNULL(CAST(SUM(session_statistics.total_refunded) AS UNSIGNED), 0) AS wc_refunded_amount')->selectRaw('IFNULL(CAST(SUM(session_statistics.net_sales) AS UNSIGNED), 0) AS wc_net_sales')->selectRaw('IFNULL(SUM(form_submissions.form_submissions), 0) AS form_submissions')->tap(function (Builder $query) { |
| 199 | foreach (Form::get_forms() as $form) { |
| 200 | $query->selectRaw('IFNULL(SUM(IF(form_submissions.form_id = ?, form_submissions.form_submissions, 0)), 0) AS ' . $form->submissions_column(), [$form->id()]); |
| 201 | } |
| 202 | })->from("{$sessions_table} AS sessions")->joinSub($session_statistics, 'session_statistics', function (JoinClause $join) { |
| 203 | $join->on('sessions.session_id', '=', 'session_statistics.session_id'); |
| 204 | })->leftJoinSub($form_submissions_query, 'form_submissions', 'sessions.session_id', '=', 'form_submissions.session_id')->whereBetween('sessions.created_at', [$range->iso_start(), $range->iso_end()])->when($is_grouped_by_date_interval, function (Builder $query) use($utc_offset, $site_offset) { |
| 205 | if ($this->chart_interval->id() === 'daily') { |
| 206 | $query->selectRaw("DATE(CONVERT_TZ(sessions.created_at, '{$utc_offset}', '{$site_offset}')) AS date"); |
| 207 | } elseif ($this->chart_interval->id() === 'monthly') { |
| 208 | $query->selectRaw("DATE_FORMAT(CONVERT_TZ(sessions.created_at, '{$utc_offset}', '{$site_offset}'), '%Y-%m-01 00:00:00') AS date"); |
| 209 | } elseif ($this->chart_interval->id() === 'weekly') { |
| 210 | $day_of_week = \IAWPSCOPED\iawp()->get_option('iawp_dow', 0) + 1; |
| 211 | $query->selectRaw("\n IF (\n DAYOFWEEK(CONVERT_TZ(sessions.created_at, '{$utc_offset}', '{$site_offset}')) - {$day_of_week} < 0,\n DATE_FORMAT(SUBDATE(CONVERT_TZ(sessions.created_at, '{$utc_offset}', '{$site_offset}'), DAYOFWEEK(CONVERT_TZ(sessions.created_at, '{$utc_offset}', '{$site_offset}')) - {$day_of_week} + 7), '%Y-%m-%d 00:00:00'),\n DATE_FORMAT(SUBDATE(CONVERT_TZ(sessions.created_at, '{$utc_offset}', '{$site_offset}'), DAYOFWEEK(CONVERT_TZ(sessions.created_at, '{$utc_offset}', '{$site_offset}')) - {$day_of_week}), '%Y-%m-%d 00:00:00')\n ) AS date\n "); |
| 212 | } else { |
| 213 | $query->selectRaw("DATE_FORMAT(CONVERT_TZ(sessions.created_at, '{$utc_offset}', '{$site_offset}'), '%Y-%m-%d %H:00:00') AS date"); |
| 214 | } |
| 215 | $query->groupByRaw("date"); |
| 216 | }); |
| 217 | $outer_query = Illuminate_Builder::get_builder()->selectRaw('statistics.*')->selectRaw('IF(statistics.visitors = 0, 0, (statistics.wc_orders / statistics.visitors) * 100) AS wc_conversion_rate')->selectRaw('IF(statistics.visitors = 0, 0, (statistics.wc_gross_sales - statistics.wc_refunded_amount) / visitors) AS wc_earnings_per_visitor')->selectRaw('IF(statistics.wc_orders = 0, 0, ROUND(CAST(statistics.wc_gross_sales / statistics.wc_orders AS DECIMAL(10, 2)))) AS wc_average_order_volume')->fromSub($statistics, 'statistics'); |
| 218 | $results = \array_map(function (object $statistic) : object { |
| 219 | return $this->clean_up_raw_statistic_row($statistic); |
| 220 | }, $outer_query->get()->all()); |
| 221 | if (!$is_grouped_by_date_interval) { |
| 222 | return $results[0]; |
| 223 | } |
| 224 | return $results; |
| 225 | } |
| 226 | private function clean_up_raw_statistic_row(object $statistic) : object |
| 227 | { |
| 228 | $statistic->wc_gross_sales = \intval($statistic->wc_gross_sales); |
| 229 | $statistic->wc_refunded_amount = \intval($statistic->wc_refunded_amount); |
| 230 | $statistic->wc_net_sales = \intval($statistic->wc_net_sales); |
| 231 | foreach ($statistic as $key => $value) { |
| 232 | if (Str::startsWith($key, 'form_submissions')) { |
| 233 | $statistic->{$key} = \intval($value); |
| 234 | } |
| 235 | } |
| 236 | return $statistic; |
| 237 | } |
| 238 | /** |
| 239 | * @param array $partial_day_range |
| 240 | * @param array $attributes |
| 241 | * |
| 242 | * @return array |
| 243 | */ |
| 244 | private function fill_in_partial_day_range(array $partial_day_range, array $attributes) : array |
| 245 | { |
| 246 | $original_start = (clone $this->date_range->start())->setTimezone(Timezone::site_timezone()); |
| 247 | $start = $this->chart_interval->calculate_start_of_interval_for($original_start); |
| 248 | $original_end = (clone $this->date_range->end())->setTimezone(Timezone::site_timezone()); |
| 249 | $end = $this->chart_interval->calculate_start_of_interval_for($original_end); |
| 250 | $end->add(new DateInterval('PT1S')); |
| 251 | $date_range = new DatePeriod($start, $this->chart_interval->date_interval(), $end); |
| 252 | $filled_in_data = []; |
| 253 | foreach ($date_range as $date) { |
| 254 | // There is no 00:00:00 on 2024-03-31 as that's when Beirut switches off DST |
| 255 | if (Timezone::site_timezone()->getName() === 'Asia/Beirut' && $date->format('H:i:s') === "01:00:00") { |
| 256 | $date->setTime(0, 0, 0); |
| 257 | } |
| 258 | $stat = $this->get_statistic_for_date($partial_day_range, $date, $attributes); |
| 259 | $filled_in_data[] = [$date, $stat]; |
| 260 | } |
| 261 | return $filled_in_data; |
| 262 | } |
| 263 | /** |
| 264 | * @param array $partial_day_range |
| 265 | * @param DateTime $datetime_to_match |
| 266 | * @param array $attributes |
| 267 | * |
| 268 | * @return float|int |
| 269 | */ |
| 270 | private function get_statistic_for_date(array $partial_day_range, DateTime $datetime_to_match, array $attributes) |
| 271 | { |
| 272 | foreach ($partial_day_range as $day) { |
| 273 | $date = $day->date; |
| 274 | $value = $attributes['compute']($day, $attributes['id']); |
| 275 | try { |
| 276 | $datetime = new DateTime($date, Timezone::site_timezone()); |
| 277 | } catch (Throwable $e) { |
| 278 | return 0; |
| 279 | } |
| 280 | // Intentionally using non-strict equality to see if two distinct DateTime objects represent the same time |
| 281 | if ($datetime == $datetime_to_match) { |
| 282 | if (\is_string($value)) { |
| 283 | if (\strpos($value, '.') !== \false) { |
| 284 | return \floatval($value); |
| 285 | } else { |
| 286 | return \intval($value); |
| 287 | } |
| 288 | } |
| 289 | return $value; |
| 290 | } |
| 291 | } |
| 292 | return 0; |
| 293 | } |
| 294 | private function get_ecommerce_icon() : ?string |
| 295 | { |
| 296 | if (\IAWPSCOPED\iawp()->is_woocommerce_support_enabled() && !\IAWPSCOPED\iawp()->is_surecart_support_enabled()) { |
| 297 | return 'woocommerce'; |
| 298 | } |
| 299 | if (\IAWPSCOPED\iawp()->is_surecart_support_enabled() && !\IAWPSCOPED\iawp()->is_woocommerce_support_enabled()) { |
| 300 | return 'surecart'; |
| 301 | } |
| 302 | return null; |
| 303 | } |
| 304 | } |
| 305 |