PluginProbe ʕ •ᴥ•ʔ
Independent Analytics – WordPress Analytics Plugin / 2.12.2
Independent Analytics – WordPress Analytics Plugin v2.12.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 / Rows / Pages.php
independent-analytics / IAWP / Rows Last commit date
Campaigns.php 10 months ago Cities.php 10 months ago Countries.php 10 months ago Device_Browsers.php 10 months ago Device_OSS.php 10 months ago Device_Types.php 10 months ago Filter.php 1 year ago Forms.php 10 months ago Link_Patterns.php 10 months ago Links.php 10 months ago Pages.php 10 months ago Referrers.php 10 months ago Rows.php 11 months ago
Pages.php
141 lines
1 <?php
2
3 namespace IAWP\Rows;
4
5 use IAWP\Database;
6 use IAWP\Form_Submissions\Form;
7 use IAWP\Illuminate_Builder;
8 use IAWP\Models\Page;
9 use IAWP\Query;
10 use IAWP\Query_Taps;
11 use IAWP\Tables;
12 use IAWPSCOPED\Illuminate\Database\Query\Builder;
13 use IAWPSCOPED\Illuminate\Database\Query\JoinClause;
14 /** @internal */
15 class Pages extends \IAWP\Rows\Rows
16 {
17 private static $has_wp_comments_table = null;
18 public function attach_filters(Builder $query) : void
19 {
20 $query->joinSub($this->query(\true), 'page_rows', function (JoinClause $join) {
21 $join->on('page_rows.id', '=', 'views.resource_id');
22 });
23 }
24 protected function fetch_rows() : array
25 {
26 $rows = $this->query()->get()->all();
27 return \array_map(function (object $row) {
28 return Page::from_row($row);
29 }, $rows);
30 }
31 private function has_wp_comments_table() : bool
32 {
33 if (\is_bool(self::$has_wp_comments_table)) {
34 return self::$has_wp_comments_table;
35 }
36 global $wpdb;
37 self::$has_wp_comments_table = Database::has_table($wpdb->prefix . 'comments');
38 return self::$has_wp_comments_table;
39 }
40 private function query(?bool $skip_pagination = \false) : Builder
41 {
42 if ($skip_pagination) {
43 $this->number_of_rows = null;
44 }
45 $views_table = Query::get_table_name(Query::VIEWS);
46 $sessions_table = Query::get_table_name(Query::SESSIONS);
47 $resources_table = Query::get_table_name(Query::RESOURCES);
48 $orders_table = Query::get_table_name(Query::ORDERS);
49 $database_sort_columns = ['title' => 'cached_title', 'url' => 'cached_url', 'author' => 'cached_author', 'type' => 'cached_type_label', 'date' => 'cached_date', 'category' => 'cached_category'];
50 $sort_column = $this->sort_configuration->column();
51 foreach ($database_sort_columns as $key => $value) {
52 if ($sort_column === $key) {
53 $sort_column = $value;
54 }
55 }
56 $orders_query = Illuminate_Builder::new();
57 $orders_query->select(['sessions.initial_view_id AS view_id'])->selectRaw('IFNULL(COUNT(DISTINCT orders.order_id), 0) AS wc_orders')->selectRaw('IFNULL(ROUND(CAST(SUM(orders.total) AS SIGNED)), 0) AS wc_gross_sales')->selectRaw('IFNULL(ROUND(CAST(SUM(orders.total_refunded) AS SIGNED)), 0) AS wc_refunded_amount')->selectRaw('IFNULL(SUM(orders.total_refunds), 0) AS wc_refunds')->from($orders_table, 'orders')->leftJoin($orders_query->raw($views_table . ' AS views'), function (JoinClause $join) {
58 $join->on('orders.view_id', '=', 'views.id');
59 })->leftJoin($orders_query->raw($sessions_table . ' AS sessions'), function (JoinClause $join) {
60 $join->on('views.session_id', '=', 'sessions.session_id');
61 })->where('orders.is_included_in_analytics', '=', \true)->whereBetween('orders.created_at', $this->get_current_period_iso_range())->groupBy('orders.view_id');
62 $pages_query = Illuminate_Builder::new();
63 $pages_query->select('resources.*')->selectRaw('COUNT(DISTINCT views.id) AS views')->selectRaw('COUNT(DISTINCT sessions.visitor_id) AS visitors')->selectRaw('COUNT(DISTINCT IF(initial_view.resource_id = resources.id, sessions.visitor_id, NULL)) AS landing_page_visitors')->selectRaw('COUNT(DISTINCT sessions.session_id) AS sessions')->selectRaw('COUNT(DISTINCT IF(sessions.final_view_id IS NULL, sessions.session_id, NULL)) AS bounces')->selectRaw('AVG(TIMESTAMPDIFF(SECOND, views.viewed_at, views.next_viewed_at)) AS average_view_duration')->selectRaw('COUNT(DISTINCT IF(resources.id = initial_view.resource_id, sessions.session_id, NULL)) AS entrances')->selectRaw('COUNT(DISTINCT IF((resources.id = final_view.resource_id OR (resources.id = initial_view.resource_id AND sessions.final_view_id IS NULL)), sessions.session_id, NULL)) AS exits')->selectRaw('COUNT(DISTINCT clicks.click_id) AS clicks')->selectRaw('IFNULL(SUM(the_orders.wc_orders), 0) AS wc_orders')->selectRaw('IFNULL(SUM(the_orders.wc_gross_sales), 0) AS wc_gross_sales')->selectRaw('IFNULL(SUM(the_orders.wc_refunded_amount), 0) AS wc_refunded_amount')->selectRaw('IFNULL(SUM(wc_refunds), 0) AS wc_refunds')->selectRaw('IFNULL(SUM(form_submissions.form_submissions), 0) AS form_submissions')->tap(function (Builder $query) {
64 foreach (Form::get_forms() as $form) {
65 $query->selectRaw("SUM(IF(form_submissions.form_id = ?, form_submissions.form_submissions, 0)) AS {$form->submissions_column()}", [$form->id()]);
66 }
67 })->from($views_table, 'views')->leftJoin($pages_query->raw($sessions_table . ' AS sessions'), function (JoinClause $join) {
68 $join->on('views.session_id', '=', 'sessions.session_id');
69 })->leftJoin($pages_query->raw($resources_table . ' AS resources'), function (JoinClause $join) {
70 $join->on('views.resource_id', '=', 'resources.id');
71 })->leftJoin($pages_query->raw($views_table . ' AS initial_view'), function (JoinClause $join) {
72 $join->on('sessions.initial_view_id', '=', 'initial_view.id');
73 })->leftJoin($pages_query->raw($views_table . ' AS final_view'), function (JoinClause $join) {
74 $join->on('sessions.final_view_id', '=', 'final_view.id');
75 })->leftJoin($pages_query->raw(Tables::clicks() . ' AS clicks'), function (JoinClause $join) {
76 $join->on('clicks.view_id', '=', 'views.id');
77 })->leftJoinSub($orders_query, 'the_orders', function (JoinClause $join) {
78 $join->on('the_orders.view_id', '=', 'views.id');
79 })->tap(Query_Taps::tap_authored_content_check(\false))->when($this->examiner_config, function (Builder $query) {
80 if ($this->examiner_config->group() !== 'link_pattern') {
81 return;
82 }
83 $query->leftJoin(Tables::clicked_links() . ' AS clicked_links', function (JoinClause $join) {
84 $join->on('clicked_links.click_id', '=', 'clicks.click_id');
85 });
86 })->tap(Query_Taps::tap_related_to_examined_record($this->examiner_config))->when($this->has_wp_comments_table(), function (Builder $query) {
87 $query->selectRaw('IFNULL(comments.comments, 0) AS comments');
88 $query->leftJoinSub($this->get_comments_query(), 'comments', 'comments.resource_id', '=', 'resources.id');
89 }, function (Builder $query) {
90 $query->selectRaw('0 AS comments');
91 })->leftJoinSub($this->get_form_submissions_query(), 'form_submissions', function (JoinClause $join) {
92 $join->on('form_submissions.view_id', '=', 'views.id');
93 })->whereBetween('views.viewed_at', $this->get_current_period_iso_range())->when(!$this->appears_to_be_for_real_time_analytics(), function (Builder $query) {
94 $query->whereBetween('sessions.created_at', $this->get_current_period_iso_range());
95 })->when(\count($this->filters) > 0, function (Builder $query) {
96 foreach ($this->filters as $filter) {
97 if (!$this->is_a_calculated_column($filter->column())) {
98 $filter->apply_to_query($query);
99 }
100 }
101 })->when(\is_int($this->solo_record_id), function (Builder $query) {
102 $query->where('resources.id', '=', $this->solo_record_id);
103 })->groupBy('resources.id')->having('views', '>', 0)->when(!$this->is_using_a_calculated_column(), function (Builder $query) use($sort_column) {
104 $query->when($this->sort_configuration->is_column_nullable(), function (Builder $query) use($sort_column) {
105 $query->orderByRaw("CASE WHEN {$sort_column} IS NULL THEN 1 ELSE 0 END");
106 })->orderBy($sort_column, $this->sort_configuration->direction())->orderBy('cached_title')->when(\is_int($this->number_of_rows), function (Builder $query) {
107 $query->limit($this->number_of_rows);
108 });
109 });
110 $previous_period_query = Illuminate_Builder::new();
111 $previous_period_query->select(['views.resource_id'])->selectRaw('COUNT(*) AS previous_period_views')->selectRaw('COUNT(DISTINCT sessions.visitor_id) AS previous_period_visitors')->from($views_table, 'views')->join($previous_period_query->raw($sessions_table . ' AS sessions'), 'views.session_id', '=', 'sessions.session_id')->whereBetween('views.viewed_at', $this->get_previous_period_iso_range())->whereBetween('sessions.created_at', $this->get_previous_period_iso_range())->groupBy('views.resource_id');
112 $outer_query = Illuminate_Builder::new();
113 $outer_query->selectRaw('pages.*')->selectRaw('IFNULL((views - previous_period_views) / previous_period_views * 100, 0) AS views_growth')->selectRaw('IFNULL((visitors - previous_period_visitors) / previous_period_visitors * 100, 0) AS visitors_growth')->selectRaw('IFNULL(bounces / sessions * 100, 0) AS bounce_rate')->selectRaw('IFNULL((exits / views) * 100, 0) AS exit_percent')->selectRaw('ROUND(CAST(wc_gross_sales - wc_refunded_amount AS SIGNED)) AS wc_net_sales')->selectRaw('IF(visitors = 0, 0, (wc_orders / landing_page_visitors) * 100) AS wc_conversion_rate')->selectRaw('IF(visitors = 0, 0, (wc_gross_sales - wc_refunded_amount) / landing_page_visitors) AS wc_earnings_per_visitor')->selectRaw('IF(wc_orders = 0, 0, ROUND(CAST(wc_gross_sales / wc_orders AS SIGNED))) AS wc_average_order_volume')->selectRaw('IF(visitors = 0, 0, (form_submissions / visitors) * 100) AS form_conversion_rate')->tap(function (Builder $query) {
114 foreach (Form::get_forms() as $form) {
115 $query->selectRaw("IF(visitors = 0, 0, ({$form->submissions_column()} / visitors) * 100) AS {$form->conversion_rate_column()}");
116 }
117 })->when(\count($this->filters) > 0, function (Builder $query) {
118 foreach ($this->filters as $filter) {
119 if ($this->is_a_calculated_column($filter->column())) {
120 $filter->apply_to_query($query);
121 }
122 }
123 })->fromSub($pages_query, 'pages')->leftJoinSub($previous_period_query, 'previous_period_stats', 'pages.id', '=', 'previous_period_stats.resource_id')->when($this->is_using_a_calculated_column(), function (Builder $query) use($sort_column) {
124 $query->when($this->sort_configuration->is_column_nullable(), function (Builder $query) use($sort_column) {
125 $query->orderByRaw("CASE WHEN {$sort_column} IS NULL THEN 1 ELSE 0 END");
126 })->orderBy($sort_column, $this->sort_configuration->direction())->orderBy('cached_title')->when(\is_int($this->number_of_rows), function (Builder $query) {
127 $query->limit($this->number_of_rows);
128 });
129 });
130 return $outer_query;
131 }
132 private function get_comments_query() : Builder
133 {
134 global $wpdb;
135 $comments_table = $wpdb->prefix . 'comments';
136 $resources_table = Query::get_table_name(Query::RESOURCES);
137 $comments_query = Illuminate_Builder::new()->select(['resources.id AS resource_id'])->selectRaw('COUNT(*) AS comments')->from($comments_table, 'comments')->join($resources_table . " AS resources", 'comments.comment_post_ID', '=', 'resources.singular_id')->where('comments.comment_type', '=', 'comment')->where('comments.comment_approved', '=', '1')->whereBetween('comments.comment_date_gmt', $this->get_current_period_iso_range())->groupBy('resources.id');
138 return $comments_query;
139 }
140 }
141