PluginProbe ʕ •ᴥ•ʔ
Independent Analytics – WordPress Analytics Plugin / 2.8.9
Independent Analytics – WordPress Analytics Plugin v2.8.9
2.15.5 2.15.4 2.15.3 2.15.2 2.15.1 2.15.0 2.14.10 trunk 1.1 1.10 1.10.1 1.11 1.12 1.13 1.14 1.15 1.16 1.17 1.17.1 1.17.2 1.17.3 1.17.4 1.18 1.18.1 1.19.0 1.19.1 1.2 1.20.0 1.21.0 1.22.0 1.22.1 1.23.0 1.23.1 1.24.0 1.24.1 1.25.0 1.25.1 1.26.0 1.27.0 1.28.0 1.28.1 1.28.2 1.28.3 1.29.0 1.3 1.30.0 1.30.1 1.4 1.5 1.6 1.7 1.8 1.9 2.0.0 2.0.1 2.1.4 2.1.5 2.1.6 2.10.0 2.10.1 2.10.2 2.10.3 2.10.4 2.11.0 2.11.1 2.11.10 2.11.2 2.11.3 2.11.4 2.11.5 2.11.6 2.11.7 2.11.8 2.11.9 2.12.0 2.12.1 2.12.2 2.13.1 2.13.2 2.13.5 2.13.6 2.14.0 2.14.1 2.14.2 2.14.4 2.14.6 2.14.7 2.14.8 2.14.9 2.2.0 2.2.1 2.3.1 2.3.2 2.4.2 2.4.3 2.5.0 2.5.1 2.6.0 2.6.1 2.6.2 2.6.3 2.6.4 2.7.0 2.7.1 2.7.2 2.7.3 2.8.2 2.8.3 2.8.4 2.8.5 2.8.6 2.8.7 2.8.8 2.8.9 2.9.2 2.9.3 2.9.4 2.9.5 2.9.6 2.9.7
independent-analytics / IAWP / Statistics / Statistics.php
independent-analytics / IAWP / Statistics Last commit date
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
318 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 $is_problematic_timezone = \in_array(Timezone::site_timezone()->getName(), ['Asia/Beirut', 'America/Santiago']);
252 // Imagine a scenario where the offset for the start date is -4 and the offset for the
253 // end date is -3. In that case, the DatePeriod is actually going to have its end date
254 // short an hour, causing a date we care about to be chopped off the end. This code makes
255 // sure that the end date is still the day after the last date we care about, so it
256 // can get chopped off without consequence.
257 if ($is_problematic_timezone) {
258 $offset_difference = $end->getOffset() - $start->getOffset();
259 $interval = DateInterval::createFromDateString($offset_difference . ' seconds');
260 $end->add($interval);
261 }
262 $date_range = new DatePeriod($start, $this->chart_interval->date_interval(), $end);
263 $filled_in_data = [];
264 foreach ($date_range as $date) {
265 // If the timezone switches at midnight, there will be a date where there is no midnight. It'll be something
266 // like 1am instead. All dates after the day that switches will also be at 1am even though they have a
267 // midnight. This alters those back to midnight, so they can be matched against correctly.
268 if ($is_problematic_timezone && $date->format('H:i:s') === "01:00:00") {
269 $date->setTime(0, 0, 0);
270 }
271 $stat = $this->get_statistic_for_date($partial_day_range, $date, $attributes);
272 $filled_in_data[] = [$date, $stat];
273 }
274 return $filled_in_data;
275 }
276 /**
277 * @param array $partial_day_range
278 * @param DateTime $datetime_to_match
279 * @param array $attributes
280 *
281 * @return float|int
282 */
283 private function get_statistic_for_date(array $partial_day_range, DateTime $datetime_to_match, array $attributes)
284 {
285 foreach ($partial_day_range as $day) {
286 $date = $day->date;
287 $value = $attributes['compute']($day, $attributes['id']);
288 try {
289 $datetime = new DateTime($date, Timezone::site_timezone());
290 } catch (Throwable $e) {
291 return 0;
292 }
293 // Intentionally using non-strict equality to see if two distinct DateTime objects represent the same time
294 if ($datetime == $datetime_to_match) {
295 if (\is_string($value)) {
296 if (\strpos($value, '.') !== \false) {
297 return \floatval($value);
298 } else {
299 return \intval($value);
300 }
301 }
302 return $value;
303 }
304 }
305 return 0;
306 }
307 private function get_ecommerce_icon() : ?string
308 {
309 if (\IAWPSCOPED\iawp()->is_woocommerce_support_enabled() && !\IAWPSCOPED\iawp()->is_surecart_support_enabled()) {
310 return 'woocommerce';
311 }
312 if (\IAWPSCOPED\iawp()->is_surecart_support_enabled() && !\IAWPSCOPED\iawp()->is_woocommerce_support_enabled()) {
313 return 'surecart';
314 }
315 return null;
316 }
317 }
318