Below is a differential between the unpatched vulnerable code and the patched update, for reference.
--- a/independent-analytics/IAWP/AJAX/AJAX_Manager.php
+++ b/independent-analytics/IAWP/AJAX/AJAX_Manager.php
@@ -24,12 +24,8 @@
$this->instances[] = new IAWPAJAXDelete_Report();
$this->instances[] = new IAWPAJAXDismiss_Notice();
$this->instances[] = new IAWPAJAXEdit_Link();
- $this->instances[] = new IAWPAJAXExport_Campaigns();
- $this->instances[] = new IAWPAJAXExport_Clicks();
- $this->instances[] = new IAWPAJAXExport_Devices();
- $this->instances[] = new IAWPAJAXExport_Geo();
- $this->instances[] = new IAWPAJAXExport_Pages();
- $this->instances[] = new IAWPAJAXExport_Referrers();
+ $this->instances[] = new IAWPAJAXExport_Report_Statistics();
+ $this->instances[] = new IAWPAJAXExport_Report_Table();
$this->instances[] = new IAWPAJAXExport_Reports();
$this->instances[] = new IAWPAJAXFilter();
$this->instances[] = new IAWPAJAXImport_Reports();
--- a/independent-analytics/IAWP/AJAX/Edit_Link.php
+++ b/independent-analytics/IAWP/AJAX/Edit_Link.php
@@ -39,6 +39,9 @@
$link_properties['value'] = Link_Validator::sanitize_domain($link_properties['value']);
} elseif ($link_properties['type'] == 'subdirectory') {
$link_properties['value'] = Link_Validator::sanitize_subdirectory($link_properties['value']);
+ } elseif ($link_properties['type'] == 'external') {
+ // There's no value for external
+ $link_properties['value'] = '';
} else {
$link_properties['value'] = sanitize_text_field($link_properties['value']);
}
--- a/independent-analytics/IAWP/AJAX/Export_Campaigns.php
+++ b/independent-analytics/IAWP/AJAX/Export_Campaigns.php
@@ -1,30 +0,0 @@
-<?php
-
-namespace IAWPAJAX;
-
-use IAWPCapability_Manager;
-use IAWPDate_RangeExact_Date_Range;
-use IAWPRowsCampaigns;
-use IAWPTablesTable_Campaigns;
-/** @internal */
-class Export_Campaigns extends IAWPAJAXAJAX
-{
- protected function action_name() : string
- {
- return 'iawp_export_campaigns';
- }
- protected function requires_pro() : bool
- {
- return true;
- }
- protected function action_callback() : void
- {
- if (!Capability_Manager::can_edit()) {
- return;
- }
- $campaigns = new Campaigns(Exact_Date_Range::comprehensive_range());
- $table = new Table_Campaigns();
- $csv = $table->csv($campaigns->rows());
- echo $csv->to_string();
- }
-}
--- a/independent-analytics/IAWP/AJAX/Export_Clicks.php
+++ b/independent-analytics/IAWP/AJAX/Export_Clicks.php
@@ -1,30 +0,0 @@
-<?php
-
-namespace IAWPAJAX;
-
-use IAWPCapability_Manager;
-use IAWPDate_RangeExact_Date_Range;
-use IAWPRowsClicks;
-use IAWPTablesTable_Clicks;
-/** @internal */
-class Export_Clicks extends IAWPAJAXAJAX
-{
- protected function action_name() : string
- {
- return 'iawp_export_clicks';
- }
- protected function requires_pro() : bool
- {
- return true;
- }
- protected function action_callback() : void
- {
- if (!Capability_Manager::can_edit()) {
- return;
- }
- $table = new Table_Clicks();
- $clicks = new Clicks(Exact_Date_Range::comprehensive_range(), null, null, $table->sanitize_sort_parameters());
- $csv = $table->csv($clicks->rows());
- echo $csv->to_string();
- }
-}
--- a/independent-analytics/IAWP/AJAX/Export_Devices.php
+++ b/independent-analytics/IAWP/AJAX/Export_Devices.php
@@ -1,26 +0,0 @@
-<?php
-
-namespace IAWPAJAX;
-
-use IAWPCapability_Manager;
-use IAWPDate_RangeExact_Date_Range;
-use IAWPRowsDevice_Types;
-use IAWPTablesTable_Devices;
-/** @internal */
-class Export_Devices extends IAWPAJAXAJAX
-{
- protected function action_name() : string
- {
- return 'iawp_export_devices';
- }
- protected function action_callback() : void
- {
- if (!Capability_Manager::can_edit()) {
- return;
- }
- $device_types = new Device_Types(Exact_Date_Range::comprehensive_range());
- $table = new Table_Devices();
- $csv = $table->csv($device_types->rows());
- echo $csv->to_string();
- }
-}
--- a/independent-analytics/IAWP/AJAX/Export_Geo.php
+++ b/independent-analytics/IAWP/AJAX/Export_Geo.php
@@ -1,26 +0,0 @@
-<?php
-
-namespace IAWPAJAX;
-
-use IAWPCapability_Manager;
-use IAWPDate_RangeExact_Date_Range;
-use IAWPRowsCountries;
-use IAWPTablesTable_Geo;
-/** @internal */
-class Export_Geo extends IAWPAJAXAJAX
-{
- protected function action_name() : string
- {
- return 'iawp_export_geo';
- }
- protected function action_callback() : void
- {
- if (!Capability_Manager::can_edit()) {
- return;
- }
- $geos = new Countries(Exact_Date_Range::comprehensive_range());
- $table = new Table_Geo();
- $csv = $table->csv($geos->rows());
- echo $csv->to_string();
- }
-}
--- a/independent-analytics/IAWP/AJAX/Export_Pages.php
+++ b/independent-analytics/IAWP/AJAX/Export_Pages.php
@@ -1,26 +0,0 @@
-<?php
-
-namespace IAWPAJAX;
-
-use IAWPCapability_Manager;
-use IAWPDate_RangeExact_Date_Range;
-use IAWPRowsPages;
-use IAWPTablesTable_Pages;
-/** @internal */
-class Export_Pages extends IAWPAJAXAJAX
-{
- protected function action_name() : string
- {
- return 'iawp_export_pages';
- }
- protected function action_callback() : void
- {
- if (!Capability_Manager::can_edit()) {
- return;
- }
- $resources = new Pages(Exact_Date_Range::comprehensive_range());
- $table = new Table_Pages();
- $csv = $table->csv($resources->rows());
- echo $csv->to_string();
- }
-}
--- a/independent-analytics/IAWP/AJAX/Export_Referrers.php
+++ b/independent-analytics/IAWP/AJAX/Export_Referrers.php
@@ -1,26 +0,0 @@
-<?php
-
-namespace IAWPAJAX;
-
-use IAWPCapability_Manager;
-use IAWPDate_RangeExact_Date_Range;
-use IAWPRowsReferrers;
-use IAWPTablesTable_Referrers;
-/** @internal */
-class Export_Referrers extends IAWPAJAXAJAX
-{
- protected function action_name() : string
- {
- return 'iawp_export_referrers';
- }
- protected function action_callback() : void
- {
- if (!Capability_Manager::can_edit()) {
- return;
- }
- $referrers = new Referrers(Exact_Date_Range::comprehensive_range());
- $table = new Table_Referrers();
- $csv = $table->csv($referrers->rows());
- echo $csv->to_string();
- }
-}
--- a/independent-analytics/IAWP/AJAX/Export_Report_Statistics.php
+++ b/independent-analytics/IAWP/AJAX/Export_Report_Statistics.php
@@ -0,0 +1,82 @@
+<?php
+
+namespace IAWPAJAX;
+
+use DateTime;
+use IAWPDate_RangeDate_Range;
+use IAWPDate_RangeExact_Date_Range;
+use IAWPDate_RangeRelative_Date_Range;
+use IAWPEnv;
+use IAWPStatisticsIntervalsIntervals;
+use IAWPStatisticsStatistics;
+use IAWPTablesTable;
+use IAWPUtilsTimezone;
+use Throwable;
+/** @internal */
+class Export_Report_Statistics extends IAWPAJAXAJAX
+{
+ protected function action_name() : string
+ {
+ return 'iawp_export_report_statistics';
+ }
+ protected function action_callback() : void
+ {
+ $date_range = $this->get_date_range();
+ $is_new_date_range = $this->get_field('is_new_date_range') === 'true';
+ $filters = $this->get_field('filters') ?? [];
+ $sort_column = $this->get_field('sort_column') ?? null;
+ $sort_direction = $this->get_field('sort_direction') ?? null;
+ $group = $this->get_field('group') ?? null;
+ $chart_interval = $is_new_date_range ? Intervals::default_for($date_range->number_of_days()) : Intervals::find_by_id($this->get_field('chart_interval'));
+ $page = intval($this->get_field('page') ?? 1);
+ $number_of_rows = $page * IAWPSCOPEDiawp()->pagination_page_size();
+ $table_type = $this->get_field('table_type');
+ $is_geo_table = $table_type === 'geo';
+ $table_class = Env::get_table();
+ /** @var Table $table */
+ $table = new $table_class($group);
+ $filters = $table->sanitize_filters($filters);
+ $sort_configuration = $table->sanitize_sort_parameters($sort_column, $sort_direction);
+ $rows_class = $table->group()->rows_class();
+ $statistics_class = $table->group()->statistics_class();
+ if ($is_geo_table) {
+ $rows_query = new $rows_class($date_range, null, $filters, $sort_configuration);
+ } else {
+ $rows_query = new $rows_class($date_range, $number_of_rows, $filters, $sort_configuration);
+ }
+ if (empty($filters)) {
+ /** @var Statistics $statistics */
+ $statistics = new $statistics_class($date_range, null, $chart_interval);
+ } else {
+ $statistics = new $statistics_class($date_range, $rows_query, $chart_interval);
+ }
+ wp_send_json_success(['csv' => $statistics->get_statistics_as_csv()->to_string()]);
+ }
+ /**
+ * Get the date range for the filter request
+ *
+ * The date info can be supplied in one of two ways.
+ *
+ * The first is to provide a relative_range_id which is converted into start, end, and label.
+ *
+ * The second is to provide explicit start and end fields which will be used as is.
+ *
+ * @return Date_Range
+ */
+ private function get_date_range() : Date_Range
+ {
+ $relative_range_id = $this->get_field('relative_range_id');
+ $exact_start = $this->get_field('exact_start');
+ $exact_end = $this->get_field('exact_end');
+ if (!is_null($exact_start) && !is_null($exact_end)) {
+ try {
+ $start = new DateTime($exact_start, Timezone::site_timezone());
+ $end = new DateTime($exact_end, Timezone::site_timezone());
+ return new Exact_Date_Range($start, $end);
+ } catch (Throwable $e) {
+ // Do nothing and fall back to default relative date range
+ }
+ }
+ return new Relative_Date_Range($relative_range_id);
+ }
+}
--- a/independent-analytics/IAWP/AJAX/Export_Report_Table.php
+++ b/independent-analytics/IAWP/AJAX/Export_Report_Table.php
@@ -0,0 +1,65 @@
+<?php
+
+namespace IAWPAJAX;
+
+use DateTime;
+use IAWPDate_RangeDate_Range;
+use IAWPDate_RangeExact_Date_Range;
+use IAWPDate_RangeRelative_Date_Range;
+use IAWPEnv;
+use IAWPTablesTable;
+use IAWPUtilsTimezone;
+use Throwable;
+/** @internal */
+class Export_Report_Table extends IAWPAJAXAJAX
+{
+ protected function action_name() : string
+ {
+ return 'iawp_export_report_table';
+ }
+ protected function action_callback() : void
+ {
+ $date_range = $this->get_date_range();
+ $filters = $this->get_field('filters') ?? [];
+ $sort_column = $this->get_field('sort_column') ?? null;
+ $sort_direction = $this->get_field('sort_direction') ?? null;
+ $group = $this->get_field('group') ?? null;
+ $table_class = Env::get_table();
+ /** @var Table $table */
+ $table = new $table_class($group);
+ $filters = $table->sanitize_filters($filters);
+ $sort_configuration = $table->sanitize_sort_parameters($sort_column, $sort_direction);
+ $rows_class = $table->group()->rows_class();
+ $rows_query = new $rows_class($date_range, null, $filters, $sort_configuration);
+ $rows = $rows_query->rows();
+ $csv = $table->csv($rows, true);
+ wp_send_json_success(['csv' => $csv->to_string()]);
+ }
+ /**
+ * Get the date range for the filter request
+ *
+ * The date info can be supplied in one of two ways.
+ *
+ * The first is to provide a relative_range_id which is converted into start, end, and label.
+ *
+ * The second is to provide explicit start and end fields which will be used as is.
+ *
+ * @return Date_Range
+ */
+ private function get_date_range() : Date_Range
+ {
+ $relative_range_id = $this->get_field('relative_range_id');
+ $exact_start = $this->get_field('exact_start');
+ $exact_end = $this->get_field('exact_end');
+ if (!is_null($exact_start) && !is_null($exact_end)) {
+ try {
+ $start = new DateTime($exact_start, Timezone::site_timezone());
+ $end = new DateTime($exact_end, Timezone::site_timezone());
+ return new Exact_Date_Range($start, $end);
+ } catch (Throwable $e) {
+ // Do nothing and fall back to default relative date range
+ }
+ }
+ return new Relative_Date_Range($relative_range_id);
+ }
+}
--- a/independent-analytics/IAWP/AJAX/Export_Reports.php
+++ b/independent-analytics/IAWP/AJAX/Export_Reports.php
@@ -34,6 +34,6 @@
$reports_array = array_map(function ($report) {
return $report->to_array();
}, $reports);
- wp_send_json_success(['json' => json_encode(['plugin_version' => '2.9.7', 'database_version' => '39', 'export_version' => '1', 'reports' => $reports_array])]);
+ wp_send_json_success(['json' => json_encode(['plugin_version' => '2.10.0', 'database_version' => '42', 'export_version' => '1', 'reports' => $reports_array])]);
}
}
--- a/independent-analytics/IAWP/AJAX/Sort_Links.php
+++ b/independent-analytics/IAWP/AJAX/Sort_Links.php
@@ -4,7 +4,6 @@
use IAWPCapability_Manager;
use IAWPIlluminate_Builder;
-use IAWPQuery;
use IAWPTables;
/** @internal */
class Sort_Links extends IAWPAJAXAJAX
--- a/independent-analytics/IAWP/Admin_Page/Analytics_Page.php
+++ b/independent-analytics/IAWP/Admin_Page/Analytics_Page.php
@@ -11,6 +11,7 @@
use IAWPPlugin_Conflict_Detector;
use IAWPQuick_Stats;
use IAWPReal_Time;
+use IAWPReport;
use IAWPReport_Finder;
use IAWPTablesTable;
use IAWPTablesTable_Campaigns;
@@ -28,49 +29,51 @@
$options = Dashboard_Options::getInstance();
$date_rage = $options->get_date_range();
$tab = (new Env())->get_tab();
+ $report = (new Report_Finder())->current();
+ $is_showing_skeleton_ui = $report instanceof Report && $report->has_filters();
if ($tab === 'views') {
$table = new Table_Pages();
$statistics_class = $table->group()->statistics_class();
$statistics = new $statistics_class($date_rage, null, $options->chart_interval());
- $stats = new Quick_Stats($statistics);
- $chart = new Chart($statistics);
+ $stats = new Quick_Stats($statistics, false, $is_showing_skeleton_ui);
+ $chart = new Chart($statistics, false, $is_showing_skeleton_ui);
$this->interface($table, $stats, $chart);
} elseif ($tab === 'referrers') {
$table = new Table_Referrers();
$statistics_class = $table->group()->statistics_class();
$statistics = new $statistics_class($date_rage, null, $options->chart_interval());
- $stats = new Quick_Stats($statistics);
- $chart = new Chart($statistics);
+ $stats = new Quick_Stats($statistics, false, $is_showing_skeleton_ui);
+ $chart = new Chart($statistics, false, $is_showing_skeleton_ui);
$this->interface($table, $stats, $chart);
} elseif ($tab === 'geo') {
$table = new Table_Geo($options->group());
$statistics_class = $table->group()->statistics_class();
$statistics = new $statistics_class($date_rage, null, $options->chart_interval());
- $stats = new Quick_Stats($statistics);
+ $stats = new Quick_Stats($statistics, false, $is_showing_skeleton_ui);
$table_data_class = $table->group()->rows_class();
$geo_data = new $table_data_class($date_rage);
- $chart = new Chart_Geo($geo_data->rows());
+ $chart = new Chart_Geo($geo_data->rows(), null, $is_showing_skeleton_ui);
$this->interface($table, $stats, $chart);
} elseif ($tab === 'campaigns') {
$table = new Table_Campaigns();
$statistics_class = $table->group()->statistics_class();
$statistics = new $statistics_class($date_rage, null, $options->chart_interval());
- $stats = new Quick_Stats($statistics);
- $chart = new Chart($statistics);
+ $stats = new Quick_Stats($statistics, false, $is_showing_skeleton_ui);
+ $chart = new Chart($statistics, false, $is_showing_skeleton_ui);
$this->interface($table, $stats, $chart);
} elseif ($tab === 'clicks') {
- $table = new Table_Clicks();
+ $table = new Table_Clicks($options->group());
$statistics_class = $table->group()->statistics_class();
$statistics = new $statistics_class($date_rage, null, $options->chart_interval());
- $stats = new Quick_Stats($statistics);
- $chart = new Chart($statistics);
+ $stats = new Quick_Stats($statistics, false, $is_showing_skeleton_ui);
+ $chart = new Chart($statistics, false, $is_showing_skeleton_ui);
$this->interface($table, $stats, $chart);
} elseif ($tab === 'devices') {
$table = new Table_Devices($options->group());
$statistics_class = $table->group()->statistics_class();
$statistics = new $statistics_class($date_rage, null, $options->chart_interval());
- $stats = new Quick_Stats($statistics);
- $chart = new Chart($statistics);
+ $stats = new Quick_Stats($statistics, false, $is_showing_skeleton_ui);
+ $chart = new Chart($statistics, false, $is_showing_skeleton_ui);
$this->interface($table, $stats, $chart);
} elseif ($tab === 'real-time') {
(new Real_Time())->render_real_time_analytics();
--- a/independent-analytics/IAWP/Chart.php
+++ b/independent-analytics/IAWP/Chart.php
@@ -11,10 +11,12 @@
{
private $statistics;
private $is_preview;
- public function __construct(Statistics $statistics, bool $is_preview = false)
+ private $is_showing_skeleton_ui;
+ public function __construct(Statistics $statistics, bool $is_preview = false, bool $is_showing_skeleton_ui = false)
{
$this->statistics = $statistics;
$this->is_preview = $is_preview;
+ $this->is_showing_skeleton_ui = $is_showing_skeleton_ui;
}
public function get_html() : string
{
@@ -26,6 +28,10 @@
}, $primary_statistic->statistic_over_time());
$data = [];
foreach ($this->statistics->get_statistics() as $statistic) {
+ if ($this->is_showing_skeleton_ui) {
+ $data[$statistic->id()] = [];
+ continue;
+ }
$data[$statistic->id()] = array_map(function ($data_point) {
return $data_point[1];
}, $statistic->statistic_over_time());
@@ -52,6 +58,13 @@
if (IAWPSCOPEDiawp()->is_surecart_support_enabled()) {
return SureCart_Store::get_currency_code();
}
+ if (IAWPSCOPEDiawp()->is_edd_support_enabled()) {
+ return edd_get_currency();
+ }
+ if (IAWPSCOPEDiawp()->is_pmpro_support_enabled()) {
+ global $pmpro_default_currency;
+ return $pmpro_default_currency;
+ }
return null;
}
}
--- a/independent-analytics/IAWP/Chart_Geo.php
+++ b/independent-analytics/IAWP/Chart_Geo.php
@@ -8,20 +8,26 @@
{
private $countries;
private $title;
+ private $is_showing_skeleton_ui;
/**
* @param Geo[] $geos
* @param $title
*/
- public function __construct(array $geos, $title = null)
+ public function __construct(array $geos, $title = null, bool $is_showing_skeleton_ui = false)
{
$this->countries = $this->parse($geos);
$this->title = $title;
+ $this->is_showing_skeleton_ui = $is_showing_skeleton_ui;
}
public function get_html()
{
- $chart_data = array_map(function ($country) {
- return [$country['country_code'], $country['views'], $this->get_tooltip($country)];
- }, $this->countries);
+ if ($this->is_showing_skeleton_ui) {
+ $chart_data = [];
+ } else {
+ $chart_data = array_map(function ($country) {
+ return [$country['country_code'], $country['views'], $this->get_tooltip($country)];
+ }, $this->countries);
+ }
$dark_mode = IAWPSCOPEDiawp()->get_option('iawp_dark_mode', '0');
ob_start();
?>
--- a/independent-analytics/IAWP/Click_Tracking.php
+++ b/independent-analytics/IAWP/Click_Tracking.php
@@ -16,9 +16,9 @@
return $link_rule->to_array();
})->all(), 'types' => self::types(), 'extensions' => self::extensions(), 'protocols' => self::protocols(), 'error_messages' => Link_Validator::error_messages(), 'show_click_tracking_cache_message' => $show_click_tracking_cache_message]);
}
- public static function types()
+ public static function types() : array
{
- return ['class' => esc_html__('Class', 'independent-analytics'), 'extension' => esc_html__('Extension', 'independent-analytics'), 'domain' => esc_html__('Domain', 'independent-analytics'), 'subdirectory' => esc_html__('Subdirectory', 'independent-analytics'), 'protocol' => esc_html__('Protocol', 'independent-analytics')];
+ return ['class' => __('Class', 'independent-analytics'), 'extension' => __('Extension', 'independent-analytics'), 'domain' => __('Domain', 'independent-analytics'), 'external' => __('External', 'independent-analytics'), 'subdirectory' => __('Subdirectory', 'independent-analytics'), 'protocol' => __('Protocol', 'independent-analytics')];
}
public static function extensions()
{
@@ -26,6 +26,6 @@
}
public static function protocols()
{
- return ['mailto', 'tel'];
+ return ['mailto', 'tel', 'sms'];
}
}
--- a/independent-analytics/IAWP/Click_Tracking/Click.php
+++ b/independent-analytics/IAWP/Click_Tracking/Click.php
@@ -52,7 +52,7 @@
if (is_null($href)) {
return null;
}
- if (Str::startsWith($href, ['tel:', 'mailto:'])) {
+ if (Str::startsWith($href, ['tel:', 'sms:', 'mailto:'])) {
return Str::before($href, ':');
}
return null;
@@ -62,7 +62,7 @@
if (is_null($href)) {
return null;
}
- if (Str::startsWith($href, ['tel:', 'mailto:'])) {
+ if (Str::startsWith($href, ['tel:', 'sms:', 'mailto:'])) {
return Str::after($href, ':');
}
return $href;
--- a/independent-analytics/IAWP/Click_Tracking/Click_Processing_Job.php
+++ b/independent-analytics/IAWP/Click_Tracking/Click_Processing_Job.php
@@ -69,14 +69,14 @@
}
private function create_job_file(string $file) : ?string
{
- if (!is_file($file)) {
+ if (!is_readable($file) || !is_writable($file)) {
return null;
}
$job_id = rand();
$extension = pathinfo($file, PATHINFO_EXTENSION);
$job_file = Str::finish(dirname($file), DIRECTORY_SEPARATOR) . "iawp-click-data-{$job_id}.{$extension}";
- rename($file, $job_file);
- if (!is_file($job_file)) {
+ $was_renamed = rename($file, $job_file);
+ if (!$was_renamed || !is_file($job_file)) {
return null;
}
return $job_file;
--- a/independent-analytics/IAWP/Click_Tracking/Link_Rule_Finder.php
+++ b/independent-analytics/IAWP/Click_Tracking/Link_Rule_Finder.php
@@ -41,6 +41,8 @@
return $this->is_matching_subdirectory($link_rule);
case 'protocol':
return $this->is_matching_protocol($link_rule);
+ case 'external':
+ return $this->is_matching_external($link_rule);
default:
return false;
}
@@ -100,6 +102,19 @@
}
return $this->protocol === $link_rule->value();
}
+ private function is_matching_external($link_rule) : bool
+ {
+ if (is_null($this->href)) {
+ return false;
+ }
+ $site_url = URL::new(get_site_url());
+ $link_url = URL::new($this->href);
+ // Only track valid http/https URLs and not other protocols like mailto:, tel:, etc
+ if (!$link_url->is_valid_url()) {
+ return false;
+ }
+ return $link_url->get_domain() !== $site_url->get_domain();
+ }
public static function new(?string $protocol, ?string $href, string $classes) : self
{
return new self($protocol, $href, $classes);
--- a/independent-analytics/IAWP/Data_Pruning/Pruning_Scheduler.php
+++ b/independent-analytics/IAWP/Data_Pruning/Pruning_Scheduler.php
@@ -5,8 +5,8 @@
use IAWPSCOPEDCarbonCarbonImmutable;
use IAWPIlluminate_Builder;
use IAWPQuery;
-use IAWPUtilsWordPress_Site_Date_Format_Pattern;
use IAWPUtilsTimezone;
+use IAWPUtilsWordPress_Site_Date_Format_Pattern;
/** @internal */
class Pruning_Scheduler
{
--- a/independent-analytics/IAWP/Date_Picker/Month.php
+++ b/independent-analytics/IAWP/Date_Picker/Month.php
@@ -2,7 +2,6 @@
namespace IAWPDate_Picker;
-use IAWPUtilsTimezone;
/** @internal */
class Month
{
--- a/independent-analytics/IAWP/Date_Range/Exact_Date_Range.php
+++ b/independent-analytics/IAWP/Date_Range/Exact_Date_Range.php
@@ -3,7 +3,6 @@
namespace IAWPDate_Range;
use DateTime;
-use IAWPUtilsTimezone;
/** @internal */
class Exact_Date_Range extends IAWPDate_RangeDate_Range
{
--- a/independent-analytics/IAWP/Ecommerce/EDD_Order.php
+++ b/independent-analytics/IAWP/Ecommerce/EDD_Order.php
@@ -0,0 +1,85 @@
+<?php
+
+namespace IAWPEcommerce;
+
+use IAWPIlluminate_Builder;
+use IAWPModelsVisitor;
+use IAWPTables;
+/** @internal */
+class EDD_Order
+{
+ private $order_id;
+ private $status;
+ private $total;
+ private $total_refunded;
+ private $total_refunds;
+ private $is_discounted;
+ public function __construct(int $order_id)
+ {
+ $order = edd_get_order($order_id);
+ $refunds = edd_get_order_refunds($order_id);
+ $total_refunded = 0;
+ $total_refunds = 0;
+ foreach ($refunds as $refund) {
+ $total_refunds++;
+ $total_refunded += abs((float) $refund->total);
+ }
+ $this->order_id = $order_id;
+ $this->status = $order->status;
+ $this->total = intval(round((float) $order->total * 100));
+ $this->total_refunded = intval(round($total_refunded * 100));
+ $this->total_refunds = $total_refunds;
+ $this->is_discounted = (float) $order->discount > 0;
+ }
+ public function insert()
+ {
+ $visitor = Visitor::fetch_current_visitor();
+ if (!$visitor->has_recorded_session()) {
+ return;
+ }
+ Illuminate_Builder::new()->from(Tables::orders())->insertOrIgnore(['is_included_in_analytics' => $this->is_included_in_analytics($this->status), 'edd_order_id' => $this->order_id, 'edd_order_status' => $this->status, 'view_id' => $visitor->most_recent_view_id(), 'initial_view_id' => $visitor->most_recent_initial_view_id(), 'total' => $this->total, 'total_refunded' => $this->total_refunded, 'total_refunds' => $this->total_refunds, 'is_discounted' => $this->is_discounted, 'created_at' => (new DateTime())->format('Y-m-d H:i:s')]);
+ }
+ public function update() : void
+ {
+ Illuminate_Builder::new()->from(Tables::orders())->where('edd_order_id', '=', $this->order_id)->update(['is_included_in_analytics' => $this->is_included_in_analytics($this->status), 'edd_order_status' => $this->status, 'total' => $this->total, 'total_refunded' => $this->total_refunded, 'total_refunds' => $this->total_refunds, 'is_discounted' => $this->is_discounted]);
+ }
+ private function is_included_in_analytics(string $status) : bool
+ {
+ return in_array($status, ['complete', 'refunded', 'partially_refunded']);
+ }
+ public static function register_hooks() : void
+ {
+ // While the EDD docs recommend it, we cannot use `edd_after_order_actions` as it runs in
+ // a cron job 30 seconds after the order is completed. We need to run in the same request,
+ // so we can determine which visitor make the purchase and attach the order correctly.
+ add_action('edd_complete_purchase', function ($order_id) {
+ try {
+ $order = new self($order_id);
+ $order->insert();
+ } catch (Throwable $e) {
+ error_log('Independent Analytics was unable to track the analytics for a EDD order. Please report this error to Independent Analytics. The error message is below.');
+ error_log($e->getMessage());
+ }
+ }, 10, 1);
+ // Track order status changes
+ add_action('edd_update_payment_status', function ($order_id) {
+ try {
+ $order = new self($order_id);
+ $order->update();
+ } catch (Throwable $e) {
+ error_log('Independent Analytics was unable to track the analytics for a EDD order. Please report this error to Independent Analytics. The error message is below.');
+ error_log($e->getMessage());
+ }
+ }, 10, 1);
+ // Track refunds to orders
+ add_action('edd_refund_order', function ($order_id) {
+ try {
+ $order = new self($order_id);
+ $order->update();
+ } catch (Throwable $e) {
+ error_log('Independent Analytics was unable to track the analytics for a EDD order. Please report this error to Independent Analytics. The error message is below.');
+ error_log($e->getMessage());
+ }
+ }, 10, 1);
+ }
+}
--- a/independent-analytics/IAWP/Ecommerce/PMPro_Order.php
+++ b/independent-analytics/IAWP/Ecommerce/PMPro_Order.php
@@ -0,0 +1,77 @@
+<?php
+
+namespace IAWPEcommerce;
+
+use IAWPIlluminate_Builder;
+use IAWPModelsVisitor;
+use IAWPTables;
+/** @internal */
+class PMPro_Order
+{
+ private $order_id;
+ private $status;
+ private $total;
+ private $total_refunded;
+ private $total_refunds;
+ private $is_discounted;
+ public function __construct(int $order_id)
+ {
+ $order = new MemberOrder($order_id);
+ $this->order_id = $order_id;
+ $this->status = $order->status;
+ $this->total = intval(round((float) $order->total * 100));
+ $this->total_refunded = $order->status === 'refunded' ? $this->total : 0;
+ $this->total_refunds = $order->status === 'refunded' ? 1 : 0;
+ $this->is_discounted = is_numeric($order->discount_code_id) && (int) $order->discount_code_id !== 0;
+ }
+ public function insert()
+ {
+ $visitor = Visitor::fetch_current_visitor();
+ if (!$visitor->has_recorded_session()) {
+ return;
+ }
+ Illuminate_Builder::new()->from(Tables::orders())->insertOrIgnore(['is_included_in_analytics' => $this->is_included_in_analytics($this->status), 'pmpro_order_id' => $this->order_id, 'pmpro_order_status' => $this->status, 'view_id' => $visitor->most_recent_view_id(), 'initial_view_id' => $visitor->most_recent_initial_view_id(), 'total' => $this->total, 'total_refunded' => $this->total_refunded, 'total_refunds' => $this->total_refunds, 'is_discounted' => $this->is_discounted, 'created_at' => (new DateTime())->format('Y-m-d H:i:s')]);
+ }
+ public function update() : void
+ {
+ Illuminate_Builder::new()->from(Tables::orders())->where('pmpro_order_id', '=', $this->order_id)->update(['is_included_in_analytics' => $this->is_included_in_analytics($this->status), 'pmpro_order_status' => $this->status, 'total' => $this->total, 'total_refunded' => $this->total_refunded, 'total_refunds' => $this->total_refunds, 'is_discounted' => $this->is_discounted]);
+ }
+ private function is_included_in_analytics(string $status) : bool
+ {
+ return in_array($status, ['success', 'refunded']);
+ }
+ public static function register_hooks() : void
+ {
+ // Create a new order when a PMPro order is created
+ add_action('pmpro_added_order', function ($pmpro_order) {
+ try {
+ $order = new self((int) $pmpro_order->id);
+ $order->insert();
+ } catch (Throwable $e) {
+ error_log('Independent Analytics was unable to track the analytics for a Paid Memberships Pro order. Please report this error to Independent Analytics. The error message is below.');
+ error_log($e->getMessage());
+ }
+ }, 10, 1);
+ // Calculating is_discounted doesn't seem possible at the time pmpro_added_order runs. This hooks
+ // runs just after it but allows is_discounted to be correctly determined.
+ add_action('pmpro_discount_code_used', function ($discount_code_id, $user_id, $order_id) {
+ try {
+ $order = new self((int) $order_id);
+ $order->update();
+ } catch (Throwable $e) {
+ error_log('Independent Analytics was unable to track the analytics for a Paid Memberships Pro order. Please report this error to Independent Analytics. The error message is below.');
+ error_log($e->getMessage());
+ }
+ }, 10, 3);
+ // Update an existing order when a PMPro order is updated
+ add_action('pmpro_updated_order', function ($pmpro_order) {
+ try {
+ $order = new self((int) $pmpro_order->id);
+ $order->update();
+ } catch (Throwable $e) {
+ error_log('Independent Analytics was unable to track the analytics for a Paid Memberships Pro order. Please report this error to Independent Analytics. The error message is below.');
+ error_log($e->getMessage());
+ }
+ }, 10, 1);
+ }
+}
--- a/independent-analytics/IAWP/Ecommerce/SureCart_Event_Sync_Job.php
+++ b/independent-analytics/IAWP/Ecommerce/SureCart_Event_Sync_Job.php
@@ -15,7 +15,8 @@
}
public function handle() : void
{
- $last_seen_event_at = get_option('iawp_last_seen_surecart_event_at', time());
+ $one_day_ago = time() - 86400;
+ $last_seen_event_at = get_option('iawp_last_seen_surecart_event_at', $one_day_ago);
$events = new Collection();
$page = 1;
while (true) {
--- a/independent-analytics/IAWP/Email_Reports/Email_Reports.php
+++ b/independent-analytics/IAWP/Email_Reports/Email_Reports.php
@@ -7,13 +7,15 @@
use IAWPRowsCampaigns;
use IAWPRowsCountries;
use IAWPRowsDevice_Types;
+use IAWPRowsForms;
+use IAWPRowsLink_Patterns;
use IAWPRowsPages;
use IAWPRowsReferrers;
use IAWPSort_Configuration;
use IAWPStatisticsPage_Statistics;
use IAWPStatisticsStatistic;
-use IAWPUtilsURL;
use IAWPUtilsTimezone;
+use IAWPUtilsURL;
/** @internal */
class Email_Reports
{
@@ -29,10 +31,6 @@
add_action('add_option_iawp_dow', [$this, 'maybe_reschedule'], 10, 0);
add_action('iawp_send_email_report', [$this, 'send_email_report']);
}
- private function interval() : IAWPEmail_ReportsInterval
- {
- return IAWPEmail_ReportsInterval_Factory::from_option();
- }
public function schedule()
{
$this->unschedule();
@@ -101,9 +99,15 @@
return;
}
$from = IAWPSCOPEDiawp()->get_option('iawp_email_report_from_address', get_option('admin_email'));
+ $reply_to = IAWPSCOPEDiawp()->get_option('iawp_email_report_reply_to_address', get_option('admin_email'));
$body = $this->get_email_body();
$headers[] = 'From: ' . get_bloginfo('name') . ' <' . esc_attr($from) . '>';
+ $headers[] = 'Reply-To: ' . esc_attr($reply_to);
$headers[] = 'Content-Type: text/html; charset=UTF-8';
+ // Prevents WP HTML Mail plugin from breaking email design (https://wordpress.org/plugins/wp-html-mail/)
+ add_filter('haet_mail_use_template', function () {
+ return false;
+ });
return wp_mail($to, $this->subject_line($is_test_email), $body, $headers);
}
public function get_email_body($colors = '')
@@ -114,6 +118,7 @@
}));
$chart = new IAWPEmail_ReportsEmail_Chart($statistics);
$colors = $colors == '' ? IAWPSCOPEDiawp()->get_option('iawp_email_report_colors', ['#5123a0', '#fafafa', '#3a1e6b', '#fafafa', '#5123a0', '#a985e6', '#ece9f2', '#f7f5fa', '#ece9f2', '#dedae6']) : explode(',', $colors);
+ $footer_text = IAWPSCOPEDiawp()->get_option('iawp_email_report_footer', sprintf(esc_html__('This email was generated and delivered by %s', 'independent-analytics'), esc_url(get_site_url())));
return IAWPSCOPEDiawp_blade()->run('email.email', [
'site_title' => get_bloginfo('name'),
'site_url' => URL::new(get_site_url())->get_domain(),
@@ -127,8 +132,13 @@
'y_labels' => $chart->y_labels,
'x_labels' => $chart->x_labels,
'colors' => $colors,
+ 'footer_text' => $footer_text,
]);
}
+ private function interval() : IAWPEmail_ReportsInterval
+ {
+ return IAWPEmail_ReportsInterval_Factory::from_option();
+ }
private function subject_line(bool $is_test_email) : string
{
$parts = [];
@@ -143,7 +153,7 @@
private function get_top_ten() : array
{
$date_range = $this->interval()->date_range();
- $queries = ['pages' => 'title', 'referrers' => 'referrer', 'countries' => 'country', 'devices' => 'device_type', 'campaigns' => 'title', 'landing_pages' => 'title', 'exit_pages' => 'title'];
+ $queries = ['pages' => 'title', 'referrers' => 'referrer', 'countries' => 'country', 'devices' => 'device_type', 'campaigns' => 'title', 'forms' => 'form_title', 'clicks' => 'link_name', 'landing_pages' => 'title', 'exit_pages' => 'title'];
$top_ten = [];
$sort_configuration = new Sort_Configuration('views', 'desc');
$title = '';
@@ -163,6 +173,12 @@
} elseif ($type === 'campaigns') {
$query = new Campaigns($date_range, 10, null, $sort_configuration);
$title = esc_html__('Campaigns', 'independent-analytics');
+ } elseif ($type === 'forms') {
+ $query = new Forms($date_range, 10, null, new Sort_Configuration('submissions', 'desc'));
+ $title = esc_html__('Forms', 'independent-analytics');
+ } elseif ($type === 'clicks') {
+ $query = new Link_Patterns($date_range, 10, null, new Sort_Configuration('link_clicks', 'desc'));
+ $title = esc_html__('Link Patterns', 'independent-analytics');
} elseif ($type === 'landing_pages') {
$query = new Pages($date_range, 10, null, new Sort_Configuration('entrances', 'desc'));
$title = esc_html__('Landing Pages', 'independent-analytics');
@@ -181,12 +197,20 @@
$edited_title = $row->device_type();
} elseif ($type == 'campaigns') {
$edited_title = $row->utm_campaign();
+ } elseif ($type == 'forms') {
+ $edited_title = $row->form_title();
+ } elseif ($type == 'clicks') {
+ $edited_title = $row->link_name();
} else {
$edited_title = $row->title();
}
$edited_title = mb_strlen($edited_title) > 30 ? mb_substr($edited_title, 0, 30) . '...' : $edited_title;
$metric = 'views';
- if ($type == 'landing_pages') {
+ if ($type == 'clicks') {
+ $metric = 'link_clicks';
+ } elseif ($type == 'forms') {
+ $metric = 'submissions';
+ } elseif ($type == 'landing_pages') {
$metric = 'entrances';
} elseif ($type == 'exit_pages') {
$metric = 'exits';
--- a/independent-analytics/IAWP/Email_Reports/Interval.php
+++ b/independent-analytics/IAWP/Email_Reports/Interval.php
@@ -6,8 +6,8 @@
use IAWPDate_RangeDate_Range;
use IAWPDate_RangeRelative_Date_Range;
use IAWPUtilsString_Util;
-use IAWPSCOPEDIlluminateSupportCarbon;
use IAWPUtilsTimezone;
+use IAWPSCOPEDIlluminateSupportCarbon;
/** @internal */
class Interval
{
--- a/independent-analytics/IAWP/Form_Submissions/Form.php
+++ b/independent-analytics/IAWP/Form_Submissions/Form.php
@@ -17,9 +17,37 @@
private $title;
private $plugin_id;
private static $forms = null;
- private static $plugins = [['id' => 1, 'name' => 'Fluent Forms', 'plugin_slugs' => ['fluentform/fluentform.php']], ['id' => 2, 'name' => 'WPForms', 'plugin_slugs' => ['wpforms-lite/wpforms.php', 'wpforms/wpforms.php']], ['id' => 3, 'name' => 'Contact Form 7', 'plugin_slugs' => ['contact-form-7/wp-contact-form-7.php']], ['id' => 4, 'name' => 'Gravity Forms', 'plugin_slugs' => ['gravityforms/gravityforms.php']], ['id' => 5, 'name' => 'Ninja Forms', 'plugin_slugs' => ['ninja-forms/ninja-forms.php']], ['id' => 6, 'name' => 'MailOptin', 'plugin_slugs' => ['mailoptin/mailoptin.php']], ['id' => 7, 'name' => 'Convert Pro', 'plugin_slugs' => ['convertpro/convertpro.php']], ['id' => 8, 'name' => 'Elementor Pro', 'plugin_slugs' => ['elementor-pro/elementor-pro.php']], ['id' => 9, 'name' => 'JetFormBuilder', 'plugin_slugs' => ['jetformbuilder/jet-form-builder.php']], ['id' => 10, 'name' => 'Formidable Forms', 'plugin_slugs' => ['formidable/formidable.php']], ['id' => 11, 'name' => 'WS Form', 'plugin_slugs' => ['ws-form/ws-form.php', 'ws-form-pro/ws-form.php']], ['id' => 12, 'name' => 'Amelia', 'plugin_slugs' => ['ameliabooking/ameliabooking.php']], ['id' => 13, 'name' => 'Bricks Builder', 'theme' => 'bricks'], ['id' => 14, 'name' => 'ARForms', 'plugin_slugs' => ['arforms-form-builder/arforms-form-builder.php']], ['id' => 15, 'name' => 'Custom form submissions'], ['id' => 16, 'name' => 'Bit Form', 'plugin_slugs' => ['bit-form/bitforms.php']], ['id' => 17, 'name' => 'Forminator', 'plugin_slugs' => ['forminator/forminator.php']], ['id' => 18, 'name' => 'Hustle', 'plugin_slugs' => ['wordpress-popup/popover.php', 'hustle/opt-in.php']], ['id' => 19, 'name' => 'Avada', 'plugin_slugs' => ['fusion-builder/fusion-builder.php', 'fusion-core/fusion-core.php']], ['id' => 20, 'name' => 'WP Store Locator', 'plugin_slugs' => ['wp-store-locator/wp-store-locator.php']]];
+ private static $plugins = [
+ ['id' => 1, 'name' => 'Fluent Forms', 'plugin_slugs' => ['fluentform/fluentform.php']],
+ ['id' => 2, 'name' => 'WPForms', 'plugin_slugs' => ['wpforms-lite/wpforms.php', 'wpforms/wpforms.php']],
+ ['id' => 3, 'name' => 'Contact Form 7', 'plugin_slugs' => ['contact-form-7/wp-contact-form-7.php']],
+ ['id' => 4, 'name' => 'Gravity Forms', 'plugin_slugs' => ['gravityforms/gravityforms.php']],
+ ['id' => 5, 'name' => 'Ninja Forms', 'plugin_slugs' => ['ninja-forms/ninja-forms.php']],
+ ['id' => 6, 'name' => 'MailOptin', 'plugin_slugs' => ['mailoptin/mailoptin.php']],
+ ['id' => 7, 'name' => 'Convert Pro', 'plugin_slugs' => ['convertpro/convertpro.php']],
+ ['id' => 8, 'name' => 'Elementor Pro', 'plugin_slugs' => ['elementor-pro/elementor-pro.php']],
+ ['id' => 9, 'name' => 'JetFormBuilder', 'plugin_slugs' => ['jetformbuilder/jet-form-builder.php']],
+ ['id' => 10, 'name' => 'Formidable Forms', 'plugin_slugs' => ['formidable/formidable.php']],
+ ['id' => 11, 'name' => 'WS Form', 'plugin_slugs' => ['ws-form/ws-form.php', 'ws-form-pro/ws-form.php']],
+ ['id' => 12, 'name' => 'Amelia', 'plugin_slugs' => ['ameliabooking/ameliabooking.php']],
+ ['id' => 13, 'name' => 'Bricks Builder', 'theme' => 'bricks'],
+ ['id' => 14, 'name' => 'ARForms', 'plugin_slugs' => ['arforms-form-builder/arforms-form-builder.php']],
+ ['id' => 15, 'name' => 'Custom form submissions'],
+ ['id' => 16, 'name' => 'Bit Form', 'plugin_slugs' => ['bit-form/bitforms.php']],
+ ['id' => 17, 'name' => 'Forminator', 'plugin_slugs' => ['forminator/forminator.php']],
+ ['id' => 18, 'name' => 'Hustle', 'plugin_slugs' => ['wordpress-popup/popover.php', 'hustle/opt-in.php']],
+ ['id' => 19, 'name' => 'Avada', 'plugin_slugs' => ['fusion-builder/fusion-builder.php', 'fusion-core/fusion-core.php']],
+ ['id' => 20, 'name' => 'WP Store Locator', 'plugin_slugs' => ['wp-store-locator/wp-store-locator.php']],
+ // [
+ // 'id' => 21,
+ // 'name' => 'Thrive Leads',
+ // 'plugin_slugs' => ['thrive-leads/thrive-leads.php'],
+ // ],
+ ['id' => 22, 'name' => 'SureForms', 'plugin_slugs' => ['sureforms/sureforms.php']],
+ ['id' => 23, 'name' => 'Kali Forms', 'plugin_slugs' => ['kali-forms/kali-forms.php']],
+ ];
/**
- * @var array An key(plugin_id) value(bool) pair of plugin IDs
+ * @var array A key/value pair (plugin_id/bool) of plugin IDs
*/
private static $has_any_tracked_submissions_cache = [];
private function __construct(int $id, string $title, int $plugin_id)
--- a/independent-analytics/IAWP/Form_Submissions/Submission_Listener.php
+++ b/independent-analytics/IAWP/Form_Submissions/Submission_Listener.php
@@ -273,6 +273,56 @@
} catch (Throwable $e) {
}
}, 10, 0);
+ // Thrive
+ // add_action('thrive_core_lead_signup', function ($data, $user) {
+ // try {
+ // $submission = new Submission(
+ // 21,
+ // intval($data['form_id']),
+ // Security::string($data['form_name'])
+ // );
+ // $submission->record_submission();
+ // } catch (Throwable $e) {
+ //
+ // }
+ // }, 10, 2);
+ // Thrive
+ // add_action('tcb_api_form_submit', function ($data) {
+ // try {
+ // // This parsing of the object is copied from Thrive Leads own tve_leads_process_conversion function
+ // $form_id = ! empty($data['thrive_leads']['tl_data']['form_type_id']) ? $data['thrive_leads']['tl_data']['form_type_id'] : null;
+ // $form_name = ! empty($data['thrive_leads']['tl_data']['form_name']) ? $data['thrive_leads']['tl_data']['form_name'] : null;
+ //
+ // if (!is_numeric($form_id) || null === $form_id || null === $form_name) {
+ // return;
+ // }
+ //
+ // $submission = new Submission(
+ // 21,
+ // intval($form_id),
+ // Security::string($form_name)
+ // );
+ // $submission->record_submission();
+ // } catch (Throwable $e) {
+ //
+ // }
+ // }, 10, 1);
+ // SureForms
+ add_action('srfm_form_submit', function ($data) {
+ try {
+ $submission = new IAWPForm_SubmissionsSubmission(22, intval($data['form_id']), Security::string($data['form_name']));
+ $submission->record_submission();
+ } catch (Throwable $e) {
+ }
+ }, 10, 1);
+ // Kali Forms
+ add_action('kaliforms_after_form_process_action', function ($data) {
+ try {
+ $submission = new IAWPForm_SubmissionsSubmission(23, intval($data['data']['formId']), Security::string(get_the_title($data['data']['formId'])));
+ $submission->record_submission();
+ } catch (Throwable $e) {
+ }
+ }, 10, 1);
// // Template
// add_action('iawp_some_form_callback', function () {
// try {
--- a/independent-analytics/IAWP/Geo_Database_Manager.php
+++ b/independent-analytics/IAWP/Geo_Database_Manager.php
@@ -10,11 +10,11 @@
/** @internal */
class Geo_Database_Manager
{
- // Updating the database? Read the Wiki page "Updating The Geo Database"
- // https://github.com/andrewjmead/independent-analytics/wiki/Updating-The-Geo-Database
- private $zip_download_url = 'https://assets.independentwp.com/iawp-geo-db-6.mmdb.zip';
- private $raw_download_url = 'https://assets.independentwp.com/iawp-geo-db-6.mmdb';
- private $database_checksum = '2213359f8d395c4f1a352007af9495ae';
+ // 🚨🚨 Updating the database? Follow the wiki: 🚨🚨
+ // https://github.com/andrewjmead/independent-analytics/wiki/Update-the-Geo-Database
+ private $zip_download_url = 'https://assets.independentwp.com/iawp-geo-db-7.mmdb.zip';
+ private $raw_download_url = 'https://assets.independentwp.com/iawp-geo-db-7.mmdb';
+ private $database_checksum = 'e26ab675eccee3de08e4cd2aceb5a217';
public function download() : void
{
if (!$this->should_download()) {
--- a/independent-analytics/IAWP/Independent_Analytics.php
+++ b/independent-analytics/IAWP/Independent_Analytics.php
@@ -11,6 +11,8 @@
use IAWPAJAXAJAX_Manager;
use IAWPClick_TrackingClick_Processing_Job;
use IAWPData_PruningPruner;
+use IAWPEcommerceEDD_Order;
+use IAWPEcommercePMPro_Order;
use IAWPEcommerceSureCart_Event_Sync_Job;
use IAWPEcommerceSureCart_Order;
use IAWPEcommerceWooCommerce_Order;
@@ -33,6 +35,8 @@
public $cron_manager;
private $is_woocommerce_support_enabled;
private $is_surecart_support_enabled;
+ private $is_edd_support_enabled;
+ private $is_pmpro_support_enabled;
private $is_form_submission_support_enabled;
// This is where we attach functions to WP hooks
private function __construct()
@@ -49,6 +53,8 @@
new IAWPTrack_Resource_Changes();
Menu_Bar_Stats::register();
WooCommerce_Order::register_hooks();
+ EDD_Order::register_hooks();
+ PMPro_Order::register_hooks();
SureCart_Order::register_hooks();
}
IAWPCron_Job::register_custom_intervals();
@@ -68,14 +74,37 @@
add_filter('plugin_action_links_independent-analytics/iawp.php', [$this, 'plugin_action_links']);
add_action('init', [$this, 'polylang_translations']);
add_action('init', [$this, 'load_textdomain']);
+ // Freemius adjustments
IAWP_FS()->add_filter('pricing_url', [$this, 'change_freemius_pricing_url'], 10);
IAWP_FS()->add_filter('show_deactivation_feedback_form', function () {
return false;
});
+ IAWP_FS()->override_i18n(['yee-haw' => __('Success', 'independent-analytics')]);
+ // Other hooks
add_action('admin_init', [$this, 'maybe_delete_mu_plugin']);
add_action('admin_body_class', [$this, 'add_body_class']);
add_filter('sgs_whitelist_wp_content', [$this, 'whitelist_click_endpoint']);
add_filter('cmplz_whitelisted_script_tags', [$this, 'whitelist_script_tag_for_complianz']);
+ add_filter('plugin_action_links_independent-analytics/iawp.php', [$this, 'add_upgrade_link_in_plugins_menu'], 999);
+ add_filter('plugin_row_meta', [$this, 'add_docs_link_in_plugins_menu'], 10, 2);
+ }
+ public function add_upgrade_link_in_plugins_menu($links)
+ {
+ if (IAWPSCOPEDiawp_is_pro()) {
+ return $links;
+ }
+ $upgrade_link = '<a target="_blank" style="color:#36B366;font-weight:700;"
+ href="https://independentwp.com/pricing/?utm_source=User+Dashboard&utm_medium=WP+Admin&utm_campaign=Plugin+Settings+Link"
+ >' . esc_html__('Upgrade to Pro', 'independent-analytics') . '</a>';
+ array_unshift($links, $upgrade_link);
+ return $links;
+ }
+ public function add_docs_link_in_plugins_menu($plugin_meta, $plugin_file)
+ {
+ if ($plugin_file == 'independent-analytics/iawp.php' || $plugin_file == 'independent-analytics-pro/iawp.php') {
+ $plugin_meta[] = '<a target="_blank" href="https://independentwp.com/knowledgebase/">' . esc_html__('Knowledge Base', 'independent-analytics') . '</a>';
+ }
+ return $plugin_meta;
}
public function add_body_class($classes)
{
@@ -326,15 +355,23 @@
}
return $this->is_surecart_support_enabled;
}
- public function is_ecommerce_support_enabled() : bool
+ public function is_edd_support_enabled() : bool
{
- return $this->is_woocommerce_support_enabled() || $this->is_surecart_support_enabled();
+ if (!is_bool($this->is_edd_support_enabled)) {
+ $this->is_edd_support_enabled = $this->actually_check_if_edd_support_is_enabled();
+ }
+ return $this->is_edd_support_enabled;
}
- // This whitelists our plugin with the "Complianz" plugin
- public function whitelist_script_tag_for_complianz($scripts)
+ public function is_pmpro_support_enabled() : bool
{
- $scripts[] = '/wp-json/iawp/search';
- return $scripts;
+ if (!is_bool($this->is_pmpro_support_enabled)) {
+ $this->is_pmpro_support_enabled = $this->actually_check_if_pmpro_support_is_enabled();
+ }
+ return $this->is_pmpro_support_enabled;
+ }
+ public function is_ecommerce_support_enabled() : bool
+ {
+ return $this->is_woocommerce_support_enabled() || $this->is_surecart_support_enabled() || $this->is_edd_support_enabled() || $this->is_pmpro_support_enabled();
}
// This is for compatibility with the "Lock and Protect System Folders" setting in the Security Optimizer plugin
public function whitelist_click_endpoint($whitelist)
@@ -345,6 +382,12 @@
$whitelist[] = 'iawp-click-endpoint.php';
return $whitelist;
}
+ // This whitelists our plugin with the "Complianz" plugin
+ public function whitelist_script_tag_for_complianz($scripts)
+ {
+ $scripts[] = '/wp-json/iawp/search';
+ return $scripts;
+ }
private function actually_check_if_woocommerce_support_is_enabled() : bool
{
global $wpdb;
@@ -372,8 +415,31 @@
if (IAWPSCOPEDiawp_is_free()) {
return false;
}
+ if (IAWPCapability_Manager::can_only_view_authored_analytics()) {
+ return false;
+ }
return is_plugin_active('surecart/surecart.php');
}
+ private function actually_check_if_edd_support_is_enabled() : bool
+ {
+ if (IAWPSCOPEDiawp_is_free()) {
+ return false;
+ }
+ if (IAWPCapability_Manager::can_only_view_authored_analytics()) {
+ return false;
+ }
+ return is_plugin_active('easy-digital-downloads/easy-digital-downloads.php') || is_plugin_active('easy-digital-downloads-pro/easy-digital-downloads.php');
+ }
+ private function actually_check_if_pmpro_support_is_enabled() : bool
+ {
+ if (IAWPSCOPEDiawp_is_free()) {
+ return false;
+ }
+ if (IAWPCapability_Manager::can_only_view_authored_analytics()) {
+ return false;
+ }
+ return is_plugin_active('paid-memberships-pro-dev/paid-memberships-pro.php') || is_plugin_active('paid-memberships-pro/paid-memberships-pro.php');
+ }
private function get_menu_icon()
{
if (is_null(IAWPEnv::get_page())) {
--- a/independent-analytics/IAWP/MainWP.php
+++ b/independent-analytics/IAWP/MainWP.php
@@ -0,0 +1,46 @@
+<?php
+
+namespace IAWP;
+
+use IAWPDate_RangeRelative_Date_Range;
+use IAWPStatisticsIntervalsIntervals;
+use IAWPUtilsSecurity;
+/** @internal */
+class MainWP
+{
+ public static function initialize()
+ {
+ add_filter('mainwp_site_sync_others_data', function ($information, $data = []) {
+ return self::attach_analytics($information, $data);
+ }, 10, 2);
+ }
+ private static function attach_analytics(array $information, array $data) : array
+ {
+ $should_sync_analytics = array_key_exists('iawp_sync_analytics', $data) && true === $data['iawp_sync_analytics'];
+ if (!$should_sync_analytics) {
+ return $information;
+ }
+ try {
+ $table = new IAWPTablesTable_Pages();
+ $statistics_class = $table->group()->statistics_class();
+ $date_range = new Relative_Date_Range('LAST_THIRTY');
+ $chart_interval = Intervals::default_for($date_range->number_of_days());
+ $statistics = new $statistics_class($date_range, null, $chart_interval);
+ $views = $statistics->get_statistic('views');
+ $visitors = $statistics->get_statistic('visitors');
+ $labels = array_map(function ($data_point) use($statistics) {
+ return Security::json_encode($statistics->chart_interval()->get_label_for($data_point[0]));
+ }, $views->statistic_over_time());
+ $views_over_time = array_map(function ($data_point) {
+ return $data_point[1];
+ }, $views->statistic_over_time());
+ $visitors_over_time = array_map(function ($data_point) {
+ return $data_point[1];
+ }, $visitors->statistic_over_time());
+ $information['iawp_analytics'] = ['analytics_dashboard_url' => IAWPSCOPEDiawp_dashboard_url(), 'labels' => $labels, 'views_over_time' => $views_over_time, 'visitors_over_time' => $visitors_over_time, 'views' => $views->value(), 'visitors' => $visitors->value()];
+ } catch (Throwable $e) {
+ // Do nothing
+ }
+ return $information;
+ }
+}
--- a/independent-analytics/IAWP/Migrations/Migration_36.php
+++ b/independent-analytics/IAWP/Migrations/Migration_36.php
@@ -2,7 +2,6 @@
namespace IAWPMigrations;
-use IAWPDatabase;
use IAWPQuery;
/** @internal */
class Migration_36 extends IAWPMigrationsStep_Migration
--- a/independent-analytics/IAWP/Migrations/Migration_40.php
+++ b/independent-analytics/IAWP/Migrations/Migration_40.php
@@ -0,0 +1,26 @@
+<?php
+
+namespace IAWPMigrations;
+
+/** @internal */
+class Migration_40 extends IAWPMigrationsStep_Migration
+{
+ /**
+ * @return int
+ */
+ protected function database_version() : int
+ {
+ return 40;
+ }
+ /**
+ * @return array
+ */
+ protected function queries() : array
+ {
+ return [$this->add_edd_to_orders_table()];
+ }
+ private function add_edd_to_orders_table() : string
+ {
+ return "n ALTER TABLE {$this->tables::orders()} n ADD COLUMN edd_order_id BIGINT(20) UNSIGNED AFTER surecart_order_status,n ADD COLUMN edd_order_status VARCHAR(64) AFTER edd_order_id,n ADD UNIQUE INDEX (edd_order_id);n ";
+ }
+}
--- a/independent-analytics/IAWP/Migrations/Migration_41.php
+++ b/independent-analytics/IAWP/Migrations/Migration_41.php
@@ -0,0 +1,26 @@
+<?php
+
+namespace IAWPMigrations;
+
+/** @internal */
+class Migration_41 extends IAWPMigrationsStep_Migration
+{
+ /**
+ * @return int
+ */
+ protected function database_version() : int
+ {
+ return 41;
+ }
+ /**
+ *