PluginProbe ʕ •ᴥ•ʔ
Independent Analytics – WordPress Analytics Plugin / 2.14.2
Independent Analytics – WordPress Analytics Plugin v2.14.2
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 / Tables / Table.php
independent-analytics / IAWP / Tables Last commit date
Columns 6 months ago Groups 1 year ago Table.php 5 months ago Table_Campaigns.php 9 months ago Table_Clicks.php 5 months ago Table_Devices.php 5 months ago Table_Geo.php 9 months ago Table_Journeys.php 5 months ago Table_Pages.php 5 months ago Table_Referrers.php 9 months ago
Table.php
484 lines
1 <?php
2
3 namespace IAWP\Tables;
4
5 use IAWP\Campaign_Builder;
6 use IAWP\Dashboard_Options;
7 use IAWP\Date_Picker\Date_Picker;
8 use IAWP\Filters;
9 use IAWP\Form_Submissions\Form;
10 use IAWP\Icon_Directory_Factory;
11 use IAWP\Plugin_Group;
12 use IAWP\Rows\Filter;
13 use IAWP\Sort_Configuration;
14 use IAWP\Statistics\Statistics;
15 use IAWP\Tables\Columns\Column;
16 use IAWP\Tables\Groups\Group;
17 use IAWP\Tables\Groups\Groups;
18 use IAWP\Utils\CSV;
19 use IAWP\Utils\Currency;
20 use IAWP\Utils\Format;
21 use IAWP\Utils\Number_Formatter;
22 use IAWP\Utils\Security;
23 use IAWP\Utils\Timezone;
24 use IAWP\Utils\URL;
25 use IAWPSCOPED\Illuminate\Support\Collection;
26 use IAWPSCOPED\Illuminate\Support\Str;
27 /** @internal */
28 abstract class Table
29 {
30 protected $default_sorting_column = 'visitors';
31 private $filters;
32 private $visible_columns;
33 private $group;
34 private $is_new_group;
35 /** @var ?Statistics */
36 private $statistics;
37 /**
38 * @param string|null $group_id
39 * @param bool $is_new_group
40 */
41 public function __construct(?string $group_id = null, bool $is_new_group = \false)
42 {
43 $this->visible_columns = Dashboard_Options::getInstance()->visible_columns();
44 $this->group = $this->groups()->find_by_id($group_id);
45 $this->is_new_group = $is_new_group;
46 $this->filters = new Filters();
47 }
48 protected abstract function groups() : Groups;
49 /**
50 * @return array<Column>
51 */
52 protected abstract function local_columns() : array;
53 public abstract function id() : string;
54 /**
55 * @return string[]
56 */
57 public function visible_column_ids() : array
58 {
59 $visible_columns = [];
60 foreach ($this->get_columns() as $column) {
61 if ($column->is_visible()) {
62 $visible_columns[] = $column->id();
63 }
64 }
65 return $visible_columns;
66 }
67 public function allow_downloading() : bool
68 {
69 return \true;
70 }
71 public function group() : Group
72 {
73 return $this->group;
74 }
75 public function column_picker_html() : string
76 {
77 return \IAWPSCOPED\iawp_blade()->run('plugin-group-options', ['option_type' => 'columns', 'option_name' => \__('Toggle Columns', 'independent-analytics'), 'option_icon' => 'columns', 'plugin_groups' => Plugin_Group::get_plugin_groups(), 'options' => $this->get_columns(\true)]);
78 }
79 public function get_table_toolbar_markup()
80 {
81 return \IAWPSCOPED\iawp_blade()->run('tables.table-toolbar', ['plugin_groups' => Plugin_Group::get_plugin_groups(), 'columns' => $this->get_columns(\true), 'groups' => $this->groups(), 'current_group' => $this->group()]);
82 }
83 public function get_table_markup(string $sort_column, string $sort_direction)
84 {
85 return \IAWPSCOPED\iawp_blade()->run('tables.table', ['table' => $this, 'all_columns' => $this->get_columns(), 'visible_column_count' => $this->visible_column_count(), 'number_of_shown_rows' => 0, 'rows' => [], 'render_skeleton' => \true, 'page_size' => \IAWPSCOPED\iawp()->pagination_page_size(), 'sort_column' => $sort_column, 'sort_direction' => $sort_direction, 'has_campaigns' => Campaign_Builder::has_campaigns()]);
86 }
87 public function set_statistics(Statistics $statistics)
88 {
89 $this->statistics = $statistics;
90 }
91 public function get_row_data_attributes($row)
92 {
93 $html = '';
94 foreach ($this->get_columns() as $column) {
95 $id = $column->id();
96 $data_val = $row->{$id}();
97 $html .= ' data-' . \esc_attr($column->id()) . '="' . \esc_attr($data_val) . '"';
98 }
99 return $html;
100 }
101 public function get_cell_content($row, Column $column)
102 {
103 $column_id = $column->id();
104 if (\is_null($row->{$column_id}())) {
105 return '-';
106 }
107 if ($column_id == 'title' && $row->is_deleted()) {
108 return Security::string($row->{$column_id}()) . ' <span class="deleted-label">' . \esc_html__('(deleted)', 'independent-analytics') . '</span>';
109 } elseif ($column_id == 'views') {
110 $views = Number_Formatter::decimal($row->views());
111 // Getting a divide by zero error from the line below?
112 // It's likely an issue with $this->views which is an instance of Views. Make sure the queries there are working.
113 $views_percentage = Number_Formatter::percent($row->views() / $this->statistics->get_statistic('views')->value() * 100, 2);
114 return '<span class="no-wrap">' . Security::string($views) . '</span> <span class="percentage">(' . Security::string($views_percentage) . ')</span>';
115 } elseif ($column_id == 'visitors') {
116 $visitors = Number_Formatter::decimal($row->visitors());
117 $visitors_percentage = Number_Formatter::percent($row->visitors() / $this->statistics->get_statistic('visitors')->value() * 100, 2);
118 return '<span class="no-wrap">' . Security::string($visitors) . '</span> <span class="percentage">(' . Security::string($visitors_percentage) . ')</span>';
119 } elseif ($column_id == 'sessions') {
120 $sessions = Number_Formatter::decimal($row->sessions());
121 $sessions_percentage = Number_Formatter::percent($row->sessions() / $this->statistics->get_statistic('sessions')->value() * 100, 2);
122 return '<span class="no-wrap">' . Security::string($sessions) . '</span> <span class="percentage">(' . Security::string($sessions_percentage) . ')</span>';
123 } elseif ($column_id === 'entrances') {
124 $entrances = Number_Formatter::decimal($row->entrances());
125 $entrances_percentage = Number_Formatter::percent($row->entrances() / $this->statistics->get_statistic('sessions')->value() * 100, 2);
126 return '<span class="no-wrap">' . Security::string($entrances) . '</span> <span class="percentage">(' . Security::string($entrances_percentage) . ')</span>';
127 } elseif ($column_id === 'exits') {
128 $exits = Number_Formatter::decimal($row->exits());
129 $exits_percentage = Number_Formatter::percent($row->exits() / $this->statistics->get_statistic('sessions')->value() * 100, 2);
130 return '<span class="no-wrap">' . Security::string($exits) . '</span> <span class="percentage">(' . Security::string($exits_percentage) . ')</span>';
131 } elseif ($column_id === 'bounce_rate') {
132 return Security::string(Number_Formatter::percent($row->bounce_rate()));
133 } elseif ($column_id === 'average_session_duration' || $column_id === 'average_view_duration') {
134 return Number_Formatter::second_to_minute_timestamp($row->{$column_id}());
135 } elseif ($column_id === 'views_growth' || $column_id === 'visitors_growth' || $column_id === 'wc_conversion_rate' || $column_id === 'exit_percent' || Str::startsWith($column_id, 'form_conversion_rate')) {
136 return Number_Formatter::percent($row->{$column_id}(), 2);
137 } elseif ($column_id == 'url') {
138 if ($row->is_deleted()) {
139 return \urldecode(\esc_url($row->url()));
140 } else {
141 return '<a href="' . \esc_url($row->url(\true)) . '" target="_blank" class="external-link">' . \urldecode(\esc_url($row->url())) . '<span class="dashicons dashicons-external"></span></a>';
142 }
143 } elseif ($column_id == 'author') {
144 return Security::html($row->avatar()) . ' ' . Security::string($row->author());
145 } elseif ($column_id == 'date') {
146 return Security::string(\date(Format::date(), \strtotime($row->date())));
147 } elseif ($column_id == 'type' && \method_exists($row, 'icon') && \method_exists($row, 'type')) {
148 return $row->icon(0) . ' ' . Security::string($row->type());
149 } elseif ($column_id == 'referrer') {
150 return \IAWPSCOPED\iawp_render('tables.referrer-column', ['row' => $row]);
151 } elseif ($column_id === 'device_type') {
152 return Icon_Directory_Factory::device_types()->find($row->device_type()) . Security::string($row->device_type());
153 } elseif ($column_id === 'browser') {
154 return Icon_Directory_Factory::browsers()->find($row->browser()) . Security::string($row->browser());
155 } elseif ($column_id === 'os') {
156 return Icon_Directory_Factory::operating_systems()->find($row->os()) . Security::string($row->os());
157 } elseif ($column_id === 'country') {
158 return Icon_Directory_Factory::flags()->find($row->country_code()) . Security::string($row->country());
159 } elseif ($column_id === 'wc_gross_sales' || $column_id === 'wc_refunded_amount' || $column_id === 'wc_net_sales' || $column_id === 'wc_average_order_volume') {
160 return Security::string(Currency::format($row->{$column_id}()));
161 } elseif ($column_id === 'wc_earnings_per_visitor') {
162 return Security::string(Currency::format($row->{$column_id}(), \false));
163 } elseif ($column_id === 'views_per_session') {
164 return Number_Formatter::decimal($row->{$column_id}(), 2);
165 } elseif ($column_id === 'link_target') {
166 $value = $row->{$column_id}();
167 if (\is_string($value) && URL::new($value)->is_valid_url()) {
168 return '<a href="' . \esc_url($value) . '" target="_blank" class="external-link">' . \esc_url(\urldecode($value)) . '<span class="dashicons dashicons-external"></span></a>';
169 }
170 return Security::string($value);
171 } else {
172 return Security::string($row->{$column_id}());
173 }
174 }
175 public function output_report_toolbar()
176 {
177 $options = Dashboard_Options::getInstance();
178 $start = $options->get_date_range()->start()->setTimezone(Timezone::site_timezone());
179 $end = $options->get_date_range()->end()->setTimezone(Timezone::site_timezone());
180 ?>
181 <div id="toolbar" class="toolbar" data-filter-count="<?php
182 echo \count($options->filters());
183 ?>">
184 <div class="date-picker-parent">
185 <div class="modal-parent dates">
186 <button id="dates-button"
187 data-testid="open-calendar"
188 class="iawp-button"
189 data-action="dates#toggleModal"
190 data-dates-target="modalButton"
191 >
192 <span class="dashicons dashicons-calendar-alt"></span>
193 <span class="iawp-label"><?php
194 echo \esc_html($options->get_date_range()->label());
195 ?></span>
196 </button>
197 <div id="modal-dates"
198 class="iawp-modal large dates"
199 data-dates-target="modal"
200 >
201 <?php
202 echo (new Date_Picker($start, $end, $options->relative_range_id()))->calendar_html();
203 ?>
204 </div>
205 </div>
206 </div>
207 <div class="filter-parent">
208 <?php
209 echo $this->filters()->get_filters_html($this->columns_that_can_be_filtered());
210 ?>
211 </div>
212 <div class="download-options-parent <?php
213 echo $this->allow_downloading() ? "" : "hide";
214 ?>" data-controller="modal">
215 <div class="modal-parent downloads">
216 <button id="download-options" data-modal-target="modalButton" data-action="click->modal#toggleModal" class="download-options">
217 <?php
218 \esc_html_e('Download Report', 'independent-analytics');
219 ?>
220 </button>
221 <div class="iawp-modal small downloads" data-modal-target="modal">
222 <div class="modal-inner">
223 <div class="title-small">
224 <?php
225 \esc_html_e('Choose a format', 'independent-analytics');
226 ?>
227 <span data-report-target="spinner" class="dashicons dashicons-update iawp-spin hidden"></span>
228 </div>
229 <div class="download-button-container">
230 <button id="download-csv" class="iawp-button" data-report-target="exportReportTable" data-action="report#exportReportTable">
231 <span class="dashicons dashicons-media-spreadsheet"></span>
232 <span class="iawp-label">
233 <?php
234 \esc_html_e('Download Table CSV', 'independent-analytics');
235 ?>
236 </span>
237 </button>
238 <button id="download-report-statistics-csv" class="iawp-button" data-report-target="exportReportStatistics" data-action="report#exportReportStatistics">
239 <span class="dashicons dashicons-media-spreadsheet"></span>
240 <span class="iawp-label">
241 <?php
242 \esc_html_e('Download Daily Metrics CSV', 'independent-analytics');
243 ?>
244 </span>
245 </button>
246 </div>
247 <div class="download-button-container">
248 <button id="download-pdf" class="iawp-button" data-report-target="exportPDF" data-action="report#exportPDF" disabled="disabled">
249 <span class="dashicons dashicons-pdf"></span>
250 <span class="iawp-label">
251 <?php
252 \esc_html_e('Download PDF', 'independent-analytics');
253 ?>
254 </span>
255 </button>
256 </div>
257 </div>
258 </div>
259 </div>
260 </div>
261 </div><?php
262 }
263 public function filters_template_html() : string
264 {
265 return $this->filters()->get_condition_html($this->columns_that_can_be_filtered());
266 }
267 public function filters_condition_buttons_html(array $filters) : string
268 {
269 return $this->filters()->condition_buttons_html($filters);
270 }
271 public final function csv(array $rows, bool $is_dashboard_export = \false) : CSV
272 {
273 $columns = $this->get_columns();
274 $csv_header = [];
275 $csv_rows = [];
276 foreach ($columns as $column) {
277 if (!$this->include_column_in_csv($column, $is_dashboard_export)) {
278 continue;
279 }
280 $csv_header[] = $column->name();
281 }
282 foreach ($rows as $row) {
283 $csv_row = [];
284 foreach ($columns as $column) {
285 if (!$this->include_column_in_csv($column, $is_dashboard_export)) {
286 continue;
287 }
288 $column_id = $column->id();
289 $value = $row->{$column_id}();
290 if (\is_string($value)) {
291 $value = \html_entity_decode($value);
292 // Fix apostrophes for Excel
293 $value = \str_replace("’", "'", $value);
294 }
295 $csv_row[] = $this->formatted_csv_cell_content($column, $value);
296 }
297 $csv_rows[] = $csv_row;
298 }
299 $csv = new CSV($csv_header, $csv_rows);
300 return $csv;
301 }
302 public function formatted_csv_cell_content(Column $column, $value) : string
303 {
304 $column_id = $column->id();
305 // Todo - This logic is similar to the rendering logic for table cells. This should
306 // all be handled via the column class itself.
307 if (\is_null($value)) {
308 return '-';
309 } elseif (\in_array($column_id, ['views', 'visitors', 'sessions', 'clicks', 'form_submissions']) || Str::startsWith($column_id, 'form_submissions_for_')) {
310 return Number_Formatter::integer($value);
311 } elseif (\in_array($column_id, ['bounce_route', 'views_growth', 'visitors_growth', 'form_conversion_rate']) || Str::startsWith($column_id, 'form_conversion_rate_for_')) {
312 return Number_Formatter::percent($value);
313 } elseif ($column_id === 'date') {
314 return \date(Format::date(), \strtotime($value));
315 } elseif ($column_id === 'average_session_duration' || $column_id === 'average_view_duration') {
316 return Number_Formatter::second_to_minute_timestamp($value);
317 } elseif ($column_id === 'views_per_session') {
318 return Number_Formatter::decimal($value, 2);
319 } elseif ($column_id === 'wc_gross_sales' || $column_id === 'wc_refunded_amount' || $column_id === 'wc_net_sales' || $column_id === 'wc_average_order_volume') {
320 return Currency::format($value);
321 } elseif ($column_id === 'wc_earnings_per_visitor') {
322 return Currency::format($value);
323 } else {
324 return $value;
325 }
326 }
327 /**
328 * @param array[] $filters Raw filter associative arrays
329 *
330 * @return Filter[]
331 */
332 public function sanitize_filters(array $filters) : array
333 {
334 return Collection::make($filters)->map(function ($filter) {
335 return $this->sanitize_filter($filter);
336 })->filter()->values()->all();
337 }
338 public function resolve_filter_conflicts(array $filters, string $filter_logic) : array
339 {
340 return $filters;
341 }
342 public function sanitize_filter(array $filter) : ?Filter
343 {
344 // column, inclusion, operator, operand
345 $column = $this->get_column($filter['column']);
346 if ($column === null || !$column->can_be_filtered()) {
347 return null;
348 }
349 $valid_inclusions = ['include', 'exclude'];
350 if (!\in_array($filter['inclusion'], $valid_inclusions)) {
351 return null;
352 }
353 if (!$column->is_valid_filter_operator($filter['operator'])) {
354 return null;
355 }
356 if (!$column->is_enabled_for_group($this->group())) {
357 return null;
358 }
359 $operand = \trim(Security::string($filter['operand']));
360 if (\strlen($operand) === 0) {
361 return null;
362 }
363 if ($column->id() === 'url' && $filter['operator'] === 'exact') {
364 $url = new URL($filter['operand']);
365 if (!$url->is_valid_url()) {
366 $filter['operand'] = \site_url($filter['operand']);
367 }
368 }
369 if ($column->options() && !$column->options()->contains($filter['operand'])) {
370 return null;
371 }
372 return new Filter(['inclusion' => Security::string($filter['inclusion']), 'operator' => Security::string($filter['operator']), 'operand' => Security::string($filter['operand']), 'column' => $column]);
373 }
374 public function get_column(string $id) : ?Column
375 {
376 $matches = \array_filter($this->local_columns(), function (Column $column) use($id) {
377 return $column->id() === $id;
378 });
379 $column = \count($matches) === 1 ? \reset($matches) : null;
380 if (\is_null($column) || !$column->is_enabled()) {
381 return null;
382 }
383 return $column;
384 }
385 public function sanitize_sort_parameters(?string $sort_column = null, ?string $sort_direction = 'desc') : Sort_Configuration
386 {
387 if ($sort_column === null) {
388 $sort_column = $this->default_sorting_column;
389 }
390 $column = $this->get_column($sort_column);
391 if ($column === null || !$column->is_enabled_for_group($this->group)) {
392 $column = $this->get_column($this->default_sorting_column);
393 }
394 return new Sort_Configuration($column, $sort_direction);
395 }
396 public function get_rendered_template(array $rows, bool $just_rows, string $sort_column, string $sort_direction)
397 {
398 if ($just_rows) {
399 return \IAWPSCOPED\iawp_blade()->run('tables.rows', ['table' => $this, 'all_columns' => $this->get_columns(), 'visible_column_count' => $this->visible_column_count(), 'number_of_shown_rows' => \count($rows), 'rows' => $rows, 'render_skeleton' => \false, 'page_size' => \IAWPSCOPED\iawp()->pagination_page_size(), 'sort_column' => $sort_column, 'sort_direction' => $sort_direction, 'has_campaigns' => Campaign_Builder::has_campaigns()]);
400 }
401 return \IAWPSCOPED\iawp_blade()->run('tables.table', ['table' => $this, 'all_columns' => $this->get_columns(), 'visible_column_count' => $this->visible_column_count(), 'number_of_shown_rows' => \count($rows), 'rows' => $rows, 'render_skeleton' => \false, 'page_size' => \IAWPSCOPED\iawp()->pagination_page_size(), 'sort_column' => $sort_column, 'sort_direction' => $sort_direction, 'has_campaigns' => Campaign_Builder::has_campaigns()]);
402 }
403 /**
404 * @return Column[]
405 */
406 public function get_columns($show_disabled_columns = \false) : array
407 {
408 $columns_for_group = \array_filter($this->local_columns(), function (Column $column) {
409 return $column->is_enabled() && $column->is_enabled_for_group($this->group) && $column->is_subgroup_plugin_enabled();
410 });
411 if (\false === $show_disabled_columns) {
412 $columns_for_group = \array_filter($columns_for_group, function (Column $column) {
413 return $column->is_group_plugin_enabled();
414 });
415 }
416 if (\is_null($this->visible_columns) || \count($this->visible_columns) === 0) {
417 return $columns_for_group;
418 }
419 if (!$this->is_new_group) {
420 return \array_map(function ($column) {
421 $column->set_visibility(\in_array($column->id(), $this->visible_columns));
422 return $column;
423 }, $columns_for_group);
424 }
425 return \array_map(function ($column) {
426 if ($column->is_group_dependent()) {
427 $column->set_visibility(\true);
428 } elseif (!\in_array($column->id(), $this->visible_columns)) {
429 $column->set_visibility(\false);
430 }
431 return $column;
432 }, $columns_for_group);
433 }
434 protected function get_woocommerce_columns() : array
435 {
436 return [new Column(['id' => 'wc_orders', 'name' => \__('Orders', 'independent-analytics'), 'plugin_group' => 'ecommerce', 'type' => 'int', 'aggregatable' => \true]), new Column(['id' => 'wc_gross_sales', 'name' => \__('Gross Sales', 'independent-analytics'), 'plugin_group' => 'ecommerce', 'type' => 'int', 'aggregatable' => \true]), new Column(['id' => 'wc_refunds', 'name' => \__('Refunds', 'independent-analytics'), 'plugin_group' => 'ecommerce', 'type' => 'int', 'aggregatable' => \true]), new Column(['id' => 'wc_refunded_amount', 'name' => \__('Refunded Amount', 'independent-analytics'), 'plugin_group' => 'ecommerce', 'type' => 'int', 'aggregatable' => \true]), new Column(['id' => 'wc_net_sales', 'name' => \__('Total Sales', 'independent-analytics'), 'plugin_group' => 'ecommerce', 'type' => 'int', 'aggregatable' => \true]), new Column(['id' => 'wc_conversion_rate', 'name' => \__('Conversion Rate', 'independent-analytics'), 'plugin_group' => 'ecommerce', 'type' => 'int']), new Column(['id' => 'wc_earnings_per_visitor', 'name' => \__('Earnings Per Visitor', 'independent-analytics'), 'plugin_group' => 'ecommerce', 'type' => 'int']), new Column(['id' => 'wc_average_order_volume', 'name' => \__('Average Order Volume', 'independent-analytics'), 'plugin_group' => 'ecommerce', 'type' => 'int'])];
437 }
438 protected function get_form_columns() : array
439 {
440 $columns = [new Column(['id' => 'form_submissions', 'name' => \__('Submissions', 'independent-analytics'), 'plugin_group' => 'forms', 'type' => 'int', 'aggregatable' => \true]), new Column(['id' => 'form_conversion_rate', 'name' => \__('Conversion Rate', 'independent-analytics'), 'plugin_group' => 'forms', 'type' => 'int'])];
441 foreach (Form::get_forms() as $form) {
442 $columns[] = new Column(['id' => $form->submissions_column(), 'name' => $form->title() . ' ' . \__('Submissions', 'independent-analytics'), 'plugin_group' => 'forms', 'is_subgroup_plugin_active' => $form->is_plugin_active(), 'plugin_group_header' => $form->plugin_name(), 'type' => 'int', 'aggregatable' => \true]);
443 $columns[] = new Column(['id' => $form->conversion_rate_column(), 'name' => $form->title() . ' ' . \__('Conversion Rate', 'independent-analytics'), 'plugin_group' => 'forms', 'is_subgroup_plugin_active' => $form->is_plugin_active(), 'plugin_group_header' => $form->plugin_name(), 'type' => 'int']);
444 }
445 return $columns;
446 }
447 private function include_column_in_csv(Column $column, bool $is_dashboard_export) : bool
448 {
449 if (!$column->is_visible() && $is_dashboard_export) {
450 return \false;
451 }
452 if (!$column->exportable() && !$is_dashboard_export) {
453 return \false;
454 }
455 if (!$column->is_group_plugin_enabled()) {
456 return \false;
457 }
458 return \true;
459 }
460 /**
461 * Get the number of visible columns
462 *
463 * @return int
464 */
465 private function visible_column_count() : int
466 {
467 $visible_columns = 0;
468 foreach ($this->get_columns() as $column) {
469 if ($column->is_visible()) {
470 $visible_columns++;
471 }
472 }
473 return $visible_columns;
474 }
475 private function filters()
476 {
477 return $this->filters;
478 }
479 private function columns_that_can_be_filtered() : array
480 {
481 return Collection::make($this->get_columns())->filter(fn(Column $column) => $column->can_be_filtered())->all();
482 }
483 }
484