AJAX
3 months ago
Admin_Page
3 months ago
Click_Tracking
5 months ago
ColumnOptions
6 months ago
Cron
9 months ago
Custom_WordPress_Columns
8 months ago
Data_Pruning
5 months ago
Date_Picker
3 months ago
Date_Range
5 months ago
Ecommerce
5 months ago
Email_Reports
3 months ago
Examiner
3 months ago
Favicon
5 months ago
Form_Submissions
5 months ago
Integrations
3 months ago
Interval
1 year ago
Journey
5 months ago
Migrations
5 months ago
Models
5 months ago
Overview
3 months ago
Public_API
5 months ago
Rows
3 months ago
Statistics
3 months ago
Tables
3 months ago
Utils
5 months ago
Views
5 months ago
WooCommerceOrderMetaBox
5 months ago
ActivationLifecycle.php
3 months ago
Admin_Bar_Stats.php
3 months ago
Appearance.php
1 year ago
Campaign_Builder.php
3 months ago
Capability_Manager.php
3 months ago
Chart.php
3 months ago
Chart_Data.php
1 year ago
Click_Tracking.php
3 months ago
ComplianzIntegration.php
3 months ago
Cron_Job.php
5 months ago
Cron_Manager.php
5 months ago
Current_Traffic_Finder.php
1 year ago
Dashboard_Options.php
6 months ago
Dashboard_Widget.php
2 years ago
Database.php
8 months ago
Database_Manager.php
5 months ago
Empty_Report_Option.php
2 years ago
Env.php
6 months ago
Examiner_Config.php
11 months ago
FetchFaviconsJob.php
5 months ago
Filters.php
3 months ago
Geo_Database_Health_Check_Job.php
9 months ago
Geo_Database_Manager.php
6 months ago
Geoposition.php
1 year ago
Icon_Directory.php
6 months ago
Icon_Directory_Factory.php
2 years ago
Illuminate_Builder.php
10 months ago
Independent_Analytics.php
5 months ago
Interrupt.php
3 months ago
Known_Referrers.php
6 months ago
MainWP.php
1 year ago
Map.php
9 months ago
Map_Data.php
1 year ago
Migration_Fixer_Job.php
5 months ago
Patch.php
1 year ago
Payload_Validator.php
9 months ago
Plugin_Conflict_Detector.php
6 months ago
Plugin_Group.php
6 months ago
Plugin_Group_Option.php
2 years ago
Query.php
1 year ago
Query_Taps.php
3 months ago
Quick_Stats.php
3 months ago
REST_API.php
3 months ago
Real_Time.php
3 months ago
Report.php
1 year ago
Report_Finder.php
6 months ago
Report_Options_Parser.php
9 months ago
Resource_Identifier.php
9 months ago
Settings.php
3 months ago
Sort_Configuration.php
9 months ago
Tables.php
8 months ago
Track_Resource_Changes.php
1 year ago
View_Counter.php
6 months ago
Views_Over_Time_Finder.php
1 year ago
VisitorSaltRefreshInterval.php
6 months ago
WP_Option_Cache_Bust.php
2 years ago
View_Counter.php
178 lines
| 1 | <?php |
| 2 | |
| 3 | namespace IAWP; |
| 4 | |
| 5 | use IAWP\Date_Range\Relative_Date_Range; |
| 6 | use IAWP\Utils\Number_Formatter; |
| 7 | use IAWP\Utils\Security; |
| 8 | use IAWPSCOPED\Illuminate\Database\Query\Builder; |
| 9 | use IAWPSCOPED\Illuminate\Database\Query\JoinClause; |
| 10 | /** @internal */ |
| 11 | class View_Counter |
| 12 | { |
| 13 | public function __construct() |
| 14 | { |
| 15 | \add_action('the_content', [$this, 'output_counter']); |
| 16 | \add_action('init', [$this, 'add_shortcode']); |
| 17 | \add_action('add_meta_boxes', [$this, 'maybe_add_meta_box'], 10); |
| 18 | \add_action('save_post', [$this, 'save_metabox_settings']); |
| 19 | } |
| 20 | public function output_counter($content) |
| 21 | { |
| 22 | if (!$this->passes_checks()) { |
| 23 | return $content; |
| 24 | } |
| 25 | $resource = $this->get_resource(); |
| 26 | if (\is_null($resource)) { |
| 27 | return $content; |
| 28 | } |
| 29 | $view_count = $this->get_view_count($resource, null); |
| 30 | // Checking here instead of passes_checks() so we don't have to always make a DB request for every page |
| 31 | if ($view_count < \IAWPSCOPED\iawp()->get_option('iawp_view_counter_threshold', 0)) { |
| 32 | return $content; |
| 33 | } |
| 34 | $view_count = Number_Formatter::decimal($view_count); |
| 35 | $counter = $this->get_counter_html($view_count); |
| 36 | $position = \IAWPSCOPED\iawp()->get_option('iawp_view_counter_position', 'after'); |
| 37 | if ($position == 'before' || $position == 'both') { |
| 38 | $content = $counter . $content; |
| 39 | } |
| 40 | if ($position == 'after' || $position == 'both') { |
| 41 | $content .= $counter; |
| 42 | } |
| 43 | return $content; |
| 44 | } |
| 45 | public function get_counter_html($view_count = 0, $label = null, $icon = null) |
| 46 | { |
| 47 | if (\is_null($label)) { |
| 48 | if (!\get_option('iawp_view_counter_label_show', \true)) { |
| 49 | $label = ''; |
| 50 | } else { |
| 51 | $default = \function_exists('IAWPSCOPED\\pll__') ? pll__('Views:', 'independent-analytics') : \__('Views:', 'independent-analytics'); |
| 52 | $label = \IAWPSCOPED\iawp()->get_option('iawp_view_counter_label', $default); |
| 53 | } |
| 54 | } |
| 55 | if (\is_null($icon)) { |
| 56 | $icon = \get_option('iawp_view_counter_icon', \true); |
| 57 | } |
| 58 | if ($icon) { |
| 59 | $svg = '<svg height="20" viewBox="0 0 192 192" width="20" fill="currentColor" style="margin-right:6px; margin-top:-2px;"><path d="m16 176v-136h-16v144a8 8 0 0 0 8 8h184v-16z"/><path d="m72 112a8 8 0 0 0 -8-8h-24a8 8 0 0 0 -8 8v56h40z"/><path d="m128 80a8 8 0 0 0 -8-8h-24a8 8 0 0 0 -8 8v88h40z"/><path d="m184 48a8 8 0 0 0 -8-8h-24a8 8 0 0 0 -8 8v120h40z"/></svg>'; |
| 60 | $label = $svg . ' ' . $label; |
| 61 | } |
| 62 | return '<div class="iawp-view-counter" style="display: flex;"><span class="view-counter-text" style="display: flex; align-items: center;">' . Security::svg($label) . '</span> <span class="view-counter-value" style="margin-left: 3px;">' . \esc_html($view_count) . '</span></div>'; |
| 63 | } |
| 64 | public function add_shortcode() |
| 65 | { |
| 66 | \add_shortcode('iawp_view_counter', [$this, 'shortcode']); |
| 67 | } |
| 68 | public function shortcode($atts) |
| 69 | { |
| 70 | $attributes = \shortcode_atts(['label' => \IAWPSCOPED\iawp()->get_option('iawp_view_counter_label', \esc_html__('Views:', 'independent-analytics')), 'icon' => \true, 'range' => \IAWPSCOPED\iawp()->get_option('iawp_view_counter_views_to_count', 'total')], $atts); |
| 71 | $resource = $this->get_resource($attributes['range']); |
| 72 | if (\is_null($resource)) { |
| 73 | return; |
| 74 | } |
| 75 | $view_count = $this->get_view_count($resource, $attributes['range']); |
| 76 | if ($view_count < \IAWPSCOPED\iawp()->get_option('iawp_view_counter_threshold', 0)) { |
| 77 | return; |
| 78 | } |
| 79 | $view_count = Number_Formatter::decimal($view_count); |
| 80 | return $this->get_counter_html($view_count, $attributes['label'], $attributes['icon']); |
| 81 | } |
| 82 | public function maybe_add_meta_box() : void |
| 83 | { |
| 84 | if (!\IAWPSCOPED\iawp()->get_option('iawp_view_counter_manual_adjustment', \false)) { |
| 85 | return; |
| 86 | } |
| 87 | foreach (\IAWPSCOPED\iawp()->get_option('iawp_view_counter_post_types', []) as $screen) { |
| 88 | \add_meta_box('iawp-view-counter-adjustment', \esc_html__('View Counter Adjustment', 'independent-analytics'), [$this, 'render_meta_box_content'], $screen, 'side'); |
| 89 | } |
| 90 | } |
| 91 | public function render_meta_box_content() : void |
| 92 | { |
| 93 | global $post; |
| 94 | echo '<p>' . \esc_html__('Increase count by:', 'independent-analytics') . '<input type="number" name="iawp_view_counter_adjustment" id="iawp_view_counter_adjustment" |
| 95 | value="' . \esc_attr(\get_post_meta($post->ID, 'iawp_view_counter_adjustment', \true)) . '" |
| 96 | placeholder="0" style="max-width: 80px; margin-left: 8px" /> |
| 97 | <a class="info-link" |
| 98 | href="https://independentwp.com/knowledgebase/dashboard/display-view-counter/" |
| 99 | target="_blank" |
| 100 | style="text-decoration:none;float:right;margin-top:4px"> |
| 101 | <span class="dashicons dashicons-editor-help"></span> |
| 102 | </a> |
| 103 | </p>'; |
| 104 | } |
| 105 | public function save_metabox_settings(int $post_id) |
| 106 | { |
| 107 | if (\array_key_exists('iawp_view_counter_adjustment', $_POST)) { |
| 108 | \update_post_meta($post_id, 'iawp_view_counter_adjustment', \absint($_POST['iawp_view_counter_adjustment'])); |
| 109 | } |
| 110 | } |
| 111 | private function get_resource($range = null) : ?\IAWP\Resource_Identifier |
| 112 | { |
| 113 | $current_resource = \IAWP\Resource_Identifier::for_resource_being_viewed(); |
| 114 | // It's critical to check because this function is called erroneously by Gutenberg in the editor |
| 115 | if (\is_null($current_resource)) { |
| 116 | return null; |
| 117 | } |
| 118 | global $post; |
| 119 | // Note: There is an unkown circumstance that can cause $post to be null with Divi |
| 120 | if (\is_null($post)) { |
| 121 | return null; |
| 122 | } |
| 123 | // Get stats for individual posts in the loop if shortcode added to each post |
| 124 | if ($post->ID != $current_resource->meta_value() && \is_main_query() && \in_the_loop()) { |
| 125 | $current_resource = \IAWP\Resource_Identifier::for_post_id($post->ID); |
| 126 | } |
| 127 | return $current_resource; |
| 128 | } |
| 129 | private function passes_checks() : bool |
| 130 | { |
| 131 | if (!\is_singular() || !\is_main_query() || !\in_the_loop()) { |
| 132 | return \false; |
| 133 | } |
| 134 | if (\IAWPSCOPED\iawp()->get_option('iawp_view_counter_enable', \false) == \false) { |
| 135 | return \false; |
| 136 | } |
| 137 | if (!\in_array(\get_post_type(), \IAWPSCOPED\iawp()->get_option('iawp_view_counter_post_types', []))) { |
| 138 | return \false; |
| 139 | } |
| 140 | if (\IAWPSCOPED\iawp()->get_option('iawp_view_counter_private', \false) && !\is_user_logged_in()) { |
| 141 | return \false; |
| 142 | } |
| 143 | $exclude = \IAWPSCOPED\iawp()->get_option('iawp_view_counter_exclude', ''); |
| 144 | if ($exclude != '') { |
| 145 | $exclude = \explode(',', $exclude); |
| 146 | if (\in_array(\get_the_ID(), $exclude)) { |
| 147 | return \false; |
| 148 | } |
| 149 | } |
| 150 | return \true; |
| 151 | } |
| 152 | private function get_view_count(\IAWP\Resource_Identifier $resource, ?string $relative_range_id) : int |
| 153 | { |
| 154 | // The shortcode has a parameter for users to enter a custom date range |
| 155 | if (\is_null($relative_range_id)) { |
| 156 | $relative_range_id = \IAWPSCOPED\iawp()->get_option('iawp_view_counter_views_to_count', 'total'); |
| 157 | } |
| 158 | $relative_range_id = \strtoupper($relative_range_id); |
| 159 | if ($relative_range_id === 'TOTAL' || !\in_array($relative_range_id, Relative_Date_Range::range_ids())) { |
| 160 | $relative_range_id = 'ALL_TIME'; |
| 161 | } |
| 162 | $resources_table = \IAWP\Query::get_table_name(\IAWP\Query::RESOURCES); |
| 163 | $views_table = \IAWP\Query::get_table_name(\IAWP\Query::VIEWS); |
| 164 | $relative_range = new Relative_Date_Range($relative_range_id); |
| 165 | $query = \IAWP\Illuminate_Builder::new()->selectRaw('COUNT(views.id) AS views')->from($resources_table, 'resources')->leftJoin("{$views_table} AS views", function (JoinClause $join) { |
| 166 | $join->on('resources.id', '=', 'views.resource_id'); |
| 167 | })->where('resource', '=', $resource->type())->when($resource->has_meta(), function (Builder $query) use($resource) { |
| 168 | $query->where($resource->meta_key(), '=', $resource->meta_value()); |
| 169 | })->whereBetween('viewed_at', [$relative_range->iso_start(), $relative_range->iso_end()])->groupBy('resources.id'); |
| 170 | $views = $query->value('views'); |
| 171 | $views = \is_null($views) ? 0 : $views; |
| 172 | if (\IAWPSCOPED\iawp()->get_option('iawp_view_counter_manual_adjustment', \false)) { |
| 173 | $views += \intval(\get_post_meta($resource->meta_value(), 'iawp_view_counter_adjustment', \true)); |
| 174 | } |
| 175 | return $views; |
| 176 | } |
| 177 | } |
| 178 |