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