PluginProbe ʕ •ᴥ•ʔ
Independent Analytics – WordPress Analytics Plugin / 1.20.0
Independent Analytics – WordPress Analytics Plugin v1.20.0
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
Column.php 3 years ago Table.php 3 years ago Table_Campaigns.php 3 years ago Table_Geo.php 3 years ago Table_Referrers.php 3 years ago Table_Views.php 3 years ago
Table.php
391 lines
1 <?php
2
3 namespace IAWP_SCOPED\IAWP\Tables;
4
5 use IAWP_SCOPED\IAWP\Dashboard_Options;
6 use IAWP_SCOPED\IAWP\Filters;
7 use IAWP_SCOPED\IAWP\Utils\Array_To_CSV;
8 use IAWP_SCOPED\IAWP\Utils\Date_Format;
9 use IAWP_SCOPED\IAWP\Utils\Number_Formatter;
10 use IAWP_SCOPED\IAWP\Utils\Relative_Range;
11 use IAWP_SCOPED\IAWP\Utils\Security;
12 abstract class Table
13 {
14 /**
15 * @return array<Column>
16 */
17 protected abstract function local_columns() : array;
18 protected abstract function table_name() : string;
19 private $filters;
20 private $visible_columns;
21 private $views;
22 public function __construct($visible_columns = null)
23 {
24 $this->filters = new Filters();
25 $this->visible_columns = $visible_columns;
26 }
27 public function get_columns() : array
28 {
29 if ($this->visible_columns === null) {
30 return $this->local_columns();
31 }
32 return \array_map(function ($column) {
33 if (\in_array($column->id(), $this->visible_columns)) {
34 $column->set_visible(\true);
35 }
36 return $column;
37 }, $this->local_columns());
38 }
39 public function visible_column_ids()
40 {
41 $visible_columns = [];
42 foreach ($this->get_columns() as $column) {
43 if ($column->visible()) {
44 $visible_columns[] = $column->id();
45 }
46 }
47 return $visible_columns;
48 }
49 public function get_table_markup()
50 {
51 $opts = new Dashboard_Options();
52 $templates = \IAWP_SCOPED\iawp()->templates();
53 return $templates->render('table/index', ['just_rows' => \false, 'table_name' => $this->table_name(), 'all_columns' => $this->get_columns(), 'visible_columns' => $this->get_visible_columns(), 'row_count' => 0, 'rows' => [], 'render_skeleton' => \true, 'page_size' => \IAWP_SCOPED\iawp()->pagination_page_size(), 'opts' => $opts]);
54 }
55 public function set_views($views)
56 {
57 $this->views = $views;
58 }
59 public function get_row_markup($rows)
60 {
61 return $this->get_rendered_template($rows, \true);
62 }
63 private function get_visible_columns() : int
64 {
65 $visible_columns = 0;
66 foreach ($this->get_columns() as $column) {
67 if ($column->visible()) {
68 $visible_columns++;
69 }
70 }
71 return $visible_columns;
72 }
73 private function get_rendered_template($rows, $just_rows = \false)
74 {
75 $opts = new Dashboard_Options();
76 $templates = \IAWP_SCOPED\iawp()->templates();
77 $templates->registerFunction('row_data_attributes', [$this, 'get_row_data_attributes']);
78 $templates->registerFunction('cell_content', [$this, 'get_cell_content']);
79 return $templates->render('table/index', ['just_rows' => $just_rows, 'table_name' => $this->table_name(), 'all_columns' => $this->get_columns(), 'visible_columns' => $this->get_visible_columns(), 'row_count' => \count($rows), 'rows' => $rows, 'render_skeleton' => \false, 'page_size' => \IAWP_SCOPED\iawp()->pagination_page_size(), 'opts' => $opts]);
80 }
81 public function get_row_data_attributes($row)
82 {
83 $html = '';
84 foreach ($this->get_columns() as $column) {
85 $id = $column->id();
86 $data_val = $row->{$id}();
87 $html .= ' data-' . \esc_attr($column->id()) . '="' . \esc_attr($data_val) . '"';
88 }
89 return $html;
90 }
91 public function get_cell_content($row, $column_id)
92 {
93 if (\is_null($row->{$column_id}())) {
94 return null;
95 }
96 if ($column_id == 'title' && $row->is_deleted()) {
97 return Security::string($row->{$column_id}()) . ' <span class="deleted-label">' . \esc_html__('(deleted)', 'iawp') . '</span>';
98 } elseif ($column_id == 'views') {
99 $views = \number_format($row->views(), 0);
100 // Getting a divide by zero error from the line below?
101 // It's likely an issue with $this->views which is an instance of Views. Make sure the queries there are working.
102 $views_percentage = Number_Formatter::format($row->views() / $this->views->views() * 100, 'percent', 2);
103 return Security::string($views) . ' <span class="percentage">(' . Security::string($views_percentage) . ')</span>';
104 } elseif ($column_id == 'visitors') {
105 $visitors = \number_format($row->visitors(), 0);
106 $visitors_percentage = Number_Formatter::format($row->visitors() / $this->views->visitors() * 100, 'percent', 2);
107 return Security::string($visitors) . ' <span class="percentage">(' . Security::string($visitors_percentage) . ')</span>';
108 } elseif ($column_id == 'sessions') {
109 $sessions = \number_format($row->sessions(), 0);
110 $sessions_percentage = Number_Formatter::format($row->sessions() / $this->views->sessions() * 100, 'percent', 2);
111 return Security::string($sessions) . ' <span class="percentage">(' . Security::string($sessions_percentage) . ')</span>';
112 } elseif ($column_id === 'views_growth' || $column_id === 'visitors_growth' || $column_id === 'woocommerce_conversion_rate') {
113 return Number_Formatter::format($row->{$column_id}(), 'percent', 2);
114 } elseif ($column_id == 'url') {
115 if ($row->is_deleted()) {
116 return Security::string(\esc_url($row->url()));
117 } else {
118 return '<a href="' . Security::string(\esc_url($row->url(\true))) . '" target="_blank" class="external-link">' . Security::string(\esc_url($row->url())) . '<span class="dashicons dashicons-external"></span></a>';
119 }
120 } elseif ($column_id == 'author') {
121 return Security::html($row->avatar()) . ' ' . Security::string($row->author());
122 } elseif ($column_id == 'date') {
123 return Security::string(\date(Date_Format::php(), $row->date()));
124 } elseif ($column_id == 'type' && \method_exists($row, 'icon') && \method_exists($row, 'type')) {
125 return $row->icon(0) . ' ' . Security::string($row->type());
126 } elseif ($column_id == 'referrer' && !$row->is_direct()) {
127 return '<a href="' . \esc_url($row->referrer_url()) . '" target="_blank" class="external-link">' . Security::string($row->referrer()) . '<span class="dashicons dashicons-external"></span></a>';
128 } elseif ($column_id === 'country') {
129 return '<img class="flag" alt="Country flag" src="' . Security::string($row->flag()) . '"/>' . Security::string($row->country());
130 } elseif (\function_exists('wc_price') && ($column_id === 'wc_gross_sales' || $column_id === 'wc_refunded_amount' || $column_id === 'wc_net_sales' || $column_id === 'woocommerce_earnings_per_visitor' || $column_id === 'woocommerce_average_order_volume')) {
131 return Security::string(\wc_price($row->{$column_id}()));
132 } else {
133 return Security::string($row->{$column_id}());
134 }
135 }
136 private function filters()
137 {
138 return $this->filters;
139 }
140 public function output_toolbar()
141 {
142 $opts = new Dashboard_Options();
143 ?>
144 <div class="toolbar">
145 <div class="buttons">
146 <div class="modal-parent"
147 data-controller="dates"
148 data-dates-relative-range-id-value="<?php
149 echo $opts->relative_range();
150 ?>"
151 data-dates-exact-start-value="<?php
152 echo $opts->start();
153 ?>"
154 data-dates-exact-end-value="<?php
155 echo $opts->end();
156 ?>"
157 data-dates-first-day-of-week-value="<?php
158 echo \absint(\IAWP_SCOPED\iawp()->get_option('iawp_dow', 0));
159 ?>"
160 data-dates-css-url-value="<?php
161 echo \esc_url(\IAWP_SCOPED\iawp_url_to('dist/styles/easepick/datepicker.css'));
162 ?>"
163 data-dates-format-value="<?php
164 echo \esc_attr(Date_Format::js());
165 ?>"
166 >
167 <button id="dates-button"
168 class="iawp-button ghost-white"
169 data-action="dates#toggleModal"
170 data-dates-target="modalButton"
171 >
172 <span class="dashicons dashicons-calendar-alt"></span>
173 <span><?php
174 echo $opts->date_label();
175 ?></span>
176 </button>
177 <div id="modal-dates"
178 class="modal large flex"
179 data-dates-target="modal"
180 >
181 <div class="modal-inner">
182 <div id="easepick-picker"
183 data-dates-target="easepick"
184 style="display: none;"
185 >
186 </div>
187 <div class="relative-dates">
188 <?php
189 foreach (Relative_Range::ranges() as $range) {
190 ?>
191 <button class="iawp-button ghost-purple"
192 data-dates-target="relativeRange"
193 data-action="dates#relativeRangeSelected"
194 data-relative-range-id="<?php
195 echo $range->id;
196 ?>"
197 data-relative-range-label="<?php
198 echo $range->label;
199 ?>"
200 data-relative-range-start="<?php
201 echo $range->start->format('Y-m-d');
202 ?>"
203 data-relative-range-end="<?php
204 echo $range->end->format('Y-m-d');
205 ?>"
206 >
207 <?php
208 echo $range->label;
209 ?>
210 </button>
211 <?php
212 }
213 ?>
214 </div>
215 <div>
216 <hr/>
217 </div>
218 <div>
219 <button class="iawp-button purple"
220 data-dates-target="apply"
221 data-action="dates#apply"
222 >
223 <?php
224 \esc_html_e('Apply', 'iawp');
225 ?>
226 </button>
227 <button class="iawp-button ghost-purple"
228 data-action="dates#closeModal"
229 >
230 <?php
231 \esc_html_e('Cancel', 'iawp');
232 ?>
233 </button>
234 </div>
235 </div>
236 </div>
237 </div>
238 <?php
239 $this->filters()->output_filters($this->get_columns());
240 ?>
241 <?php
242 $this->column_picker();
243 ?>
244 </div>
245 <div class="buttons">
246 <button class="iawp-button ghost-white"
247 data-controller="clipboard"
248 data-action="clipboard#copy"
249 >
250 <span class="dashicons dashicons-admin-page"></span>
251 <span data-clipboard-target="statusTextElement">
252 <?php
253 \esc_html_e('Copy Dashboard URL', 'iawp');
254 ?>
255 </span>
256 </button>
257 <a class="learn-more"
258 href="https://independentwp.com/knowledgebase/dashboard/save-reports-revisit-later/"
259 target="_blank"><span class="dashicons dashicons-info-outline"></span></a>
260 </div>
261 </div><?php
262 }
263 private function column_picker()
264 {
265 ?>
266
267 <div class="customize-columns modal-parent small"
268 data-controller="columns"
269 >
270 <button id="customize-columns"
271 class="iawp-button ghost-white"
272 data-action="columns#toggleModal"
273 data-columns-target="modalButton"
274 >
275 <span class="dashicons dashicons-columns"></span>
276 <span><?php
277 \esc_html_e('Edit Columns', 'iawp');
278 ?></span>
279 </button>
280 <div id="modal-columns"
281 class="modal small"
282 data-columns-target="modal"
283 >
284 <div class="modal-inner">
285 <div class="title-small">
286 <?php
287 \esc_html_e('Columns', 'iawp');
288 ?>
289 </div>
290 <?php
291 foreach ($this->get_columns() as $column) {
292 ?>
293 <?php
294 if ($column->id() === 'wc_orders') {
295 ?>
296 <p class="title-small wc-title">
297 <?php
298 \esc_html_e('WooCommerce', 'iawp');
299 ?>
300 <?php
301 if (\IAWP_SCOPED\iawp_is_free()) {
302 ?>
303 <span class="pro-label"><?php
304 \esc_html_e('PRO', 'iawp');
305 ?></span>
306 <?php
307 }
308 ?>
309 </p>
310 <?php
311 }
312 ?>
313
314 <label class="column-label"
315 for="iawp-column-<?php
316 echo \esc_attr($column->id());
317 ?>"
318 >
319 <input id="iawp-column-<?php
320 echo \esc_attr($column->id());
321 ?>"
322 <?php
323 if ($column->requires_woocommerce() && \IAWP_SCOPED\iawp_is_free()) {
324 ?>
325 <?php
326 \checked(\true, \false, \true);
327 ?>
328 disabled="disabled"
329 data-locked-behind-pro="true"
330 <?php
331 } else {
332 ?>
333 <?php
334 \checked(\true, $column->visible(), \true);
335 ?>
336 data-columns-target="checkbox"
337 data-action="columns#check"
338 <?php
339 }
340 ?>
341 type="checkbox"
342 name="<?php
343 \esc_attr_e($column->id());
344 ?>"
345 data-test-visibility="<?php
346 echo $column->visible() ? 'visible' : 'hidden';
347 ?>"
348 >
349 <span><?php
350 echo \esc_html($column->label());
351 ?></span>
352 </label>
353 <?php
354 }
355 ?>
356 </div>
357 </div>
358 </div>
359 <?php
360 }
361 public final function csv($rows)
362 {
363 $columns = $this->get_columns();
364 $csv_header = [];
365 $csv_rows = [];
366 foreach ($columns as $column) {
367 if (!$column->exportable() || $column->requires_woocommerce() && \IAWP_SCOPED\iawp_is_free()) {
368 continue;
369 }
370 $csv_header[] = $column->label();
371 }
372 foreach ($rows as $row) {
373 $csv_row = [];
374 foreach ($columns as $column) {
375 if (!$column->exportable() || $column->requires_woocommerce() && \IAWP_SCOPED\iawp_is_free()) {
376 continue;
377 }
378 $column_id = $column->id();
379 if ($column_id === 'date') {
380 $csv_row[] = \date(Date_Format::php(), $row->{$column_id}());
381 } else {
382 $csv_row[] = $row->{$column_id}();
383 }
384 }
385 $csv_rows[] = $csv_row;
386 }
387 $csv = \array_merge([$csv_header], $csv_rows);
388 return Array_To_CSV::array2csv($csv);
389 }
390 }
391