OrderIAWP/AJAX/AJAX.php 0000644 00000011146 14760033122 0007264 0 ustar 00 requires_pro()) {
\add_action('wp_ajax_' . $this->action_name(), [$this, 'intercept_ajax']);
}
}
/**
* Classes must define an action name for the ajax request
*
* The required nonce for the ajax request will be the action name with a "_nonce" postfix
* Example: "iawp_delete_data" require a "iawp_delete_data_nonce" nonce field
*
* @return string
*/
protected abstract function action_name() : string;
/**
* Classes must define an action callback to run when an ajax request is made
*
* @return void
*/
protected abstract function action_callback() : void;
/**
* This is the direct handler for ajax requests.
* Permissions and nonce values are checked before executing the ajax action_callback function.
*
* @return void
*/
public function intercept_ajax() : void
{
// Todo - Should this be can_edit() instead?
$is_not_migrating = $this->allowed_during_migrations() || !Migrations\Migrations::is_migrating();
$valid_fields = !$this->missing_fields();
$can_view = Capability_Manager::can_view();
\check_ajax_referer($this->action_name(), 'nonce');
if ($is_not_migrating && $valid_fields && $can_view) {
Server::increase_max_execution_time();
$this->action_callback();
} else {
\wp_send_json_error(['errorMessage' => 'Unable to process IAWP AJAX request'], 400);
}
\wp_die();
}
public function get_action_signature() : array
{
$shorthand_name = $this->action_name();
if (\strpos($this->action_name(), "iawp_") === 0) {
$shorthand_name = \substr($this->action_name(), 5);
}
return [$shorthand_name => ['action' => $this->action_name(), 'nonce' => \wp_create_nonce($this->action_name())]];
}
/**
* Classes can define a set of required fields for an ajax request
*
* @return array
*/
protected function action_required_fields() : array
{
return [];
}
/**
* Override method to allow the AJAX request to run during migrations
*
* @return bool false by default
*/
protected function allowed_during_migrations() : bool
{
return \false;
}
protected function requires_pro() : bool
{
return \false;
}
/**
* Get a field value. This method supports text and arrays. Returns array if no field found.
*
* @param $field
*
* @return array|string|null
*/
protected function get_field($field)
{
if (!\array_key_exists($field, $_POST)) {
return null;
}
$type = \gettype($_POST[$field]);
if ($type == 'array') {
if ($this->array_is_list($_POST[$field])) {
return \rest_sanitize_array($_POST[$field]);
} else {
return \rest_sanitize_object($_POST[$field]);
}
} else {
return \stripslashes(\sanitize_text_field($_POST[$field]));
}
}
protected function get_int_field($field) : ?int
{
if (!\array_key_exists($field, $_POST)) {
return null;
}
$type = \gettype($_POST[$field]);
if ($type === 'int') {
return $_POST[$field];
} elseif ($type === 'string') {
return \ctype_digit($_POST[$field]) ? (int) $_POST[$field] : null;
} else {
return null;
}
}
protected function get_boolean_field($field) : ?bool
{
if (!\array_key_exists($field, $_POST)) {
return null;
}
$type = \gettype($_POST[$field]);
if ($type === 'string') {
return $_POST[$field] === 'true';
} else {
return null;
}
}
// This is the recommended polyfill: https://wiki.php.net/rfc/is_list
private function array_is_list(array $array) : bool
{
$expectedKey = 0;
foreach ($array as $i => $_) {
if ($i !== $expectedKey) {
return \false;
}
$expectedKey++;
}
return \true;
}
private function missing_fields() : bool
{
foreach ($this->action_required_fields() as $required_field) {
if (!\array_key_exists($required_field, $_POST)) {
return \true;
}
}
return \false;
}
}
IAWP/AJAX/AJAX_Manager.php 0000644 00000005103 14760033122 0010712 0 ustar 00 instances[] = new \IAWP\AJAX\Archive_Link();
$this->instances[] = new \IAWP\AJAX\Click_Tracking_Cache_Cleared();
$this->instances[] = new \IAWP\AJAX\Configure_Pruner();
$this->instances[] = new \IAWP\AJAX\Set_WooCommerce_Statuses_To_Track();
$this->instances[] = new \IAWP\AJAX\Copy_Report();
$this->instances[] = new \IAWP\AJAX\Create_Campaign();
$this->instances[] = new \IAWP\AJAX\Create_Report();
$this->instances[] = new \IAWP\AJAX\Delete_Campaign();
$this->instances[] = new \IAWP\AJAX\Delete_Data();
$this->instances[] = new \IAWP\AJAX\Delete_Link();
$this->instances[] = new \IAWP\AJAX\Delete_Report();
$this->instances[] = new \IAWP\AJAX\Dismiss_Notice();
$this->instances[] = new \IAWP\AJAX\Edit_Link();
$this->instances[] = new \IAWP\AJAX\Export_Campaigns();
$this->instances[] = new \IAWP\AJAX\Export_Clicks();
$this->instances[] = new \IAWP\AJAX\Export_Devices();
$this->instances[] = new \IAWP\AJAX\Export_Geo();
$this->instances[] = new \IAWP\AJAX\Export_Pages();
$this->instances[] = new \IAWP\AJAX\Export_Referrers();
$this->instances[] = new \IAWP\AJAX\Export_Reports();
$this->instances[] = new \IAWP\AJAX\Filter();
$this->instances[] = new \IAWP\AJAX\Import_Reports();
$this->instances[] = new \IAWP\AJAX\Migration_Status();
$this->instances[] = new \IAWP\AJAX\Preview_Email();
$this->instances[] = new \IAWP\AJAX\Real_Time_Data();
$this->instances[] = new \IAWP\AJAX\Rename_Report();
$this->instances[] = new \IAWP\AJAX\Reset_Analytics();
$this->instances[] = new \IAWP\AJAX\Save_Report();
$this->instances[] = new \IAWP\AJAX\Set_Favorite_Report();
$this->instances[] = new \IAWP\AJAX\Sort_Links();
$this->instances[] = new \IAWP\AJAX\Sort_Reports();
$this->instances[] = new \IAWP\AJAX\Test_Email();
$this->instances[] = new \IAWP\AJAX\Update_Capabilities();
$this->instances[] = new \IAWP\AJAX\Update_User_Settings();
}
public function get_action_signatures() : array
{
$action_signatures = [];
foreach ($this->instances as $instance) {
$action_signatures = \array_merge($action_signatures, $instance->get_action_signature());
}
return $action_signatures;
}
}
IAWP/AJAX/Archive_Link.php 0000644 00000002522 14760033122 0011075 0 ustar 00 get_field('id');
$link_rule = Click_Tracking\Link_Rule::find($id);
if (\is_null($link_rule)) {
\wp_send_json_error([]);
}
\delete_option('iawp_click_tracking_cache_cleared');
$link_rule->toggle_active();
Illuminate_Builder::new()->from(Tables::link_rules())->where('is_active', '=', $link_rule->is_active() ? 1 : 0)->increment('position');
Illuminate_Builder::new()->from(Tables::link_rules())->where('link_rule_id', '=', $link_rule->id())->update(['position' => 0]);
// Send response
$response = \IAWPSCOPED\iawp_blade()->run('click-tracking.link', ['link' => $link_rule->to_array(), 'types' => Click_Tracking::types(), 'extensions' => Click_Tracking::extensions(), 'protocols' => Click_Tracking::protocols()]);
echo \wp_json_encode($response);
}
}
IAWP/AJAX/Click_Tracking_Cache_Cleared.php 0000644 00000000714 14760033122 0014111 0 ustar 00 get_field('pruningCutoff');
$is_confirmed = $this->get_boolean_field('isConfirmed');
$pruning_scheduler = new Pruning_Scheduler();
if ($cutoff !== 'disabled' && !$is_confirmed) {
\wp_send_json_error(['confirmationText' => $pruning_scheduler->get_pruning_description($cutoff)]);
}
$was_updated = $pruning_scheduler->update_pruning_cutoff($cutoff);
if ($was_updated && $pruning_scheduler->is_enabled()) {
Pruner::prune();
}
if ($was_updated) {
\wp_send_json_success(['isEnabled' => $pruning_scheduler->is_enabled(), 'statusMessage' => $pruning_scheduler->status_message()]);
} else {
\wp_send_json_error([]);
}
}
}
IAWP/AJAX/Copy_Report.php 0000644 00000004120 14760033122 0011000 0 ustar 00 get_existing_report_options();
if (\is_null($existing_report_options)) {
\wp_send_json_error();
}
$new_report_id = Illuminate_Builder::new()->from($reports_table)->insertGetId($existing_report_options);
$report_options_parser = Report_Options_Parser::from_json($_POST['changes']);
if (\count($report_options_parser->get_options_for_updating()) > 0) {
Illuminate_Builder::new()->from($reports_table)->where('report_id', '=', $new_report_id)->update($report_options_parser->get_options_for_updating());
}
$row = Illuminate_Builder::new()->from($reports_table)->where('report_id', '=', $new_report_id)->first();
$report = new Report($row);
\wp_send_json_success(['url' => $report->url()]);
}
private function get_existing_report_options() : ?array
{
if (\strlen($this->get_field('id')) === 0) {
return ['name' => $this->get_field('name'), 'type' => $this->get_field('type')];
}
$reports_table = Query::get_table_name(Query::REPORTS);
$existing_report = Illuminate_Builder::new()->from($reports_table)->where('report_id', '=', $this->get_field('id'))->first();
if (\is_null($existing_report)) {
return null;
}
$existing_report = (array) $existing_report;
unset($existing_report['report_id']);
$existing_report['name'] = $this->get_field('name');
return $existing_report;
}
}
IAWP/AJAX/Create_Campaign.php 0000644 00000001553 14760033122 0011544 0 ustar 00 create_campaign(Security::string(\trim($this->get_field('path'))), Security::string(\trim($this->get_field('utm_source'))), Security::string(\trim($this->get_field('utm_medium'))), Security::string(\trim($this->get_field('utm_campaign'))), Security::string(\trim($this->get_field('utm_term'))), Security::string(\trim($this->get_field('utm_content'))));
\wp_send_json_success(['html' => $html]);
}
}
IAWP/AJAX/Create_Report.php 0000644 00000001177 14760033122 0011302 0 ustar 00 'New Report', 'type' => $this->get_field('type')]);
\wp_send_json_success(['url' => $report->url()]);
}
}
IAWP/AJAX/Delete_Campaign.php 0000644 00000000732 14760033122 0011541 0 ustar 00 get_field('campaign_url_id'));
\wp_send_json_success([]);
}
}
IAWP/AJAX/Delete_Data.php 0000644 00000001737 14760033122 0010701 0 ustar 00 get_field('confirmation');
$valid = \strtolower($confirmation) == 'delete all data';
if (!$valid) {
\wp_send_json_error([], 400);
}
$database_manager = new Database_Manager();
$database_manager->delete_all_data();
$geo_database_manager = new Geo_Database_Manager();
$geo_database_manager->delete();
Capability_Manager::reset_capabilities();
\deactivate_plugins(\IAWP_PLUGIN_FILE);
\wp_send_json_success(['redirectUrl' => \admin_url()]);
}
}
IAWP/AJAX/Delete_Link.php 0000644 00000003064 14760033122 0010720 0 ustar 00 get_int_field('id');
if (\is_null($link_rule_id)) {
\wp_send_json_error([], 400);
}
// Delete the link
Illuminate_Builder::new()->from(Tables::link_rules())->where('link_rule_id', '=', $link_rule_id)->delete();
// Delete the linked clicks
Illuminate_Builder::new()->from(Tables::clicked_links())->where('link_rule_id', '=', $link_rule_id)->delete();
// Delete the clicks
$clicked_links_table = Tables::clicked_links();
Illuminate_Builder::new()->from(Tables::clicks(), 'clicks')->leftJoin("{$clicked_links_table} AS clicked_links", "clicks.click_id", '=', "clicked_links.click_id")->whereNull('clicked_links.click_id')->delete();
// Delete the click targets
$clicks_table = Tables::clicks();
Illuminate_Builder::new()->from(Tables::click_targets(), 'click_targets')->leftJoin("{$clicks_table} AS clicks", "click_targets.click_target_id", '=', "clicks.click_target_id")->whereNull('clicks.click_target_id')->delete();
\wp_send_json_success(['id' => $link_rule_id]);
}
}
IAWP/AJAX/Delete_Report.php 0000644 00000003166 14760033122 0011301 0 ustar 00 from($reports_table)->where('report_id', '=', $this->get_field('id'))->first();
if (\is_null($existing_report)) {
\wp_send_json_error();
}
$report = new Report((object) ['type' => $existing_report->type]);
$report_finder = new Report_Finder();
$reports = $report_finder->by_type($existing_report->type);
$report_index = 0;
foreach ($reports as $index => $report) {
if ($report->id() === $existing_report->report_id) {
$report_index = $index;
}
}
if (\array_key_exists($report_index + 1, $reports)) {
$report = $reports[$report_index + 1];
} elseif ($report_index > 0 && \array_key_exists($report_index - 1, $reports)) {
$report = $reports[$report_index - 1];
}
Illuminate_Builder::new()->from($reports_table)->where('report_id', '=', $this->get_field('id'))->delete();
\wp_send_json_success(['url' => $report->url()]);
}
}
IAWP/AJAX/Dismiss_Notice.php 0000644 00000001573 14760033122 0011460 0 ustar 00 get_field('id');
if ($id == 'iawp_need_clear_cache') {
\update_option('iawp_need_clear_cache', \false, \true);
} elseif ($id == 'iawp_show_gsg') {
\update_option('iawp_show_gsg', '0', \true);
} elseif ($id == 'iawp_clicks_sync_notice') {
\update_option('iawp_clicks_sync_notice', \true, \true);
} elseif ($id == 'enable-logged-in-tracking') {
\update_option('iawp_logged_in_tracking_notice', \true, \true);
}
return;
}
}
IAWP/AJAX/Edit_Link.php 0000644 00000005467 14760033122 0010414 0 ustar 00 get_int_field('id');
$link_properties = ['name' => $this->get_field('name'), 'type' => $this->get_field('type'), 'value' => $this->get_field('value')];
// Validate
foreach ($link_properties as $key => $value) {
$error = Link_Validator::validate($key, $value, $link_properties['type']);
if ($error) {
\wp_send_json_error(['error' => $error, 'property' => $key]);
}
}
// Sanitize
$link_properties['name'] = \sanitize_text_field($link_properties['name']);
$link_properties['type'] = \sanitize_text_field($link_properties['type']);
if ($link_properties['type'] == 'domain') {
$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']);
} else {
$link_properties['value'] = \sanitize_text_field($link_properties['value']);
}
$link_rule = null;
if (\is_int($link_id)) {
$link_rule = Click_Tracking\Link_Rule::find($link_id);
if ($link_rule->type() !== $link_properties['type'] || $link_rule->value() !== $link_properties['value']) {
\delete_option('iawp_click_tracking_cache_cleared');
}
} else {
\delete_option('iawp_click_tracking_cache_cleared');
}
if ($link_rule) {
Illuminate_Builder::new()->from(Tables::link_rules())->where('link_rule_id', '=', $link_id)->update($link_properties);
} else {
$link_properties['created_at'] = (new \DateTime())->format('Y-m-d H:i:s');
$link_id = Illuminate_Builder::new()->from(Tables::link_rules())->insertGetId($link_properties);
}
// Fetch a fresh copy
$link_rule = Click_Tracking\Link_Rule::find($link_id);
\wp_send_json_success(['shouldShowCacheMessage' => \get_option('iawp_click_tracking_cache_cleared') === \false, 'html' => \IAWPSCOPED\iawp_blade()->run('click-tracking.link', ['link' => $link_rule->to_array(), 'types' => Click_Tracking::types(), 'extensions' => Click_Tracking::extensions(), 'protocols' => Click_Tracking::protocols()])]);
}
}
IAWP/AJAX/Export_Campaigns.php 0000644 00000001335 14760033122 0012003 0 ustar 00 csv($campaigns->rows());
echo $csv->to_string();
}
}
IAWP/AJAX/Export_Clicks.php 0000644 00000001365 14760033122 0011314 0 ustar 00 sanitize_sort_parameters());
$csv = $table->csv($clicks->rows());
echo $csv->to_string();
}
}
IAWP/AJAX/Export_Devices.php 0000644 00000001222 14760033122 0011456 0 ustar 00 csv($device_types->rows());
echo $csv->to_string();
}
}
IAWP/AJAX/Export_Geo.php 0000644 00000001154 14760033122 0010612 0 ustar 00 csv($geos->rows());
echo $csv->to_string();
}
}
IAWP/AJAX/Export_Pages.php 0000644 00000001166 14760033122 0011142 0 ustar 00 csv($resources->rows());
echo $csv->to_string();
}
}
IAWP/AJAX/Export_Referrers.php 0000644 00000001216 14760033122 0012036 0 ustar 00 csv($referrers->rows());
echo $csv->to_string();
}
}
IAWP/AJAX/Export_Reports.php 0000644 00000001726 14760033122 0011543 0 ustar 00 get_field('ids');
if (\count($ids) === 0) {
\wp_send_json_error([], 400);
}
$report_finder = new Report_Finder();
$reports = $report_finder->by_ids($ids);
$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])]);
}
}
IAWP/AJAX/Filter.php 0000644 00000012004 14760033122 0007760 0 ustar 00 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;
$as_csv = $this->get_field('as_csv') ?? \false;
$is_new_group = $this->get_field('is_new_group') === 'true';
$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 * \IAWPSCOPED\iawp()->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, $is_new_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 ($as_csv) {
$rows_query = new $rows_class($date_range, null, $filters, $sort_configuration);
$rows = $rows_query->rows();
$csv = $table->csv($rows, \true);
echo $csv->to_string();
return;
}
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);
}
$rows = $rows_query->rows();
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);
}
$total_number_of_rows = $statistics->total_number_of_rows();
if ($is_geo_table) {
$chart = new Chart_Geo($rows, $date_range->label());
$rows = \array_slice($rows, 0, $number_of_rows);
} else {
$chart = new Chart($statistics);
}
$table->set_statistics($statistics);
$quick_stats = new Quick_Stats($statistics);
\wp_send_json_success(['rows' => $table->get_rendered_template($rows, \true, $sort_configuration->column(), $sort_configuration->direction()), 'table' => $table->get_rendered_template($rows, \false, $sort_configuration->column(), $sort_configuration->direction()), 'totalNumberOfRows' => $total_number_of_rows, 'chart' => $chart->get_html(), 'stats' => $quick_stats->get_html(), 'label' => $date_range->label(), 'isLastPage' => \count($rows) < \IAWPSCOPED\iawp()->pagination_page_size() * $page, 'columns' => $table->visible_column_ids(), 'columnsHTML' => $table->column_picker_html(), 'groupId' => $table->group()->id(), 'filters' => $filters, 'filtersTemplateHTML' => $table->filters_template_html(), 'filtersButtonsHTML' => $table->filters_condition_buttons_html($filters), 'chartInterval' => $chart_interval->id()]);
}
/**
* 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);
}
}
IAWP/AJAX/Import_Reports.php 0000644 00000001507 14760033122 0011531 0 ustar 00 get_options_for_creating());
}
\wp_send_json_success([]);
}
}
IAWP/AJAX/Migration_Status.php 0000644 00000002221 14760033122 0012027 0 ustar 00 Migrations\Migrations::is_migrating()];
if (\get_option('iawp_migration_error', null) && \get_option('iawp_migration_error_query', null)) {
$response['errorHtml'] = \IAWPSCOPED\iawp_blade()->run('interrupt.migration-error', ['plugin_version' => \IAWP_VERSION, 'migration_db_version' => \intval(\get_option('iawp_db_version', 0)) + 1, 'migration_step' => \intval(\get_option('iawp_last_finished_migration_step', 0)) + 1, 'migration_error' => \get_option('iawp_migration_error', null), 'migration_error_query' => \get_option('iawp_migration_error_query', null)]);
}
\wp_send_json_success($response);
}
}
IAWP/AJAX/Preview_Email.php 0000644 00000001222 14760033122 0011263 0 ustar 00 get_field('colors')));
$email = \IAWPSCOPED\iawp()->email_reports->get_email_body($colors);
\wp_send_json_success(['html' => $email]);
}
}
IAWP/AJAX/Real_Time_Data.php 0000644 00000000712 14760033122 0011330 0 ustar 00 get_real_time_analytics());
}
}
IAWP/AJAX/Rename_Report.php 0000644 00000001570 14760033122 0011303 0 ustar 00 get_field('name'));
if (\strlen($name) === 0) {
\wp_send_json_error([], 400);
}
Illuminate_Builder::new()->from($reports_table)->where('report_id', '=', $this->get_field('id'))->update(['name' => $name]);
\wp_send_json_success(['name' => $name]);
}
}
IAWP/AJAX/Reset_Analytics.php 0000644 00000001322 14760033122 0011625 0 ustar 00 get_field('confirmation');
$valid = \strtolower($confirmation) == 'reset analytics';
if (!$valid) {
\wp_send_json_error([], 400);
}
$manager = new Database_Manager();
$manager->reset_analytics();
\wp_send_json_success([]);
}
}
IAWP/AJAX/Save_Report.php 0000644 00000001644 14760033122 0010774 0 ustar 00 get_options_for_updating()) > 0) {
Illuminate_Builder::new()->from($reports_table)->where('report_id', '=', $this->get_field('id'))->update($report_options_parser->get_options_for_updating());
}
}
}
IAWP/AJAX/Set_Favorite_Report.php 0000644 00000002261 14760033122 0012464 0 ustar 00 get_field('id');
$type = $this->get_field('type');
if (!\is_null(Report_Finder::by_id($id))) {
\delete_user_meta(\get_current_user_id(), 'iawp_favorite_report_id');
\delete_user_meta(\get_current_user_id(), 'iawp_favorite_report_type');
\update_user_meta(\get_current_user_id(), 'iawp_favorite_report_id', $id);
\wp_send_json_success([]);
}
if (Report::is_valid_report_type($type)) {
\delete_user_meta(\get_current_user_id(), 'iawp_favorite_report_id');
\delete_user_meta(\get_current_user_id(), 'iawp_favorite_report_type');
\update_user_meta(\get_current_user_id(), 'iawp_favorite_report_type', $type);
\wp_send_json_success([]);
}
\wp_send_json_error([], 400);
}
}
IAWP/AJAX/Set_WooCommerce_Statuses_To_Track.php 0000644 00000001747 14760033122 0015262 0 ustar 00 get_field('statusesToTrack');
$reset_to_default = $this->get_boolean_field('resetToDefault');
$status_manager = new WooCommerce_Status_Manager();
if ($reset_to_default) {
$status_manager->reset_tracked_statuses();
$status_manager->update_order_records_based_on_tracked_statuses();
} elseif (\is_array($statuses_to_track)) {
$status_manager->set_tracked_statuses($statuses_to_track);
$status_manager->update_order_records_based_on_tracked_statuses();
}
\wp_send_json_success(['statusesToTrack' => $status_manager->get_statuses()]);
}
}
IAWP/AJAX/Sort_Links.php 0000644 00000001550 14760033122 0010626 0 ustar 00 get_field('ids') as $index => $id) {
Illuminate_Builder::new()->from(Tables::link_rules())->where('link_rule_id', '=', $id)->update(['position' => $index]);
}
\wp_send_json_success();
}
}
IAWP/AJAX/Sort_Reports.php 0000644 00000002115 14760033122 0011202 0 ustar 00 from($reports_table)->where('type', '=', $this->get_field('type'))->update(['position' => null]);
foreach ($this->get_field('ids') as $index => $id) {
Illuminate_Builder::new()->from($reports_table)->where('type', '=', $this->get_field('type'))->where('report_id', '=', $id)->update(['position' => $index]);
}
\wp_send_json_success();
}
}
IAWP/AJAX/Test_Email.php 0000644 00000001045 14760033122 0010564 0 ustar 00 email_reports->send_email_report(\true);
echo \rest_sanitize_boolean($sent);
}
}
IAWP/AJAX/Update_Capabilities.php 0000644 00000001107 14760033122 0012430 0 ustar 00 get_field('capabilities');
Capability_Manager::edit_all_capabilities($capabilities);
\update_option('iawp_white_label', $this->get_boolean_field('white_label'), \true);
}
}
IAWP/AJAX/Update_User_Settings.php 0000644 00000001040 14760033122 0012631 0 ustar 00 get_boolean_field('is_sidebar_collapsed');
if (\is_bool($is_sidebar_collapsed)) {
\update_user_meta(\get_current_user_id(), 'iawp_is_sidebar_collapsed', $is_sidebar_collapsed);
}
\wp_send_json_success([]);
}
}
IAWP/Admin_Page/Admin_Page.php 0000644 00000004057 14760033122 0011771 0 ustar 00 run('interrupt.migration-is-running');
return;
}
$options = Dashboard_Options::getInstance();
$tab = (new Env())->get_tab();
?>
get_date_range();
$tab = (new Env())->get_tab();
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);
$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);
$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);
$table_data_class = $table->group()->rows_class();
$geo_data = new $table_data_class($date_rage);
$chart = new Chart_Geo($geo_data->rows());
$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);
$this->interface($table, $stats, $chart);
} elseif ($tab === 'clicks') {
$table = new Table_Clicks();
$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);
$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);
$this->interface($table, $stats, $chart);
} elseif ($tab === 'real-time') {
(new Real_Time())->render_real_time_analytics();
}
}
private function interface(Table $table, $stats, $chart)
{
$options = Dashboard_Options::getInstance();
$sort_configuration = $table->sanitize_sort_parameters($options->sort_column(), $options->sort_direction());
?>
get_html();
?>
get_html();
?>
get_table_toolbar_markup();
?>
get_table_markup($sort_configuration->column(), $sort_configuration->direction());
?>
';
echo \esc_html_x('Geolocation data powered by', 'Following text is a noun: DB-IP', 'independent-analytics') . ' ' . 'DB-IP .';
echo '';
}
?>
has_conflict()) {
echo \IAWPSCOPED\iawp_blade()->run('notices.notice', ['notice_text' => $plugin_conflict_detector->get_error(), 'button_text' => \false, 'id' => 'plugin-conflict', 'notice' => 'iawp-error', 'url' => 'https://independentwp.com/knowledgebase/tracking/secure-rest-api/']);
} elseif (\IAWPSCOPED\iawp_is_pro() && \is_plugin_active('better-wp-security/better-wp-security.php')) {
$settings = \get_option('itsec-storage');
if (\array_key_exists('system-tweaks', $settings)) {
if (\array_key_exists('plugins_php', $settings['system-tweaks'])) {
if ($settings['system-tweaks']['plugins_php']) {
echo \IAWPSCOPED\iawp_blade()->run('notices.notice', ['notice_text' => \__('The "Solid Security" plugin is disabling PHP execution in the plugins folder, and this is preventing click tracking from working. Please visit the Security > Settings page, click on the Advanced section, click on System Tweaks Settings, uncheck the "Disable PHP Plugins" option, and then save.', 'independent-analytics'), 'button_text' => \false, 'id' => 'plugin-conflict', 'notice' => 'iawp-error', 'url' => 'https://independentwp.com/knowledgebase/click-tracking/allow-php-execution-plugins-folder/']);
}
}
}
}
if (\get_option('iawp_need_clear_cache')) {
echo \IAWPSCOPED\iawp_blade()->run('notices.notice', ['notice_text' => \__('Please clear your cache to ensure tracking works properly.', 'independent-analytics'), 'button_text' => \__('I\'ve cleared the cache', 'independent-analytics'), 'id' => 'iawp_need_clear_cache', 'notice' => 'iawp-warning', 'url' => 'https://independentwp.com/knowledgebase/common-questions/views-not-recording/']);
}
$requires_logged_in_tracking = $plugin_conflict_detector->plugin_requiring_logged_in_tracking();
$show_logged_in_tracking_notice = $requires_logged_in_tracking && !\get_option('iawp_track_authenticated_users') && !\get_option('iawp_need_clear_cache') && !\get_option('iawp_logged_in_tracking_notice');
if ($show_logged_in_tracking_notice) {
echo \IAWPSCOPED\iawp_blade()->run('notices.notice', ['notice_text' => '' . \sprintf(\_x('%s compatibility:', 'Variable is the name of a plugin', 'independent-analytics'), $requires_logged_in_tracking) . ' ' . \__('We recommend you enable tracking for logged-in visitors.', 'independent-analytics'), 'button_text' => \__('Dismiss', 'independent-analytics'), 'id' => 'enable-logged-in-tracking', 'notice' => 'iawp-warning', 'url' => 'https://independentwp.com/knowledgebase/tracking/how-to-track-logged-in-visitors/']);
}
if (\IAWPSCOPED\iawp_db_version() > 0 && !Database::has_correct_database_privileges()) {
echo \IAWPSCOPED\iawp_blade()->run('notices.notice', ['notice_text' => \__('Your site is missing the following critical database permissions:', 'independent-analytics') . ' ' . \implode(', ', Database::missing_database_privileges()) . '. ' . \__('There is no issue at this time, but you will need to enable the missing permissions before updating the plugin to a newer version to ensure an error is avoided. Please click this link to read our tutorial:', 'independent-analytics'), 'button_text' => \false, 'id' => 'missing-permissions', 'notice' => 'iawp-error', 'url' => 'https://independentwp.com/knowledgebase/common-questions/missing-database-permissions/']);
}
if (Env::get_tab() === 'clicks') {
if (!\get_option('iawp_clicks_sync_notice')) {
echo \IAWPSCOPED\iawp_blade()->run('notices.notice', ['notice_text' => \__('Click data syncs every 60 seconds. Please allow for this delay when testing clicks on new links.', 'independent-analytics'), 'button_text' => \__('Dismiss', 'independent-analytics'), 'id' => 'iawp_clicks_sync_notice', 'notice' => 'iawp-warning', 'url' => 'https://independentwp.com/knowledgebase/click-tracking/click-tracking-update-process/']);
}
}
}
?>
has_conflict() && (Env::get_tab() !== 'clicks' || Env::get_tab() === 'clicks' && \get_option('iawp_clicks_sync_notice'))) {
echo \IAWPSCOPED\iawp_blade()->run('notices.getting-started');
}
}
}
IAWP/Admin_Page/Campaign_Builder_Page.php 0000644 00000000401 14760033122 0014113 0 ustar 00 render_campaign_builder();
}
}
IAWP/Admin_Page/Click_Tracking_Page.php 0000644 00000000767 14760033122 0013614 0 ustar 00 ' . \esc_html__('You do not have permission to edit the click tracking settings.', 'independent-analytics') . '';
}
}
}
IAWP/Admin_Page/Settings_Page.php 0000644 00000000733 14760033122 0012536 0 ustar 00 settings->render_settings();
} else {
echo '' . \esc_html__('You do not have permission to edit the settings.', 'independent-analytics') . '
';
}
}
}
IAWP/Admin_Page/Support_Page.php 0000644 00000000734 14760033122 0012413 0 ustar 00 run('support');
} else {
echo '' . \esc_html__('You do not have permission to view this page.', 'independent-analytics') . '
';
}
}
}
IAWP/Admin_Page/Updates_Page.php 0000644 00000001226 14760033122 0012341 0 ustar 00 run('updates');
$this->update_latest_update_viewed();
} else {
echo '' . \esc_html__('You do not have permission to view this page.', 'independent-analytics') . '
';
}
}
private function update_latest_update_viewed()
{
\update_option('iawp_last_update_viewed', \IAWP_VERSION, \true);
}
}
IAWP/Click_Tracking/Click.php 0000644 00000007666 14760033122 0011726 0 ustar 00 protocol = $this->extract_protocol_from_href($record['href']);
$this->value = $this->extract_target_value_from_href($record['href']);
$this->href = $record['href'];
$this->classes = $record['classes'];
$this->resource_id = $record['resource_id'];
$this->visitor_id = $record['visitor_id'];
$this->created_at = $record['created_at'];
}
/**
* Update the database
*
* @return void
*/
public function track() : void
{
$link_rules = \IAWP\Click_Tracking\Link_Rule_Finder::new($this->protocol, $this->href, $this->classes)->links();
if ($link_rules->isEmpty()) {
return;
}
$click_target = $this->get_click_target();
$view_id = $this->get_view_id();
if (\is_null($view_id)) {
return;
}
$click_id = Illuminate_Builder::new()->from(Tables::clicks())->insertGetId(['click_target_id' => $click_target->click_target_id, 'view_id' => $view_id, 'created_at' => $this->created_at->format('Y-m-d H:i:s')]);
$link_rules->each(function ($link_rule) use($click_id) {
Illuminate_Builder::new()->from(Tables::clicked_links())->insertGetId(['click_id' => $click_id, 'link_rule_id' => $link_rule->id()]);
});
}
private function extract_protocol_from_href(?string $href) : ?string
{
if (\is_null($href)) {
return null;
}
if (Str::startsWith($href, ['tel:', 'mailto:'])) {
return Str::before($href, ':');
}
return null;
}
private function extract_target_value_from_href(?string $href) : ?string
{
if (\is_null($href)) {
return null;
}
if (Str::startsWith($href, ['tel:', 'mailto:'])) {
return Str::after($href, ':');
}
return $href;
}
private function get_click_target() : object
{
$select_query = Illuminate_Builder::new()->from(Tables::click_targets())->where('target', '=', $this->value)->when(\is_null($this->protocol), function (Builder $query) {
$query->whereNull('protocol');
})->when(\is_string($this->protocol), function (Builder $query) {
$query->where('protocol', '=', $this->protocol);
});
$target = $select_query->first();
if (\is_object($target)) {
return $target;
}
Illuminate_Builder::new()->from(Tables::click_targets())->insertOrIgnore(['target' => $this->value, 'protocol' => $this->protocol]);
return $select_query->first();
}
private function get_view_id() : ?int
{
$sessions_table = Tables::sessions();
$view_id = Illuminate_Builder::new()->from(Tables::views(), 'views')->join("{$sessions_table} AS sessions", 'views.session_id', '=', 'sessions.session_id')->where('views.resource_id', '=', $this->resource_id)->where('sessions.visitor_id', '=', $this->visitor_id)->where('views.viewed_at', '<=', $this->created_at->format('Y-m-d H:i:s'))->orderByDesc('views.viewed_at')->limit(1)->value('views.id');
// There's a small chance that view_id is a string instead of an int. In that case,
// it should be converted to a string.
// https://github.com/andrewjmead/independent-analytics/issues/1335
if (\is_string($view_id)) {
return (int) $view_id;
}
if (\is_int($view_id)) {
return $view_id;
}
return null;
}
public static function new(array $record) : ?self
{
return new self($record);
}
}
IAWP/Click_Tracking/Click_Processing_Job.php 0000644 00000006030 14760033122 0014674 0 ustar 00 get_click_data_file();
if ($click_data_file === null) {
return;
}
$job_file = $this->create_job_file($click_data_file);
if ($job_file === null) {
return;
}
$job_handle = \fopen($job_file, 'r');
if ($job_handle === \false) {
return;
}
// The first line for the PHP file is an exit statement to keep the contents private. This
// should be skipped when parsing the file.
if (\pathinfo($job_file, \PATHINFO_EXTENSION) === 'php') {
\fgets($job_handle);
// Skip first line
}
while (($json = \fgets($job_handle)) !== \false) {
$event = \json_decode($json, \true);
$event['href'] = Security::string($event['href']);
$event['classes'] = Security::string($event['classes']);
if (\is_null($event)) {
continue;
}
$payload_validator = Payload_Validator::new($event['payload'], $event['signature']);
if (!$payload_validator->is_valid() || \is_null($payload_validator->resource())) {
continue;
}
$click = \IAWP\Click_Tracking\Click::new(['href' => $event['href'], 'classes' => $event['classes'], 'resource_id' => $payload_validator->resource()['id'], 'visitor_id' => Visitor::fetch_visitor_id_by_hash($event['visitor_token']), 'created_at' => \DateTime::createFromFormat('U', $event['created_at'])]);
$click->track();
}
\fclose($job_handle);
\unlink($job_file);
}
private function get_click_data_file() : ?string
{
$text_file = Str::finish(\sys_get_temp_dir(), \DIRECTORY_SEPARATOR) . "iawp-click-data.txt";
if (\is_file($text_file)) {
return $text_file;
}
$php_file = \IAWPSCOPED\iawp_path_to('iawp-click-data.php');
if (\is_file($php_file)) {
return $php_file;
}
return null;
}
private function create_job_file(string $file) : ?string
{
if (!\is_file($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)) {
return null;
}
return $job_file;
}
}
IAWP/Click_Tracking/Config_File_Manager.php 0000644 00000003573 14760033122 0014470 0 ustar 00 \IAWPSCOPED\iawp_is_pro(), 'visitor_token_salt' => Salt::visitor_token_salt()];
if (\is_string(Request::custom_ip_header())) {
$data['custom_ip_header'] = Request::custom_ip_header();
}
$contents = "\n";
$contents .= \json_encode($data);
\file_put_contents(self::config_file_path(), $contents);
}
/**
* For a couple releases, click tracking files were in the uploads folder. This method is responsible for
* cleaning them up if they are still there.
*
* @return void
*/
private static function remove_legacy_files() : void
{
self::delete_file(\IAWPSCOPED\iawp_upload_path_to('/iawp-click-endpoint.php'));
self::delete_file(\IAWPSCOPED\iawp_upload_path_to('/iawp-click-config.php'));
self::delete_file(\IAWPSCOPED\iawp_upload_path_to('/iawp-click-data.php'));
}
private static function config_file_path() : string
{
return \IAWPSCOPED\iawp_path_to('/iawp-click-config.php');
}
private static function delete_file(string $file) : void
{
if (\is_file($file)) {
\unlink($file);
}
}
}
IAWP/Click_Tracking/Link_Rule.php 0000644 00000004125 14760033122 0012550 0 ustar 00 is_active)) {
$attributes->is_active = (int) $attributes->is_active;
}
$this->attributes = $attributes;
}
public function id() : int
{
return $this->attributes->link_rule_id;
}
public function name() : string
{
return $this->attributes->name;
}
public function type() : string
{
return $this->attributes->type;
}
public function value() : string
{
return $this->attributes->value;
}
public function toggle_active() : bool
{
$new_is_active = !$this->is_active() ? 1 : 0;
$records_updated = Illuminate_Builder::new()->from(Tables::link_rules())->where('link_rule_id', '=', $this->id())->update(['is_active' => $new_is_active]);
if ($records_updated === 1) {
$this->attributes->is_active = $new_is_active;
return \true;
} else {
return \false;
}
}
public function is_active() : bool
{
return $this->attributes->is_active === 1;
}
public function to_array() : array
{
$array = (array) $this->attributes;
// Rename id
$array['id'] = $array['link_rule_id'];
unset($array['link_rule_id']);
// Convert is_active to a boolean
$array['is_active'] = $array['is_active'] === 1 ? \true : \false;
return $array;
}
public static function find(int $id) : ?self
{
$link_rule = Illuminate_Builder::new()->from(Tables::link_rules())->where('link_rule_id', '=', $id)->first();
if (\is_null($link_rule)) {
return null;
}
return new self($link_rule);
}
}
IAWP/Click_Tracking/Link_Rule_Finder.php 0000644 00000010455 14760033122 0014042 0 ustar 00 protocol = $protocol;
$this->href = $href;
$this->classes = $classes;
}
public function links() : ?Collection
{
return self::get_database_records()->filter(function ($link_rule) {
return $link_rule->is_active();
})->filter(function ($link_rule) {
return $this->is_match($link_rule);
})->values();
}
private function is_match($link_rule) : bool
{
switch ($link_rule->type()) {
case 'class':
return $this->is_matching_class($link_rule);
case 'domain':
return $this->is_matching_domain($link_rule);
case 'extension':
return $this->is_matching_extension($link_rule);
case 'subdirectory':
return $this->is_matching_subdirectory($link_rule);
case 'protocol':
return $this->is_matching_protocol($link_rule);
default:
return \false;
}
}
private function is_matching_class($link_rule) : bool
{
if ($this->classes === "") {
return \false;
}
return Collection::make(\explode(' ', $this->classes))->contains(function ($value, $key) use($link_rule) {
return $link_rule->value() === $value;
});
}
private function is_matching_domain($link_rule) : bool
{
if (\is_null($this->href)) {
return \false;
}
$url = new URL($this->href);
if (!$url->is_valid_url()) {
return \false;
}
return $link_rule->value() === $url->get_domain();
}
private function is_matching_extension($link_rule) : bool
{
if (\is_null($this->href)) {
return \false;
}
$url = new URL($this->href);
if (!$url->is_valid_url()) {
return \false;
}
return $link_rule->value() === $url->get_extension();
}
private function is_matching_subdirectory($link_rule) : bool
{
if (\is_null($this->href)) {
return \false;
}
$url = URL::new($this->href);
$site_url = URL::new(\get_site_url());
if (!$url->is_valid_url() || $url->get_domain() !== $site_url->get_domain()) {
return \false;
}
$path = $url->get_path();
$path_parts = Collection::make(\explode('/', $path))->filter()->values();
if ($path_parts->isEmpty()) {
return \false;
}
return $link_rule->value() === $path_parts->first();
}
private function is_matching_protocol($link_rule) : bool
{
if (\is_null($this->href)) {
return \false;
}
return $this->protocol === $link_rule->value();
}
public static function new(?string $protocol, ?string $href, string $classes) : self
{
return new self($protocol, $href, $classes);
}
public static function link_rules() : Collection
{
return self::get_database_records();
}
public static function active_link_rules() : Collection
{
return self::get_database_records()->filter(function ($link_rule) {
return $link_rule->is_active();
});
}
public static function inactive_link_rules() : Collection
{
return self::get_database_records()->filter(function ($link_rule) {
return !$link_rule->is_active();
});
}
private static function get_database_records() : Collection
{
if (\is_null(static::$database_records)) {
$records = Illuminate_Builder::new()->from(Tables::link_rules())->orderBy('position')->orderByDesc('created_at')->get();
static::$database_records = $records->map(function ($link_rule) {
return new \IAWP\Click_Tracking\Link_Rule($link_rule);
});
}
return static::$database_records;
}
}
IAWP/Custom_WordPress_Columns/Views_Column.php 0000644 00000006267 14760033122 0015422 0 ustar 00 'integer', 'single' => \true, 'default' => 0, 'show_in_rest' => \true]);
\add_filter("manage_edit-{$post_type_slug}_sortable_columns", [self::class, 'enable_sorting']);
}
}
public static function set_column_header(array $columns, string $post_type = null) : array
{
// manage_pages_columns doesn't set the $post_type argument, so checking is_null() works for it
if (\is_null($post_type) || \in_array($post_type, self::post_type_slugs())) {
$columns[self::$meta_key] = \__('Views', 'independent-analytics') . ' ( Independent Analytics) ';
}
return $columns;
}
public static function echo_cell_content($column_id, $post_id) : void
{
if ($column_id === self::$meta_key) {
$total_views = \intval(\get_post_meta($post_id, self::$meta_key, \true));
echo Number_Formatter::decimal($total_views);
}
}
public static function enable_sorting(array $columns) : array
{
$columns[self::$meta_key] = [self::$meta_key, 'DESC'];
return $columns;
}
public static function configure_sorting($query) : void
{
// Limit to admin menus
if (!\is_admin() || !$query->is_main_query() || \wp_doing_ajax() || \wp_doing_cron()) {
return;
}
$order_by = $query->get('orderby');
if ($order_by === self::$meta_key) {
$meta_query = ['relation' => 'OR', ['key' => self::$meta_key, 'compare' => 'NOT EXISTS'], ['key' => self::$meta_key]];
$query->set('meta_query', $meta_query);
$query->set('orderby', 'meta_value_num');
}
}
private static function post_type_slugs() : array
{
$built_in_post_type_slugs = ['post', 'page'];
$post_type_slugs = \get_post_types(['public' => \true, '_builtin' => \false]);
$slugs = \array_merge($built_in_post_type_slugs, $post_type_slugs);
$disallowed = ['elementor_library', 'e-landing-page'];
return \array_diff($slugs, $disallowed);
}
}
IAWP/Data_Pruning/Pruner.php 0000644 00000011625 14760033122 0011646 0 ustar 00 cutoff_date = (new \IAWP\Data_Pruning\Pruning_Scheduler())->get_pruning_cutoff_as_datetime();
}
private function run()
{
if (\is_null($this->cutoff_date)) {
return;
}
$db = Illuminate_Builder::get_connection();
$db->transaction(function () {
$sessions_table = Query::get_table_name(Query::SESSIONS);
Illuminate_Builder::new()->from($sessions_table)->where('created_at', '<', $this->cutoff_date->format('Y-m-d\\TH:i:s'))->delete();
// Delete orphaned views
$views_table = Query::get_table_name(Query::VIEWS);
$this->delete_session_orphans($views_table, 'session_id');
// Delete orphaned form submissions
$form_submissions_table = Query::get_table_name(Query::FORM_SUBMISSIONS);
$this->delete_session_orphans($form_submissions_table, 'session_id');
// Delete orphaned WooCommerce orders
$orders_table = Query::get_table_name(Query::ORDERS);
$this->delete_view_orphans($orders_table, 'view_id', 'id');
// Delete orphaned visitors
$visitors_table = Query::get_table_name(Query::VISITORS);
$this->delete_session_orphans($visitors_table, 'visitor_id');
// Delete orphaned resources
$resources_table = Query::get_table_name(Query::RESOURCES);
$this->delete_view_orphans($resources_table, 'id', 'resource_id');
// Delete orphaned referrers
$referrers_table = Query::get_table_name(Query::REFERRERS);
$this->delete_session_orphans($referrers_table, 'id', 'referrer_id');
// Delete orphaned forms
$forms_table = Query::get_table_name(Query::FORMS);
Illuminate_Builder::new()->from($forms_table, 'orphans')->leftJoin("{$form_submissions_table} AS form_submissions", "orphans.form_id", '=', "form_submissions.form_id")->whereNull('form_submissions.form_id')->delete();
// Delete orphaned device browsers
$device_browsers_table = Query::get_table_name(Query::DEVICE_BROWSERS);
$this->delete_session_orphans($device_browsers_table, 'device_browser_id');
// Delete orphaned device oss
$device_oss_table = Query::get_table_name(Query::DEVICE_OSS);
$this->delete_session_orphans($device_oss_table, 'device_os_id');
// Delete orphaned device types
$device_types_table = Query::get_table_name(Query::DEVICE_TYPES);
$this->delete_session_orphans($device_types_table, 'device_type_id');
// Don't touch cities or countries for now
// This would be a very different custom query as cities reference countries
// Delete orphaned campaigns
$campaigns_table = Query::get_table_name(Query::CAMPAIGNS);
$this->delete_session_orphans($campaigns_table, 'campaign_id');
// Delete orphaned clicks
$this->delete_view_orphans(Tables::clicks(), 'view_id', 'id');
// Delete orphaned clicked links
$clicks_table = Tables::clicks();
Illuminate_Builder::new()->from(Tables::clicked_links(), 'orphans')->leftJoin("{$clicks_table} AS clicks", "orphans.click_id", '=', "clicks.click_id")->whereNull('clicks.click_id')->delete();
// Delete orphaned click targets
Illuminate_Builder::new()->from(Tables::click_targets(), 'orphans')->leftJoin("{$clicks_table} AS clicks", "orphans.click_target_id", '=', "clicks.click_target_id")->whereNull('clicks.click_id')->delete();
});
\delete_option('iawp_beginning_of_time');
}
private function delete_session_orphans(string $table, string $column, ?string $sessions_column = null) : int
{
$sessions_table = Query::get_table_name(Query::SESSIONS);
$sessions_column = $sessions_column ?? $column;
return Illuminate_Builder::new()->from($table, 'orphans')->leftJoin("{$sessions_table} AS sessions", "orphans.{$column}", '=', "sessions.{$sessions_column}")->whereNull('sessions.session_id')->delete();
}
private function delete_view_orphans(string $table, string $column, ?string $views_column = null) : int
{
$views_table = Query::get_table_name(Query::VIEWS);
$views_column = $views_column ?? $column;
return Illuminate_Builder::new()->from($table, 'orphans')->leftJoin("{$views_table} AS views", "orphans.{$column}", '=', "views.{$views_column}")->whereNull('views.id')->delete();
}
public static function register_hook()
{
\add_action('iawp_prune', function () {
self::prune();
});
}
public static function prune()
{
$pruner = new self();
$pruner->run();
}
}
IAWP/Data_Pruning/Pruning_Scheduler.php 0000644 00000013217 14760033122 0014012 0 ustar 00 is_enabled()) {
return null;
}
return $this->convert_cutoff_to_date($this->get_pruning_cutoff());
}
public function status_message() : ?string
{
if (!$this->is_enabled()) {
return null;
}
$scheduled_at = new \DateTime();
$scheduled_at->setTimezone(Timezone::site_timezone());
$scheduled_at->setTimestamp(\wp_next_scheduled('iawp_prune'));
$day = $scheduled_at->format(\get_option('date_format'));
$time = $scheduled_at->format(\IAWPSCOPED\iawp()->get_option('time_format', 'g:i a'));
return \sprintf(\__('Next data pruning scheduled for %s at %s.', 'independent-analytics'), '' . $day . ' ', '' . $time . ' ');
}
public function get_pruning_description(string $cutoff) : string
{
$date = $this->convert_cutoff_to_date($cutoff, \true);
$utc_date = $this->convert_cutoff_to_date($cutoff);
$formatted_date = $date->format(WordPress_Site_Date_Format_Pattern::for_php());
$estimates = $this->get_pruning_estimates($utc_date);
return \sprintf(\__("All data from before %1\$s will be deleted immediately. This will remove %2\$s of your %3\$s tracked sessions. \n\n This process will repeat daily at midnight.", 'independent-analytics'), $formatted_date, \number_format_i18n($estimates['sessions_to_be_deleted']), \number_format_i18n($estimates['sessions']));
}
/**
* @return array{sessions: int, sessions_to_be_deleted: int}
*/
public function get_pruning_estimates(\DateTime $cutoff_date) : array
{
$sessions_table = Query::get_table_name(Query::SESSIONS);
$sessions = Illuminate_Builder::new()->from($sessions_table)->selectRaw('COUNT(*) as sessions')->value('sessions');
$sessions_to_be_deleted = Illuminate_Builder::new()->from($sessions_table)->selectRaw('COUNT(*) as sessions')->where('created_at', '<', $cutoff_date)->value('sessions');
return ['sessions' => $sessions, 'sessions_to_be_deleted' => $sessions_to_be_deleted];
}
public function update_pruning_cutoff(string $cutoff) : bool
{
$is_valid_cutoff = \false;
foreach (self::$cutoff_options as $option) {
if ($option[0] === $cutoff) {
$is_valid_cutoff = \true;
}
}
if (!$is_valid_cutoff) {
return \false;
}
\update_option('iawp_pruning_cutoff', $cutoff, \true);
$this->schedule_pruning($cutoff);
return \true;
}
/**
* Attempt to schedule pruning based on whatever existing cutoff option is saved
*
* @return void
*/
public function schedule() : void
{
$cutoff = \get_option('iawp_pruning_cutoff', '');
$this->update_pruning_cutoff($cutoff);
}
public function unschedule() : void
{
$scheduled_at_timestamp = \wp_next_scheduled('iawp_prune');
if (\is_int($scheduled_at_timestamp)) {
\wp_unschedule_event($scheduled_at_timestamp, 'iawp_prune');
}
}
private function schedule_pruning(string $cutoff) : void
{
$this->unschedule();
if ($cutoff === 'disabled') {
return;
}
$tomorrow = new \DateTime('tomorrow', Timezone::site_timezone());
\wp_schedule_event($tomorrow->getTimestamp(), 'daily', 'iawp_prune');
}
private function convert_cutoff_to_date(string $cutoff, bool $as_site_timezone = \false) : \DateTime
{
$beginning_of_today = new CarbonImmutable('today', Timezone::site_timezone());
if (!$as_site_timezone) {
$beginning_of_today = $beginning_of_today->setTimezone(Timezone::utc_timezone());
}
switch ($cutoff) {
case 'thirty-days':
return $beginning_of_today->subDays(30)->toDate();
case 'sixty-days':
return $beginning_of_today->subDays(60)->toDate();
case 'ninety-days':
return $beginning_of_today->subDays(90)->toDate();
case 'one-hundred-and-eighty-days':
return $beginning_of_today->subDays(180)->toDate();
case 'one-year':
return $beginning_of_today->subYearsNoOverflow(1)->toDate();
case 'two-years':
return $beginning_of_today->subYearsNoOverflow(2)->toDate();
case 'three-years':
return $beginning_of_today->subYearsNoOverflow(3)->toDate();
case 'four-years':
return $beginning_of_today->subYearsNoOverflow(4)->toDate();
}
return $beginning_of_today->toDate();
}
}
IAWP/Date_Picker/Date_Picker.php 0000644 00000003315 14760033122 0012341 0 ustar 00 start = $start;
$this->end = $end;
$this->relative_range = $relative_range;
$this->first_data = Relative_Date_Range::beginning_of_time();
}
public function calendar_html()
{
return \IAWPSCOPED\iawp_blade()->run('date-picker.date-picker', ['months' => $this->months(), 'start_date' => $this->start, 'end_date' => $this->end, 'relative_range' => $this->relative_range, 'date_ranges' => Relative_Date_Range::ranges(), 'timezone' => Timezone::site_timezone(), 'user_format' => \get_option('date_format'), 'first_data' => $this->first_data->format('Y-m-d'), 'site_offset_in_seconds' => Timezone::site_offset_in_seconds($this->start)]);
}
private function months() : array
{
$first_day_last_year = new \DateTime('first day of January last year', Timezone::site_timezone());
$start = $this->first_data < $first_day_last_year ? clone $this->first_data : clone $first_day_last_year;
$start->modify('first day of this month')->setTime(0, 0, 0);
$end = (new \DateTime('last day of this month', Timezone::site_timezone()))->setTime(23, 59, 59);
$interval = new \DateInterval('P1M');
// 1 month interval
$period = new \DatePeriod($start, $interval, $end);
$months = [];
foreach ($period as $month) {
$months[] = new \IAWP\Date_Picker\Month($month, $start);
}
return $months;
}
}
IAWP/Date_Picker/Month.php 0000644 00000006611 14760033122 0011256 0 ustar 00 date = $date;
$this->first_month = $first_month;
}
public function name() : string
{
return \IAWPSCOPED\iawp()->date_i18n('F Y', $this->date);
}
public function date_string() : string
{
return $this->date->format('Y-m');
}
public function days() : \DatePeriod
{
$start = $this->date->modify('first day of this month');
$end = (clone $this->date)->modify('last day of this month');
$end->setTime(23, 59, 59);
$interval = new \DateInterval('P1D');
// 1 day interval
return new \DatePeriod($start, $interval, $end);
}
public function extra_cells() : int
{
$user_dow = \IAWPSCOPED\iawp()->get_option('iawp_dow', 0);
$start = $this->date->modify('first day of this month');
$month_dow = $start->format('w');
if ($month_dow >= $user_dow) {
return $month_dow - $user_dow;
} else {
return 7 - ($user_dow - $month_dow);
}
}
public function month_class() : string
{
$now = new \DateTime('now');
$month = clone $this->date;
$class = 'iawp-calendar-month';
if ($month->format('Y-m') === $this->first_month->format('Y-m')) {
$class .= ' iawp-first-month';
}
if ($now->format('Y-m') === $month->format('Y-m')) {
$class .= ' iawp-current iawp-last-month';
}
// Modifying $month here
if ($now->format('Y n') === $month->modify('first day of +1 month')->format('Y n')) {
$class .= ' iawp-previous';
}
return $class;
}
public function day_class(\DateTime $day, string $first_data, string $start_date, string $end_date) : string
{
$date = $day->format('Y-m-d');
$class = 'iawp-day iawp-cell';
if ($date === \date('Y-m-d')) {
$class .= ' iawp-today';
}
if ($day->format('j') == '1') {
$class .= ' first-of-month';
}
if ($date === $first_data) {
$class .= ' iawp-first-data';
}
if ($date < $first_data || $date > \date('Y-m-d')) {
$class .= ' out-of-range';
}
if ($date === $start_date) {
$class .= ' iawp-start';
if ($date === $end_date) {
$class .= ' iawp-end';
}
} elseif ($date === $end_date) {
$class .= ' iawp-end';
} elseif ($date > $start_date && $date < $end_date) {
$class .= ' in-range';
}
return $class;
}
public function days_of_week() : string
{
$days = [];
$html = '';
// Get the correct HTML
for ($i = 0; $i < 7; $i++) {
$days[] = '' . \date_i18n("D", \strtotime("Sunday +{$i} days")) . ' ';
}
// Shift based on the user's selection
for ($i = 0; $i < \IAWPSCOPED\iawp()->get_option('iawp_dow', 0); $i++) {
$first_day = \array_shift($days);
\array_push($days, $first_day);
}
// Create the HTMl string
foreach ($days as $day) {
$html .= $day;
}
return $html;
}
}
IAWP/Date_Range/Date_Range.php 0000644 00000006555 14760033122 0012010 0 ustar 00 start;
}
/**
* @return string
*/
public function iso_start() : string
{
return $this->start->format('Y-m-d\\TH:i:s');
}
/**
* @return DateTime
*/
public function end() : DateTime
{
return $this->end;
}
/**
* @return string
*/
public function iso_end() : string
{
return $this->end->format('Y-m-d\\TH:i:s');
}
/**
* TODO - Doesn't work well for units of varying size such as months
*
* @return Date_Range
*/
public function previous_period() : \IAWP\Date_Range\Date_Range
{
$range_size = $this->range_size_in_days();
$previous_start = (clone $this->start)->modify("-{$range_size} days");
$previous_end = (clone $this->end)->modify("-{$range_size} days");
return new \IAWP\Date_Range\Exact_Date_Range($previous_start, $previous_end, \false);
}
/**
* TODO - Doesn't work well for units of varying size such as months
*
* @return Date_Range
*/
public function next_period() : \IAWP\Date_Range\Date_Range
{
$range_size = $this->range_size_in_days();
$next_start = (clone $this->start)->modify("+{$range_size} days");
$next_end = (clone $this->end)->modify("+{$range_size} days");
return new \IAWP\Date_Range\Exact_Date_Range($next_start, $next_end, \false);
}
public function number_of_days() : int
{
return \intval($this->start->diff($this->end)->format('%a')) + 1;
}
protected function set_range(DateTime $start, DateTime $end, bool $convert_to_full_days)
{
$start = clone $start;
$end = clone $end;
if ($convert_to_full_days) {
$start = $this->start_of_locale_day($start);
$end = $this->end_of_locale_day($end);
}
$this->start = $start;
$this->end = $end;
}
/**
* Return the range size in days for previous period calculations
*
* TODO - Doesn't work well for units of varying size such as months
*
* @return int
*/
private function range_size_in_days() : int
{
return $this->start->diff($this->end)->days + 1;
}
/**
* Return a new DateTime representing the start of the day in the users timezone
*
* @param DateTime $datetime
*
* @return DateTime
*/
private function start_of_locale_day(\DateTime $datetime) : \DateTime
{
$datetime = clone $datetime;
return $datetime->setTimezone(Timezone::site_timezone())->setTime(0, 0, 0)->setTimezone(Timezone::utc_timezone());
}
/**
* Return a new DateTime representing the end of the day in the users timezone
*
* @param DateTime $datetime
*
* @return DateTime
*/
private function end_of_locale_day(\DateTime $datetime) : \DateTime
{
$datetime = clone $datetime;
return $datetime->setTimezone(Timezone::site_timezone())->setTime(23, 59, 59)->setTimezone(Timezone::utc_timezone());
}
}
IAWP/Date_Range/Exact_Date_Range.php 0000644 00000002300 14760033122 0013114 0 ustar 00 set_range($start, $end, $convert_to_full_days);
}
/**
* Get a formatted label for the range
*
* @return string
*/
public function label() : string
{
$formatted_start = \IAWPSCOPED\iawp()->date_i18n(\get_option('date_format'), $this->start);
$formatted_end = \IAWPSCOPED\iawp()->date_i18n(\get_option('date_format'), $this->end);
return $formatted_start . ' - ' . $formatted_end;
}
/**
* Get a range that covers the entirety of the plugins lifetime
*
* @return Exact_Date_Range
*/
public static function comprehensive_range() : \IAWP\Date_Range\Exact_Date_Range
{
return new \IAWP\Date_Range\Exact_Date_Range(new DateTime('1991-01-06'), new DateTime());
}
}
IAWP/Date_Range/Relative_Date_Range.php 0000644 00000022203 14760033122 0013627 0 ustar 00 relative_range_id = $relative_range_id;
}
// Call the method whose name matches the relative range id
$method_name = \strtolower($relative_range_id);
list($start, $end, $label) = $this->{$method_name}();
$this->set_range($start, $end, $convert_to_full_days);
$this->label = $label;
}
/**
* Get the id of the current range such as THIS_YEAR
*
* @return string
*/
public function relative_range_id() : string
{
return $this->relative_range_id;
}
public function label() : string
{
return $this->label;
}
private function today() : array
{
$tz = Timezone::site_timezone();
$today = new DateTime('now', $tz);
return [$today, $today, \__('Today', 'independent-analytics')];
}
private function yesterday() : array
{
$tz = Timezone::site_timezone();
$yesterday = new DateTime('-1 day', $tz);
return [$yesterday, $yesterday, \__('Yesterday', 'independent-analytics')];
}
private function last_seven() : array
{
$tz = Timezone::site_timezone();
$today = new DateTime('now', $tz);
$seven_days_ago = new DateTime('-6 days', $tz);
return [$seven_days_ago, $today, \__('Last 7 Days', 'independent-analytics')];
}
private function last_thirty() : array
{
$tz = Timezone::site_timezone();
$today = new DateTime('now', $tz);
$thirty_days_ago = new DateTime('-29 days', $tz);
return [$thirty_days_ago, $today, \__('Last 30 Days', 'independent-analytics')];
}
private function last_sixty() : array
{
$tz = Timezone::site_timezone();
$today = new DateTime('now', $tz);
$sixty_days_ago = new DateTime('-59 days', $tz);
return [$sixty_days_ago, $today, \__('Last 60 Days', 'independent-analytics')];
}
private function last_ninety() : array
{
$tz = Timezone::site_timezone();
$today = new DateTime('now', $tz);
$ninety_days_ago = new DateTime('-89 days', $tz);
return [$ninety_days_ago, $today, \__('Last 90 Days', 'independent-analytics')];
}
private function this_week() : array
{
$tz = Timezone::site_timezone();
$today = new DateTime('now', $tz);
$firstDayOfWeek = \intval(\get_option('iawp_dow'));
$currentDayOfWeek = \intval($today->format('w'));
$startOfWeekDaysAgo = $currentDayOfWeek - $firstDayOfWeek;
if ($startOfWeekDaysAgo < 0) {
$startOfWeekDaysAgo += 7;
}
$startOfWeek = new DateTime("-{$startOfWeekDaysAgo} days", $tz);
$endOfWeek = (clone $startOfWeek)->modify('+6 days');
return [$startOfWeek, $endOfWeek, \__('This Week', 'independent-analytics')];
}
private function last_week() : array
{
list($start, $end) = $this->this_week();
$startOfWeek = $start->modify('-7 days');
$endOfWeek = $end->modify('-7 days');
return [$startOfWeek, $endOfWeek, \__('Last Week', 'independent-analytics')];
}
private function this_month() : array
{
$tz = Timezone::site_timezone();
$today = new DateTime('now', $tz);
$day_of_month = \intval($today->format('d')) - 1;
$days_in_month = \intval($today->format('t')) - 1;
$start_of_month = (clone $today)->modify("-{$day_of_month} days");
$end_of_month = (clone $start_of_month)->modify("+{$days_in_month} days");
return [$start_of_month, $end_of_month, \__('This Month', 'independent-analytics')];
}
private function last_month() : array
{
list($start, $end) = $this->this_month();
$start_of_last_month = (clone $start)->modify('-1 month');
$days_in_last_month = \intval($start_of_last_month->format('t')) - 1;
$end_of_last_month = (clone $start_of_last_month)->modify("+{$days_in_last_month} days");
return [$start_of_last_month, $end_of_last_month, \__('Last Month', 'independent-analytics')];
}
private function last_three_months() : array
{
$tz = Timezone::site_timezone();
$first_of_three_months_ago = new DateTime('first day of last month', $tz);
$first_of_three_months_ago = $first_of_three_months_ago->modify('-2 months');
$last_of_last_month = new DateTime('last day of last month', $tz);
return [$first_of_three_months_ago, $last_of_last_month, \__('Last 3 Months', 'independent-analytics')];
}
private function last_six_months() : array
{
$tz = Timezone::site_timezone();
$first_of_six_months_ago = new DateTime('first day of last month', $tz);
$first_of_six_months_ago = $first_of_six_months_ago->modify('-5 months');
$last_of_last_month = new DateTime('last day of last month', $tz);
return [$first_of_six_months_ago, $last_of_last_month, \__('Last 6 Months', 'independent-analytics')];
}
private function last_twelve_months() : array
{
$tz = Timezone::site_timezone();
$first_of_twelve_months_ago = new DateTime('first day of last month', $tz);
$first_of_twelve_months_ago = $first_of_twelve_months_ago->modify('-11 months');
$last_of_last_month = new DateTime('last day of last month', $tz);
return [$first_of_twelve_months_ago, $last_of_last_month, \__('Last 12 Months', 'independent-analytics')];
}
private function this_year() : array
{
$tz = Timezone::site_timezone();
$today = new DateTime('now', $tz);
$year = \intval($today->format('Y'));
$start_of_year = (clone $today)->setDate($year, 1, 1);
$end_of_year = clone $today;
return [$start_of_year, $end_of_year, \__('This Year', 'independent-analytics')];
}
private function last_year() : array
{
$tz = Timezone::site_timezone();
$today = new DateTime('now', $tz);
$last_year = \intval($today->format('Y')) - 1;
$start_of_last_year = (clone $today)->setDate($last_year, 1, 1);
$end_of_last_year = (clone $today)->setDate($last_year, 12, 31);
return [$start_of_last_year, $end_of_last_year, \__('Last Year', 'independent-analytics')];
}
private function all_time() : array
{
$tz = Timezone::site_timezone();
$today = new DateTime('now', $tz);
return [self::beginning_of_time(), $today, \__('All Time', 'independent-analytics')];
}
/**
* Returns an array of relative ranges representing all supported ranges
*
* @return Relative_Date_Range[]
*/
public static function ranges() : array
{
return \array_map(function (string $range_id) {
return new self($range_id);
}, self::VALID_RELATIVE_RANGE_IDS);
}
/**
* @return string[]
*/
public static function range_ids() : array
{
return self::VALID_RELATIVE_RANGE_IDS;
}
/**
* @param string $relative_range_id
*
* @return bool
*/
public static function is_valid_range(string $relative_range_id) : bool
{
if (\in_array($relative_range_id, self::VALID_RELATIVE_RANGE_IDS)) {
return \true;
}
return \false;
}
public static function beginning_of_time() : DateTime
{
$option_value = \get_option('iawp_beginning_of_time');
if ($option_value !== \false && $option_value !== '') {
try {
$date = new DateTime($option_value, Timezone::utc_timezone());
$date->setTimezone(Timezone::site_timezone());
return $date;
} catch (\Throwable $e) {
return new DateTime('now', Timezone::site_timezone());
}
}
$views_table = Query::get_table_name(Query::VIEWS);
$first_view_at = Illuminate_Builder::new()->select('viewed_at')->from($views_table, 'views')->orderBy('viewed_at')->value('viewed_at');
if (\is_null($first_view_at)) {
return new DateTime('now', Timezone::site_timezone());
}
try {
$date = new DateTime($first_view_at, Timezone::utc_timezone());
\update_option('iawp_beginning_of_time', $first_view_at);
return $date;
} catch (\Throwable $e) {
return new DateTime('now', Timezone::site_timezone());
}
}
}
IAWP/Ecommerce/SureCart_Event_Sync_Job.php 0000644 00000004344 14760033122 0014376 0 ustar 00 is_surecart_support_enabled();
}
public function handle() : void
{
$last_seen_event_at = \get_option('iawp_last_seen_surecart_event_at', \time());
$events = new Collection();
$page = 1;
while (\true) {
// If an event is older than the last one we've seen, then we have all the events we need
if ($events->isNotEmpty() && $events->last()->created_at < $last_seen_event_at) {
break;
}
if (!\class_exists('\\SureCart\\Models\\Event')) {
break;
}
$page_of_events = \SureCart\Models\Event::where(['type' => ['refund.succeeded', 'purchase.created'], 'limit' => 100, 'page' => $page])->get();
if (\is_wp_error($page_of_events) || \count($page_of_events) === 0) {
break;
}
$events = $events->concat($page_of_events);
$page = $page + 1;
}
if ($events->isNotEmpty()) {
\update_option('iawp_last_seen_surecart_event_at', $events->first()->created_at);
}
$events = $events->filter(function ($event) use($last_seen_event_at) {
return $event->created_at > $last_seen_event_at;
});
$events->filter(function ($event) {
return $event->type === 'refund.succeeded';
})->map(function ($event) {
return $event->data->object->charge;
})->unique()->each(function ($charge_id) {
\IAWP\Ecommerce\SureCart_Order::update_order_using_charge_id($charge_id);
});
$events->filter(function ($event) {
return $event->type === 'purchase.created';
})->map(function ($event) {
return $event->data->object->initial_order;
})->unique()->each(function ($order_id) {
\IAWP\Ecommerce\SureCart_Order::update_order_using_order_id($order_id);
});
}
}
IAWP/Ecommerce/SureCart_Order.php 0000644 00000007174 14760033122 0012606 0 ustar 00 find($order_id);
$this->order_id = $order_id;
$this->status = $order->checkout->status;
$this->total = $order->checkout->total_amount;
$this->total_refunded = \absint($order->checkout->refunded_amount);
$this->total_refunds = 0;
if ($this->total_refunded > 0) {
$refunds = \SureCart\Models\Refund::where(['charge_ids' => (new Collection($order->checkout->charges->data))->pluck('id')->toArray()])->get();
$this->total_refunds = \count($refunds);
}
$this->is_discounted = \absint($order->checkout->discount_amount) > 0 || \absint($order->checkout->total_savings_amount) > 0;
}
public function insert() : void
{
$visitor = Visitor::fetch_current_visitor();
if (!$visitor->has_recorded_session()) {
return;
}
$orders_table = Query::get_table_name(Query::ORDERS);
Illuminate_Builder::new()->from($orders_table)->insertOrIgnore(['is_included_in_analytics' => $this->status === 'paid', 'surecart_order_id' => $this->order_id, 'surecart_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
{
$orders_table = Query::get_table_name(Query::ORDERS);
Illuminate_Builder::new()->from($orders_table)->where('surecart_order_id', '=', $this->order_id)->update(['is_included_in_analytics' => $this->status === 'paid', 'surecart_order_status' => $this->status, 'total' => $this->total, 'total_refunded' => $this->total_refunded, 'total_refunds' => $this->total_refunds, 'is_discounted' => $this->is_discounted]);
}
public static function register_hooks()
{
\add_action('surecart/purchase_created', function ($purchase) {
try {
$surecart_order = new self($purchase->getAttribute('initial_order'));
$surecart_order->insert();
} catch (\Throwable $e) {
\error_log('Independent Analytics was unable to track the analytics for a SureCart order. Please report this error to Independent Analytics. The error message is below.');
\error_log($e->getMessage());
}
}, 10, 1);
}
public static function update_order_using_charge_id(string $charge_id) : void
{
if (!\class_exists('\\SureCart\\Models\\Charge')) {
return;
}
$charge = \SureCart\Models\Charge::with(['checkout'])->find($charge_id);
$surecart_order = new self($charge->checkout->order);
$surecart_order->update();
}
public static function update_order_using_order_id(string $order_id) : void
{
$surecart_order = new self($order_id);
$surecart_order->update();
}
}
IAWP/Ecommerce/SureCart_Store.php 0000644 00000001737 14760033122 0012626 0 ustar 00 currency);
}
} catch (\Throwable $e) {
\update_option('iawp_surecart_currency_code', 'usd');
}
}
}
public static function get_currency_code() : string
{
$currency_code = \get_option('iawp_surecart_currency_code', 'usd');
if (!\class_exists('\\SureCart\\Support\\Currency')) {
return 'usd';
}
if (!\array_key_exists($currency_code, \SureCart\Support\Currency::getSupportedCurrencies())) {
$currency_code = 'usd';
}
return $currency_code;
}
}
IAWP/Ecommerce/WooCommerce_Order.php 0000644 00000016230 14760033122 0013266 0 ustar 00 get_total() * 100));
// Total based on order currency, not shop currency
$total_refunded = \intval(\round(\floatval($order->get_total_refunded()) * 100));
// Refund amount based on order currency, not shop currency
// Aelia Currency Switcher
$aelia_exchange_rate = $order->get_meta('_base_currency_exchange_rate');
if (\is_numeric($aelia_exchange_rate)) {
// Exchange rate is from order currency to shop currency (multiply)
$total = \intval(\round($total * \floatval($aelia_exchange_rate)));
$total_refunded = \intval(\round($total_refunded * \floatval($aelia_exchange_rate)));
}
// WPML
$wpml_exchange_rate = $this->wpml_exchange_rate($order->get_currency());
if (\is_float($wpml_exchange_rate)) {
// Exchange rate is from shop currency to order currency (divide)
$total = \intval(\round($total / $wpml_exchange_rate));
$total_refunded = \intval(\round($total_refunded / $wpml_exchange_rate));
}
// Price Based on Country for WooCommerce
$wcpbc_exchange_rate = $order->get_meta('_wcpbc_base_exchange_rate');
if (\is_numeric($wcpbc_exchange_rate)) {
// Exchange rate is from order currency to shop currency (multiply)
$total = \intval(\round($total * \floatval($wcpbc_exchange_rate)));
$total_refunded = \intval(\round($total_refunded * \floatval($wcpbc_exchange_rate)));
}
$this->order_id = $order_id;
$this->status = $order->get_status();
$this->total = $total;
$this->total_refunded = $total_refunded;
$this->total_refunds = \count($order->get_refunds());
$this->is_discounted = $this->is_discounted_order($order);
}
public function insert() : void
{
$visitor = Visitor::fetch_current_visitor();
if (!$visitor->has_recorded_session()) {
return;
}
$orders_table = Query::get_table_name(Query::ORDERS);
Illuminate_Builder::new()->from($orders_table)->insertOrIgnore(['is_included_in_analytics' => (new \IAWP\Ecommerce\WooCommerce_Status_Manager())->is_tracked_status($this->status), 'woocommerce_order_id' => $this->order_id, 'woocommerce_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
{
$orders_table = Query::get_table_name(Query::ORDERS);
Illuminate_Builder::new()->from($orders_table)->where('woocommerce_order_id', '=', $this->order_id)->update(['is_included_in_analytics' => (new \IAWP\Ecommerce\WooCommerce_Status_Manager())->is_tracked_status($this->status), 'woocommerce_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_discounted_order($order) : bool
{
if ($order->get_total_discount() > 0) {
return \true;
}
foreach ($order->get_items() as $item) {
if ($item->get_product()->is_on_sale()) {
return \true;
}
}
return \false;
}
private function wpml_exchange_rate(string $currency_code) : ?float
{
if (!\is_plugin_active('woocommerce-multilingual/wpml-woocommerce.php')) {
return null;
}
$wcml_options = \get_option('_wcml_settings');
if (!\is_array($wcml_options)) {
return null;
}
if (!\array_key_exists('currency_options', $wcml_options)) {
return null;
}
if (!\is_array($wcml_options['currency_options']) || !\array_key_exists($currency_code, $wcml_options['currency_options'])) {
return null;
}
if (!\is_array($wcml_options['currency_options'][$currency_code]) || !\array_key_exists('rate', $wcml_options['currency_options'][$currency_code])) {
return null;
}
$exchange_rate = \floatval($wcml_options['currency_options'][$currency_code]['rate']);
// Was there an error parsing value as float?
if ($exchange_rate === 0.0) {
return null;
}
return $exchange_rate;
}
public static function register_hooks()
{
// Required for block checkout
\add_action('woocommerce_store_api_checkout_order_processed', function ($order) {
try {
$woocommerce_order = new self($order->get_id());
$woocommerce_order->insert();
} catch (\Throwable $e) {
\error_log('Independent Analytics was unable to track the analytics for a WooCommerce order. Please report this error to Independent Analytics. The error message is below.');
\error_log($e->getMessage());
}
});
// Required for shortcode checkout
\add_action('woocommerce_checkout_order_created', function ($order) {
try {
$woocommerce_order = new self($order->get_id());
$woocommerce_order->insert();
} catch (\Throwable $e) {
\error_log('Independent Analytics was unable to track the analytics for a WooCommerce order. Please report this error to Independent Analytics. The error message is below.');
\error_log($e->getMessage());
}
});
\add_action('woocommerce_order_status_changed', function ($order_id) {
try {
$woocommerce_order = new self($order_id);
$woocommerce_order->update();
} catch (\Throwable $e) {
\error_log('Independent Analytics was unable to track the analytics for a WooCommerce order. Please report this error to Independent Analytics. The error message is below.');
\error_log($e->getMessage());
}
});
// Captures a partial refund, something that woocommerce_order_status_changed will not do
\add_action('woocommerce_order_refunded', function ($order_id) {
try {
$woocommerce_order = new self($order_id);
$woocommerce_order->update();
} catch (\Throwable $e) {
\error_log('Independent Analytics was unable to track the analytics for a WooCommerce order. Please report this error to Independent Analytics. The error message is below.');
\error_log($e->getMessage());
}
});
}
}
IAWP/Ecommerce/WooCommerce_Referrer_Meta_Box.php 0000644 00000014614 14760033122 0015551 0 ustar 00 is_woocommerce_support_enabled()) {
return;
}
$order = $post_or_order_object instanceof \WP_Post ? wc_get_order($post_or_order_object->ID) : $post_or_order_object;
if ($order === \false) {
return;
}
$woocommerce_screen = \class_exists('\\Automattic\\WooCommerce\\Internal\\DataStores\\Orders\\CustomOrdersTableController') && wc_get_container()->get(CustomOrdersTableController::class)->custom_orders_table_usage_is_enabled() ? wc_get_page_screen_id('shop-order') : 'shop_order';
$current_screen = \get_current_screen();
if (\is_null($current_screen) || $current_screen->id !== $woocommerce_screen) {
return;
}
$referrer_row = $this->get_referrer_for($order->get_id());
$this->referrer = \is_object($referrer_row) ? new Referrer($referrer_row) : null;
$campaign_row = $this->get_campaign_for($order->get_id());
$this->campaign = \is_object($campaign_row) ? new Campaign($campaign_row) : null;
if (\is_null($this->referrer) && \is_null($this->campaign)) {
return;
}
\add_meta_box('iawp-wc-referrer-source', \esc_html__('Order Referrer', 'independent-analytics'), [$this, 'render_meta_box_content'], $woocommerce_screen, 'side');
}
public function render_meta_box_content($post_or_order_object) : void
{
$order = $post_or_order_object instanceof \WP_Post ? wc_get_order($post_or_order_object->ID) : $post_or_order_object;
if (!\is_null($this->referrer)) {
if ($this->referrer->has_link()) {
$content = '' . Security::string($this->referrer->referrer()) . ' ';
} else {
$content = Security::string($this->referrer->referrer());
}
echo '' . \esc_html__('Referrer:', 'independent-analytics') . ' ' . $content . '
';
}
if (!\is_null($this->campaign)) {
if (\is_string($this->campaign->utm_source())) {
echo '' . \__('Campaign Source', 'independent-analytics') . ': ' . Security::string($this->campaign->utm_source()) . '
';
}
if (\is_string($this->campaign->utm_medium())) {
echo '' . \__('Campaign Medium', 'independent-analytics') . ': ' . Security::string($this->campaign->utm_medium()) . '
';
}
if (\is_string($this->campaign->utm_campaign())) {
echo '' . \__('Campaign Name', 'independent-analytics') . ': ' . Security::string($this->campaign->utm_campaign()) . '
';
}
if (\is_string($this->campaign->utm_term())) {
echo '' . \__('Campaign Term', 'independent-analytics') . ': ' . Security::string($this->campaign->utm_term()) . '
';
}
if (\is_string($this->campaign->utm_content())) {
echo '' . \__('Campaign Content', 'independent-analytics') . ': ' . Security::string($this->campaign->utm_content()) . '
';
}
}
}
private function get_campaign_for($order_id) : ?object
{
$orders_table = Query::get_table_name(Query::ORDERS);
$campaigns_table = Query::get_table_name(Query::CAMPAIGNS);
$views_table = Query::get_table_name(Query::VIEWS);
$sessions_table = Query::get_table_name(Query::SESSIONS);
$campaign_query = Illuminate_Builder::new()->select("landing_page_title AS title", "utm_source", "utm_medium", "utm_campaign", "utm_term", "utm_content")->from($orders_table, 'orders')->join("{$views_table} AS views", function (JoinClause $join) {
$join->on('views.id', '=', 'orders.view_id');
})->join("{$sessions_table} AS sessions", function (JoinClause $join) {
$join->on('sessions.session_id', '=', 'views.session_id');
})->join("{$campaigns_table} AS campaigns", function (JoinClause $join) {
$join->on('sessions.campaign_id', '=', 'campaigns.campaign_id');
})->where('orders.woocommerce_order_id', '=', $order_id);
$record = $campaign_query->get()->first();
return $record;
}
private function get_referrer_for($order_id) : ?object
{
$orders_table = Query::get_table_name(Query::ORDERS);
$views_table = Query::get_table_name(Query::VIEWS);
$sessions_table = Query::get_table_name(Query::SESSIONS);
$referrer_table = Query::get_table_name(Query::REFERRERS);
$referrer_query = Illuminate_Builder::new()->select('sessions.referrer_id', 'referrer', 'type AS referrer_type', 'domain')->from($orders_table, 'orders')->join("{$views_table} AS views", function (JoinClause $join) {
$join->on('views.id', '=', 'orders.view_id');
})->join("{$sessions_table} AS sessions", function (JoinClause $join) {
$join->on('sessions.session_id', '=', 'views.session_id');
})->join("{$referrer_table} AS referrers", function (JoinClause $join) {
$join->on('referrers.id', '=', 'sessions.referrer_id');
})->where('orders.woocommerce_order_id', '=', $order_id);
$record = $referrer_query->get()->first();
return $record;
}
}
IAWP/Ecommerce/WooCommerce_Status_Manager.php 0000644 00000006743 14760033122 0015140 0 ustar 00 $value) {
if (Str::startsWith($key, 'wc-')) {
$key = Str::replaceFirst('wc-', '', $key);
}
$statuses[] = ['id' => \strval($key), 'name' => \strval($value), 'is_tracked' => $this->is_tracked_status($key)];
}
return $statuses;
}
public function is_valid_status(string $status_id) : bool
{
$statuses = $this->get_statuses();
foreach ($statuses as $status) {
if ($status['id'] === $status_id) {
return \true;
}
}
return \false;
}
/**
* Use the currently configured statuses to recalculate if a given order in `wp_orders`
* should be included in the analytics or not.
*
* @return void
*/
public function update_order_records_based_on_tracked_statuses() : void
{
$orders_table = Query::get_table_name(Query::ORDERS);
Illuminate_Builder::new()->from($orders_table)->whereNotIn('woocommerce_order_status', $this->get_tracked_status_ids())->update(['is_included_in_analytics' => \false]);
Illuminate_Builder::new()->from($orders_table)->whereIn('woocommerce_order_status', $this->get_tracked_status_ids())->update(['is_included_in_analytics' => \true]);
}
public function set_tracked_statuses(array $tracked_status_ids) : void
{
$filtered_statuses = \array_filter($tracked_status_ids, function ($status_id) {
return $this->is_valid_status($status_id);
});
\update_option('iawp_tracked_woocommerce_status_ids', $filtered_statuses);
}
public function is_tracked_status(string $status_id) : bool
{
return \in_array($status_id, $this->get_tracked_status_ids());
}
public function reset_tracked_statuses() : void
{
\delete_option('iawp_tracked_woocommerce_status_ids');
}
/**
* @return string[]
*/
private function get_tracked_status_ids() : array
{
$status_ids = \IAWPSCOPED\iawp()->get_option('iawp_tracked_woocommerce_status_ids', []);
$prefixed_statuses = [];
if (!\is_array($status_ids) || \count($status_ids) === 0) {
$status_ids = self::$default_status_to_track;
}
// These need to be prefixed, because you never know what you're going to get back from WooCommerce
foreach ($status_ids as $status_id) {
$prefixed_statuses[] = 'wc-' . $status_id;
}
return \array_merge($status_ids, $prefixed_statuses);
}
}
IAWP/Email_Reports/Email_Chart.php 0000644 00000004067 14760033122 0012737 0 ustar 00 statistics = $statistics;
$this->views = self::views();
$this->most_views = self::most_views();
$this->y_labels = self::y_labels();
$this->x_labels = self::x_labels();
}
public function views()
{
return \array_map(function ($day) {
return $day[1];
}, $this->statistics->get_statistic('views')->statistic_over_time());
}
public function most_views()
{
return \round(\max($this->views) * 1.1);
}
public function y_labels()
{
return [Number::abbreviate($this->most_views), Number::abbreviate($this->most_views / 2), 0];
}
public function x_labels()
{
$interval = \IAWPSCOPED\iawp()->get_option('iawp_email_report_interval', 'monthly');
$format = 'M j';
if ($interval == 'weekly') {
$format = 'D';
} elseif ($interval == 'daily') {
$format = \IAWPSCOPED\iawp()->get_option('time_format', 'g:i a');
}
$all_x_labels = \array_map(function ($day) use($format) {
return $day[0]->format($format);
}, $this->statistics->get_statistic('views')->statistic_over_time());
$x_labels = [];
if ($interval == 'monthly') {
for ($x = 0; $x < \count($all_x_labels); $x++) {
if (($x + 5) % 5 == 0) {
$x_labels[] = $all_x_labels[$x];
}
}
} elseif ($interval == 'weekly') {
$x_labels = $all_x_labels;
} elseif ($interval == 'daily') {
for ($x = 0; $x < \count($all_x_labels); $x++) {
if (($x + 6) % 6 == 0) {
$x_labels[] = $all_x_labels[$x];
}
}
}
return $x_labels;
}
}
IAWP/Email_Reports/Email_Reports.php 0000644 00000022634 14760033122 0013334 0 ustar 00 unschedule();
if (empty(\IAWPSCOPED\iawp()->get_option('iawp_email_report_email_addresses', []))) {
return;
}
\wp_schedule_event($this->interval()->next_interval_start()->getTimestamp(), $this->interval()->id(), 'iawp_send_email_report');
}
public function unschedule()
{
$timestamp = \wp_next_scheduled('iawp_send_email_report');
if (\is_int($timestamp)) {
\wp_unschedule_event($timestamp, 'iawp_send_email_report');
}
}
/**
* For testing purposes, get the
*
* @return DateTime
*/
public function next_event_scheduled_at() : ?DateTime
{
if (!\wp_next_scheduled('iawp_send_email_report')) {
return null;
}
$date = new DateTime();
$date->setTimezone(Timezone::site_timezone());
$date->setTimestamp(\wp_next_scheduled('iawp_send_email_report'));
return $date;
}
public function next_email_at_for_humans() : string
{
if (!\wp_next_scheduled('iawp_send_email_report')) {
return \esc_html__('There is no email scheduled.', 'independent-analytics');
}
$date = $this->interval()->next_interval_start();
$day = $date->format(\get_option('date_format'));
$time = $date->format(\IAWPSCOPED\iawp()->get_option('time_format', 'g:i a'));
return \sprintf(\__('Next email scheduled for %s at %s.', 'independent-analytics'), '' . $day . ' ', '' . $time . ' ');
}
public function maybe_reschedule()
{
if (!\wp_next_scheduled('iawp_send_email_report')) {
return;
}
if (\IAWPSCOPED\iawp()->get_option('iawp_email_report_interval', 'monthly') != 'weekly') {
return;
}
$this->schedule();
}
public function send_email_report(bool $is_test_email = \false)
{
// This code was added to fix an issue with monthly email reports. When you set up a monthly
// email report, the first email will always be correct because we pick the exact timestamp
// we want to send it. The issue is with the recurring interval. It's backed by MONTH_IN_SECONDS
// which is a fixed constant. Months have a varying number of seconds so this caused slight
// differences in when subsequent monthly email reports were sent. The code below fixes this by
// rescheduling monthly email reports as they're sent. That allows us to pinpoint the exact
// correct next time to run it, while still falling back to the inaccurate monthly interval
// should a given email never send for some reason.
if ($this->interval()->id() === 'monthly') {
$this->schedule();
}
$to = \IAWPSCOPED\iawp()->get_option('iawp_email_report_email_addresses', []);
if (empty($to)) {
return;
}
$from = \IAWPSCOPED\iawp()->get_option('iawp_email_report_from_address', \get_option('admin_email'));
$body = $this->get_email_body();
$headers[] = 'From: ' . \get_bloginfo('name') . ' <' . \esc_attr($from) . '>';
$headers[] = 'Content-Type: text/html; charset=UTF-8';
return \wp_mail($to, $this->subject_line($is_test_email), $body, $headers);
}
public function get_email_body($colors = '')
{
$statistics = new Page_Statistics($this->interval()->date_range());
$quick_stats = \array_values(\array_filter($statistics->get_statistics(), function (Statistic $statistics) {
return $statistics->is_visible() && $statistics->is_group_plugin_enabled();
}));
$chart = new \IAWP\Email_Reports\Email_Chart($statistics);
$colors = $colors == '' ? \IAWPSCOPED\iawp()->get_option('iawp_email_report_colors', ['#5123a0', '#fafafa', '#3a1e6b', '#fafafa', '#5123a0', '#a985e6', '#ece9f2', '#f7f5fa', '#ece9f2', '#dedae6']) : \explode(',', $colors);
return \IAWPSCOPED\iawp_blade()->run('email.email', [
'site_title' => \get_bloginfo('name'),
'site_url' => URL::new(\get_site_url())->get_domain(),
'date' => $this->interval()->report_time_period_for_humans(),
// The value that needs to change
'stats' => $quick_stats,
'top_ten' => $this->get_top_ten(),
'chart_views' => $chart->views,
'chart_title' => $this->interval()->chart_title(),
'most_views' => $chart->most_views,
'y_labels' => $chart->y_labels,
'x_labels' => $chart->x_labels,
'colors' => $colors,
]);
}
private function subject_line(bool $is_test_email) : string
{
$parts = [];
if ($is_test_email) {
$parts[] = \__('[Test]', 'independent-analytics');
}
$parts[] = \__('Analytics Report for', 'independent-analytics');
$parts[] = \get_bloginfo('name');
$parts[] = '[' . $this->interval()->report_time_period_for_humans() . ']';
return \esc_html(\implode(' ', $parts));
}
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'];
$top_ten = [];
$sort_configuration = new Sort_Configuration('views', 'desc');
$title = '';
foreach ($queries as $type => $title) {
if ($type === 'pages') {
$query = new Pages($date_range, 10, null, $sort_configuration);
$title = \esc_html__('Pages', 'independent-analytics');
} elseif ($type === 'referrers') {
$query = new Referrers($date_range, 10, null, $sort_configuration);
$title = \esc_html__('Referrers', 'independent-analytics');
} elseif ($type === 'countries') {
$query = new Countries($date_range, 10, null, $sort_configuration);
$title = \esc_html__('Countries', 'independent-analytics');
} elseif ($type === 'devices') {
$query = new Device_Types($date_range, 10, null, $sort_configuration);
$title = \esc_html__('Devices', 'independent-analytics');
} elseif ($type === 'campaigns') {
$query = new Campaigns($date_range, 10, null, $sort_configuration);
$title = \esc_html__('Campaigns', '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');
} elseif ($type === 'exit_pages') {
$query = new Pages($date_range, 10, null, new Sort_Configuration('exits', 'desc'));
$title = \esc_html__('Exit Pages', 'independent-analytics');
} else {
continue;
}
$rows = \array_map(function ($row, $index) use($type) {
if ($type == 'referrers') {
$edited_title = $row->referrer();
} elseif ($type == 'countries') {
$edited_title = $row->country();
} elseif ($type == 'devices') {
$edited_title = $row->device_type();
} elseif ($type == 'campaigns') {
$edited_title = $row->utm_campaign();
} 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') {
$metric = 'entrances';
} elseif ($type == 'exit_pages') {
$metric = 'exits';
}
return ['title' => $edited_title, 'views' => $row->{$metric}()];
}, $query->rows(), \array_keys($query->rows()));
if (\count($rows) == 0) {
continue;
}
$top_ten[$type] = ['title' => $title, 'rows' => $rows];
}
return $top_ten;
}
}
IAWP/Email_Reports/Interval.php 0000644 00000004630 14760033122 0012347 0 ustar 00 id = $attributes['id'];
$this->relative_date_range_id = $attributes['relative_date_range_id'];
$this->datetime_prefix = $attributes['datetime_prefix'] ?? '';
$this->datetime_format_pattern = $attributes['datetime_format_pattern'];
$this->chart_title = $attributes['chart_title'];
}
public function id() : string
{
return $this->id;
}
public function report_time_period_for_humans() : string
{
$prefix = $this->datetime_prefix;
if (\strlen($prefix) > 0 && !String_Util::str_ends_with($prefix, ' ')) {
$prefix .= ' ';
}
$start = $this->date_range()->start()->setTimezone(Timezone::site_timezone());
$formatted_date = Carbon::parse($start)->translatedFormat($this->datetime_format_pattern);
return $prefix . $formatted_date;
}
public function chart_title() : string
{
return $this->chart_title;
}
public function next_interval_start() : DateTime
{
$start = $this->current_date_range()->next_period()->start();
$delivery_hour = \intval(\IAWPSCOPED\iawp()->get_option('iawp_email_report_time', 9));
$start->setTimezone(Timezone::site_timezone());
$start->setTime($delivery_hour, 0, 0);
return $start;
}
/**
* This is the date range that the email report covers, which is the previous period, not the
* current period.
*
* @return Date_Range
*/
public function date_range() : Date_Range
{
// This exception is necessary because in Date_Range, range_sizes_in_days doesn't take the
// months length into account
if ($this->id === 'monthly') {
return new Relative_Date_Range('LAST_MONTH');
}
return $this->current_date_range()->previous_period();
}
private function current_date_range() : Relative_Date_Range
{
return new Relative_Date_Range($this->relative_date_range_id);
}
}
IAWP/Email_Reports/Interval_Factory.php 0000644 00000002735 14760033122 0014042 0 ustar 00 'daily', 'relative_date_range_id' => 'TODAY', 'datetime_format_pattern' => 'l, M jS', 'chart_title' => \__('Hourly Views', 'independent-analytics')]);
}
public static function weekly() : \IAWP\Email_Reports\Interval
{
return new \IAWP\Email_Reports\Interval(['id' => 'weekly', 'relative_date_range_id' => 'THIS_WEEK', 'datetime_prefix' => \__('Week of', 'independent-analytics'), 'datetime_format_pattern' => 'l, M jS', 'chart_title' => \__('Daily Views', 'independent-analytics')]);
}
public static function monthly() : \IAWP\Email_Reports\Interval
{
return new \IAWP\Email_Reports\Interval(['id' => 'monthly', 'relative_date_range_id' => 'THIS_MONTH', 'datetime_format_pattern' => 'F Y', 'chart_title' => \__('Daily Views', 'independent-analytics')]);
}
}
IAWP/Filter_Lists/Author_Filter_List.php 0000644 00000001217 14760033122 0014161 0 ustar 00 roles as $role_name => $role_obj) {
if ($role_obj['capabilities']['edit_posts'] ?? \false) {
$roles_that_can_edit_posts[] = $role_name;
}
}
$authors = \get_users(['role__in' => $roles_that_can_edit_posts]);
return \array_map(function ($author) {
return [$author->ID, $author->display_name];
}, $authors);
}
}
IAWP/Filter_Lists/Category_Filter_List.php 0000644 00000000517 14760033122 0014476 0 ustar 00 term_id, $category->name];
}, \get_categories());
}
}
IAWP/Filter_Lists/Device_Browser_Filter_List.php 0000644 00000001140 14760033122 0015614 0 ustar 00 from($device_browsers_table)->select('device_browser_id', 'device_browser')->get()->all();
return \array_map(function ($record) {
return [$record->device_browser_id, $record->device_browser];
}, $records);
}
}
IAWP/Filter_Lists/Device_OS_Filter_List.php 0000644 00000001070 14760033122 0014514 0 ustar 00 from($device_oss_table)->select('device_os_id', 'device_os')->get()->all();
return \array_map(function ($record) {
return [$record->device_os_id, $record->device_os];
}, $records);
}
}
IAWP/Filter_Lists/Device_Type_Filter_List.php 0000644 00000001110 14760033122 0015107 0 ustar 00 from($device_types_table)->select('device_type_id', 'device_type')->get()->all();
return \array_map(function ($record) {
return [$record->device_type_id, $record->device_type];
}, $records);
}
}
IAWP/Filter_Lists/Filter_List_Trait.php 0000644 00000001245 14760033122 0014003 0 ustar 00 from(Tables::link_rules())->select('link_rule_id', 'name')->get()->all();
return \array_map(function ($record) {
return [$record->link_rule_id, $record->name];
}, $records);
}
}
IAWP/Filter_Lists/Page_Type_Filter_List.php 0000644 00000003606 14760033122 0014600 0 ustar 00 \true, '_builtin' => \false]) as $custom_type) {
$options[] = [$custom_type, \get_post_type_object($custom_type)->labels->singular_name];
}
$options[] = ['category', \esc_html__('Category', 'independent-analytics')];
$options[] = ['post_tag', \esc_html__('Tag', 'independent-analytics')];
foreach (\get_taxonomies(['public' => \true, '_builtin' => \false]) as $taxonomy) {
$label = \get_taxonomy_labels(\get_taxonomy($taxonomy))->singular_name;
/**
* WooCommerce category and tag taxonomies have the same singular name as WordPress
* category and tag taxonomies, so use the name here instead
*/
if (\in_array($taxonomy, ['product_cat', 'product_tag'])) {
$label = \get_taxonomy_labels(\get_taxonomy($taxonomy))->name;
}
$options[] = [$taxonomy, \ucwords($label)];
}
$options[] = ['blog-archive', \esc_html__('Blog Home', 'independent-analytics')];
$options[] = ['author-archive', \esc_html__('Author Archive', 'independent-analytics')];
$options[] = ['date-archive', \esc_html__('Date Archive', 'independent-analytics')];
$options[] = ['search-archive', \esc_html__('Search Results', 'independent-analytics')];
$options[] = ['not-found', \esc_html__('404', 'independent-analytics')];
return $options;
}
}
IAWP/Filter_Lists/Referrer_Type_Filter_List.php 0000644 00000001003 14760033122 0015465 0 ustar 00 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']]];
/**
* @var array An key(plugin_id) value(bool) pair of plugin IDs
*/
private static $has_any_tracked_submissions_cache = [];
private function __construct(int $id, string $title, int $plugin_id)
{
$this->id = $id;
$this->title = $title;
$this->plugin_id = $plugin_id;
}
public function id() : int
{
return $this->id;
}
public function title() : string
{
return $this->title;
}
public function icon() : string
{
$lowercase = \strtolower($this->plugin_name());
$hyphenated = \str_replace(' ', '_', $lowercase);
return $hyphenated;
}
public function plugin_name() : string
{
return \IAWP\Form_Submissions\Form::find_plugin_by_id($this->plugin_id)['name'];
}
public function is_plugin_active() : bool
{
return self::static_is_plugin_active($this->plugin_id);
}
public function submissions_column() : string
{
return "form_submissions_for_{$this->id}";
}
public function conversion_rate_column() : string
{
return "form_conversion_rate_for_{$this->id}";
}
public static function has_active_form_plugin() : bool
{
return \is_array(self::get_first_active_form_plugin());
}
public static function get_first_active_form_plugin_name() : ?string
{
$active_plugin = self::get_first_active_form_plugin();
return \is_array($active_plugin) ? $active_plugin['name'] : null;
}
public static function find_form_by_column_name(string $column_name) : ?\IAWP\Form_Submissions\Form
{
$id = \intval(\preg_match('/(\\d+)\\z/', $column_name));
$forms = self::get_forms();
foreach ($forms as $form) {
if ($id === $form->id()) {
return $form;
}
}
return null;
}
/**
* @return Form[]
*/
public static function get_forms() : array
{
if (\is_array(self::$forms)) {
return self::$forms;
}
$forms_table = Query::get_table_name(Query::FORMS);
$query = Illuminate_Builder::new()->select(['form_id', 'cached_form_title', 'plugin_id'])->from($forms_table);
$forms = \array_filter(\array_map(function ($form) {
if (\is_null(self::find_plugin_by_id($form->plugin_id))) {
return null;
}
return new self($form->form_id, $form->cached_form_title, $form->plugin_id);
}, $query->get()->all()));
\usort($forms, function (\IAWP\Form_Submissions\Form $a, \IAWP\Form_Submissions\Form $b) {
// First level sort by plugin name
$plugin_name_comparison = \strcmp($a->plugin_name(), $b->plugin_name());
// If types are equal, sort by 'name'
if ($plugin_name_comparison === 0) {
return \strcmp($a->title(), $b->title());
}
return $plugin_name_comparison;
});
self::$forms = $forms;
return self::$forms;
}
private static function has_any_tracked_submissions(int $plugin_id) : bool
{
if (\array_key_exists($plugin_id, self::$has_any_tracked_submissions_cache)) {
return self::$has_any_tracked_submissions_cache[$plugin_id];
}
$forms_table = Query::get_table_name(Query::FORMS);
$form_submissions_table = Query::get_table_name(Query::FORM_SUBMISSIONS);
$has_submissions = Illuminate_Builder::new()->from($forms_table, 'forms')->join("{$form_submissions_table} AS form_submissions", 'forms.form_id', '=', 'form_submissions.form_id')->where('forms.plugin_id', '=', $plugin_id)->exists();
self::$has_any_tracked_submissions_cache[$plugin_id] = $has_submissions;
return $has_submissions;
}
private static function get_first_active_form_plugin() : ?array
{
foreach (\IAWP\Form_Submissions\Form::$plugins as $plugin) {
if (self::static_is_plugin_active($plugin['id'])) {
return $plugin;
}
}
return null;
}
private static function static_is_plugin_active(int $plugin_id) : bool
{
$plugin = \IAWP\Form_Submissions\Form::find_plugin_by_id($plugin_id);
if (!\array_key_exists('plugin_slugs', $plugin) && !\array_key_exists('theme', $plugin)) {
return self::has_any_tracked_submissions($plugin_id);
}
if (\array_key_exists('theme', $plugin)) {
if (\get_template() === $plugin['theme']) {
return \true;
}
}
if (\array_key_exists('plugin_slugs', $plugin)) {
foreach ($plugin['plugin_slugs'] as $slug) {
if (\is_plugin_active($slug)) {
return \true;
}
}
}
return \false;
}
private static function find_plugin_by_id(int $id) : ?array
{
foreach (self::$plugins as $plugin) {
if ($plugin['id'] === $id) {
return $plugin;
}
}
return null;
}
}
IAWP/Form_Submissions/Submission.php 0000644 00000002771 14760033122 0013456 0 ustar 00 plugin_id = $plugin_id;
$this->plugin_form_id = $plugin_form_id;
$this->form_title = $form_title;
}
public function record_submission() : void
{
$form_submissions_table = Query::get_table_name(Query::FORM_SUBMISSIONS);
$visitor = Visitor::fetch_current_visitor();
if (!$visitor->has_recorded_session()) {
return;
}
Illuminate_Builder::new()->from($form_submissions_table)->insert(['form_id' => $this->get_form_id(), 'session_id' => $visitor->most_recent_session_id(), 'view_id' => $visitor->most_recent_view_id(), 'initial_view_id' => $visitor->most_recent_initial_view_id(), 'created_at' => (new \DateTime())->format('Y-m-d\\TH:i:s')]);
}
private function get_form_id() : int
{
$forms_table = Query::get_table_name(Query::FORMS);
Illuminate_Builder::new()->from($forms_table)->updateOrInsert(['plugin_id' => $this->plugin_id, 'plugin_form_id' => $this->plugin_form_id], ['cached_form_title' => $this->form_title]);
return Illuminate_Builder::new()->from($forms_table)->where(['plugin_id' => $this->plugin_id, 'plugin_form_id' => $this->plugin_form_id])->value('form_id');
}
}
IAWP/Form_Submissions/Submission_Listener.php 0000644 00000031404 14760033122 0015316 0 ustar 00 id), Security::string($form->title));
$submission->record_submission();
} catch (\Throwable $e) {
}
}, 20, 3);
// WPForms
\add_action('wpforms_process_complete', function ($fields, $entry, $form_data, $entry_id) {
try {
$submission = new \IAWP\Form_Submissions\Submission(2, \intval($form_data['id']), Security::string($form_data['settings']['form_title']));
$submission->record_submission();
} catch (\Throwable $e) {
}
}, 10, 4);
// Contact Form 7
\add_action('wpcf7_mail_sent', function ($form) {
try {
$submission = new \IAWP\Form_Submissions\Submission(3, \intval($form->id()), Security::string($form->title()));
$submission->record_submission();
} catch (\Throwable $e) {
}
});
// Gravity Forms
\add_action('gform_after_submission', function ($entry, $form) {
try {
$submission = new \IAWP\Form_Submissions\Submission(4, \intval($form['id']), Security::string($form['title']));
$submission->record_submission();
} catch (\Throwable $e) {
}
}, 10, 2);
// Ninja Forms
\add_action('ninja_forms_after_submission', function ($form_data) {
try {
$submission = new \IAWP\Form_Submissions\Submission(5, \intval($form_data['form_id']), Security::string($form_data['settings']['title']));
$submission->record_submission();
} catch (\Throwable $e) {
}
}, 10, 1);
// MailOptin
\add_action('mailoptin_track_conversions', function ($lead_data) {
try {
if (!\class_exists('\\MailOptin\\Core\\Repositories\\OptinCampaignsRepository')) {
return;
}
$form_title = \MailOptin\Core\Repositories\OptinCampaignsRepository::get_optin_campaign_name($lead_data['optin_campaign_id']);
if (\is_null($form_title)) {
return;
}
$submission = new \IAWP\Form_Submissions\Submission(6, \intval($lead_data['optin_campaign_id']), Security::string($form_title));
$submission->record_submission();
} catch (\Throwable $e) {
}
}, 10, 1);
// Convert Pro
\add_action('cpro_form_submit', function ($response, $post_data) {
try {
$post_id = \intval($post_data['style_id']);
$post = \get_post($post_id);
if (\is_null($post)) {
return;
}
$submission = new \IAWP\Form_Submissions\Submission(7, \intval($post_id), Security::string($post->post_title));
$submission->record_submission();
} catch (\Throwable $e) {
}
}, 10, 2);
// Elementor
\add_action('elementor_pro/forms/new_record', function ($record) {
// Elementor form ids are generated using dechex(rand()), so hexdec is required to
// convert the id back into an integer
try {
$submission = new \IAWP\Form_Submissions\Submission(8, \intval(\hexdec($record->get_form_settings('id'))), Security::string($record->get_form_settings('form_name')));
$submission->record_submission();
} catch (\Throwable $e) {
}
}, 10, 1);
// JetFormBuilder
\add_action('jet-form-builder/form-handler/after-send', function ($form) {
try {
if (!$form->is_success) {
return;
}
$post_id = \intval($form->form_id);
$post = \get_post($post_id);
if (\is_null($post)) {
return;
}
$submission = new \IAWP\Form_Submissions\Submission(9, \intval($post_id), Security::string($post->post_title));
$submission->record_submission();
} catch (\Throwable $e) {
}
}, 10, 1);
// Formidable Forms
\add_action('frm_after_create_entry', function ($entry_id, $form_id) {
try {
if (!\class_exists('\\FrmForm')) {
return;
}
$form = \FrmForm::getOne($form_id);
$submission = new \IAWP\Form_Submissions\Submission(10, \intval($form_id), Security::string($form->name));
$submission->record_submission();
} catch (\Throwable $e) {
}
}, 10, 2);
// WS Form
\add_action('wsf_submit_post_complete', function ($submission) {
try {
$submission = new \IAWP\Form_Submissions\Submission(11, \intval($submission->form_id), Security::string($submission->form_object->label));
$submission->record_submission();
} catch (\Throwable $e) {
}
}, 10, 1);
// Amelia
\add_action('amelia_after_appointment_booking_saved', function ($booking, $reservation) {
try {
$submission = new \IAWP\Form_Submissions\Submission(12, 1, 'Amelia ' . \__('Appointment', 'independent-analytics'));
$submission->record_submission();
} catch (\Throwable $e) {
}
}, 10, 2);
// Amelia
\add_action('amelia_after_event_booking_saved', function ($booking, $reservation) {
try {
$submission = new \IAWP\Form_Submissions\Submission(12, 2, 'Amelia ' . \__('Event', 'independent-analytics'));
$submission->record_submission();
} catch (\Throwable $e) {
}
}, 10, 2);
// Bricks Builder
\add_action('bricks/form/custom_action', function ($form) {
try {
$fields = $form->get_fields();
if (!\array_key_exists('iawp-form-id', $fields) || \intval($fields['iawp-form-id']) === 0) {
return;
}
if (!\array_key_exists('iawp-form-title', $fields) || \strlen($fields['iawp-form-title']) === 0) {
return;
}
$submission = new \IAWP\Form_Submissions\Submission(13, \intval($fields['iawp-form-id']), Security::string($fields['iawp-form-title']));
$submission->record_submission();
} catch (\Throwable $e) {
}
}, 10, 1);
// ARForms Pro
\add_action('arfaftercreateentry', function ($entry_id, $form_id) {
try {
global $wpdb;
$forms_table = "{$wpdb->prefix}arf_forms";
$form_name = Illuminate_Builder::new()->from($forms_table)->where('id', $form_id)->value('name');
if (\is_null($form_name)) {
return;
}
$submission = new \IAWP\Form_Submissions\Submission(14, \intval($form_id), Security::string($form_name));
$submission->record_submission();
} catch (\Throwable $e) {
}
}, 10, 2);
// ARForms Lite
\add_action('arfliteaftercreateentry', function ($entry_id, $form_id) {
try {
global $wpdb;
$forms_table = "{$wpdb->prefix}arf_forms";
$form_name = Illuminate_Builder::new()->from($forms_table)->where('id', $form_id)->value('name');
if (\is_null($form_name)) {
return;
}
$submission = new \IAWP\Form_Submissions\Submission(14, \intval($form_id), Security::string($form_name));
$submission->record_submission();
} catch (\Throwable $e) {
}
}, 10, 2);
// Custom form submissions
\add_action('iawp_custom_form_submissions', function (int $form_id, string $form_title) {
try {
$submission = new \IAWP\Form_Submissions\Submission(15, \intval($form_id), Security::string($form_title));
$submission->record_submission();
} catch (\Throwable $e) {
}
}, 10, 2);
// Bit Form
\add_action('bitform_submit_success', function ($form_id, $entry_id, $form_data) {
try {
if (!\class_exists('\\BitCode\\BitForm\\Core\\Form\\FormManager')) {
return;
}
$form = new \BitCode\BitForm\Core\Form\FormManager($form_id);
$form_name = $form->getFormName();
$submission = new \IAWP\Form_Submissions\Submission(16, \intval($form_id), Security::string($form_name));
$submission->record_submission();
} catch (\Throwable $e) {
}
}, 10, 3);
// Forminator
\add_action('forminator_form_submit_response', function ($response, $form_id) {
if (!\function_exists('IAWPSCOPED\\forminator_get_form_name')) {
return $response;
}
$form_name = forminator_get_form_name($form_id);
try {
$submission = new \IAWP\Form_Submissions\Submission(17, \intval($form_id), Security::string($form_name));
$submission->record_submission();
} catch (\Throwable $e) {
}
return $response;
}, 10, 2);
// Forminator (ajax)
\add_action('forminator_form_ajax_submit_response', function ($response, $form_id) {
if (!\function_exists('IAWPSCOPED\\forminator_get_form_name')) {
return $response;
}
$form_name = forminator_get_form_name($form_id);
try {
$submission = new \IAWP\Form_Submissions\Submission(17, \intval($form_id), Security::string($form_name));
$submission->record_submission();
} catch (\Throwable $e) {
}
return $response;
}, 10, 2);
// Hustle
\add_action('hustle_form_after_handle_submit', function ($module_id, $response) {
try {
if ($response['success'] === \false) {
return;
}
if (!\class_exists('\\Hustle_Model')) {
return;
}
$module = \Hustle_Model::get_module($module_id);
if (\is_wp_error($module)) {
return;
}
$submission = new \IAWP\Form_Submissions\Submission(18, \intval($module_id), Security::string($module->module_name));
$submission->record_submission();
} catch (\Throwable $e) {
}
}, 10, 2);
// Avada
\add_action('fusion_form_submission_data', function ($form_data, $form_post_id) {
try {
$form_id = $form_data['submission']['form_id'];
$form_name = \get_the_title($form_post_id);
$submission = new \IAWP\Form_Submissions\Submission(19, \intval($form_id), Security::string($form_name));
$submission->record_submission();
} catch (\Throwable $e) {
}
}, 10, 2);
// WP Store Locator
\add_action('wpsl_store_search', function () {
try {
$is_autoloaded = isset($_GET['autoload']) && $_GET['autoload'];
// This hooks fires after the locations are fetched on page load. We only want to track
// manual form submissions.
if ($is_autoloaded) {
return;
}
// There's only one possible form for this plugin. This is why the form id and the forms
// name are hardcoded.
$submission = new \IAWP\Form_Submissions\Submission(20, \intval(1), Security::string('WP Store Locator'));
$submission->record_submission();
} catch (\Throwable $e) {
}
}, 10, 0);
// // Template
// add_action('iawp_some_form_callback', function () {
// try {
// return;
// $submission = new Submission(
// 0,
// intval(0), // Form id
// Security::string('') // Form title
// );
// $submission->record_submission();
// } catch (\Throwable $e) {
//
// }
// }, 10, 0);
}
}
IAWP/Interval/Interval.php 0000644 00000002441 14760033122 0011364 0 ustar 00 interval_multiplier();
if ($interval === 0) {
return \esc_html__('now', 'independent-analytics');
} else {
return '-' . $interval . ' ' . $this->short_label();
}
}, $intervals);
}
public function get_full_labels($intervals) : array
{
return \array_map(function ($interval) {
$interval = $interval * $this->interval_multiplier();
if ($interval === 1) {
return $interval . ' ' . $this->long_label_singular();
} else {
return $interval . ' ' . $this->long_label_plural();
}
}, $intervals);
}
}
IAWP/Interval/Minute_Interval.php 0000644 00000002650 14760033122 0012707 0 ustar 00 from($views_table, 'views')->selectRaw('COUNT(DISTINCT (sessions.visitor_id)) AS visitors')->selectRaw('COUNT(*) AS views')->selectRaw("ABS(CEILING(TIMESTAMPDIFF(MINUTE, '{$date_range->iso_end()}', views.viewed_at))) AS interval_ago")->leftJoin("{$sessions_table} AS sessions", function (JoinClause $join) {
$join->on('views.session_id', '=', 'sessions.session_id');
})->whereBetween('viewed_at', [$date_range->iso_start(), $date_range->iso_end()])->groupBy('interval_ago')->get()->all();
}
public function get_date_interval() : \DateInterval
{
return new \DateInterval('PT1M');
}
public function short_label() : string
{
return \__('min');
}
public function long_label_singular() : string
{
return \__('minute ago');
}
public function long_label_plural() : string
{
return \__('minutes ago');
}
public function interval_multiplier() : int
{
return 1;
}
}
IAWP/Interval/Ten_Second_Interval.php 0000644 00000002663 14760033122 0013473 0 ustar 00 from($views_table, 'views')->selectRaw('COUNT(DISTINCT (sessions.visitor_id)) AS visitors')->selectRaw('COUNT(*) AS views')->selectRaw("ABS(CEILING(TIMESTAMPDIFF(SECOND, '{$date_range->iso_end()}', views.viewed_at) / 10)) AS interval_ago")->leftJoin("{$sessions_table} AS sessions", function (JoinClause $join) {
$join->on('views.session_id', '=', 'sessions.session_id');
})->whereBetween('viewed_at', [$date_range->iso_start(), $date_range->iso_end()])->groupBy('interval_ago')->get()->all();
}
public function get_date_interval() : \DateInterval
{
return new \DateInterval('PT10S');
}
public function short_label() : string
{
return \__('sec');
}
public function long_label_singular() : string
{
return \__('second ago');
}
public function long_label_plural() : string
{
return \__('seconds ago');
}
public function interval_multiplier() : int
{
return 10;
}
}
IAWP/Menu_Bar_Stats/Menu_Bar_Stats.php 0000644 00000013001 14760033122 0013522 0 ustar 00 current_resource_identifier = Resource_Identifier::for_resource_being_edited();
} else {
$this->current_resource_identifier = Resource_Identifier::for_resource_being_viewed();
}
if (!\is_null($this->current_resource_identifier)) {
$this->views_today = self::get_views_in_date_range($today);
$this->views_yesterday = self::get_views_in_date_range($yesterday);
$this->views_last_thirty = self::get_views_in_date_range($last_thirty);
$this->views_total = self::get_views_in_date_range($all_time);
}
}
/**
* @return bool
*/
public function is_enabled() : bool
{
if (!self::is_option_enabled()) {
return \false;
}
if (\is_null($this->current_resource_identifier)) {
return \false;
}
return \true;
}
/**
* @return array[]
*/
private function get_menu_bar_items() : array
{
$today = Number_Formatter::decimal($this->views_today);
$yesterday = Number_Formatter::decimal($this->views_yesterday);
$last_thirty = Number_Formatter::decimal($this->views_last_thirty);
$total = Number_Formatter::decimal($this->views_total);
return [['id' => 'iawp_admin_bar', 'title' => ' ' . \sprintf('%d %s', $today, \esc_html__('Views', 'independent-analytics')), 'meta' => ['class' => 'iawp_admin_bar_button']], ['id' => 'iawp_admin_bar_group_title', 'title' => '' . \esc_html__('Date', 'independent-analytics') . ' ' . '' . \esc_html__('Views', 'independent-analytics') . ' ', 'parent' => 'iawp_admin_bar'], ['id' => 'iawp_admin_bar_today', 'title' => '' . \esc_html__('Today:', 'independent-analytics') . ' ' . \esc_html__($today) . ' ', 'parent' => 'iawp_admin_bar'], ['id' => 'iawp_admin_bar_yesterday', 'title' => '' . \esc_html__('Yesterday:', 'independent-analytics') . ' ' . \esc_html__($yesterday) . ' ', 'parent' => 'iawp_admin_bar'], ['id' => 'iawp_admin_bar_last_thirty', 'title' => '' . \esc_html__('Last 30 Days:', 'independent-analytics') . ' ' . \esc_html__($last_thirty) . ' ', 'parent' => 'iawp_admin_bar'], ['id' => 'iawp_admin_bar_total', 'title' => '' . \esc_html__('All Time:', 'independent-analytics') . ' ' . \esc_html__($total) . ' ', 'parent' => 'iawp_admin_bar'], ['id' => 'iawp_admin_bar_dashboard_group', 'parent' => 'iawp_admin_bar', 'is_group' => \true], ['id' => 'iawp_admin_bar_dashboard_link', 'title' => \esc_html__('Analytics Dashboard', 'independent-analytics') . ' →', 'href' => \esc_url(\IAWPSCOPED\iawp_dashboard_url()), 'parent' => 'iawp_admin_bar_dashboard_group']];
}
private function get_views_in_date_range(Date_Range $date_range) : int
{
$resources_table = Query::get_table_name(Query::RESOURCES);
$views_table = Query::get_table_name(Query::VIEWS);
$resource_statistics_query = Illuminate_Builder::new();
$resource = $this->current_resource_identifier;
$resource_statistics_query->selectRaw('COUNT(*) AS views')->from("{$resources_table} as resources")->join("{$views_table} AS views", function (JoinClause $join) {
$join->on('resources.id', '=', 'views.resource_id');
})->where('resource', '=', $resource->type())->when($resource->has_meta(), function (Builder $query) use($resource) {
$query->where($resource->meta_key(), '=', $resource->meta_value());
})->whereBetween('views.viewed_at', [$date_range->iso_start(), $date_range->iso_end()]);
$resource_statistics = $resource_statistics_query->get()->first();
return $resource_statistics->views ?? 0;
}
public static function is_option_enabled() : bool
{
return \IAWPSCOPED\iawp()->get_option('iawp_disable_admin_toolbar_analytics', \false) === \false && Capability_Manager::can_view();
}
public static function register()
{
\add_action('admin_bar_menu', function ($admin_bar) {
$menu_bar_stats = new self();
if (!$menu_bar_stats->is_enabled()) {
return;
}
foreach ($menu_bar_stats->get_menu_bar_items() as $menu_bar_item) {
$is_group = $menu_bar_item['is_group'] ?? \false;
// Should the item be registered as a group or a node?
if ($is_group) {
$admin_bar->add_group($menu_bar_item);
} else {
$admin_bar->add_node($menu_bar_item);
}
}
}, 100);
}
}
IAWP/Migrations/Creates_Reports.php 0000644 00000002176 14760033122 0013241 0 ustar 00 $value) {
$columns[] = $key;
$values_placeholders[] = "%s";
$values[] = $value;
}
$columns = \implode(', ', $columns);
$values_placeholders = \implode(', ', $values_placeholders);
return $wpdb->prepare("\n INSERT INTO {$tables::reports()}\n ({$columns})\n VALUES\n ({$values_placeholders});\n ", ...$values);
}
}
IAWP/Migrations/Migration.php 0000644 00000001315 14760033122 0012060 0 ustar 00 database_version, '<')) {
$this->migrate();
\update_option('iawp_db_version', $this->database_version, \true);
}
}
/**
* Classes that extend must define a handle method where migration work is done
*
* @return void
*/
protected abstract function migrate() : void;
}
IAWP/Migrations/Migrations.php 0000644 00000016140 14760033122 0012245 0 ustar 00 ');
}
public static function is_actually_migrating() : bool
{
return \get_option('iawp_is_migrating') === '1';
}
/**
* @return bool
*/
public static function should_migrate() : bool
{
$db_version = \get_option('iawp_db_version', '0');
$is_migrating = \get_option('iawp_is_migrating') === '1';
$is_current = \version_compare($db_version, '39', '=');
$is_outdated = !$is_current;
return $is_outdated && !$is_migrating;
}
public static function handle_migration_18_error() : void
{
$directory = \trailingslashit(\wp_upload_dir()['basedir']) . 'iawp/';
$db_version = \get_option('iawp_db_version', '0');
$is_migrating = \get_option('iawp_is_migrating', '0') === '1';
if ($db_version === '17' && $is_migrating && \is_dir($directory)) {
\update_option('iawp_db_version', '18', \true);
\update_option('iawp_is_migrating', '0', \true);
\delete_option('iawp_last_finished_migration_step');
\delete_option('iawp_migration_error');
\delete_option('iawp_migration_error_query');
try {
$directory = \trailingslashit(\wp_upload_dir()['basedir']) . 'iawp/';
Dir::delete($directory);
} catch (\Throwable $e) {
}
}
}
public static function handle_migration_22_error() : void
{
$db_version = \get_option('iawp_db_version', '0');
$is_migrating = \get_option('iawp_is_migrating', '0') === '1';
$last_finished_step = \get_option('iawp_last_finished_migration_step', '0');
$has_error = \get_option('iawp_migration_error_query', null) !== null && \get_option('iawp_migration_error', null) !== null;
$referrers_table = Query::get_table_name(Query::REFERRERS);
$has_index = Database::has_index($referrers_table, 'referrers_domain_index');
if ($db_version === '21' && $is_migrating && $last_finished_step === '0' && $has_error && !$has_index) {
\update_option('iawp_is_migrating', '0', \true);
\delete_option('iawp_last_finished_migration_step');
\delete_option('iawp_migration_error');
\delete_option('iawp_migration_error_query');
}
}
public static function handle_migration_29_error() : void
{
global $wpdb;
$db_version = \get_option('iawp_db_version', '0');
$is_migrating = \get_option('iawp_is_migrating', '0') === '1';
$last_finished_step = \get_option('iawp_last_finished_migration_step', '0');
$has_error = \get_option('iawp_migration_error_query', null) !== null && \get_option('iawp_migration_error', null) !== null;
if ($db_version === '28' && $is_migrating && $last_finished_step === '5' && $has_error) {
$sessions_table = Query::get_table_name(Query::SESSIONS);
$wpdb->query("ALTER TABLE {$sessions_table} DROP COLUMN visitor_id");
$wpdb->query("ALTER TABLE {$sessions_table} CHANGE COLUMN old_visitor_id visitor_id varchar(32)");
\delete_option('iawp_last_finished_migration_step');
\delete_option('iawp_migration_error');
\delete_option('iawp_migration_error_query');
\update_option('iawp_is_migrating', '0', \true);
}
}
/**
* @param Step_Migration[] $migrations
*
* @return bool
*/
private static function run_step_migrations(array $migrations) : bool
{
foreach ($migrations as $migration) {
$completed = $migration->migrate();
if (!$completed) {
return \false;
}
}
return \true;
}
}
IAWP/Migrations/Migration_10.php 0000644 00000011245 14760033122 0012363 0 ustar 00 query("\n UPDATE {$referrers_table} SET domain = SUBSTRING(domain, 1, 255) WHERE LENGTH(domain) > 255;\n ");
$wpdb->query("\n ALTER TABLE {$referrers_table} MODIFY COLUMN domain VARCHAR(255) NOT NULL;\n ");
$wpdb->query("\n UPDATE {$referrer_groups_table} SET name = SUBSTRING(name, 1, 255) WHERE LENGTH(name) > 255;\n ");
$wpdb->query("\n ALTER TABLE {$referrer_groups_table} MODIFY COLUMN name VARCHAR(255) NOT NULL;\n ");
$wpdb->query("\n UPDATE {$referrer_groups_table} SET domain = SUBSTRING(domain, 1, 255) WHERE LENGTH(domain) > 255;\n ");
$wpdb->query("\n ALTER TABLE {$referrer_groups_table} MODIFY COLUMN domain VARCHAR(255) NOT NULL;\n ");
$wpdb->query("\n UPDATE {$referrer_groups_table} SET domain_to_match = SUBSTRING(domain_to_match, 1, 255) WHERE LENGTH(domain_to_match) > 255;\n ");
$wpdb->query("\n ALTER TABLE {$referrer_groups_table} MODIFY COLUMN domain_to_match VARCHAR(255) NOT NULL;\n ");
$wpdb->query("\n CREATE INDEX views_viewed_at_index\n ON {$views_table} (viewed_at);\n ");
$wpdb->query("\n CREATE INDEX views_resource_id_index\n ON {$views_table} (resource_id);\n ");
$wpdb->query("\n CREATE INDEX wc_orders_view_id_index\n ON {$wc_orders_table} (view_id);\n ");
$wpdb->query("\n CREATE INDEX wc_orders_created_at_index\n ON {$wc_orders_table} (created_at);\n ");
$wpdb->query("\n CREATE INDEX sessions_created_at_index\n ON {$sessions_table} (created_at);\n ");
// Remove any duplicate referrer groups where a given domain_to_match already exists
$wpdb->query("\n DELETE referrer_groups FROM {$referrer_groups_table} AS referrer_groups\n INNER JOIN (\n SELECT\n domain_to_match,\n MIN(referrer_group_id) AS min_referrer_group_id\n FROM\n {$referrer_groups_table}\n GROUP BY\n domain_to_match\n HAVING\n COUNT(*) > 1) AS duplicates ON referrer_groups.domain_to_match = duplicates.domain_to_match\n AND referrer_groups.referrer_group_id > duplicates.min_referrer_group_id;\n ");
$wpdb->query("\n CREATE UNIQUE INDEX referrer_groups_domain_to_match_index\n ON {$referrer_groups_table} (domain_to_match);\n ");
$wpdb->query("\n UPDATE\n {$sessions_table} AS sessions\n INNER JOIN {$referrers_table} AS referrers ON sessions.referrer_id = referrers.id\n INNER JOIN (\n SELECT\n MIN(referrers.id) AS min_referrer_id,\n referrers.domain\n FROM\n {$sessions_table} AS sessions\n INNER JOIN {$referrers_table} AS referrers ON sessions.referrer_id = referrers.id\n GROUP BY\n referrers.domain) AS matcher ON referrers.domain = matcher.domain\n AND referrers.id != matcher.min_referrer_id SET sessions.referrer_id = matcher.min_referrer_id;\n ");
$wpdb->query("\n DELETE referrers FROM {$referrers_table} AS referrers\n LEFT JOIN {$sessions_table} AS sessions ON referrers.id = sessions.referrer_id\n WHERE sessions.session_id IS NULL;\n ");
$wpdb->query("\n CREATE UNIQUE INDEX referrers_domain_index\n ON {$referrers_table} (domain);\n ");
$wpdb->query("\n ALTER TABLE {$referrer_groups_table} MODIFY COLUMN type ENUM ('Search', 'Social', 'Referrer') NOT NULL;\n ");
Known_Referrers::replace_known_referrers_table();
}
}
IAWP/Migrations/Migration_11.php 0000644 00000006016 14760033122 0012364 0 ustar 00 query("\n ALTER TABLE {$views_table} ADD COLUMN next_view_id BIGINT(20) UNSIGNED, ADD COLUMN next_viewed_at DATETIME;\n ");
$wpdb->query("\n ALTER TABLE {$sessions_table} ADD COLUMN final_view_id BIGINT(20) UNSIGNED, ADD COLUMN ended_at DATETIME;\n ");
// Populate ended_at for all sessions where legacy_view=0
// Find the sessions last view and use it's viewed_at value for sessions.ended_at
$wpdb->query("\n UPDATE\n {$sessions_table} AS sessions\n INNER JOIN (\n SELECT\n sessions.session_id AS session_id,\n MAX(views.id) AS final_view_id,\n MAX(views.viewed_at) AS ended_at\n FROM\n {$sessions_table} AS sessions\n INNER JOIN {$views_table} AS views ON sessions.session_id = views.session_id\n AND sessions.initial_view_id != views.id\n WHERE\n sessions.legacy_view = FALSE\n GROUP BY\n sessions.session_id) AS query ON sessions.session_id = query.session_id\n SET sessions.ended_at = query.ended_at, sessions.final_view_id = query.final_view_id\n ");
// Populate next_viewed_at for all views where session.legacy_view=0
// Find the most previous view based on views.viewed_at that belongs to the same session
$wpdb->query("\n UPDATE\n {$views_table} AS views\n INNER JOIN (\n SELECT\n views.id AS id,\n views.viewed_at AS viewed_at,\n MIN(query.id) AS next_view_id,\n MIN(query.viewed_at) AS next_viewed_at\n FROM\n {$views_table} AS views\n INNER JOIN (\n SELECT\n *\n FROM\n {$views_table} AS views) AS query ON views.session_id = query.session_id\n AND views.id != query.id\n WHERE\n views.id < query.id\n GROUP BY\n views.id) AS query ON views.id = query.id\n SET views.next_viewed_at = query.next_viewed_at, views.next_view_id = query.next_view_id\n ");
}
}
IAWP/Migrations/Migration_12.php 0000644 00000004071 14760033122 0012364 0 ustar 00 prefix . 'wc_order_stats';
$wpdb->query("\n ALTER TABLE {$wc_orders_table} \n ADD COLUMN total DOUBLE,\n ADD COLUMN total_refunded DOUBLE,\n ADD COLUMN total_refunds SMALLINT,\n ADD COLUMN status VARCHAR(200);\n ");
if (\IAWPSCOPED\iawp()->is_woocommerce_support_enabled()) {
$wpdb->query("\n UPDATE\n {$wc_orders_table} AS wc_orders\n LEFT JOIN (\n SELECT\n wc_order_stats.order_id,\n wc_order_stats.status,\n wc_order_stats.total_sales,\n IFNULL(ABS(SUM(refunds.total_sales)), 0) AS total_refunded,\n COUNT(DISTINCT refunds.order_id) AS total_refunds\n FROM\n {$wc_orders_table} AS wc_orders\n JOIN {$wc_order_stats_table} AS wc_order_stats ON wc_orders.order_id = wc_order_stats.order_id\n LEFT JOIN {$wc_order_stats_table} AS refunds ON wc_order_stats.order_id = refunds.parent_id\n AND refunds.total_sales < 0\n GROUP BY\n wc_order_stats.order_id\n ) AS wc_order_stats ON wc_orders.order_id = wc_order_stats.order_id\n SET\n wc_orders.status = wc_order_stats.status,\n wc_orders.total = wc_order_stats.total_sales,\n wc_orders.total_refunded = wc_order_stats.total_refunded,\n wc_orders.total_refunds = wc_order_stats.total_refunds;\n ");
}
}
}
IAWP/Migrations/Migration_13.php 0000644 00000014613 14760033122 0012370 0 ustar 00 remove_city_neighborhood_data();
$this->add_index_for_visitors_table();
$this->create_cities_table();
$this->create_countries_table();
$this->add_foreign_keys_to_sessions();
$this->populate_countries();
$this->populate_cities();
$this->link_sessions_to_city_and_country();
$this->drop_visitors_table();
}
private function add_index_for_visitors_table()
{
global $wpdb;
$visitors_table = Query::get_table_name(Query::VISITORS);
$wpdb->query("\n CREATE INDEX visitors_migration_index\n ON {$visitors_table} (country_code, subdivision, city)\n ");
}
private function create_cities_table()
{
global $wpdb;
$charset_and_collation = $wpdb->get_charset_collate();
$cities_table = Query::get_table_name(Query::CITIES);
$wpdb->query("DROP TABLE IF EXISTS {$cities_table}");
$wpdb->query("\n CREATE TABLE {$cities_table} (\n city_id bigint(20) UNSIGNED AUTO_INCREMENT,\n country_id bigint(20) UNSIGNED NOT NULL,\n subdivision varchar(64) NOT NULL,\n city varchar(64) NOT NULL,\n PRIMARY KEY (city_id)\n ) {$charset_and_collation}\n ");
$wpdb->query("\n CREATE UNIQUE INDEX cities_unique_index\n ON {$cities_table} (country_id, subdivision, city)\n ");
}
private function create_countries_table()
{
global $wpdb;
$charset_and_collation = $wpdb->get_charset_collate();
$countries_table = Query::get_table_name(Query::COUNTRIES);
$wpdb->query("DROP TABLE IF EXISTS {$countries_table}");
$wpdb->query("\n CREATE TABLE {$countries_table} (\n country_id bigint(20) UNSIGNED AUTO_INCREMENT,\n country_code varchar(4) NOT NULL,\n country varchar(64) NOT NULL,\n continent varchar(16) NOT NULL,\n PRIMARY KEY (country_id)\n ) {$charset_and_collation}\n ");
$wpdb->query("\n CREATE UNIQUE INDEX countries_unique_index\n ON {$countries_table} (country_code, country, continent)\n ");
}
private function add_foreign_keys_to_sessions()
{
global $wpdb;
$sessions_table = Query::get_table_name(Query::SESSIONS);
$wpdb->query("\n ALTER TABLE {$sessions_table}\n ADD COLUMN city_id BIGINT(20) UNSIGNED,\n ADD COLUMN country_id BIGINT(20) UNSIGNED;\n ");
$wpdb->query("\n ALTER TABLE {$sessions_table}\n ADD INDEX(city_id),\n ADD INDEX(country_id);\n ");
}
private function remove_city_neighborhood_data()
{
global $wpdb;
$visitors_table = Query::get_table_name(Query::VISITORS);
$wpdb->query("\n UPDATE\n {$visitors_table}\n SET\n city = TRIM(SUBSTRING_INDEX(city, '(', 1)) \n ");
}
private function populate_countries()
{
global $wpdb;
$countries_tables = Query::get_table_name(Query::COUNTRIES);
$visitors_table = Query::get_table_name(Query::VISITORS);
$wpdb->query("\n INSERT IGNORE INTO {$countries_tables} (continent, country_code, country)\n SELECT\n continent,\n country_code,\n country\n FROM\n {$visitors_table}\n WHERE\n continent IS NOT NULL\n AND country_code IS NOT NULL\n AND country IS NOT NULL\n GROUP BY\n continent,\n country_code,\n country \n ");
}
private function populate_cities()
{
global $wpdb;
$cities_tables = Query::get_table_name(Query::CITIES);
$countries_table = Query::get_table_name(Query::COUNTRIES);
$visitors_table = Query::get_table_name(Query::VISITORS);
$wpdb->query("\n INSERT IGNORE INTO {$cities_tables} (country_id, subdivision, city)\n SELECT\n countries.country_id,\n subdivision,\n city\n FROM\n {$visitors_table} AS visitors\n LEFT JOIN {$countries_table} AS countries ON visitors.country_code = countries.country_code\n WHERE\n subdivision IS NOT NULL\n AND city IS NOT NULL\n GROUP BY\n countries.country_id,\n subdivision,\n city\n ");
}
private function link_sessions_to_city_and_country()
{
global $wpdb;
$cities_tables = Query::get_table_name(Query::CITIES);
$countries_table = Query::get_table_name(Query::COUNTRIES);
$visitors_table = Query::get_table_name(Query::VISITORS);
$sessions_table = Query::get_table_name(Query::SESSIONS);
$wpdb->query("\n UPDATE\n {$sessions_table} AS sessions\n LEFT JOIN {$visitors_table} AS visitors ON sessions.visitor_id = visitors.visitor_id\n LEFT JOIN (\n SELECT\n countries.country_id,\n cities.city_id,\n countries.country_code,\n cities.subdivision,\n cities.city\n FROM\n {$cities_tables} AS cities\n LEFT JOIN {$countries_table} AS countries ON cities.country_id = countries.country_id) AS locations ON visitors.country_code = locations.country_code\n AND visitors.subdivision = locations.subdivision\n AND visitors.city = locations.city\n SET sessions.country_id = locations.country_id, sessions.city_id = locations.city_id\n ");
}
private function drop_visitors_table()
{
global $wpdb;
$visitors_table = Query::get_table_name(Query::VISITORS);
$wpdb->query("DROP TABLE IF EXISTS {$visitors_table}");
}
}
IAWP/Migrations/Migration_14.php 0000644 00000003505 14760033122 0012367 0 ustar 00 create_devices_table();
$this->add_foreign_keys_to_sessions();
}
private function create_devices_table()
{
global $wpdb;
$charset_and_collation = $wpdb->get_charset_collate();
$devices_table = Query::get_table_name(Query::DEVICES);
$wpdb->query("DROP TABLE IF EXISTS {$devices_table}");
$wpdb->query("\n CREATE TABLE {$devices_table} (\n device_id bigint(20) UNSIGNED AUTO_INCREMENT,\n type varchar(16),\n os varchar(16),\n browser varchar(32),\n PRIMARY KEY (device_id)\n ) {$charset_and_collation}\n ");
$wpdb->query("\n CREATE UNIQUE INDEX devices_unique_index\n ON {$devices_table} (type, os, browser)\n ");
$wpdb->query("\n CREATE INDEX type_index\n ON {$devices_table} (type)\n ");
$wpdb->query("\n CREATE INDEX os_index\n ON {$devices_table} (os)\n ");
$wpdb->query("\n CREATE INDEX browser_index\n ON {$devices_table} (browser)\n ");
}
private function add_foreign_keys_to_sessions()
{
global $wpdb;
$sessions_table = Query::get_table_name(Query::SESSIONS);
$wpdb->query("\n ALTER TABLE {$sessions_table}\n ADD COLUMN device_id BIGINT(20) UNSIGNED;\n ");
$wpdb->query("\n ALTER TABLE {$sessions_table}\n ADD INDEX(device_id);\n ");
}
}
IAWP/Migrations/Migration_15.php 0000644 00000001072 14760033122 0012365 0 ustar 00 make_subdivision_nullable();
}
private function make_subdivision_nullable() : void
{
global $wpdb;
$cities_table = Query::get_table_name(Query::CITIES);
$wpdb->query("ALTER TABLE {$cities_table} MODIFY subdivision VARCHAR(64);");
}
}
IAWP/Migrations/Migration_16.php 0000644 00000002522 14760033122 0012367 0 ustar 00 create_reports_table();
}
private function create_reports_table() : void
{
global $wpdb;
$charset_collate = $wpdb->get_charset_collate();
$reports_table = Query::get_table_name(Query::REPORTS);
$wpdb->query("DROP TABLE IF EXISTS {$reports_table}");
$wpdb->query("CREATE TABLE {$reports_table} (\n report_id bigint(20) UNSIGNED AUTO_INCREMENT,\n user_created_report boolean NOT NULL DEFAULT true,\n name varchar(255) NOT NULL,\n type varchar(64) NOT NULL,\n exact_start datetime,\n exact_end datetime,\n relative_range_id varchar(64),\n sort_column varchar(64),\n sort_direction varchar(64),\n group_name varchar(64),\n chart_interval varchar(64),\n columns text,\n filters text,\n visible_datasets text,\n position int,\n PRIMARY KEY (report_id)\n ) {$charset_collate}");
}
}
IAWP/Migrations/Migration_17.php 0000644 00000007067 14760033122 0012401 0 ustar 00 add_initial_saved_reports();
}
private function add_initial_saved_reports() : void
{
Report_Finder::create_report(['name' => \esc_html__('Blog Posts', 'independent-analytics'), 'type' => 'views', 'user_created_report' => 0, 'filters' => [['inclusion' => 'include', 'column' => 'type', 'operator' => 'is', 'operand' => 'post']]]);
Report_Finder::create_report(['name' => \esc_html__('Top Landing Pages', 'independent-analytics'), 'type' => 'views', 'user_created_report' => 0, 'sort_column' => 'entrances', 'sort_direction' => 'desc', 'columns' => ['title', 'visitors', 'views', 'average_view_duration', 'bounce_rate', 'entrances', 'url', 'type']]);
Report_Finder::create_report(['name' => \esc_html__('Fastest-Growing Pages', 'independent-analytics'), 'type' => 'views', 'user_created_report' => 0, 'sort_column' => 'visitors_growth', 'sort_direction' => 'desc', 'columns' => ['title', 'visitors', 'views', 'average_view_duration', 'bounce_rate', 'visitors_growth', 'url', 'type'], 'filters' => [['inclusion' => 'exclude', 'column' => 'visitors', 'operator' => 'lesser', 'operand' => '5']]]);
Report_Finder::create_report(['name' => \esc_html__('Today', 'independent-analytics'), 'type' => 'views', 'user_created_report' => 0, 'relative_range_id' => 'TODAY']);
Report_Finder::create_report(['name' => \esc_html__('Search Engine Traffic', 'independent-analytics'), 'type' => 'referrers', 'user_created_report' => 0, 'filters' => [['inclusion' => 'include', 'column' => 'referrer_type', 'operator' => 'is', 'operand' => 'Search']]]);
Report_Finder::create_report(['name' => \esc_html__('Social Media Traffic', 'independent-analytics'), 'type' => 'referrers', 'user_created_report' => 0, 'filters' => [['inclusion' => 'include', 'column' => 'referrer_type', 'operator' => 'is', 'operand' => 'Social']]]);
Report_Finder::create_report(['name' => \esc_html__('Fastest-Growing Referrers', 'independent-analytics'), 'type' => 'referrers', 'user_created_report' => 0, 'sort_column' => 'visitors_growth', 'sort_direction' => 'desc', 'columns' => ['referrer', 'referrer_type', 'visitors', 'views', 'average_session_duration', 'bounce_rate', 'visitors_growth'], 'filters' => [['inclusion' => 'exclude', 'column' => 'visitors', 'operator' => 'lesser', 'operand' => '5']]]);
Report_Finder::create_report(['name' => \esc_html__('Last 7 Days', 'independent-analytics'), 'type' => 'referrers', 'user_created_report' => 0, 'relative_range_id' => 'LAST_SEVEN']);
Report_Finder::create_report(['name' => \esc_html__('Cities', 'independent-analytics'), 'type' => 'geo', 'group_name' => 'city', 'user_created_report' => 0]);
Report_Finder::create_report(['name' => \esc_html__('European Countries', 'independent-analytics'), 'type' => 'geo', 'user_created_report' => 0, 'filters' => [['inclusion' => 'include', 'column' => 'continent', 'operator' => 'exact', 'operand' => 'Europe']]]);
Report_Finder::create_report(['name' => \esc_html__('Browsers', 'independent-analytics'), 'type' => 'devices', 'group_name' => 'browser', 'user_created_report' => 0]);
Report_Finder::create_report(['name' => \esc_html_x('OS', 'short for operating system', 'independent-analytics'), 'type' => 'devices', 'group_name' => 'os', 'user_created_report' => 0]);
}
}
IAWP/Migrations/Migration_18.php 0000644 00000000725 14760033122 0012374 0 ustar 00 get_charset_collate();
$referrers_table = Query::get_table_name(Query::REFERRERS);
$wpdb->query("DROP TABLE IF EXISTS {$referrers_table}");
$wpdb->query("CREATE TABLE {$referrers_table} (\n id bigint(20) UNSIGNED AUTO_INCREMENT,\n url varchar(2048) NOT NULL,\n PRIMARY KEY (id)\n ) {$charset_collate}");
$views_table = Query::get_table_name(Query::VIEWS);
$wpdb->query("DROP TABLE IF EXISTS {$views_table}");
$wpdb->query("CREATE TABLE {$views_table} (\n id bigint(20) UNSIGNED AUTO_INCREMENT,\n referrer_id bigint(20) UNSIGNED,\n resource_id bigint(20) UNSIGNED NOT NULL,\n viewed_at datetime,\n PRIMARY KEY (id)\n ) {$charset_collate}");
$resources_table = Query::get_table_name(Query::RESOURCES);
$wpdb->query("DROP TABLE IF EXISTS {$resources_table}");
$wpdb->query("CREATE TABLE {$resources_table} (\n id bigint(20) UNSIGNED AUTO_INCREMENT,\n resource varchar(256) NOT NULL,\n page bigint(20) UNSIGNED NOT NULL DEFAULT 1,\n singular_id bigint(20) UNSIGNED,\n author_id bigint(20) UNSIGNED,\n date_archive varchar(256),\n search_query varchar(256),\n post_type varchar(256),\n term_id bigint(20) UNSIGNED,\n not_found_url varchar(256),\n cached_title varchar(256),\n cached_url varchar(256),\n cached_type varchar(256),\n cached_type_label varchar(256),\n cached_author_id bigint(20) UNSIGNED,\n cached_author varchar(256),\n cached_date varchar(256),\n PRIMARY KEY (id)\n ) {$charset_collate}");
}
}
IAWP/Migrations/Migration_1_6.php 0000644 00000001546 14760033122 0012533 0 ustar 00 get_charset_collate();
$views_table = Query::get_table_name(Query::VIEWS);
$wpdb->query("ALTER TABLE {$views_table} ADD visitor_id bigint(20) UNSIGNED");
$visitors_table = Query::get_table_name(Query::VISITORS);
$wpdb->query("DROP TABLE IF EXISTS {$visitors_table}");
$wpdb->query("CREATE TABLE {$visitors_table} (\n id bigint(20) UNSIGNED AUTO_INCREMENT,\n visitor_token varchar(256),\n PRIMARY KEY (id)\n ) {$charset_collate}");
}
}
IAWP/Migrations/Migration_1_8.php 0000644 00000011114 14760033122 0012525 0 ustar 00 get_charset_collate();
$views_table = Query::get_table_name(Query::VIEWS);
$resources_table = Query::get_table_name(Query::RESOURCES);
$referrer_groups_table = Query::get_table_name(Query::REFERRER_GROUPS);
$referrers_table = Query::get_table_name(Query::REFERRERS);
$known_referrers = Known_Referrers::referrers();
// Create the groups table
$wpdb->query("DROP TABLE IF EXISTS {$referrer_groups_table}");
$wpdb->query("CREATE TABLE {$referrer_groups_table} (\n referrer_group_id bigint(20) UNSIGNED AUTO_INCREMENT,\n name varchar(2048) NOT NULL,\n domain varchar(2048) NOT NULL,\n domain_to_match varchar(2048) NOT NULL,\n type ENUM ('Search', 'Social') NOT NULL,\n PRIMARY KEY (referrer_group_id)\n ) {$charset_collate}");
// Insert predefined groups
foreach ($known_referrers as $group) {
foreach ($group['domains'] as $domain) {
$wpdb->insert($referrer_groups_table, ['name' => $group['name'], 'domain' => $group['domains'][0], 'domain_to_match' => $domain, 'type' => $group['type']]);
}
}
$wpdb->query("\n ALTER TABLE {$referrers_table} CHANGE COLUMN url domain varchar(2048) NOT NULL;\n ");
$rows = $wpdb->get_results("SELECT * FROM {$referrers_table}");
foreach ($rows as $row) {
$potential_url = new URL($row->domain);
if ($potential_url->is_valid_url()) {
$wpdb->query($wpdb->prepare("UPDATE {$referrers_table} SET domain = %s WHERE id = %d", $potential_url->get_domain(), $row->id));
}
}
// add a new page field to view table
$wpdb->query("\n ALTER TABLE {$views_table} ADD COLUMN page bigint(20) UNSIGNED NOT NULL DEFAULT 1;\n ");
// move the page number to the view and set the resource_id to first of similar resources
$wpdb->query("\n UPDATE {$views_table} AS views\n INNER JOIN {$resources_table} AS resources ON views.resource_id = resources.id\n INNER JOIN\n (\n SELECT MIN({$resources_table}.id) as resource_id,\n resource,\n singular_id,\n author_id,\n date_archive,\n search_query,\n post_type,\n term_id,\n not_found_url\n FROM {$views_table}\n INNER JOIN {$resources_table}\n ON {$resources_table}.id = {$views_table}.resource_id\n GROUP BY resource, singular_id, author_id, date_archive, search_query, post_type, term_id, not_found_url\n ) AS matcher ON resources.resource = matcher.resource\n AND (resources.singular_id = matcher.singular_id OR resources.singular_id IS NULL OR matcher.singular_id IS NULL)\n AND (resources.author_id = matcher.author_id OR resources.author_id IS NULL OR matcher.author_id IS NULL)\n AND (resources.date_archive = matcher.date_archive OR resources.date_archive IS NULL OR matcher.date_archive IS NULL)\n AND (resources.search_query = matcher.search_query OR resources.search_query IS NULL OR matcher.search_query IS NULL)\n AND (resources.post_type = matcher.post_type OR resources.post_type IS NULL OR matcher.post_type IS NULL)\n AND (resources.term_id = matcher.term_id OR resources.term_id IS NULL OR matcher.term_id IS NULL)\n AND (resources.not_found_url = matcher.not_found_url OR resources.not_found_url IS NULL OR matcher.not_found_url IS NULL)\n AND resources.id != matcher.resource_id\n SET views.resource_id = matcher.resource_id, views.page = resources.page\n ");
// delete the extra duplicate resources (or don't?)
$wpdb->query("\n DELETE resources FROM {$resources_table} AS resources \n LEFT JOIN {$views_table} AS views ON resources.id = views.resource_id\n WHERE views.id IS NULL\n ");
// remove the page column from resources
$wpdb->query("\n ALTER TABLE {$resources_table} DROP COLUMN page;\n ");
}
}
IAWP/Migrations/Migration_1_9.php 0000644 00000001261 14760033122 0012530 0 ustar 00 query("\n ALTER TABLE {$visitors_table}\n ADD (\n country_code varchar(256),\n city varchar(256),\n subdivision varchar(256),\n country varchar(256),\n continent varchar(256)\n )\n ");
}
}
IAWP/Migrations/Migration_2.php 0000644 00000001030 14760033122 0012273 0 ustar 00 query("\n ALTER TABLE {$resources_table}\n ADD (\n cached_category varchar(256)\n )\n ");
}
}
IAWP/Migrations/Migration_20.php 0000644 00000002250 14760033122 0012360 0 ustar 00 query("\n ALTER TABLE {$views_table}\n ADD INDEX(session_id, viewed_at)\n ");
$wpdb->query("\n ALTER TABLE {$sessions_table}\n ADD COLUMN total_views int\n ");
$wpdb->query("\n UPDATE\n {$sessions_table} AS sessions\n LEFT JOIN (\n SELECT\n session_id,\n COUNT(*) AS view_count\n FROM\n {$views_table} AS views\n GROUP BY\n session_id\n ) AS view_counts ON sessions.session_id = view_counts.session_id\n SET sessions.total_views = COALESCE(view_counts.view_count, 0)\n ");
}
}
IAWP/Migrations/Migration_21.php 0000644 00000001171 14760033122 0012362 0 ustar 00 query("\n ALTER TABLE {$referrer_groups_table} MODIFY COLUMN type ENUM ('Search', 'Social', 'Referrer', 'Ad') NOT NULL;\n ");
Known_Referrers::replace_known_referrers_table();
}
}
IAWP/Migrations/Migration_22.php 0000644 00000013330 14760033122 0012363 0 ustar 00 remove_index(), $this->add_columns(), $this->clip_domains(), $this->reduce_domain_column_size(), $this->populate_group_data(), $this->update_non_grouped_referrers(), $this->match_session_with_new_referrers(), $this->remove_duplicates(), $this->restore_index(), $this->create_direct_referrer(), $this->link_direct_sessions_to_direct_referrer(), $this->drop_referrer_groups()];
}
private function remove_index() : ?string
{
$referrers_table = Query::get_table_name(Query::REFERRERS);
if (!Database::has_index($referrers_table, 'referrers_domain_index')) {
return null;
}
return "\n ALTER TABLE {$referrers_table} DROP INDEX referrers_domain_index;\n ";
}
private function add_columns() : string
{
$referrers_table = Query::get_table_name(Query::REFERRERS);
return "\n ALTER TABLE {$referrers_table}\n ADD COLUMN type ENUM('Ad', 'Direct', 'Referrer', 'Search', 'Social'),\n ADD COLUMN referrer VARCHAR(128)\n ";
}
private function clip_domains() : string
{
$referrers_table = Query::get_table_name(Query::REFERRERS);
return "\n UPDATE {$referrers_table}\n SET domain = SUBSTRING(domain, 1, 128)\n WHERE LENGTH(domain) > 128;\n ";
}
private function reduce_domain_column_size() : string
{
$referrers_table = Query::get_table_name(Query::REFERRERS);
return "\n ALTER TABLE {$referrers_table}\n MODIFY COLUMN domain VARCHAR(128) NOT NULL;\n ";
}
private function populate_group_data() : string
{
$referrers_table = Query::get_table_name(Query::REFERRERS);
$referrer_groups_table = Query::get_table_name(Query::REFERRER_GROUPS);
return "\n UPDATE {$referrers_table} AS referrers\n JOIN {$referrer_groups_table} AS referrer_groups ON referrers.domain = referrer_groups.domain_to_match\n SET\n referrers.referrer = referrer_groups.name,\n referrers.type = referrer_groups.type,\n referrers.domain = referrer_groups.domain\n ";
}
private function update_non_grouped_referrers() : string
{
$referrers_table = Query::get_table_name(Query::REFERRERS);
return "\n UPDATE {$referrers_table} AS referrers\n SET type = 'Referrer', referrer = IF(referrers.domain LIKE 'www.%', SUBSTR(referrers.domain, 5), referrers.domain)\n WHERE referrers.referrer IS NULL\n ";
}
private function match_session_with_new_referrers() : string
{
$referrers_table = Query::get_table_name(Query::REFERRERS);
$sessions_table = Query::get_table_name(Query::SESSIONS);
return "\n UPDATE {$sessions_table} AS sessions\n JOIN {$referrers_table} AS referrers ON sessions.referrer_id = referrers.id\n JOIN (\n SELECT\n MIN(referrers.id) AS referrer_id,\n domain,\n type,\n referrer\n FROM {$sessions_table} AS sessions\n JOIN {$referrers_table} AS referrers ON sessions.referrer_id = referrers.id\n WHERE domain IS NOT NULL AND type IS NOT NULL AND referrer IS NOT NULL\n GROUP BY domain, type, referrer\n ) AS first_match\n ON referrers.domain = first_match.domain\n AND referrers.type = first_match.type\n AND referrers.referrer = first_match.referrer\n SET sessions.referrer_id = first_match.referrer_id\n ";
}
private function remove_duplicates() : string
{
$referrers_table = Query::get_table_name(Query::REFERRERS);
$sessions_table = Query::get_table_name(Query::SESSIONS);
return "\n DELETE referrers FROM {$referrers_table} AS referrers\n LEFT JOIN {$sessions_table} AS sessions on referrers.id = sessions.referrer_id\n WHERE sessions.session_id IS NULL\n ";
}
private function restore_index() : string
{
$referrers_table = Query::get_table_name(Query::REFERRERS);
return "\n CREATE UNIQUE INDEX referrers_domain_index ON {$referrers_table} (domain);\n ";
}
private function create_direct_referrer() : string
{
global $wpdb;
$referrers_table = Query::get_table_name(Query::REFERRERS);
return $wpdb->prepare("\n INSERT INTO {$referrers_table}\n (domain, type, referrer)\n VALUES (%s, %s, %s); \n ", '', 'Direct', 'Direct');
}
private function link_direct_sessions_to_direct_referrer() : string
{
$referrers_table = Query::get_table_name(Query::REFERRERS);
$sessions_table = Query::get_table_name(Query::SESSIONS);
return "\n UPDATE {$sessions_table} AS sessions\n SET\n sessions.referrer_id = (\n SELECT id FROM {$referrers_table} WHERE domain = ''\n )\n WHERE sessions.referrer_id IS NULL \n ";
}
private function drop_referrer_groups() : string
{
$referrer_groups_table = Query::get_table_name(Query::REFERRER_GROUPS);
return "\n DROP TABLE IF EXISTS {$referrer_groups_table}\n ";
}
}
IAWP/Migrations/Migration_23.php 0000644 00000015676 14760033122 0012403 0 ustar 00 maybe_drop_device_types_table(), $this->create_device_types_table(), $this->maybe_drop_device_oss_table(), $this->create_device_oss_table(), $this->maybe_drop_device_browsers_table(), $this->create_device_browsers_table(), $this->add_columns_to_sessions(), $this->populate_device_types(), $this->populate_device_oss(), $this->populate_device_browsers(), $this->link_sessions_with_types(), $this->link_sessions_with_oss(), $this->link_sessions_with_browsers(), $this->drop_device_id_column_from_sessions(), $this->drop_original_devices_table()];
}
private function maybe_drop_device_types_table() : string
{
$device_types_table = Query::get_table_name(Query::DEVICE_TYPES);
return "\n DROP TABLE IF EXISTS {$device_types_table}\n ";
}
private function create_device_types_table() : string
{
global $wpdb;
$charset_collate = $wpdb->get_charset_collate();
$device_types_table = Query::get_table_name(Query::DEVICE_TYPES);
return "\n CREATE TABLE {$device_types_table} (\n device_type_id bigint(20) UNSIGNED AUTO_INCREMENT,\n device_type varchar(64) NOT NULL UNIQUE,\n PRIMARY KEY (device_type_id)\n ) {$charset_collate}\n ";
}
private function maybe_drop_device_oss_table() : string
{
$device_oss_table = Query::get_table_name(Query::DEVICE_OSS);
return "\n DROP TABLE IF EXISTS {$device_oss_table}\n ";
}
private function create_device_oss_table() : string
{
global $wpdb;
$charset_collate = $wpdb->get_charset_collate();
$device_oss_table = Query::get_table_name(Query::DEVICE_OSS);
return "\n CREATE TABLE {$device_oss_table} (\n device_os_id bigint(20) UNSIGNED AUTO_INCREMENT,\n device_os varchar(64) NOT NULL UNIQUE,\n PRIMARY KEY (device_os_id)\n ) {$charset_collate}\n ";
}
private function maybe_drop_device_browsers_table() : string
{
$device_browsers_table = Query::get_table_name(Query::DEVICE_BROWSERS);
return "\n DROP TABLE IF EXISTS {$device_browsers_table}\n ";
}
private function create_device_browsers_table() : string
{
global $wpdb;
$charset_collate = $wpdb->get_charset_collate();
$device_browsers_table = Query::get_table_name(Query::DEVICE_BROWSERS);
return "\n CREATE TABLE {$device_browsers_table} (\n device_browser_id bigint(20) UNSIGNED AUTO_INCREMENT,\n device_browser varchar(64) NOT NULL UNIQUE,\n PRIMARY KEY (device_browser_id)\n ) {$charset_collate}\n ";
}
private function add_columns_to_sessions() : string
{
$sessions_table = Query::get_table_name(Query::SESSIONS);
return "\n ALTER TABLE {$sessions_table}\n ADD COLUMN device_type_id BIGINT(20) UNSIGNED,\n ADD COLUMN device_os_id BIGINT(20) UNSIGNED,\n ADD COLUMN device_browser_id BIGINT(20) UNSIGNED,\n ADD INDEX (device_type_id),\n ADD INDEX (device_os_id),\n ADD INDEX (device_browser_id);\n ";
}
private function populate_device_types() : string
{
$devices_table = Query::get_table_name(Query::DEVICES);
$device_types_table = Query::get_table_name(Query::DEVICE_TYPES);
return "\n INSERT INTO {$device_types_table} (device_type)\n SELECT DISTINCT type\n FROM {$devices_table} WHERE type IS NOT NULL\n ";
}
private function populate_device_oss() : string
{
$devices_table = Query::get_table_name(Query::DEVICES);
$device_oss_table = Query::get_table_name(Query::DEVICE_OSS);
return "\n INSERT INTO {$device_oss_table} (device_os)\n SELECT DISTINCT os\n FROM {$devices_table} WHERE os IS NOT NULL\n ";
}
private function populate_device_browsers()
{
$devices_table = Query::get_table_name(Query::DEVICES);
$device_browsers_table = Query::get_table_name(Query::DEVICE_BROWSERS);
return "\n INSERT INTO {$device_browsers_table} (device_browser)\n SELECT DISTINCT browser\n FROM {$devices_table} WHERE browser IS NOT NULL\n ";
}
private function link_sessions_with_types() : string
{
$sessions_table = Query::get_table_name(Query::SESSIONS);
$devices_table = Query::get_table_name(Query::DEVICES);
$device_types_table = Query::get_table_name(Query::DEVICE_TYPES);
return "\n UPDATE {$sessions_table} AS sessions\n JOIN {$devices_table} AS devices ON sessions.device_id = devices.device_id\n JOIN {$device_types_table} AS device_types ON devices.type = device_types.device_type\n SET sessions.device_type_id = device_types.device_type_id;\n ";
}
private function link_sessions_with_oss() : string
{
$sessions_table = Query::get_table_name(Query::SESSIONS);
$devices_table = Query::get_table_name(Query::DEVICES);
$device_oss_table = Query::get_table_name(Query::DEVICE_OSS);
return "\n UPDATE {$sessions_table} AS sessions\n JOIN {$devices_table} AS devices ON sessions.device_id = devices.device_id\n JOIN {$device_oss_table} AS device_oss ON devices.os = device_oss.device_os\n SET sessions.device_os_id = device_oss.device_os_id;\n ";
}
private function link_sessions_with_browsers() : string
{
$sessions_table = Query::get_table_name(Query::SESSIONS);
$devices_table = Query::get_table_name(Query::DEVICES);
$device_browsers_table = Query::get_table_name(Query::DEVICE_BROWSERS);
return "\n UPDATE {$sessions_table} AS sessions\n JOIN {$devices_table} AS devices ON sessions.device_id = devices.device_id\n JOIN {$device_browsers_table} AS device_browsers ON devices.browser = device_browsers.device_browser\n SET sessions.device_browser_id = device_browsers.device_browser_id;\n ";
}
private function drop_device_id_column_from_sessions() : string
{
$sessions_table = Query::get_table_name(Query::SESSIONS);
return "\n ALTER TABLE {$sessions_table} DROP COLUMN device_id;\n ";
}
private function drop_original_devices_table() : string
{
$devices_table = Query::get_table_name(Query::DEVICES);
return "\n DROP TABLE IF EXISTS {$devices_table};\n ";
}
}
IAWP/Migrations/Migration_24.php 0000644 00000007272 14760033122 0012375 0 ustar 00 add_column(), $this->insert_campaigns(), $this->link_sessions_with_campaigns(), $this->delete_unused_campaigns()];
}
private function add_column() : string
{
$campaigns_table = Query::get_table_name(Query::CAMPAIGNS);
return "\n ALTER TABLE {$campaigns_table}\n ADD COLUMN landing_page_title VARCHAR(128) AFTER campaign_id\n ";
}
private function insert_campaigns() : string
{
$views_table = Query::get_table_name(Query::VIEWS);
$sessions_table = Query::get_table_name(Query::SESSIONS);
$campaigns_table = Query::get_table_name(Query::CAMPAIGNS);
$resources_table = Query::get_table_name(Query::RESOURCES);
return "\n INSERT INTO {$campaigns_table} (landing_page_title, utm_source, utm_medium, utm_campaign, utm_term, utm_content)\n SELECT DISTINCT\n initial_resource.cached_title,\n campaigns.utm_source,\n campaigns.utm_medium,\n campaigns.utm_campaign,\n campaigns.utm_term,\n campaigns.utm_content\n FROM {$resources_table} AS initial_resource\n JOIN {$views_table} AS initial_view ON initial_resource.id = initial_view.resource_id\n JOIN {$sessions_table} AS sessions ON initial_view.session_id = sessions.session_id AND initial_view.id = sessions.initial_view_id\n JOIN {$campaigns_table} AS campaigns ON sessions.campaign_id = campaigns.campaign_id \n ";
}
private function link_sessions_with_campaigns() : string
{
$views_table = Query::get_table_name(Query::VIEWS);
$sessions_table = Query::get_table_name(Query::SESSIONS);
$campaigns_table = Query::get_table_name(Query::CAMPAIGNS);
$resources_table = Query::get_table_name(Query::RESOURCES);
return "\n UPDATE {$sessions_table} AS sessions\n JOIN {$views_table} AS initial_view ON initial_view.session_id = sessions.session_id AND sessions.initial_view_id = initial_view.id\n JOIN {$resources_table} AS initial_resource ON initial_view.resource_id = initial_resource.id\n JOIN {$campaigns_table} AS campaigns ON sessions.campaign_id = campaigns.campaign_id\n JOIN {$campaigns_table} AS new_campaign ON initial_resource.cached_title = new_campaign.landing_page_title\n AND campaigns.utm_source = new_campaign.utm_source\n AND campaigns.utm_medium = new_campaign.utm_medium\n AND campaigns.utm_campaign = new_campaign.utm_campaign\n AND (campaigns.utm_term = new_campaign.utm_term OR (campaigns.utm_term IS NULL AND new_campaign.utm_term IS NULL))\n AND (campaigns.utm_content = new_campaign.utm_content OR (campaigns.utm_content IS NULL AND new_campaign.utm_content IS NULL))\n SET sessions.campaign_id = new_campaign.campaign_id \n ";
}
private function delete_unused_campaigns() : string
{
$sessions_table = Query::get_table_name(Query::SESSIONS);
$campaigns_table = Query::get_table_name(Query::CAMPAIGNS);
return "\n DELETE campaigns from {$campaigns_table} AS campaigns\n LEFT JOIN {$sessions_table} AS sessions ON campaigns.campaign_id = sessions.campaign_id\n WHERE sessions.session_id IS NULL \n ";
}
}
IAWP/Migrations/Migration_25.php 0000644 00000003002 14760033122 0012361 0 ustar 00 add_temporary_column(), $this->copy_timestamp_data_to_temporary_column(), $this->delete_original_column(), $this->rename_temporary_column()];
}
private function add_temporary_column() : string
{
$resources_table = Query::get_table_name(Query::RESOURCES);
return "\n ALTER TABLE {$resources_table} ADD COLUMN cached_date_temp DATE; \n ";
}
private function copy_timestamp_data_to_temporary_column() : string
{
$resources_table = Query::get_table_name(Query::RESOURCES);
return "\n UPDATE {$resources_table} SET cached_date_temp = FROM_UNIXTIME(cached_date) WHERE cached_date REGEXP '^[0-9]+\$';\n ";
}
private function delete_original_column() : string
{
$resources_table = Query::get_table_name(Query::RESOURCES);
return "\n ALTER TABLE {$resources_table} DROP COLUMN cached_date;\n ";
}
private function rename_temporary_column() : string
{
$resources_table = Query::get_table_name(Query::RESOURCES);
return "\n ALTER TABLE {$resources_table} CHANGE COLUMN cached_date_temp cached_date DATE;\n ";
}
}
IAWP/Migrations/Migration_26.php 0000644 00000002335 14760033122 0012372 0 ustar 00 set_empty_values_to_null('cached_title'), $this->set_empty_values_to_null('cached_url'), $this->set_empty_values_to_null('cached_type'), $this->set_empty_values_to_null('cached_type_label'), $this->set_empty_values_to_null('cached_author'), $this->set_empty_values_to_null('cached_category'), $this->nullify_authors_with_id_of_zero()];
}
private function set_empty_values_to_null(string $column) : string
{
$resources_table = Query::get_table_name(Query::RESOURCES);
return "\n UPDATE {$resources_table} SET {$column} = NULL WHERE {$column} = '' \n ";
}
private function nullify_authors_with_id_of_zero() : string
{
$resources_table = Query::get_table_name(Query::RESOURCES);
return "\n UPDATE {$resources_table} SET cached_author_id = NULL, cached_author = NULL WHERE cached_author_id = 0\n ";
}
}
IAWP/Migrations/Migration_27.php 0000644 00000001203 14760033122 0012364 0 ustar 00 add_virtual_page_id()];
}
private function add_virtual_page_id() : string
{
$resources_table = Query::get_table_name(Query::RESOURCES);
return "\n ALTER TABLE {$resources_table} ADD COLUMN virtual_page_id VARCHAR(32) AFTER author_id;\n ";
}
}
IAWP/Migrations/Migration_28.php 0000644 00000002744 14760033122 0012400 0 ustar 00 add_initial_view_id_column(), $this->populate_column(), $this->index_column()];
}
private function add_initial_view_id_column() : string
{
$wc_orders_table = Query::get_table_name(Query::WC_ORDERS);
return "\n ALTER TABLE {$wc_orders_table} ADD COLUMN initial_view_id BIGINT(20) UNSIGNED AFTER view_id;\n ";
}
private function populate_column() : string
{
$views_table = Query::get_table_name(Query::VIEWS);
$sessions_table = Query::get_table_name(Query::SESSIONS);
$wc_orders_table = Query::get_table_name(Query::WC_ORDERS);
return "\n UPDATE {$wc_orders_table} AS orders\n JOIN {$views_table} AS views ON orders.view_id = views.id\n JOIN {$sessions_table} AS sessions on views.session_id = sessions.session_id\n SET orders.initial_view_id = sessions.initial_view_id\n ";
}
private function index_column() : string
{
$wc_orders_table = Query::get_table_name(Query::WC_ORDERS);
return "\n CREATE INDEX initial_view_id ON {$wc_orders_table} (initial_view_id)\n ";
}
}
IAWP/Migrations/Migration_29.php 0000644 00000006224 14760033122 0012376 0 ustar 00 rename_visitor_id_column(), $this->create_new_visitor_id_column(), $this->drop_table_if_exists(Query::get_table_name(Query::VISITORS)), $this->create_visitors_table(), $this->populate_visitors_table(), $this->populate_token_id_column(), $this->add_index(), $this->remove_very_old_visitors_archive_table()];
}
private function rename_visitor_id_column() : string
{
$sessions_table = Query::get_table_name(Query::SESSIONS);
return "\n ALTER TABLE {$sessions_table} CHANGE COLUMN visitor_id old_visitor_id varchar(32);\n ";
}
private function create_new_visitor_id_column() : string
{
$sessions_table = Query::get_table_name(Query::SESSIONS);
return "\n ALTER TABLE {$sessions_table} ADD COLUMN visitor_id BIGINT(20) UNSIGNED AFTER old_visitor_id\n ";
}
private function create_visitors_table() : string
{
$visitors_table = Query::get_table_name(Query::VISITORS);
$character_set = Database::character_set();
$collation = Database::collation();
return "\n CREATE TABLE IF NOT EXISTS {$visitors_table} (\n visitor_id BIGINT(20) UNSIGNED AUTO_INCREMENT,\n hash VARCHAR(32) NOT NULL,\n PRIMARY KEY (visitor_id),\n UNIQUE INDEX (hash)\n ) DEFAULT CHARACTER SET {$character_set} COLLATE {$collation};\n ";
}
private function populate_visitors_table() : string
{
$sessions_table = Query::get_table_name(Query::SESSIONS);
$visitors_table = Query::get_table_name(Query::VISITORS);
return "\n INSERT INTO {$visitors_table} (hash)\n SELECT DISTINCT old_visitor_id\n FROM {$sessions_table}\n WHERE old_visitor_id IS NOT NULL\n ";
}
private function populate_token_id_column() : string
{
$sessions_table = Query::get_table_name(Query::SESSIONS);
$visitors_table = Query::get_table_name(Query::VISITORS);
return "\n UPDATE {$sessions_table} AS sessions\n JOIN {$visitors_table} AS visitors on sessions.old_visitor_id = visitors.hash\n SET sessions.visitor_id = visitors.visitor_id\n ";
}
private function add_index() : string
{
$sessions_table = Query::get_table_name(Query::SESSIONS);
return "\n CREATE INDEX new_bigint_visitor_id ON {$sessions_table} (visitor_id)\n ";
}
private function remove_very_old_visitors_archive_table() : ?string
{
$visitors_archive_table = Query::get_table_name(Query::VISITORS_1_16_ARCHIVE);
if (\strlen($visitors_archive_table) > 64) {
return null;
}
return "\n DROP TABLE IF EXISTS {$visitors_archive_table};\n ";
}
}
IAWP/Migrations/Migration_3.php 0000644 00000003447 14760033122 0012312 0 ustar 00 get_charset_collate();
$campaigns_table = Query::get_table_name(Query::CAMPAIGNS);
$wpdb->query("DROP TABLE IF EXISTS {$campaigns_table}");
$wpdb->query("CREATE TABLE {$campaigns_table} (\n campaign_id bigint(20) UNSIGNED AUTO_INCREMENT,\n utm_source varchar(2048) NOT NULL, \n utm_medium varchar(2048) NOT NULL,\n utm_campaign varchar(2048) NOT NULL,\n utm_term varchar(2048),\n utm_content varchar(2048),\n PRIMARY KEY (campaign_id)\n ) {$charset_collate}");
$campaign_urls_table = Query::get_table_name(Query::CAMPAIGN_URLS);
$wpdb->query("DROP TABLE IF EXISTS {$campaign_urls_table}");
$wpdb->query("CREATE TABLE {$campaign_urls_table} (\n campaign_url_id bigint(20) UNSIGNED AUTO_INCREMENT,\n path varchar(2048), \n utm_source varchar(2048) NOT NULL, \n utm_medium varchar(2048) NOT NULL,\n utm_campaign varchar(2048) NOT NULL,\n utm_term varchar(2048),\n utm_content varchar(2048),\n created_at datetime NOT NULL,\n PRIMARY KEY (campaign_url_id)\n ) {$charset_collate}");
$views_table = Query::get_table_name(Query::VIEWS);
$wpdb->query("\n ALTER TABLE {$views_table}\n ADD (\n campaign_id bigint(20) UNSIGNED\n )\n ");
}
}
IAWP/Migrations/Migration_30.php 0000644 00000006015 14760033122 0012364 0 ustar 00 add_session_index(), $this->add_session_country_index(), $this->add_session_city_index(), $this->add_session_device_type_index(), $this->add_session_device_browser_index(), $this->add_session_device_os_index(), $this->add_session_campaign_index(), $this->add_views_index()];
}
private function add_session_index() : string
{
$sessions_table = Query::get_table_name(Query::SESSIONS);
return "\n CREATE UNIQUE INDEX sessions_summary_index ON {$sessions_table} (created_at, session_id, visitor_id, referrer_id, total_views)\n ";
}
private function add_session_country_index() : string
{
$sessions_table = Query::get_table_name(Query::SESSIONS);
return "\n CREATE UNIQUE INDEX sessions_country_summary_index ON {$sessions_table} (created_at, session_id, visitor_id, country_id, total_views)\n ";
}
private function add_session_city_index() : string
{
$sessions_table = Query::get_table_name(Query::SESSIONS);
return "\n CREATE UNIQUE INDEX sessions_city_summary_index ON {$sessions_table} (created_at, session_id, visitor_id, city_id, total_views)\n ";
}
private function add_session_device_type_index() : string
{
$sessions_table = Query::get_table_name(Query::SESSIONS);
return "\n CREATE UNIQUE INDEX sessions_device_type_summary_index ON {$sessions_table} (created_at, session_id, visitor_id, device_type_id, total_views)\n ";
}
private function add_session_device_browser_index() : string
{
$sessions_table = Query::get_table_name(Query::SESSIONS);
return "\n CREATE UNIQUE INDEX sessions_device_browser_summary_index ON {$sessions_table} (created_at, session_id, visitor_id, device_browser_id, total_views)\n ";
}
private function add_session_device_os_index() : string
{
$sessions_table = Query::get_table_name(Query::SESSIONS);
return "\n CREATE UNIQUE INDEX sessions_device_os_summary_index ON {$sessions_table} (created_at, session_id, visitor_id, device_os_id, total_views)\n ";
}
private function add_session_campaign_index() : string
{
$sessions_table = Query::get_table_name(Query::SESSIONS);
return "\n CREATE UNIQUE INDEX sessions_campaign_summary_index ON {$sessions_table} (created_at, session_id, visitor_id, campaign_id, total_views)\n ";
}
private function add_views_index() : string
{
$views_table = Query::get_table_name(Query::VIEWS);
return "\n CREATE INDEX views_summary_index ON {$views_table} (session_id, viewed_at, resource_id)\n ";
}
}
IAWP/Migrations/Migration_31.php 0000644 00000004115 14760033122 0012364 0 ustar 00 drop_table_if_exists(Query::get_table_name(Query::FORMS)), $this->drop_table_if_exists(Query::get_table_name(Query::FORM_SUBMISSIONS)), $this->create_forms_table(), $this->create_form_submissions_table()];
}
private function create_forms_table() : string
{
$forms_table = Query::get_table_name(Query::FORMS);
$character_set = Database::character_set();
$collation = Database::collation();
return "\n CREATE TABLE IF NOT EXISTS {$forms_table} (\n form_id BIGINT(20) UNSIGNED AUTO_INCREMENT,\n plugin_id BIGINT(20) UNSIGNED NOT NULL,\n plugin_form_id BIGINT(20) UNSIGNED NOT NULL,\n cached_form_title VARCHAR(64) NOT NULL,\n PRIMARY KEY (form_id),\n UNIQUE INDEX (plugin_id, plugin_form_id)\n ) DEFAULT CHARACTER SET {$character_set} COLLATE {$collation};\n ";
}
private function create_form_submissions_table() : string
{
$form_submissions_table = Query::get_table_name(Query::FORM_SUBMISSIONS);
$character_set = Database::character_set();
$collation = Database::collation();
return "\n CREATE TABLE IF NOT EXISTS {$form_submissions_table} (\n form_submission_id BIGINT(20) UNSIGNED AUTO_INCREMENT,\n form_id BIGINT(20) UNSIGNED NOT NULL,\n session_id BIGINT(20) UNSIGNED NOT NULL,\n view_id BIGINT(20) UNSIGNED NOT NULL,\n initial_view_id BIGINT(20) UNSIGNED NOT NULL,\n created_at DATETIME NOT NULL,\n PRIMARY KEY (form_submission_id)\n ) DEFAULT CHARACTER SET {$character_set} COLLATE {$collation};\n ";
}
}
IAWP/Migrations/Migration_32.php 0000644 00000001237 14760033122 0012367 0 ustar 00 add_quick_stats_column_to_reports()];
}
private function add_quick_stats_column_to_reports() : string
{
$reports_table = Query::get_table_name(Query::REPORTS);
return "\n ALTER TABLE {$reports_table}\n ADD COLUMN quick_stats TEXT AFTER group_name\n ";
}
}
IAWP/Migrations/Migration_33.php 0000644 00000001413 14760033122 0012364 0 ustar 00 add_chart_metrics_to_reports()];
}
private function add_chart_metrics_to_reports() : string
{
$reports_table = Query::get_table_name(Query::REPORTS);
return "\n ALTER TABLE {$reports_table}\n ADD COLUMN primary_chart_metric_id varchar(255),\n ADD COLUMN secondary_chart_metric_id varchar(255),\n DROP COLUMN visible_datasets\n ";
}
}
IAWP/Migrations/Migration_34.php 0000644 00000001217 14760033122 0012367 0 ustar 00 add_index_for_cached_author_id()];
}
private function add_index_for_cached_author_id() : string
{
$resources_table = Query::get_table_name(Query::RESOURCES);
return "\n ALTER TABLE {$resources_table}\n ADD INDEX(cached_author_id);\n ";
}
}
IAWP/Migrations/Migration_35.php 0000644 00000007022 14760033122 0012370 0 ustar 00 maybe_drop_order_table(), $this->create_orders_table(), $this->populate_orders_table()];
}
private function maybe_drop_order_table() : string
{
$orders_table = Query::get_table_name(Query::ORDERS);
return "\n DROP TABLE IF EXISTS {$orders_table}\n ";
}
private function create_orders_table() : string
{
$orders_table = Query::get_table_name(Query::ORDERS);
$character_set = Database::character_set();
$collation = Database::collation();
return "\n CREATE TABLE {$orders_table} (\n order_id BIGINT(20) UNSIGNED AUTO_INCREMENT,\n is_included_in_analytics BOOLEAN NOT NULL, \n \n woocommerce_order_id BIGINT(20) UNSIGNED,\n woocommerce_order_status VARCHAR(64),\n surecart_order_id VARCHAR(36),\n surecart_order_status VARCHAR(64),\n \n view_id BIGINT(20) UNSIGNED NOT NULL,\n initial_view_id BIGINT(20) UNSIGNED NOT NULL,\n \n total INT NOT NULL,\n total_refunded INT NOT NULL,\n total_refunds SMALLINT NOT NULL,\n\n is_discounted BOOLEAN NOT NULL, \n \n created_at DATETIME NOT NULL,\n \n PRIMARY KEY (order_id),\n INDEX(view_id),\n INDEX(initial_view_id),\n INDEX(created_at)\n ) DEFAULT CHARACTER SET {$character_set} COLLATE {$collation};\n ";
}
private function populate_orders_table() : string
{
$wc_orders_table = Query::get_table_name(Query::WC_ORDERS);
$orders_table = Query::get_table_name(Query::ORDERS);
return "\n INSERT INTO {$orders_table} (\n is_included_in_analytics,\n woocommerce_order_id,\n woocommerce_order_status,\n surecart_order_id,\n surecart_order_status,\n view_id,\n initial_view_id,\n total,\n total_refunded,\n total_refunds,\n is_discounted,\n created_at\n )\n SELECT\n IF(status IN('wc-completed', 'completed', 'wc-processing', 'processing', 'wc-refunded', 'refunded', 'wc-shipped', 'shipped', 'wc-partial-shipped', 'partial-shipped', 'wc-delivered', 'delivered', 'wc-sent-to-fba', 'sent-to-fba', 'wc-part-to-fba', 'part-to-fba'), TRUE, FALSE) AS is_included_in_analytics,\n wc.order_id AS woocommerce_order_id,\n wc.status AS woocommerce_order_status,\n NULL AS surecart_order_id,\n NULL AS surecart_order_status,\n wc.view_id AS view_id,\n wc.initial_view_id AS initial_view_id,\n ROUND(wc.total * 100) AS total,\n ROUND(wc.total_refunded * 100) AS total_refunded,\n wc.total_refunds AS total_refunds,\n FALSE AS is_discounted,\n wc.created_at AS created_at\n FROM {$wc_orders_table} AS wc\n ";
}
}
IAWP/Migrations/Migration_36.php 0000644 00000001233 14760033122 0012367 0 ustar 00 increase_size_of_virtual_page_id()];
}
private function increase_size_of_virtual_page_id() : string
{
$resources_table = Query::get_table_name(Query::RESOURCES);
return "\n ALTER TABLE {$resources_table} MODIFY virtual_page_id VARCHAR(64)\n ";
}
}
IAWP/Migrations/Migration_37.php 0000644 00000004617 14760033122 0012401 0 ustar 00 remove_duplicate_woocommerce_orders(), $this->remove_duplicate_surecart_orders(), $this->add_unique_index_for_woocommerce_order_id(), $this->add_unique_index_for_surecart_order_id()];
}
private function remove_duplicate_woocommerce_orders() : string
{
$orders_table = Query::get_table_name(Query::ORDERS);
return "\n DELETE orders\n FROM\n {$orders_table} orders\n JOIN (\n SELECT\n woocommerce_order_id,\n MIN(order_id) AS first_order_id\n FROM\n {$orders_table}\n GROUP BY\n woocommerce_order_id\n ) first_orders ON orders.woocommerce_order_id = first_orders.woocommerce_order_id\n AND orders.order_id > first_orders.first_order_id; \n ";
}
private function remove_duplicate_surecart_orders() : string
{
$orders_table = Query::get_table_name(Query::ORDERS);
return "\n DELETE orders\n FROM\n {$orders_table} orders\n JOIN (\n SELECT\n surecart_order_id,\n MIN(order_id) AS first_order_id\n FROM\n {$orders_table}\n GROUP BY\n surecart_order_id\n ) first_orders ON orders.surecart_order_id = first_orders.surecart_order_id\n AND orders.order_id > first_orders.first_order_id;\n ";
}
private function add_unique_index_for_woocommerce_order_id() : string
{
$orders_table = Query::get_table_name(Query::ORDERS);
return "\n CREATE UNIQUE INDEX orders_woocommerce_order_id_index ON {$orders_table} (woocommerce_order_id)\n ";
}
private function add_unique_index_for_surecart_order_id() : string
{
$orders_table = Query::get_table_name(Query::ORDERS);
return "\n CREATE UNIQUE INDEX orders_surecart_order_id_index ON {$orders_table} (surecart_order_id)\n ";
}
}
IAWP/Migrations/Migration_38.php 0000644 00000012112 14760033122 0012367 0 ustar 00 drop_table_if_exists($this->tables::clicks()), $this->create_clicks_table(), $this->drop_table_if_exists($this->tables::click_targets()), $this->create_click_targets_table(), $this->drop_table_if_exists($this->tables::clicked_links()), $this->create_clicked_links_table(), $this->drop_table_if_exists($this->tables::link_rules()), $this->create_link_rules_table(), $this->add_initial_rules(), $this->create_pdf_report(), $this->create_zip_report(), $this->create_email_report(), $this->create_phone_number_report()];
}
private function create_clicks_table() : string
{
return "\n CREATE TABLE {$this->tables::clicks()} (\n click_id BIGINT(20) UNSIGNED AUTO_INCREMENT,\n view_id BIGINT(20) UNSIGNED,\n click_target_id BIGINT(20) UNSIGNED,\n created_at DATETIME NOT NULL,\n PRIMARY KEY (click_id),\n INDEX (view_id),\n INDEX (click_target_id)\n ) DEFAULT CHARACTER SET {$this->character_set()} COLLATE {$this->collation()};\n \n ";
}
private function create_click_targets_table() : string
{
return "\n CREATE TABLE {$this->tables::click_targets()} (\n click_target_id BIGINT(20) UNSIGNED AUTO_INCREMENT,\n target VARCHAR(2083),\n protocol ENUM('mailto', 'tel'),\n PRIMARY KEY (click_target_id)\n ) DEFAULT CHARACTER SET {$this->character_set()} COLLATE {$this->collation()};\n ";
}
private function create_clicked_links_table() : string
{
return "\n CREATE TABLE {$this->tables::clicked_links()} (\n click_id BIGINT(20) UNSIGNED AUTO_INCREMENT,\n link_rule_id BIGINT(20) UNSIGNED,\n PRIMARY KEY (click_id, link_rule_id)\n ) DEFAULT CHARACTER SET {$this->character_set()} COLLATE {$this->collation()};\n \n ";
}
private function create_link_rules_table() : string
{
return "\n CREATE TABLE {$this->tables::link_rules()} (\n link_rule_id BIGINT(20) UNSIGNED AUTO_INCREMENT,\n name VARCHAR(255) NOT NULL,\n type VARCHAR(255) NOT NULL,\n value VARCHAR(255) NOT NULL,\n is_active BOOLEAN NOT NULL DEFAULT TRUE,\n position INT UNSIGNED DEFAULT 0,\n created_at DATETIME NOT NULL,\n PRIMARY KEY (link_rule_id)\n ) DEFAULT CHARACTER SET {$this->character_set()} COLLATE {$this->collation()};\n ";
}
private function add_initial_rules() : string
{
global $wpdb;
$created_at = (new \DateTime())->format('Y-m-d H:i:s');
return $wpdb->prepare("\n INSERT INTO {$this->tables::link_rules()}\n (link_rule_id, name, type, value, position, created_at)\n VALUES\n (1, 'PDF', 'extension', 'pdf', 0, %s),\n (2, 'Zip', 'extension', 'zip', 1, %s),\n (3, 'Email', 'protocol', 'mailto', 2, %s),\n (4, 'Phone number', 'protocol', 'tel', 3, %s);\n ", $created_at, $created_at, $created_at, $created_at);
}
private function create_pdf_report() : string
{
return $this->build_report_insert_query(['name' => \esc_html__('PDFs', 'independent-analytics'), 'type' => 'clicks', 'user_created_report' => 0, 'sort_column' => 'link_clicks', 'sort_direction' => 'desc', 'filters' => [['inclusion' => 'include', 'column' => 'link_name', 'operator' => 'is', 'operand' => '1']]]);
}
private function create_zip_report() : string
{
return $this->build_report_insert_query(['name' => \esc_html__('Zips', 'independent-analytics'), 'type' => 'clicks', 'user_created_report' => 0, 'sort_column' => 'link_clicks', 'sort_direction' => 'desc', 'filters' => [['inclusion' => 'include', 'column' => 'link_name', 'operator' => 'is', 'operand' => '2']]]);
}
private function create_email_report() : string
{
return $this->build_report_insert_query(['name' => \esc_html__('Emails', 'independent-analytics'), 'type' => 'clicks', 'user_created_report' => 0, 'sort_column' => 'link_clicks', 'sort_direction' => 'desc', 'filters' => [['inclusion' => 'include', 'column' => 'link_name', 'operator' => 'is', 'operand' => '3']]]);
}
private function create_phone_number_report() : string
{
return $this->build_report_insert_query(['name' => \esc_html__('Phone numbers', 'independent-analytics'), 'type' => 'clicks', 'user_created_report' => 0, 'sort_column' => 'link_clicks', 'sort_direction' => 'desc', 'filters' => [['inclusion' => 'include', 'column' => 'link_name', 'operator' => 'is', 'operand' => '4']]]);
}
}
IAWP/Migrations/Migration_39.php 0000644 00000001525 14760033122 0012376 0 ustar 00 increase_size_of_cached_url(), $this->increase_size_of_not_found_url()];
}
private function increase_size_of_cached_url() : string
{
return "\n ALTER TABLE {$this->tables::resources()} MODIFY COLUMN cached_url VARCHAR(2083);\n ";
}
private function increase_size_of_not_found_url() : string
{
return "\n ALTER TABLE {$this->tables::resources()} MODIFY COLUMN not_found_url VARCHAR(2083);\n ";
}
}
IAWP/Migrations/Migration_4.php 0000644 00000000543 14760033122 0012305 0 ustar 00 get_charset_collate();
$sessions_table = Query::get_table_name(Query::SESSIONS);
$views_table = Query::get_table_name(Query::VIEWS);
$visitors_table = Query::get_table_name(Query::VISITORS);
$wpdb->query("DROP TABLE IF EXISTS {$sessions_table};");
$wpdb->query("CREATE TABLE {$sessions_table} (\n session_id bigint(20) UNSIGNED AUTO_INCREMENT,\n visitor_id varchar(32),\n initial_view_id bigint(20) UNSIGNED,\n referrer_id bigint(20) UNSIGNED,\n campaign_id bigint(20) UNSIGNED,\n created_at datetime NOT NULL,\n legacy_view boolean DEFAULT false NOT NULL,\n PRIMARY KEY (session_id)\n ) {$charset_collate};");
$wpdb->query("\n ALTER TABLE {$views_table}\n ADD (\n session_id bigint(20) UNSIGNED\n ),\n ADD INDEX (visitor_id);\n ");
$wpdb->query("\n INSERT INTO {$sessions_table} (visitor_id, initial_view_id, referrer_id, campaign_id, created_at, legacy_view)\n SELECT IF(visitors.visitor_token = '', NULL, LEFT(visitors.visitor_token, 32)) AS visitor_id,\n views.id AS initial_view_id,\n views.referrer_id,\n views.campaign_id,\n views.viewed_at AS created_at,\n 1 AS legacy_view\n FROM {$views_table} AS views\n LEFT JOIN {$visitors_table} AS visitors ON views.visitor_id = visitors.id;\n ");
// Add the indices after bulk insert
$wpdb->query("\n ALTER TABLE {$sessions_table}\n ADD INDEX(visitor_id),\n ADD INDEX(initial_view_id),\n ADD INDEX(referrer_id),\n ADD INDEX(campaign_id);\n ");
$wpdb->query("\n UPDATE\n {$views_table} AS views\n INNER JOIN {$sessions_table} AS sessions ON views.id = sessions.initial_view_id\n SET\n views.session_id = sessions.session_id;\n ");
$wpdb->query("\n ALTER TABLE {$views_table} DROP COLUMN referrer_id, DROP INDEX visitor_id, DROP COLUMN visitor_id, DROP COLUMN campaign_id, ADD INDEX (session_id);\n ");
$visitors_tmp_table = Query::get_table_name(Query::VISITORS_TMP);
$visitors_archive_table = Query::get_table_name(Query::VISITORS_1_16_ARCHIVE);
$wpdb->query("DROP TABLE IF EXISTS {$visitors_tmp_table};");
$wpdb->query("CREATE TABLE {$visitors_tmp_table} (\n visitor_id varchar(32),\n country_code varchar(256),\n city varchar(256),\n subdivision varchar(256),\n country varchar(256),\n continent varchar(256),\n PRIMARY KEY (visitor_id)\n ) {$charset_collate};");
$wpdb->query("INSERT INTO {$visitors_tmp_table} (visitor_id, country_code, city, subdivision, country, continent)\n SELECT\n LEFT(visitor_token, 32) AS visitor_token,\n country_code,\n city,\n subdivision,\n country,\n continent\n FROM\n {$visitors_table} AS visitors ON DUPLICATE KEY UPDATE country_code = visitors.country_code,\n city = visitors.city,\n subdivision = visitors.subdivision,\n country = visitors.country,\n continent = visitors.continent;\n ");
$wpdb->query("DROP TABLE IF EXISTS {$visitors_archive_table};");
$wpdb->query("RENAME TABLE {$visitors_table} TO {$visitors_archive_table};");
$wpdb->query("RENAME TABLE {$visitors_tmp_table} TO {$visitors_table};");
}
}
IAWP/Migrations/Migration_8.php 0000644 00000001423 14760033122 0012307 0 ustar 00 get_charset_collate();
$wc_orders_table = Query::get_table_name(Query::WC_ORDERS);
$wpdb->query("DROP TABLE IF EXISTS {$wc_orders_table};");
$wpdb->query("CREATE TABLE {$wc_orders_table} (\n order_id bigint(20) UNSIGNED NOT NULL,\n view_id bigint(20) UNSIGNED NOT NULL,\n created_at datetime NOT NULL,\n PRIMARY KEY (order_id)\n ) {$charset_collate};");
}
}
IAWP/Migrations/Migration_9.php 0000644 00000003303 14760033122 0012307 0 ustar 00 sessions_fix_required()) {
$wpdb->query("\n ALTER TABLE {$sessions_table} MODIFY COLUMN visitor_id VARCHAR(32);\n ");
}
if ($this->visitors_fix_required()) {
$wpdb->query("\n ALTER TABLE {$visitors_table} MODIFY COLUMN visitor_id VARCHAR(32);\n ");
}
}
private function sessions_fix_required() : bool
{
$sessions_table = Query::get_table_name(Query::SESSIONS);
return $this->fix_required($sessions_table);
}
private function visitors_fix_required() : bool
{
$visitors_table = Query::get_table_name(Query::VISITORS);
return $this->fix_required($visitors_table);
}
private function fix_required(string $table) : bool
{
global $wpdb;
$big_field = $wpdb->get_row("\n SELECT\n CHARACTER_MAXIMUM_LENGTH\n FROM\n information_schema.columns\n WHERE\n TABLE_NAME = '" . $table . "'\n AND COLUMN_NAME = 'visitor_id'\n AND CHARACTER_MAXIMUM_LENGTH > 32;\n ");
if (\is_null($big_field) || $wpdb->last_error !== '') {
return \false;
}
return \true;
}
}
IAWP/Migrations/Migration_Job.php 0000644 00000001515 14760033122 0012654 0 ustar 00 dispatch();
}
}
}
IAWP/Migrations/Step_Migration.php 0000644 00000005235 14760033122 0013060 0 ustar 00 database_version()), '>=')) {
return \true;
}
$completed = $this->run_queries();
if ($completed) {
\update_option('iawp_db_version', $this->database_version(), \true);
}
return $completed;
}
public function character_set() : string
{
return Database::character_set();
}
public function collation() : string
{
return Database::collation();
}
protected function drop_table_if_exists(string $table_name) : string
{
return "\n DROP TABLE IF EXISTS {$table_name};\n ";
}
private function run_queries() : bool
{
global $wpdb;
$queries = $this->queries();
foreach ($queries as $index => $query) {
// Skip the step if there is no query to run
if (\is_null($query)) {
\update_option('iawp_last_finished_migration_step', $index + 1, \true);
continue;
}
$initial_response = $wpdb->query($query);
if ($initial_response === \false) {
\sleep(1);
\update_option('iawp_migration_error_original_error_message', \trim($wpdb->last_error), \true);
$is_connected = $wpdb->check_connection(\false);
if (!$is_connected) {
// There is no database connection at this point, so options cannot be updated
return \false;
}
$retry_response = $wpdb->query($query);
if ($retry_response === \false) {
// You cannot take these variable values and inline them below. The calls to
// update_option use $wpdb, so last_error and last_query will be altered
$last_error = \trim($wpdb->last_error);
$last_query = \trim($wpdb->last_query);
\update_option('iawp_migration_error', $last_error, \true);
\update_option('iawp_migration_error_query', $last_query, \true);
return \false;
}
}
\update_option('iawp_last_finished_migration_step', $index + 1, \true);
}
return \true;
}
}
IAWP/Models/Campaign.php 0000644 00000003665 14760033122 0010767 0 ustar 00 row = $row;
$this->title = $row->title;
$this->utm_source = $row->utm_source;
$this->utm_medium = $row->utm_medium;
$this->utm_campaign = $row->utm_campaign;
$this->utm_term = $row->utm_term;
$this->utm_content = $row->utm_content;
}
/*
* Column names have shared logic between tables. So "title" for resources has the same logic
* as "title" for campaigns. Adding is_deleted ensures that the method can be called even though
* campaigns can never be deleted. A better code base would allow this to be removed.
*/
public function is_deleted()
{
return \false;
}
public function title()
{
return $this->title;
}
public function utm_source()
{
return $this->utm_source;
}
public function utm_medium()
{
return $this->utm_medium;
}
public function utm_campaign()
{
return $this->utm_campaign;
}
public function utm_term()
{
return $this->utm_term;
}
public function utm_content()
{
return $this->utm_content;
}
/**
* This isn't building a URL param that's used in a URL. This is building a unique id that's
* used for uniqueness in real-times most popular campaign list.
*
* @return string
*/
public function params() : string
{
return \http_build_query(['title' => $this->title(), 'utm_source' => $this->utm_source(), 'utm_medium' => $this->utm_medium(), 'utm_campaign' => $this->utm_campaign(), 'utm_term' => $this->utm_term(), 'utm_content' => $this->utm_content()]);
}
}
IAWP/Models/Click.php 0000644 00000001220 14760033122 0010256 0 ustar 00 row = $row;
$this->link_name = $row->link_name;
$this->link_target = $row->link_target;
$this->link_clicks = \intval($row->link_clicks);
}
public function link_name() : string
{
return $this->link_name;
}
public function link_target() : ?string
{
return $this->link_target;
}
public function link_clicks() : int
{
return $this->link_clicks;
}
}
IAWP/Models/ClickWhale_Link_Page.php 0000644 00000002222 14760033122 0013153 0 ustar 00 virtual_page_id, 'clickwhale_link_page_');
global $wpdb;
$table_name = $wpdb->prefix . 'clickwhale_linkpages';
$this->database_record = Illuminate_Builder::new()->from($table_name)->find($link_page_id);
parent::__construct($row);
}
protected function calculate_url()
{
if (\is_null($this->database_record)) {
return null;
}
return \esc_url(\home_url('/' . $this->database_record->slug . '/'));
}
protected function calculate_title()
{
if (\is_null($this->database_record)) {
return 'ClickWhale Link Page';
}
return $this->database_record->title;
}
protected function calculate_type()
{
return 'clickwhale_link_page';
}
protected function calculate_type_label()
{
return 'ClickWhale Link Page';
}
}
IAWP/Models/Current_Traffic.php 0000644 00000002224 14760033122 0012316 0 ustar 00 visitor_count = \intval($row->visitor_count);
$this->page_count = \intval($row->page_count);
$this->referrer_count = \intval($row->referrer_count);
$this->country_count = \intval($row->country_count);
$this->campaign_count = \intval($row->campaign_count);
$this->view_count = \intval($row->view_count);
}
public function get_visitor_count()
{
return $this->visitor_count;
}
public function get_page_count()
{
return $this->page_count;
}
public function get_referrer_count()
{
return $this->referrer_count;
}
public function get_country_count()
{
return $this->country_count;
}
public function get_campaign_count()
{
return $this->campaign_count;
}
public function get_view_count()
{
return $this->view_count;
}
}
IAWP/Models/Device.php 0000644 00000001143 14760033122 0010434 0 ustar 00 row = $row;
$this->type = $row->device_type ?? null;
$this->os = $row->os ?? null;
$this->browser = $row->browser ?? null;
}
public function device_type()
{
return $this->type;
}
public function browser()
{
return $this->browser;
}
public function os()
{
return $this->os;
}
}
IAWP/Models/Geo.php 0000644 00000001644 14760033122 0007755 0 ustar 00 row = $row;
$this->continent = $row->continent;
$this->country = $row->country;
$this->country_code = $row->country_code;
$this->subdivision = $row->subdivision ?? '';
$this->city = $row->city ?? '';
}
public function continent()
{
return $this->continent;
}
public function country()
{
return $this->country;
}
public function country_code()
{
return $this->country_code;
}
public function subdivision()
{
return $this->subdivision;
}
public function city()
{
return $this->city;
}
}
IAWP/Models/Page.php 0000644 00000021374 14760033122 0010121 0 ustar 00 row = $row;
$this->id = $row->id ?? null;
$this->resource = $row->resource ?? null;
$this->entrances = $row->entrances ?? 0;
$this->exits = $row->exits ?? 0;
$this->exit_percent = $row->exit_percent ?? 0;
// If $row is a full row from the database, use that for the cache
// Eventually, I'd like to avoid selecting resources.* and just get the cached_.*
// fields for the rows that are going to be shown.
if (\is_string($row->cached_title ?? null)) {
$this->cache = $row;
}
}
protected abstract function resource_key();
protected abstract function resource_value();
protected abstract function calculate_is_deleted() : bool;
protected abstract function calculate_url();
protected abstract function calculate_title();
protected abstract function calculate_type();
protected abstract function calculate_type_label();
protected abstract function calculate_icon();
protected abstract function calculate_author();
protected abstract function calculate_author_id();
protected abstract function calculate_avatar();
protected abstract function calculate_date();
protected abstract function calculate_category();
public function entrances() : int
{
return $this->entrances;
}
public function exits() : int
{
return $this->exits;
}
public function exit_percent() : float
{
return $this->exit_percent;
}
/**
* By default, pages don't have the ability to have comments.
* This can be overridden by a subclass to return an actual comments value.
*
* @return int|null
*/
public function comments() : ?int
{
return null;
}
public function get_singular_id() : ?int
{
if ($this->resource_key() !== 'singular_id') {
return null;
}
return $this->resource_value();
}
public final function is_deleted() : bool
{
if (!\is_null($this->is_deleted)) {
return $this->is_deleted;
}
$this->is_deleted = $this->calculate_is_deleted();
return $this->is_deleted;
}
public final function update_cache() : void
{
$resources_table = Query::get_table_name(Query::RESOURCES);
$resource_key = $this->resource_key();
$resource_value = $this->resource_value();
$url = $this->calculate_url();
Illuminate_Builder::new()->from($resources_table)->where($resource_key, '=', $resource_value)->update(['cached_title' => $this->calculate_title(), 'cached_url' => \is_string($url) ? Str::limit($url, 2083) : $url, 'cached_type' => $this->calculate_type(), 'cached_type_label' => $this->calculate_type_label(), 'cached_author_id' => $this->calculate_author_id(), 'cached_author' => $this->calculate_author(), 'cached_date' => $this->calculate_date(), 'cached_category' => !empty($this->calculate_category()) ? \implode(', ', $this->calculate_category()) : null]);
}
public final function id()
{
return $this->id;
}
public final function url($full_url = \false)
{
if ($this->use_cache()) {
$url = $this->cache->cached_url;
} else {
$url = $this->calculate_url();
}
if (\is_null($url)) {
return null;
}
if ($full_url) {
return $url;
} else {
return Request::path_relative_to_site_url($url);
}
}
public final function title()
{
if ($this->use_cache()) {
return $this->cache->cached_title;
}
if (\is_null($this->cached_title)) {
$this->cached_title = $this->calculate_title();
}
return \strlen($this->cached_title) > 0 ? $this->cached_title : '(no title)';
}
public final function type($raw = \false)
{
if ($raw) {
if ($this->use_cache()) {
return $this->cache->cached_type;
}
if (\is_null($this->cached_type)) {
$this->cached_type = $this->calculate_type();
}
return $this->cached_type;
} else {
if ($this->use_cache()) {
return $this->cache->cached_type_label;
}
if (\is_null($this->cached_type_label)) {
$this->cached_type_label = $this->calculate_type_label();
}
return $this->cached_type_label;
}
}
public final function icon()
{
if (\is_null($this->cached_icon)) {
$this->cached_icon = $this->calculate_icon();
}
return $this->cached_icon;
}
public final function author()
{
if ($this->use_cache()) {
return $this->cache->cached_author;
}
if (\is_null($this->cached_author)) {
$this->cached_author = $this->calculate_author();
}
return $this->cached_author;
}
public final function author_id()
{
if ($this->use_cache()) {
return $this->cache->cached_author_id;
}
if (\is_null($this->cached_author_id)) {
$this->cached_author_id = $this->calculate_author_id();
}
return $this->cached_author_id;
}
public final function avatar()
{
if (\is_null($this->cached_avatar)) {
$this->cached_avatar = $this->calculate_avatar();
}
return $this->cached_avatar;
}
public final function date()
{
if (\is_null($this->cached_date)) {
$this->cached_date = $this->calculate_date();
}
return $this->cached_date;
}
public final function formatted_category() : ?string
{
$categories = $this->category(\false);
$category_names = [];
if (\count($categories) === 0) {
return null;
}
foreach ($categories as $category_id) {
$category = \get_the_category_by_ID($category_id);
if (!\is_wp_error($category)) {
$category_names[] = $category;
}
}
return \implode(', ', $category_names);
}
public final function category($formatted = \true)
{
if ($formatted === \true) {
return $this->formatted_category();
}
if (\is_null($this->cached_category)) {
$this->cached_category = $this->calculate_category();
}
return $this->cached_category;
}
public function most_popular_subtitle() : ?string
{
return null;
}
private function use_cache() : bool
{
if (!\is_null($this->cache)) {
return \true;
}
$deleted = $this->is_deleted();
if ($deleted) {
$this->cache = $this->get_cache();
}
return $deleted;
}
private function get_cache()
{
global $wpdb;
$resources_table = Query::get_table_name(Query::RESOURCES);
$resource_key = $this->resource_key();
$resource_value = $this->resource_value();
$query = $wpdb->prepare("SELECT * FROM {$resources_table} WHERE {$resource_key} = %s", $resource_value);
return $wpdb->get_row($query);
}
public static function from_row(object $row) : \IAWP\Models\Page
{
switch ($row->resource) {
case 'singular':
return new \IAWP\Models\Page_Singular($row);
case 'author_archive':
return new \IAWP\Models\Page_Author_Archive($row);
case 'date_archive':
return new \IAWP\Models\Page_Date_Archive($row);
case 'post_type_archive':
return new \IAWP\Models\Page_Post_Type_Archive($row);
case 'term_archive':
return new \IAWP\Models\Page_Term_Archive($row);
case 'search':
return new \IAWP\Models\Page_Search($row);
case 'home':
return new \IAWP\Models\Page_Home($row);
case 'virtual_page':
return \IAWP\Models\Page_Virtual::from($row);
default:
return new \IAWP\Models\Page_Not_Found($row);
}
}
}
IAWP/Models/Page_Author_Archive.php 0000644 00000003165 14760033122 0013102 0 ustar 00 author_id = $row->author_id;
parent::__construct($row);
}
protected function resource_key() : string
{
return 'author_id';
}
protected function resource_value() : string
{
return $this->author_id;
}
protected function calculate_is_deleted() : bool
{
return \get_userdata($this->author_id) == \false;
}
protected function calculate_url()
{
return \get_author_posts_url($this->author_id);
}
protected function calculate_title()
{
return \get_the_author_meta('display_name', $this->author_id) . ' ' . \esc_html__('Archive', 'independent-analytics');
}
protected function calculate_type()
{
return 'author-archive';
}
protected function calculate_type_label()
{
return \esc_html__('Author Archive', 'independent-analytics');
}
protected function calculate_icon()
{
return ' ';
}
protected function calculate_author_id()
{
return $this->author_id;
}
protected function calculate_author()
{
return \get_the_author_meta('display_name', $this->author_id);
}
protected function calculate_avatar()
{
return \get_avatar($this->author_id, 20);
}
protected function calculate_date()
{
return null;
}
protected function calculate_category()
{
return [];
}
}
IAWP/Models/Page_Date_Archive.php 0000644 00000004575 14760033122 0012523 0 ustar 00 date_archive = $row->date_archive;
parent::__construct($row);
}
protected function resource_key() : string
{
return 'date_archive';
}
protected function resource_value() : string
{
return $this->date_archive;
}
protected function calculate_is_deleted() : bool
{
return \false;
}
protected function calculate_url()
{
list($type, $year, $month, $day) = $this->date_archive_type();
if ($type == 'year') {
return \get_year_link($year);
} elseif ($type == 'month') {
return \get_month_link($year, $month);
} else {
return \get_day_link($year, $month, $day);
}
}
protected function calculate_title()
{
return $this->date_archive;
}
protected function calculate_type()
{
return 'date-archive';
}
protected function calculate_type_label()
{
list($type) = $this->date_archive_type();
if ($type == 'year') {
return \esc_html__('Date Archive (Year)', 'independent-analytics');
} elseif ($type == 'month') {
return \esc_html__('Date Archive (Month)', 'independent-analytics');
} else {
return \esc_html__('Date Archive (Day)', 'independent-analytics');
}
}
protected function calculate_icon()
{
return ' ';
}
protected function calculate_author_id()
{
return null;
}
protected function calculate_author()
{
return null;
}
protected function calculate_avatar()
{
return null;
}
protected function calculate_date()
{
return null;
}
protected function calculate_category()
{
return [];
}
private function date_archive_type()
{
list($year, $month, $day) = \array_pad(\explode('-', $this->date_archive), 3, null);
if (\is_null($day) && \is_null($month)) {
return ['year', $year, null, null];
} elseif (\is_null($day)) {
return ['month', $year, $month, null];
} else {
return ['day', $year, $month, $day];
}
}
}
IAWP/Models/Page_Home.php 0000644 00000003330 14760033122 0011061 0 ustar 00 ';
} else {
return ' ';
}
}
protected function calculate_author_id()
{
return null;
}
protected function calculate_author()
{
return null;
}
protected function calculate_avatar()
{
return null;
}
protected function calculate_date()
{
return null;
}
protected function calculate_category()
{
return [];
}
}
IAWP/Models/Page_Not_Found.php 0000644 00000002762 14760033122 0012074 0 ustar 00 not_found_url = $row->not_found_url;
parent::__construct($row);
}
public function most_popular_subtitle() : string
{
return $this->url();
}
protected function resource_key() : string
{
return 'not_found_url';
}
protected function resource_value() : string
{
return Str::limit($this->not_found_url, 2083);
}
protected function calculate_is_deleted() : bool
{
return \false;
}
protected function calculate_url()
{
return \site_url($this->not_found_url);
}
protected function calculate_title()
{
return '404';
}
protected function calculate_type()
{
return 'not-found';
}
protected function calculate_type_label()
{
return '404';
}
protected function calculate_icon()
{
return ' ';
}
protected function calculate_author_id()
{
return null;
}
protected function calculate_author()
{
return null;
}
protected function calculate_avatar()
{
return null;
}
protected function calculate_date()
{
return null;
}
protected function calculate_category()
{
return [];
}
}
IAWP/Models/Page_Post_Type_Archive.php 0000644 00000004523 14760033122 0013565 0 ustar 00 post_type = $row->post_type;
parent::__construct($row);
}
protected function resource_key() : string
{
return 'post_type';
}
protected function resource_value() : string
{
return $this->post_type;
}
protected function calculate_is_deleted() : bool
{
return \is_null(\get_post_type_object($this->post_type));
}
protected function calculate_url()
{
return \get_post_type_archive_link($this->post_type);
}
protected function calculate_title()
{
if ($this->post_type === 'product') {
return \esc_html__('Shop', 'independent-analytics');
}
$post_type_object = \get_post_type_object($this->post_type);
if (\is_null($post_type_object)) {
return null;
}
return \get_post_type_object($this->post_type)->labels->singular_name . ' ' . \esc_html__('Archive', 'independent-analytics');
}
protected function calculate_type()
{
return $this->post_type . '-archive';
}
protected function calculate_type_label()
{
return $this->title();
}
protected function calculate_icon()
{
$icon = null;
if (!$this->calculate_is_deleted()) {
$icon = \get_post_type_object($this->post_type)->menu_icon;
}
$has_icon = !\is_null($icon);
$html = '';
if ($has_icon) {
if (\esc_url_raw($icon) === $icon) {
$html .= ' ';
} else {
$html .= ' ';
}
} else {
$html .= ' ';
}
return $html;
}
protected function calculate_author_id()
{
return null;
}
protected function calculate_author()
{
return null;
}
protected function calculate_avatar()
{
return null;
}
protected function calculate_date()
{
return null;
}
protected function calculate_category()
{
return [];
}
}
IAWP/Models/Page_Search.php 0000644 00000002720 14760033122 0011400 0 ustar 00 search_query = $row->search_query;
parent::__construct($row);
}
public function calculate_url()
{
return \get_search_link($this->search_query);
}
protected function resource_key() : string
{
return 'search_query';
}
protected function resource_value() : string
{
return $this->search_query;
}
protected function calculate_is_deleted() : bool
{
return \false;
}
protected function calculate_title()
{
return \esc_html__('Search:', 'independent-analytics') . ' "' . $this->search_query . '"';
}
protected function calculate_type()
{
return 'search-archive';
}
protected function calculate_type_label()
{
return \esc_html__('Search', 'independent-analytics');
}
protected function calculate_icon()
{
return ' ';
}
protected function calculate_author_id()
{
return null;
}
protected function calculate_author()
{
return null;
}
protected function calculate_avatar()
{
return null;
}
protected function calculate_date()
{
return null;
}
protected function calculate_category()
{
return [];
}
}
IAWP/Models/Page_Singular.php 0000644 00000010215 14760033122 0011755 0 ustar 00 singular_id = $row->singular_id;
$this->comments = $row->comments ?? 0;
parent::__construct($row);
}
/**
* Override comments method to add comments support for singular pages.
*
* @return int|null
*/
public function comments() : ?int
{
return $this->comments;
}
protected function resource_key() : string
{
return 'singular_id';
}
protected function resource_value() : string
{
return $this->singular_id;
}
protected function calculate_is_deleted() : bool
{
$post = \get_post($this->singular_id);
return \is_null($post) || \is_null(\get_post_type_object($post->post_type));
}
protected function calculate_url()
{
return $this->convert_wpml_url(\get_permalink($this->singular_id));
}
protected function calculate_title()
{
return \get_the_title($this->singular_id);
}
protected function calculate_type()
{
$post_type_object = \get_post_type_object(\get_post_type($this->singular_id));
if (\is_null($post_type_object)) {
return null;
}
return $post_type_object->name;
}
protected function calculate_type_label()
{
$post_type_object = \get_post_type_object(\get_post_type($this->singular_id));
if (\is_null($post_type_object)) {
return null;
}
return $post_type_object->labels->singular_name;
}
protected function calculate_icon()
{
$icon = null;
if (!$this->calculate_is_deleted()) {
$icon = \get_post_type_object($this->type(\true))->menu_icon;
}
$has_icon = !\is_null($icon);
$html = '';
if ($has_icon) {
if (\esc_url_raw($icon) == $icon) {
if (String_Util::str_contains($icon, 'svg')) {
$html .= '
';
} else {
$html .= '
';
}
} else {
$html .= '
';
}
} else {
$html .= '
';
}
$html .= '
';
return $html;
}
protected function calculate_author_id()
{
$author_id = \get_post_field('post_author', $this->singular_id);
if ($author_id === '') {
return null;
}
return $author_id;
}
protected function calculate_author()
{
return \get_the_author_meta('display_name', $this->author_id());
}
protected function calculate_avatar()
{
return \get_avatar($this->author_id(), 20);
}
protected function calculate_date()
{
$date = \get_the_date('Y-m-d', $this->singular_id);
if (!\is_string($date)) {
return null;
}
return $date;
}
protected function calculate_category()
{
$post_type_still_registered = \in_array($this->calculate_type(), \get_post_types());
$categories = [];
if (!$post_type_still_registered) {
return [];
}
foreach (\get_the_category($this->singular_id) as $category) {
$categories[] = $category->term_id;
}
return $categories;
}
protected function convert_wpml_url($permalink)
{
if (\is_plugin_active('sitepress-multilingual-cms/sitepress.php')) {
$language = \apply_filters('wpml_post_language_details', null, $this->singular_id);
$permalink = \apply_filters('wpml_permalink', $permalink, $language['language_code'], \true);
}
return $permalink;
}
}
IAWP/Models/Page_Term_Archive.php 0000644 00000003677 14760033122 0012557 0 ustar 00 term_id = \intval($row->term_id);
parent::__construct($row);
}
protected function resource_key() : string
{
return 'term_id';
}
protected function resource_value() : string
{
return $this->term_id;
}
protected function calculate_is_deleted() : bool
{
try {
$term = \get_term($this->term_id);
return \is_wp_error($term) || \is_null($term);
} catch (\Throwable $e) {
return \true;
}
}
protected function calculate_url()
{
return \get_term_link($this->term_id);
}
protected function calculate_title()
{
return $this->term()->name;
}
protected function calculate_type()
{
return $this->term()->taxonomy;
}
protected function calculate_type_label()
{
return \get_taxonomy_labels(\get_taxonomy($this->term()->taxonomy))->singular_name;
}
protected function calculate_icon()
{
$icon = 'dashicons-category';
if (!$this->calculate_is_deleted()) {
if ($this->type() == 'Tag') {
$icon = 'dashicons-tag';
}
}
$html = '';
$html .= ' ';
$html .= '
';
return $html;
}
protected function calculate_author_id()
{
return null;
}
protected function calculate_author()
{
return null;
}
protected function calculate_avatar()
{
return null;
}
protected function calculate_date()
{
return null;
}
protected function calculate_category()
{
return [];
}
private function term()
{
return \get_term($this->term_id);
}
}
IAWP/Models/Page_Virtual.php 0000644 00000014042 14760033122 0011621 0 ustar 00 virtual_page_id = $row->virtual_page_id;
parent::__construct($row);
}
protected function resource_key() : string
{
return 'virtual_page_id';
}
protected function resource_value() : string
{
return $this->virtual_page_id;
}
protected function calculate_is_deleted() : bool
{
return \false;
}
protected function calculate_url()
{
$surecart_product = $this->get_surecart_product();
if ($surecart_product) {
return $surecart_product->getPermalinkAttribute();
}
$surecart_collection = $this->get_surecart_collection();
if ($surecart_collection) {
return $surecart_collection->getPermalinkAttribute();
}
$surecart_upsell = $this->get_surecart_upsell();
if ($surecart_upsell) {
return $surecart_upsell->getPermalinkAttribute();
}
return null;
}
protected function calculate_title()
{
if ($this->virtual_page_id === 'wc_checkout_success') {
return \__('Checkout Success', 'independent-analytics');
}
$surecart_product = $this->get_surecart_product();
if ($surecart_product) {
return $surecart_product->name;
}
$surecart_collection = $this->get_surecart_collection();
if ($surecart_collection) {
return $surecart_collection->name;
}
$surecart_upsell = $this->get_surecart_upsell();
if ($surecart_upsell) {
return $surecart_upsell->metadata->title;
}
return \__('Page', 'independent-analytics');
}
protected function calculate_type()
{
$surecart_product = $this->get_surecart_product();
if ($surecart_product) {
return 'sc_product';
}
$surecart_collection = $this->get_surecart_collection();
if ($surecart_collection) {
return 'sc_collection';
}
$surecart_upsell = $this->get_surecart_upsell();
if ($surecart_upsell) {
return 'sc_upsell';
}
return 'page';
}
protected function calculate_type_label()
{
$surecart_product = $this->get_surecart_product();
if ($surecart_product) {
return \__('Product', 'independent-analytics');
}
$surecart_collection = $this->get_surecart_collection();
if ($surecart_collection) {
return \__('Collection', 'independent-analytics');
}
$surecart_upsell = $this->get_surecart_upsell();
if ($surecart_upsell) {
return \__('Upsell', 'independent-analytics');
}
return 'Page';
}
protected function calculate_icon()
{
$surecart_product = $this->get_surecart_product();
$surecart_collection = $this->get_surecart_collection();
$surecart_upsell = $this->get_surecart_upsell();
if ($surecart_product || $surecart_collection || $surecart_upsell) {
return ' ';
}
return ' ';
}
protected function calculate_author_id()
{
return null;
}
protected function calculate_author()
{
return null;
}
protected function calculate_avatar()
{
return null;
}
protected function calculate_date()
{
return null;
}
protected function calculate_category()
{
return [];
}
private function get_surecart_product() : ?object
{
if (\is_object($this->surecart_product)) {
return $this->surecart_product;
}
if (Str::startsWith($this->virtual_page_id, 'sc_product_') && \class_exists('\\SureCart\\Models\\Product')) {
try {
$id = Str::after($this->virtual_page_id, 'sc_product_');
$this->surecart_product = \SureCart\Models\Product::find($id);
return $this->surecart_product;
} catch (\Throwable $e) {
return null;
}
}
return null;
}
private function get_surecart_collection() : ?object
{
if (\is_object($this->surecart_collection)) {
return $this->surecart_collection;
}
if (Str::startsWith($this->virtual_page_id, 'sc_collection_') && \class_exists('IAWPSCOPED\\SureCart\\Models\\ProductCollection')) {
try {
$id = Str::after($this->virtual_page_id, 'sc_collection_');
$this->surecart_collection = \IAWPSCOPED\SureCart\Models\ProductCollection::find($id);
return $this->surecart_collection;
} catch (\Throwable $e) {
return null;
}
}
return null;
}
private function get_surecart_upsell() : ?object
{
if (\is_object($this->surecart_upsell)) {
return $this->surecart_upsell;
}
if (Str::startsWith($this->virtual_page_id, 'sc_upsell_') && \class_exists('\\SureCart\\Models\\Upsell')) {
try {
$id = Str::after($this->virtual_page_id, 'sc_upsell_');
$this->surecart_upsell = \SureCart\Models\Upsell::find($id);
return $this->surecart_upsell;
} catch (\Throwable $e) {
return null;
}
}
return null;
}
public static function from(object $row) : \IAWP\Models\Page_Virtual
{
$virtual_page_id = $row->virtual_page_id;
if (Str::startsWith($virtual_page_id, 'clickwhale_link_page')) {
return new \IAWP\Models\ClickWhale_Link_Page($row);
}
return new self($row);
}
}
IAWP/Models/Referrer.php 0000644 00000002473 14760033122 0011020 0 ustar 00 row = $row;
$this->is_direct = $row->domain === '';
$this->referrer = $row->referrer;
$this->domain = $row->domain;
$this->referrer_type = $row->referrer_type;
}
/**
* Return group name, referrer url, or direct.
*
* @return string Referrer
*/
// Todo - This is the one the table is doing...
public function referrer() : string
{
return $this->referrer;
}
public function referrer_url() : string
{
return $this->domain;
}
/**
* Return group referrer type, referrer, or direct.
*
* @return string Referrer type
*/
public function referrer_type() : string
{
return $this->referrer_type;
}
public function is_direct() : bool
{
return $this->is_direct;
}
/**
* Should the referrer record link back to the referrering domain?
*
* @return bool
*/
public function has_link() : bool
{
return !$this->is_direct() && $this->referrer_type !== 'Ad';
}
}
IAWP/Models/Universal_Model_Columns.php 0000644 00000011336 14760033122 0014032 0 ustar 00 as_int($name);
} elseif (Str::startsWith($name, 'form_conversion_rate_for_')) {
return $this->as_float($name);
}
}
public function form_submissions() : int
{
return $this->as_int('form_submissions');
}
public function form_conversion_rate() : float
{
return $this->as_float('form_conversion_rate');
}
public function wc_orders() : float
{
return $this->as_float('wc_orders');
}
public function wc_gross_sales() : float
{
return $this->as_float('wc_gross_sales');
}
public function wc_refunds() : float
{
return $this->as_float('wc_refunds');
}
public function wc_refunded_amount() : float
{
return $this->as_float('wc_refunded_amount');
}
public function wc_net_sales() : float
{
return $this->as_float('wc_net_sales');
}
public function wc_conversion_rate() : float
{
return $this->as_float('wc_conversion_rate');
}
public function wc_earnings_per_visitor() : float
{
return $this->as_float('wc_earnings_per_visitor');
}
public function wc_average_order_volume() : float
{
return $this->as_float('wc_average_order_volume');
}
public function views() : int
{
return $this->as_int('views');
}
public function previous_period_views() : int
{
return $this->as_int('previous_period_views');
}
public function views_growth() : float
{
return $this->as_float('views_growth');
}
public function views_per_session() : float
{
return $this->as_float('views_per_session');
}
public function visitors() : int
{
return $this->as_int('visitors');
}
public function previous_period_visitors() : int
{
return $this->as_int('previous_period_views');
}
public function visitors_growth() : float
{
return $this->as_float('visitors_growth');
}
public function clicks() : float
{
return $this->as_int('clicks');
}
public function average_session_duration() : ?int
{
return $this->as_int('average_session_duration', null);
}
public function average_session_duration_growth() : float
{
$current = $this->average_session_duration();
$previous = $this->previous_period_average_session_duration();
if ($current == 0 || $previous == 0) {
return 0;
} else {
return ($current - $previous) / $previous * 100;
}
}
public function average_view_duration() : ?int
{
return $this->as_int('average_view_duration', null);
}
public function average_view_duration_growth() : float
{
$current = $this->average_view_duration();
$previous = $this->previous_period_average_view_duration();
if ($current == 0 || $previous == 0) {
return 0;
} else {
return ($current - $previous) / $previous * 100;
}
}
public function sessions() : int
{
return $this->as_int('sessions');
}
public function previous_period_sessions() : int
{
return $this->as_int('previous_period_sessions');
}
public function sessions_growth() : float
{
$current = $this->sessions();
$previous = $this->previous_period_sessions();
if ($current == 0 || $previous == 0) {
return 0;
} else {
return ($current - $previous) / $previous * 100;
}
}
public function previous_period_average_session_duration() : int
{
return $this->as_int('previous_period_average_session_duration');
}
public function previous_period_average_view_duration() : int
{
return $this->as_int('previous_period_average_view_duration');
}
public function bounces() : int
{
return $this->as_int('bounces');
}
public function bounce_rate() : float
{
return $this->as_float('bounce_rate');
}
private function as_float($property, $default = 0) : ?float
{
return \property_exists($this->row, $property) && $this->row->{$property} !== null ? \floatval($this->row->{$property}) : $default;
}
private function as_int($property, $default = 0) : ?int
{
return \property_exists($this->row, $property) && $this->row->{$property} !== null ? \intval($this->row->{$property}) : $default;
}
}
IAWP/Models/Visitor.php 0000644 00000007160 14760033122 0010701 0 ustar 00 id();
* @internal
*/
class Visitor
{
private $id;
private $geoposition;
private $current_session;
/**
* New instances should be created with a string ip address
*
* @param string $ip
* @param string $user_agent
*/
public function __construct(string $ip, string $user_agent)
{
$this->id = $this->fetch_visitor_id_by_hash($this->calculate_hash($ip, $user_agent));
$this->geoposition = new Geoposition($ip);
$this->current_session = $this->fetch_current_session();
}
public function geoposition() : Geoposition
{
return $this->geoposition;
}
public function has_recorded_session() : bool
{
return \is_object($this->current_session);
}
public function most_recent_session_id() : ?int
{
$session_id = \IAWPSCOPED\iawp_intify($this->current_session->session_id);
if ($this->has_recorded_session() && \is_int($session_id)) {
return $session_id;
} else {
return null;
}
}
public function most_recent_initial_view_id() : ?int
{
$initial_view_id = \IAWPSCOPED\iawp_intify($this->current_session->initial_view_id);
if ($this->has_recorded_session() && \is_int($initial_view_id)) {
return $initial_view_id;
} else {
return null;
}
}
public function most_recent_final_view_id() : ?int
{
$final_view_id = \IAWPSCOPED\iawp_intify($this->current_session->final_view_id);
if ($this->has_recorded_session() && \is_int($final_view_id)) {
return $final_view_id;
} else {
return null;
}
}
public function most_recent_view_id() : ?int
{
return $this->most_recent_final_view_id() ?? $this->most_recent_initial_view_id();
}
/**
* Return the database id for a visitor
*
* @return string
*/
public function id() : string
{
return $this->id;
}
/**
* @param string $ip
* @param string $user_agent
* @return string
*/
private function calculate_hash(string $ip, string $user_agent) : string
{
$salt = Salt::visitor_token_salt();
$result = $salt . $ip . $user_agent;
return \md5($result);
}
private function fetch_current_session()
{
$sessions_table = Query::get_table_name(Query::SESSIONS);
$session = Illuminate_Builder::new()->from($sessions_table, 'sessions')->selectRaw('IFNULL(ended_at, created_at) AS latest_view_at')->selectRaw('sessions.*')->where('visitor_id', '=', $this->id)->havingRaw('latest_view_at > DATE_SUB(UTC_TIMESTAMP(), INTERVAL 30 MINUTE)')->orderBy('latest_view_at', 'DESC')->first();
return $session;
}
public static function fetch_visitor_id_by_hash(string $hash) : int
{
$visitors_table = Query::get_table_name(Query::VISITORS);
Illuminate_Builder::new()->from($visitors_table)->insertOrIgnore([['hash' => $hash]]);
return Illuminate_Builder::new()->from($visitors_table)->where('hash', '=', $hash)->value('visitor_id');
}
public static function fetch_current_visitor() : self
{
return new \IAWP\Models\Visitor(Request::ip(), Request::user_agent());
}
}
IAWP/Public_API/Analytics.php 0000644 00000003024 14760033122 0011650 0 ustar 00 views = $row->views ?? 0;
$this->visitors = $row->visitors ?? 0;
$this->sessions = $row->sessions ?? 0;
}
/**
* @param Date_Range $date_range
*
* @return self
*/
public static function for(Date_Range $date_range) : self
{
$resources_table = Query::get_table_name(Query::RESOURCES);
$views_table = Query::get_table_name(Query::VIEWS);
$sessions_table = Query::get_table_name(Query::SESSIONS);
$resource_statistics_query = Illuminate_Builder::new();
$resource_statistics_query->selectRaw('COUNT(DISTINCT views.id) AS views')->selectRaw('COUNT(DISTINCT sessions.visitor_id) AS visitors')->selectRaw('COUNT(DISTINCT sessions.session_id) AS sessions')->from("{$views_table} as views")->join("{$resources_table} AS resources", function (JoinClause $join) {
$join->on('resources.id', '=', 'views.resource_id');
})->join("{$sessions_table} AS sessions", function (JoinClause $join) {
$join->on('sessions.session_id', '=', 'views.session_id');
})->whereBetween('views.viewed_at', [$date_range->iso_start(), $date_range->iso_end()]);
return new self($resource_statistics_query->get()->first());
}
}
IAWP/Public_API/Singular_Analytics.php 0000644 00000003605 14760033122 0013521 0 ustar 00 singular_id = $singular_id;
$this->views = $row->views ?? 0;
$this->visitors = $row->visitors ?? 0;
$this->sessions = $row->sessions ?? 0;
}
/**
* @param string|int $singular_id
* @param Date_Range $date_range
*
* @return self
*/
public static function for($singular_id, Date_Range $date_range) : ?self
{
if (\get_post($singular_id) === null) {
return null;
}
$resources_table = Query::get_table_name(Query::RESOURCES);
$views_table = Query::get_table_name(Query::VIEWS);
$sessions_table = Query::get_table_name(Query::SESSIONS);
$resource_statistics_query = Illuminate_Builder::new();
$resource_statistics_query->selectRaw('COUNT(DISTINCT views.id) AS views')->selectRaw('COUNT(DISTINCT sessions.visitor_id) AS visitors')->selectRaw('COUNT(DISTINCT sessions.session_id) AS sessions')->from("{$views_table} as views")->join("{$resources_table} AS resources", function (JoinClause $join) {
$join->on('resources.id', '=', 'views.resource_id');
})->join("{$sessions_table} AS sessions", function (JoinClause $join) {
$join->on('sessions.session_id', '=', 'views.session_id');
})->where('resources.resource', '=', 'singular')->where('resources.singular_id', '=', $singular_id)->whereBetween('views.viewed_at', [$date_range->iso_start(), $date_range->iso_end()])->groupBy('resources.id');
return new self((int) $singular_id, $resource_statistics_query->get()->first());
}
}
IAWP/Rows/Campaigns.php 0000644 00000017277 14760033122 0010665 0 ustar 00 joinSub($this->query(\true), 'campaign_rows', function (JoinClause $join) {
$join->on('campaign_rows.campaign_id', '=', 'sessions.campaign_id');
});
}
protected function fetch_rows() : array
{
$rows = $this->query()->get()->all();
return \array_map(function ($row) {
return new Campaign($row);
}, $rows);
}
private function query(?bool $skip_pagination = \false) : Builder
{
if ($skip_pagination) {
$this->number_of_rows = null;
}
$views_table = Query::get_table_name(Query::VIEWS);
$sessions_table = Query::get_table_name(Query::SESSIONS);
$orders_table = Query::get_table_name(Query::ORDERS);
$campaigns_table = Query::get_table_name(Query::CAMPAIGNS);
$orders_query = Illuminate_Builder::new();
$orders_query->select(['orders.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')->where('orders.is_included_in_analytics', '=', \true)->whereBetween('orders.created_at', $this->get_current_period_iso_range())->groupBy('orders.view_id');
$campaigns_query = Illuminate_Builder::new();
$campaigns_query->select('campaigns.campaign_id', 'landing_page_title AS title', 'utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content')->selectRaw('COUNT(DISTINCT views.id) AS views')->selectRaw('COUNT(DISTINCT sessions.visitor_id) AS visitors')->selectRaw('COUNT(DISTINCT sessions.session_id) AS sessions')->selectRaw('ROUND(AVG( TIMESTAMPDIFF(SECOND, sessions.created_at, sessions.ended_at))) AS average_session_duration')->selectRaw('COUNT(DISTINCT IF(sessions.final_view_id IS NULL, sessions.session_id, NULL)) AS bounces')->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(the_orders.wc_refunds), 0) AS wc_refunds')->selectRaw('IFNULL(SUM(form_submissions.form_submissions), 0) AS form_submissions')->tap(function (Builder $query) {
foreach (Form::get_forms() as $form) {
$query->selectRaw("SUM(IF(form_submissions.form_id = ?, form_submissions.form_submissions, 0)) AS {$form->submissions_column()}", [$form->id()]);
}
})->from($views_table, 'views')->leftJoin($campaigns_query->raw($sessions_table . ' AS sessions'), function (JoinClause $join) {
$join->on('views.session_id', '=', 'sessions.session_id');
})->join($campaigns_query->raw($campaigns_table . ' AS campaigns'), function (JoinClause $join) {
$join->on('sessions.campaign_id', '=', 'campaigns.campaign_id');
})->leftJoin($campaigns_query->raw(Tables::clicks() . ' AS clicks'), function (JoinClause $join) {
$join->on('clicks.view_id', '=', 'views.id');
})->leftJoinSub($orders_query, 'the_orders', function (JoinClause $join) {
$join->on('the_orders.view_id', '=', 'views.id');
})->leftJoinSub($this->get_form_submissions_query(), 'form_submissions', function (JoinClause $join) {
$join->on('form_submissions.view_id', '=', 'views.id');
})->whereBetween('views.viewed_at', $this->get_current_period_iso_range())->when(!$this->appears_to_be_for_real_time_analytics(), function (Builder $query) {
$query->whereBetween('sessions.created_at', $this->get_current_period_iso_range());
})->tap(Query_Taps::tap_authored_content_check())->when(\count($this->filters) > 0, function (Builder $query) {
foreach ($this->filters as $filter) {
if (!$this->is_a_calculated_column($filter->column())) {
$filter->apply_to_query($query);
}
}
})->groupBy('campaigns.campaign_id')->having('views', '>', 0)->when(!$this->is_using_a_calculated_column(), function (Builder $query) {
$query->when($this->sort_configuration->is_column_nullable(), function (Builder $query) {
$query->orderByRaw("CASE WHEN {$this->sort_configuration->column()} IS NULL THEN 1 ELSE 0 END");
})->orderBy($this->sort_configuration->column(), $this->sort_configuration->direction())->orderBy('title')->when(\is_int($this->number_of_rows), function (Builder $query) {
$query->limit($this->number_of_rows);
});
});
$previous_period_query = Illuminate_Builder::new();
$previous_period_query->select(['sessions.campaign_id'])->selectRaw('SUM(sessions.total_views) AS previous_period_views')->selectRaw('COUNT(DISTINCT sessions.visitor_id) AS previous_period_visitors')->from($sessions_table, 'sessions')->whereBetween('sessions.created_at', $this->get_previous_period_iso_range())->groupBy('sessions.campaign_id');
$outer_query = Illuminate_Builder::new();
$outer_query->selectRaw('campaigns.*')->selectRaw('IF(sessions = 0, 0, views / sessions) AS views_per_session')->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('ROUND(CAST(wc_gross_sales - wc_refunded_amount AS SIGNED)) AS wc_net_sales')->selectRaw('IF(visitors = 0, 0, (wc_orders / visitors) * 100) AS wc_conversion_rate')->selectRaw('IF(visitors = 0, 0, (wc_gross_sales - wc_refunded_amount) / 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) {
foreach (Form::get_forms() as $form) {
$query->selectRaw("IF(visitors = 0, 0, ({$form->submissions_column()} / visitors) * 100) AS {$form->conversion_rate_column()}");
}
})->when(\count($this->filters) > 0, function (Builder $query) {
foreach ($this->filters as $filter) {
if ($this->is_a_calculated_column($filter->column())) {
$filter->apply_to_query($query);
}
}
})->fromSub($campaigns_query, 'campaigns')->leftJoinSub($previous_period_query, 'previous_period_stats', 'campaigns.campaign_id', '=', 'previous_period_stats.campaign_id')->when($this->is_using_a_calculated_column(), function (Builder $query) {
$query->when($this->sort_configuration->is_column_nullable(), function (Builder $query) {
$query->orderByRaw("CASE WHEN {$this->sort_configuration->column()} IS NULL THEN 1 ELSE 0 END");
})->orderBy($this->sort_configuration->column(), $this->sort_configuration->direction())->orderBy('title')->when(\is_int($this->number_of_rows), function (Builder $query) {
$query->limit($this->number_of_rows);
});
});
return $outer_query;
}
}
IAWP/Rows/Cities.php 0000644 00000017541 14760033122 0010175 0 ustar 00 joinSub($this->query(\true), 'city_rows', function (JoinClause $join) {
$join->on('city_rows.city_id', '=', 'sessions.city_id');
});
}
protected function fetch_rows() : array
{
$rows = $this->query()->get()->all();
return \array_map(function ($row) {
return new Geo($row);
}, $rows);
}
private function query(?bool $skip_pagination = \false) : Builder
{
if ($skip_pagination) {
$this->number_of_rows = null;
}
$views_table = Query::get_table_name(Query::VIEWS);
$sessions_table = Query::get_table_name(Query::SESSIONS);
$orders_table = Query::get_table_name(Query::ORDERS);
$countries_table = Query::get_table_name(Query::COUNTRIES);
$cities_table = Query::get_table_name(Query::CITIES);
$orders_query = Illuminate_Builder::new();
$orders_query->select(['orders.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')->where('orders.is_included_in_analytics', '=', \true)->whereBetween('orders.created_at', $this->get_current_period_iso_range())->groupBy('orders.view_id');
$cities_query = Illuminate_Builder::new();
$cities_query->select('countries.country_id', 'countries.country_code', 'countries.country', 'countries.continent', 'cities.subdivision', 'cities.city', 'cities.city_id')->selectRaw('COUNT(DISTINCT views.id) AS views')->selectRaw('COUNT(DISTINCT sessions.visitor_id) AS visitors')->selectRaw('COUNT(DISTINCT sessions.session_id) AS sessions')->selectRaw('ROUND(AVG( TIMESTAMPDIFF(SECOND, sessions.created_at, sessions.ended_at))) AS average_session_duration')->selectRaw('COUNT(DISTINCT IF(sessions.final_view_id IS NULL, sessions.session_id, NULL)) AS bounces')->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(the_orders.wc_refunds), 0) AS wc_refunds')->selectRaw('IFNULL(SUM(form_submissions.form_submissions), 0) AS form_submissions')->tap(function (Builder $query) {
foreach (Form::get_forms() as $form) {
$query->selectRaw("SUM(IF(form_submissions.form_id = ?, form_submissions.form_submissions, 0)) AS {$form->submissions_column()}", [$form->id()]);
}
})->from($views_table, 'views')->leftJoin($cities_query->raw($sessions_table . ' AS sessions'), function (JoinClause $join) {
$join->on('views.session_id', '=', 'sessions.session_id');
})->join($cities_query->raw($cities_table . ' AS cities'), function (JoinClause $join) {
$join->on('sessions.city_id', '=', 'cities.city_id');
})->join($cities_query->raw($countries_table . ' AS countries'), function (JoinClause $join) {
$join->on('cities.country_id', '=', 'countries.country_id');
})->leftJoin($cities_query->raw(Tables::clicks() . ' AS clicks'), function (JoinClause $join) {
$join->on('clicks.view_id', '=', 'views.id');
})->leftJoinSub($orders_query, 'the_orders', function (JoinClause $join) {
$join->on('the_orders.view_id', '=', 'views.id');
})->leftJoinSub($this->get_form_submissions_query(), 'form_submissions', function (JoinClause $join) {
$join->on('form_submissions.view_id', '=', 'views.id');
})->whereBetween('views.viewed_at', $this->get_current_period_iso_range())->when(!$this->appears_to_be_for_real_time_analytics(), function (Builder $query) {
$query->whereBetween('sessions.created_at', $this->get_current_period_iso_range());
})->tap(Query_Taps::tap_authored_content_check())->when(\count($this->filters) > 0, function (Builder $query) {
foreach ($this->filters as $filter) {
if (!$this->is_a_calculated_column($filter->column())) {
$filter->apply_to_query($query);
}
}
})->groupBy('cities.city_id')->having('views', '>', 0)->when(!$this->is_using_a_calculated_column(), function (Builder $query) {
$query->when($this->sort_configuration->is_column_nullable(), function (Builder $query) {
$query->orderByRaw("CASE WHEN {$this->sort_configuration->column()} IS NULL THEN 1 ELSE 0 END");
})->orderBy($this->sort_configuration->column(), $this->sort_configuration->direction())->orderBy('city')->when(\is_int($this->number_of_rows), function (Builder $query) {
$query->limit($this->number_of_rows);
});
});
$previous_period_query = Illuminate_Builder::new();
$previous_period_query->select(['sessions.city_id'])->selectRaw('SUM(sessions.total_views) AS previous_period_views')->selectRaw('COUNT(DISTINCT sessions.visitor_id) AS previous_period_visitors')->from($sessions_table, 'sessions')->whereBetween('sessions.created_at', $this->get_previous_period_iso_range())->groupBy('sessions.city_id');
$outer_query = Illuminate_Builder::new();
$outer_query->selectRaw('cities.*')->selectRaw('IF(sessions = 0, 0, views / sessions) AS views_per_session')->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('ROUND(CAST(wc_gross_sales - wc_refunded_amount AS SIGNED)) AS wc_net_sales')->selectRaw('IF(visitors = 0, 0, (wc_orders / visitors) * 100) AS wc_conversion_rate')->selectRaw('IF(visitors = 0, 0, (wc_gross_sales - wc_refunded_amount) / 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) {
foreach (Form::get_forms() as $form) {
$query->selectRaw("IF(visitors = 0, 0, ({$form->submissions_column()} / visitors) * 100) AS {$form->conversion_rate_column()}");
}
})->when(\count($this->filters) > 0, function (Builder $query) {
foreach ($this->filters as $filter) {
if ($this->is_a_calculated_column($filter->column())) {
$filter->apply_to_query($query);
}
}
})->fromSub($cities_query, 'cities')->leftJoinSub($previous_period_query, 'previous_period_stats', 'cities.city_id', '=', 'previous_period_stats.city_id')->when($this->is_using_a_calculated_column(), function (Builder $query) {
$query->when($this->sort_configuration->is_column_nullable(), function (Builder $query) {
$query->orderByRaw("CASE WHEN {$this->sort_configuration->column()} IS NULL THEN 1 ELSE 0 END");
})->orderBy($this->sort_configuration->column(), $this->sort_configuration->direction())->orderBy('city')->when(\is_int($this->number_of_rows), function (Builder $query) {
$query->limit($this->number_of_rows);
});
});
return $outer_query;
}
}
IAWP/Rows/Clicks.php 0000644 00000004521 14760033122 0010157 0 ustar 00 joinSub($this->query(\true), 'click_rows', function (JoinClause $join) {
$join->on('click_rows.link_rule_id', '=', 'link_rules.link_rule_id');
$join->on('click_rows.click_target_id', '=', 'click_targets.click_target_id');
});
}
protected function fetch_rows() : array
{
$rows = $this->query()->get()->all();
return \array_map(function ($row) {
return new Click($row);
}, $rows);
}
private function query(?bool $skip_pagination = \false) : Builder
{
if ($skip_pagination) {
$this->number_of_rows = null;
}
$query = Illuminate_Builder::new()->select(['link_rules.link_rule_id AS link_rule_id', 'click_targets.click_target_id AS click_target_id', 'link_rules.name AS link_name', 'click_targets.target AS link_target'])->selectRaw('COUNT(DISTINCT clicks.click_id) AS link_clicks')->from($this->tables::link_rules(), 'link_rules')->leftJoin($this->tables::clicked_links() . ' AS clicked_links', 'clicked_links.link_rule_id', '=', 'link_rules.link_rule_id')->leftJoin($this->tables::clicks() . ' AS clicks', 'clicks.click_id', '=', 'clicked_links.click_id')->leftJoin($this->tables::click_targets() . ' AS click_targets', 'click_targets.click_target_id', '=', 'clicks.click_target_id')->whereBetween('clicks.created_at', $this->get_current_period_iso_range())->when(\count($this->filters) > 0, function (Builder $query) {
foreach ($this->filters as $filter) {
if (!$this->is_a_calculated_column($filter->column())) {
$filter->apply_to_query($query);
}
}
})->when(\is_int($this->number_of_rows), function (Builder $query) {
$query->limit($this->number_of_rows);
})->tap(Query_Taps::tap_authored_content_for_clicks())->orderBy($this->sort_configuration->column(), $this->sort_configuration->direction())->orderBy('link_name')->groupBy('link_rules.link_rule_id', 'clicks.click_target_id');
return $query;
}
}
IAWP/Rows/Countries.php 0000644 00000017215 14760033122 0010726 0 ustar 00 joinSub($this->query(\true), 'country_rows', function (JoinClause $join) {
$join->on('country_rows.country_id', '=', 'sessions.country_id');
});
}
protected function fetch_rows() : array
{
$rows = $this->query()->get()->all();
return \array_map(function ($row) {
return new Geo($row);
}, $rows);
}
private function query(?bool $skip_pagination = \false) : Builder
{
if ($skip_pagination) {
$this->number_of_rows = null;
}
$views_table = Query::get_table_name(Query::VIEWS);
$sessions_table = Query::get_table_name(Query::SESSIONS);
$orders_table = Query::get_table_name(Query::ORDERS);
$countries_table = Query::get_table_name(Query::COUNTRIES);
$orders_query = Illuminate_Builder::new();
$orders_query->select(['orders.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')->where('orders.is_included_in_analytics', '=', \true)->whereBetween('orders.created_at', $this->get_current_period_iso_range())->groupBy('orders.view_id');
$countries_query = Illuminate_Builder::new();
$countries_query->select('countries.country_id', 'countries.country_code', 'countries.country', 'countries.continent')->selectRaw('COUNT(DISTINCT views.id) AS views')->selectRaw('COUNT(DISTINCT sessions.visitor_id) AS visitors')->selectRaw('COUNT(DISTINCT sessions.session_id) AS sessions')->selectRaw('ROUND(AVG( TIMESTAMPDIFF(SECOND, sessions.created_at, sessions.ended_at))) AS average_session_duration')->selectRaw('COUNT(DISTINCT IF(sessions.final_view_id IS NULL, sessions.session_id, NULL)) AS bounces')->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(the_orders.wc_refunds), 0) AS wc_refunds')->selectRaw('IFNULL(SUM(form_submissions.form_submissions), 0) AS form_submissions')->tap(function (Builder $query) {
foreach (Form::get_forms() as $form) {
$query->selectRaw("SUM(IF(form_submissions.form_id = ?, form_submissions.form_submissions, 0)) AS {$form->submissions_column()}", [$form->id()]);
}
})->from($views_table, 'views')->leftJoin($countries_query->raw($sessions_table . ' AS sessions'), function (JoinClause $join) {
$join->on('views.session_id', '=', 'sessions.session_id');
})->join($countries_query->raw($countries_table . ' AS countries'), function (JoinClause $join) {
$join->on('sessions.country_id', '=', 'countries.country_id');
})->leftJoin($countries_query->raw(Tables::clicks() . ' AS clicks'), function (JoinClause $join) {
$join->on('clicks.view_id', '=', 'views.id');
})->leftJoinSub($orders_query, 'the_orders', function (JoinClause $join) {
$join->on('the_orders.view_id', '=', 'views.id');
})->leftJoinSub($this->get_form_submissions_query(), 'form_submissions', function (JoinClause $join) {
$join->on('form_submissions.view_id', '=', 'views.id');
})->whereBetween('views.viewed_at', $this->get_current_period_iso_range())->when(!$this->appears_to_be_for_real_time_analytics(), function (Builder $query) {
$query->whereBetween('sessions.created_at', $this->get_current_period_iso_range());
})->tap(Query_Taps::tap_authored_content_check())->when(\count($this->filters) > 0, function (Builder $query) {
foreach ($this->filters as $filter) {
if (!$this->is_a_calculated_column($filter->column())) {
$filter->apply_to_query($query);
}
}
})->groupBy('countries.country_id')->having('views', '>', 0)->when(!$this->is_using_a_calculated_column(), function (Builder $query) {
$query->when($this->sort_configuration->is_column_nullable(), function (Builder $query) {
$query->orderByRaw("CASE WHEN {$this->sort_configuration->column()} IS NULL THEN 1 ELSE 0 END");
})->orderBy($this->sort_configuration->column(), $this->sort_configuration->direction())->orderBy('country')->when(\is_int($this->number_of_rows), function (Builder $query) {
$query->limit($this->number_of_rows);
});
});
$previous_period_query = Illuminate_Builder::new();
$previous_period_query->select(['sessions.country_id'])->selectRaw('SUM(sessions.total_views) AS previous_period_views')->selectRaw('COUNT(DISTINCT sessions.visitor_id) AS previous_period_visitors')->from($sessions_table, 'sessions')->whereBetween('sessions.created_at', $this->get_previous_period_iso_range())->groupBy('sessions.country_id');
$outer_query = Illuminate_Builder::new();
$outer_query->selectRaw('countries.*')->selectRaw('IF(sessions = 0, 0, views / sessions) AS views_per_session')->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('ROUND(CAST(wc_gross_sales - wc_refunded_amount AS SIGNED)) AS wc_net_sales')->selectRaw('IF(visitors = 0, 0, (wc_orders / visitors) * 100) AS wc_conversion_rate')->selectRaw('IF(visitors = 0, 0, (wc_gross_sales - wc_refunded_amount) / 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) {
foreach (Form::get_forms() as $form) {
$query->selectRaw("IF(visitors = 0, 0, ({$form->submissions_column()} / visitors) * 100) AS {$form->conversion_rate_column()}");
}
})->when(\count($this->filters) > 0, function (Builder $query) {
foreach ($this->filters as $filter) {
if ($this->is_a_calculated_column($filter->column())) {
$filter->apply_to_query($query);
}
}
})->fromSub($countries_query, 'countries')->leftJoinSub($previous_period_query, 'previous_period_stats', 'countries.country_id', '=', 'previous_period_stats.country_id')->when($this->is_using_a_calculated_column(), function (Builder $query) {
$query->when($this->sort_configuration->is_column_nullable(), function (Builder $query) {
$query->orderByRaw("CASE WHEN {$this->sort_configuration->column()} IS NULL THEN 1 ELSE 0 END");
})->orderBy($this->sort_configuration->column(), $this->sort_configuration->direction())->orderBy('country')->when(\is_int($this->number_of_rows), function (Builder $query) {
$query->limit($this->number_of_rows);
});
});
return $outer_query;
}
}
IAWP/Rows/Device_Browsers.php 0000644 00000017464 14760033122 0012046 0 ustar 00 joinSub($this->query(\true), 'device_browser_rows', function (JoinClause $join) {
$join->on('device_browser_rows.device_browser_id', '=', 'sessions.device_browser_id');
});
}
protected function fetch_rows() : array
{
$rows = $this->query()->get()->all();
return \array_map(function ($row) {
return new Device($row);
}, $rows);
}
private function query(?bool $skip_pagination = \false) : Builder
{
if ($skip_pagination) {
$this->number_of_rows = null;
}
$views_table = Query::get_table_name(Query::VIEWS);
$sessions_table = Query::get_table_name(Query::SESSIONS);
$orders_table = Query::get_table_name(Query::ORDERS);
$device_browsers_table = Query::get_table_name(Query::DEVICE_BROWSERS);
$orders_query = Illuminate_Builder::new();
$orders_query->select(['orders.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')->where('orders.is_included_in_analytics', '=', \true)->whereBetween('orders.created_at', $this->get_current_period_iso_range())->groupBy('orders.view_id');
$device_browsers_query = Illuminate_Builder::new();
$device_browsers_query->select('device_browsers.device_browser_id', 'device_browsers.device_browser AS browser')->selectRaw('COUNT(DISTINCT views.id) AS views')->selectRaw('COUNT(DISTINCT sessions.visitor_id) AS visitors')->selectRaw('COUNT(DISTINCT sessions.session_id) AS sessions')->selectRaw('ROUND(AVG( TIMESTAMPDIFF(SECOND, sessions.created_at, sessions.ended_at))) AS average_session_duration')->selectRaw('COUNT(DISTINCT IF(sessions.final_view_id IS NULL, sessions.session_id, NULL)) AS bounces')->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(the_orders.wc_refunds), 0) AS wc_refunds')->selectRaw('IFNULL(SUM(form_submissions.form_submissions), 0) AS form_submissions')->tap(function (Builder $query) {
foreach (Form::get_forms() as $form) {
$query->selectRaw("SUM(IF(form_submissions.form_id = ?, form_submissions.form_submissions, 0)) AS {$form->submissions_column()}", [$form->id()]);
}
})->from($views_table, 'views')->leftJoin($device_browsers_query->raw($sessions_table . ' AS sessions'), function (JoinClause $join) {
$join->on('views.session_id', '=', 'sessions.session_id');
})->join($device_browsers_query->raw($device_browsers_table . ' AS device_browsers'), function (JoinClause $join) {
$join->on('sessions.device_browser_id', '=', 'device_browsers.device_browser_id');
})->leftJoin($device_browsers_query->raw(Tables::clicks() . ' AS clicks'), function (JoinClause $join) {
$join->on('clicks.view_id', '=', 'views.id');
})->leftJoinSub($orders_query, 'the_orders', function (JoinClause $join) {
$join->on('the_orders.view_id', '=', 'views.id');
})->leftJoinSub($this->get_form_submissions_query(), 'form_submissions', function (JoinClause $join) {
$join->on('form_submissions.view_id', '=', 'views.id');
})->whereBetween('views.viewed_at', $this->get_current_period_iso_range())->when(!$this->appears_to_be_for_real_time_analytics(), function (Builder $query) {
$query->whereBetween('sessions.created_at', $this->get_current_period_iso_range());
})->tap(Query_Taps::tap_authored_content_check())->when(\count($this->filters) > 0, function (Builder $query) {
foreach ($this->filters as $filter) {
if (!$this->is_a_calculated_column($filter->column())) {
$filter->apply_to_query($query);
}
}
})->groupBy('device_browsers.device_browser_id')->having('views', '>', 0)->when(!$this->is_using_a_calculated_column(), function (Builder $query) {
$query->when($this->sort_configuration->is_column_nullable(), function (Builder $query) {
$query->orderByRaw("CASE WHEN {$this->sort_configuration->column()} IS NULL THEN 1 ELSE 0 END");
})->orderBy($this->sort_configuration->column(), $this->sort_configuration->direction())->orderBy('browser')->when(\is_int($this->number_of_rows), function (Builder $query) {
$query->limit($this->number_of_rows);
});
});
$previous_period_query = Illuminate_Builder::new();
$previous_period_query->select(['sessions.device_browser_id'])->selectRaw('SUM(sessions.total_views) AS previous_period_views')->selectRaw('COUNT(DISTINCT sessions.visitor_id) AS previous_period_visitors')->from($sessions_table, 'sessions')->whereBetween('sessions.created_at', $this->get_previous_period_iso_range())->groupBy('sessions.device_browser_id');
$outer_query = Illuminate_Builder::new();
$outer_query->selectRaw('device_browsers.*')->selectRaw('IF(sessions = 0, 0, views / sessions) AS views_per_session')->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('ROUND(CAST(wc_gross_sales - wc_refunded_amount AS SIGNED)) AS wc_net_sales')->selectRaw('IF(visitors = 0, 0, (wc_orders / visitors) * 100) AS wc_conversion_rate')->selectRaw('IF(visitors = 0, 0, (wc_gross_sales - wc_refunded_amount) / 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) {
foreach (Form::get_forms() as $form) {
$query->selectRaw("IF(visitors = 0, 0, ({$form->submissions_column()} / visitors) * 100) AS {$form->conversion_rate_column()}");
}
})->when(\count($this->filters) > 0, function (Builder $query) {
foreach ($this->filters as $filter) {
if ($this->is_a_calculated_column($filter->column())) {
$filter->apply_to_query($query);
}
}
})->fromSub($device_browsers_query, 'device_browsers')->leftJoinSub($previous_period_query, 'previous_period_stats', 'device_browsers.device_browser_id', '=', 'previous_period_stats.device_browser_id')->when($this->is_using_a_calculated_column(), function (Builder $query) {
$query->when($this->sort_configuration->is_column_nullable(), function (Builder $query) {
$query->orderByRaw("CASE WHEN {$this->sort_configuration->column()} IS NULL THEN 1 ELSE 0 END");
})->orderBy($this->sort_configuration->column(), $this->sort_configuration->direction())->orderBy('browser')->when(\is_int($this->number_of_rows), function (Builder $query) {
$query->limit($this->number_of_rows);
});
});
return $outer_query;
}
}
IAWP/Rows/Device_OSS.php 0000644 00000017271 14760033122 0010700 0 ustar 00 joinSub($this->query(\true), 'device_os_rows', function (JoinClause $join) {
$join->on('device_os_rows.device_os_id', '=', 'sessions.device_os_id');
});
}
protected function fetch_rows() : array
{
$rows = $this->query()->get()->all();
return \array_map(function ($row) {
return new Device($row);
}, $rows);
}
private function query(?bool $skip_pagination = \false) : Builder
{
if ($skip_pagination) {
$this->number_of_rows = null;
}
$views_table = Query::get_table_name(Query::VIEWS);
$sessions_table = Query::get_table_name(Query::SESSIONS);
$orders_table = Query::get_table_name(Query::ORDERS);
$device_oss_table = Query::get_table_name(Query::DEVICE_OSS);
$orders_query = Illuminate_Builder::new();
$orders_query->select(['orders.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')->where('orders.is_included_in_analytics', '=', \true)->whereBetween('orders.created_at', $this->get_current_period_iso_range())->groupBy('orders.view_id');
$device_oss_query = Illuminate_Builder::new();
$device_oss_query->select('device_oss.device_os_id', 'device_oss.device_os AS os')->selectRaw('COUNT(DISTINCT views.id) AS views')->selectRaw('COUNT(DISTINCT sessions.visitor_id) AS visitors')->selectRaw('COUNT(DISTINCT sessions.session_id) AS sessions')->selectRaw('ROUND(AVG( TIMESTAMPDIFF(SECOND, sessions.created_at, sessions.ended_at))) AS average_session_duration')->selectRaw('COUNT(DISTINCT IF(sessions.final_view_id IS NULL, sessions.session_id, NULL)) AS bounces')->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(the_orders.wc_refunds), 0) AS wc_refunds')->selectRaw('IFNULL(SUM(form_submissions.form_submissions), 0) AS form_submissions')->tap(function (Builder $query) {
foreach (Form::get_forms() as $form) {
$query->selectRaw("SUM(IF(form_submissions.form_id = ?, form_submissions.form_submissions, 0)) AS {$form->submissions_column()}", [$form->id()]);
}
})->from($views_table, 'views')->leftJoin($device_oss_query->raw($sessions_table . ' AS sessions'), function (JoinClause $join) {
$join->on('views.session_id', '=', 'sessions.session_id');
})->join($device_oss_query->raw($device_oss_table . ' AS device_oss'), function (JoinClause $join) {
$join->on('sessions.device_os_id', '=', 'device_oss.device_os_id');
})->leftJoin($device_oss_query->raw(Tables::clicks() . ' AS clicks'), function (JoinClause $join) {
$join->on('clicks.view_id', '=', 'views.id');
})->leftJoinSub($orders_query, 'the_orders', function (JoinClause $join) {
$join->on('the_orders.view_id', '=', 'views.id');
})->leftJoinSub($this->get_form_submissions_query(), 'form_submissions', function (JoinClause $join) {
$join->on('form_submissions.view_id', '=', 'views.id');
})->whereBetween('views.viewed_at', $this->get_current_period_iso_range())->when(!$this->appears_to_be_for_real_time_analytics(), function (Builder $query) {
$query->whereBetween('sessions.created_at', $this->get_current_period_iso_range());
})->tap(Query_Taps::tap_authored_content_check())->when(\count($this->filters) > 0, function (Builder $query) {
foreach ($this->filters as $filter) {
if (!$this->is_a_calculated_column($filter->column())) {
$filter->apply_to_query($query);
}
}
})->groupBy('device_oss.device_os_id')->having('views', '>', 0)->when(!$this->is_using_a_calculated_column(), function (Builder $query) {
$query->when($this->sort_configuration->is_column_nullable(), function (Builder $query) {
$query->orderByRaw("CASE WHEN {$this->sort_configuration->column()} IS NULL THEN 1 ELSE 0 END");
})->orderBy($this->sort_configuration->column(), $this->sort_configuration->direction())->orderBy('os')->when(\is_int($this->number_of_rows), function (Builder $query) {
$query->limit($this->number_of_rows);
});
});
$previous_period_query = Illuminate_Builder::new();
$previous_period_query->select(['sessions.device_os_id'])->selectRaw('SUM(sessions.total_views) AS previous_period_views')->selectRaw('COUNT(DISTINCT sessions.visitor_id) AS previous_period_visitors')->from($sessions_table, 'sessions')->whereBetween('sessions.created_at', $this->get_previous_period_iso_range())->groupBy('sessions.device_os_id');
$outer_query = Illuminate_Builder::new();
$outer_query->selectRaw('device_oss.*')->selectRaw('IF(sessions = 0, 0, views / sessions) AS views_per_session')->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('ROUND(CAST(wc_gross_sales - wc_refunded_amount AS SIGNED)) AS wc_net_sales')->selectRaw('IF(visitors = 0, 0, (wc_orders / visitors) * 100) AS wc_conversion_rate')->selectRaw('IF(visitors = 0, 0, (wc_gross_sales - wc_refunded_amount) / 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) {
foreach (Form::get_forms() as $form) {
$query->selectRaw("IF(visitors = 0, 0, ({$form->submissions_column()} / visitors) * 100) AS {$form->conversion_rate_column()}");
}
})->when(\count($this->filters) > 0, function (Builder $query) {
foreach ($this->filters as $filter) {
if ($this->is_a_calculated_column($filter->column())) {
$filter->apply_to_query($query);
}
}
})->fromSub($device_oss_query, 'device_oss')->leftJoinSub($previous_period_query, 'previous_period_stats', 'device_oss.device_os_id', '=', 'previous_period_stats.device_os_id')->when($this->is_using_a_calculated_column(), function (Builder $query) {
$query->when($this->sort_configuration->is_column_nullable(), function (Builder $query) {
$query->orderByRaw("CASE WHEN {$this->sort_configuration->column()} IS NULL THEN 1 ELSE 0 END");
})->orderBy($this->sort_configuration->column(), $this->sort_configuration->direction())->orderBy('os')->when(\is_int($this->number_of_rows), function (Builder $query) {
$query->limit($this->number_of_rows);
});
});
Illuminate_Builder::ray($outer_query);
return $outer_query;
}
}
IAWP/Rows/Device_Types.php 0000644 00000017324 14760033122 0011337 0 ustar 00 joinSub($this->query(\true), 'device_type_rows', function (JoinClause $join) {
$join->on('device_type_rows.device_type_id', '=', 'sessions.device_type_id');
});
}
protected function fetch_rows() : array
{
$rows = $this->query()->get()->all();
return \array_map(function ($row) {
return new Device($row);
}, $rows);
}
private function query(?bool $skip_pagination = \false) : Builder
{
if ($skip_pagination) {
$this->number_of_rows = null;
}
$views_table = Query::get_table_name(Query::VIEWS);
$sessions_table = Query::get_table_name(Query::SESSIONS);
$orders_table = Query::get_table_name(Query::ORDERS);
$device_types_table = Query::get_table_name(Query::DEVICE_TYPES);
$orders_query = Illuminate_Builder::new();
$orders_query->select(['orders.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')->where('orders.is_included_in_analytics', '=', \true)->whereBetween('orders.created_at', $this->get_current_period_iso_range())->groupBy('orders.view_id');
$device_types_query = Illuminate_Builder::new();
$device_types_query->select('device_types.device_type_id', 'device_types.device_type')->selectRaw('COUNT(DISTINCT views.id) AS views')->selectRaw('COUNT(DISTINCT sessions.visitor_id) AS visitors')->selectRaw('COUNT(DISTINCT sessions.session_id) AS sessions')->selectRaw('ROUND(AVG( TIMESTAMPDIFF(SECOND, sessions.created_at, sessions.ended_at))) AS average_session_duration')->selectRaw('COUNT(DISTINCT IF(sessions.final_view_id IS NULL, sessions.session_id, NULL)) AS bounces')->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(the_orders.wc_refunds), 0) AS wc_refunds')->selectRaw('IFNULL(SUM(form_submissions.form_submissions), 0) AS form_submissions')->tap(function (Builder $query) {
foreach (Form::get_forms() as $form) {
$query->selectRaw("SUM(IF(form_submissions.form_id = ?, form_submissions.form_submissions, 0)) AS {$form->submissions_column()}", [$form->id()]);
}
})->from($views_table, 'views')->leftJoin($device_types_query->raw($sessions_table . ' AS sessions'), function (JoinClause $join) {
$join->on('views.session_id', '=', 'sessions.session_id');
})->join($device_types_query->raw($device_types_table . ' AS device_types'), function (JoinClause $join) {
$join->on('sessions.device_type_id', '=', 'device_types.device_type_id');
})->leftJoin($device_types_query->raw(Tables::clicks() . ' AS clicks'), function (JoinClause $join) {
$join->on('clicks.view_id', '=', 'views.id');
})->leftJoinSub($orders_query, 'the_orders', function (JoinClause $join) {
$join->on('the_orders.view_id', '=', 'views.id');
})->leftJoinSub($this->get_form_submissions_query(), 'form_submissions', function (JoinClause $join) {
$join->on('form_submissions.view_id', '=', 'views.id');
})->whereBetween('views.viewed_at', $this->get_current_period_iso_range())->when(!$this->appears_to_be_for_real_time_analytics(), function (Builder $query) {
$query->whereBetween('sessions.created_at', $this->get_current_period_iso_range());
})->tap(Query_Taps::tap_authored_content_check())->when(\count($this->filters) > 0, function (Builder $query) {
foreach ($this->filters as $filter) {
if (!$this->is_a_calculated_column($filter->column())) {
$filter->apply_to_query($query);
}
}
})->groupBy('device_types.device_type_id')->having('views', '>', 0)->when(!$this->is_using_a_calculated_column(), function (Builder $query) {
$query->when($this->sort_configuration->is_column_nullable(), function (Builder $query) {
$query->orderByRaw("CASE WHEN {$this->sort_configuration->column()} IS NULL THEN 1 ELSE 0 END");
})->orderBy($this->sort_configuration->column(), $this->sort_configuration->direction())->orderBy('device_type')->when(\is_int($this->number_of_rows), function (Builder $query) {
$query->limit($this->number_of_rows);
});
});
$previous_period_query = Illuminate_Builder::new();
$previous_period_query->select(['sessions.device_type_id'])->selectRaw('SUM(sessions.total_views) AS previous_period_views')->selectRaw('COUNT(DISTINCT sessions.visitor_id) AS previous_period_visitors')->from($sessions_table, 'sessions')->whereBetween('sessions.created_at', $this->get_previous_period_iso_range())->groupBy('sessions.device_type_id');
$outer_query = Illuminate_Builder::new();
$outer_query->selectRaw('device_types.*')->selectRaw('IF(sessions = 0, 0, views / sessions) AS views_per_session')->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('ROUND(CAST(wc_gross_sales - wc_refunded_amount AS SIGNED)) AS wc_net_sales')->selectRaw('IF(visitors = 0, 0, (wc_orders / visitors) * 100) AS wc_conversion_rate')->selectRaw('IF(visitors = 0, 0, (wc_gross_sales - wc_refunded_amount) / 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) {
foreach (Form::get_forms() as $form) {
$query->selectRaw("IF(visitors = 0, 0, ({$form->submissions_column()} / visitors) * 100) AS {$form->conversion_rate_column()}");
}
})->when(\count($this->filters) > 0, function (Builder $query) {
foreach ($this->filters as $filter) {
if ($this->is_a_calculated_column($filter->column())) {
$filter->apply_to_query($query);
}
}
})->fromSub($device_types_query, 'device_types')->leftJoinSub($previous_period_query, 'previous_period_stats', 'device_types.device_type_id', '=', 'previous_period_stats.device_type_id')->when($this->is_using_a_calculated_column(), function (Builder $query) {
$query->when($this->sort_configuration->is_column_nullable(), function (Builder $query) {
$query->orderByRaw("CASE WHEN {$this->sort_configuration->column()} IS NULL THEN 1 ELSE 0 END");
})->orderBy($this->sort_configuration->column(), $this->sort_configuration->direction())->orderBy('device_type')->when(\is_int($this->number_of_rows), function (Builder $query) {
$query->limit($this->number_of_rows);
});
});
return $outer_query;
}
}
IAWP/Rows/Filter.php 0000644 00000022455 14760033122 0010202 0 ustar 00 filter = $filter;
}
public function filter() : array
{
return $this->filter;
}
public function apply_to_query(Builder $query) : void
{
if ($this->filter['column'] === 'category') {
$this->apply_category_filter($query);
} else {
$method = $this->method();
$query->{$method}($this->column(), $this->operator(), $this->value());
}
// If a filter is based on comments, remove all non-singular pages
if ($this->filter['column'] === 'comments') {
$query->whereNotNull('pages.singular_id');
}
}
public function html_description() : string
{
return $this->condition_string($this->filter());
}
public function method() : string
{
if ($this->filter['column'] === $this->filter['database_column']) {
return 'having';
} else {
return 'where';
}
}
public function column() : string
{
return $this->filter['database_column'];
}
// Fix deprecation warning in PHP 8 while still working in PHP 7
#[\ReturnTypeWillChange]
public function jsonSerialize()
{
return $this->filter;
}
/**
* Category filters are different from the other filters
*
* @param Builder $query
* @return void
*/
private function apply_category_filter(Builder $query) : void
{
$wp_query = new \WP_Query(['posts_per_page' => -1, 'cat' => $this->filter['operand'], 'fields' => 'ids']);
$post_ids = $wp_query->posts;
$include = $this->filter['inclusion'] === 'include';
$is = $this->filter['operator'] === 'is';
if ($include === $is) {
$query->whereIn('singular_id', $post_ids);
} else {
$query->where(function (Builder $query) use($post_ids) {
$query->whereNotIn('singular_id', $post_ids)->orWhereNull('singular_id');
});
}
}
private function condition_string(array $condition) : string
{
$full_string = '';
foreach ($condition as $key => $value) {
if (!\in_array($key, ['inclusion', 'column', 'operator', 'operand'])) {
continue;
}
$condition_string = '';
if ($key == 'inclusion' && $value == 'include') {
$condition_string = \esc_html__('Include', 'independent-analytics');
} elseif ($key == 'inclusion' && $value == 'exclude') {
$condition_string = \esc_html__('Exclude', 'independent-analytics');
} elseif ($key == 'operator' && $value == 'lesser') {
$condition_string = '<';
} elseif ($key == 'operator' && $value == 'greater') {
$condition_string = '>';
} elseif ($key == 'operator' && $value == 'equal') {
$condition_string = '=';
} elseif ($key == 'operator' && $value == 'on') {
$condition_string = \esc_html__('On', 'independent-analytics');
} elseif ($key == 'operator' && $value == 'before') {
$condition_string = \esc_html__('Before', 'independent-analytics');
} elseif ($key == 'operator' && $value == 'after') {
$condition_string = \esc_html__('After', 'independent-analytics');
} elseif ($key == 'operator' && $value == 'contains') {
$condition_string = \esc_html__('Contains', 'independent-analytics');
} elseif ($key == 'operator' && $value == 'exact') {
$condition_string = \esc_html__('Exactly matches', 'independent-analytics');
} elseif ($key == 'operator' && $value == 'is') {
$condition_string = \esc_html__('Is', 'independent-analytics');
} elseif ($key == 'operator' && $value == 'isnt') {
$condition_string = \esc_html__("Isn't", 'independent-analytics');
} elseif ($key == 'operand' && $condition['column'] == 'browser') {
$condition_string = Device_Browser_Filter_List::option($value);
} elseif ($key == 'operand' && $condition['column'] == 'os') {
$condition_string = Device_OS_Filter_List::option($value);
} elseif ($key == 'operand' && $condition['column'] == 'device_type') {
$condition_string = Device_Type_Filter_List::option($value);
} elseif ($key == 'operand' && $condition['column'] == 'date') {
try {
$date = \DateTime::createFromFormat('U', $value);
$condition_string = $date->format(WordPress_Site_Date_Format_Pattern::for_php());
} catch (\Throwable $e) {
$condition_string = $value;
}
} elseif ($key == 'operand' && $condition['column'] == 'author') {
$condition_string = Author_Filter_List::option($value);
} elseif ($key == 'operand' && $condition['column'] == 'category') {
$condition_string = Category_Filter_List::option($value);
} elseif ($key == 'operand' && $condition['column'] == 'referrer_type') {
$condition_string = Referrer_Type_Filter_List::option($value);
} elseif ($key == 'operand' && $condition['column'] == 'link_name') {
$condition_string = Link_Name_Filter_List::option($value);
} elseif ($key == 'operand' && $condition['column'] == 'type') {
$condition_string = Page_Type_Filter_List::option($value);
} elseif ($key == 'column' && \str_contains($value, 'wc')) {
$condition_string = \str_replace(['_', '-'], ' ', $value);
$condition_string = \str_replace('wc', 'WC', $condition_string);
} elseif ($key == 'column' && String_Util::str_starts_with($condition['column'], 'form_submissions_for_')) {
$condition_string = \__('Submissions for', 'independent-analytics') . ' ' . Form::find_form_by_column_name($condition['column'])->title();
} elseif ($key == 'column' && String_Util::str_starts_with($condition['column'], 'form_conversion_rate_for_')) {
$condition_string = \__('Conversion rate for', 'independent-analytics') . ' ' . Form::find_form_by_column_name($condition['column'])->title();
} elseif ($key == 'column' && $condition['column'] == 'link_name') {
$condition_string = \__('Link Pattern', 'independent-analytics') . ' ';
} else {
$condition_string .= \ucwords(\str_replace(['_', '-'], ' ', $value)) . ' ';
}
if ($key == 'column' || $key == 'operand') {
$condition_string = '' . $condition_string . ' ';
}
$full_string .= $condition_string . ' ';
}
return \trim($full_string);
}
private function operator() : string
{
$operator = $this->filter['operator'];
$result = '';
if ($operator === 'equal' || $operator === 'is' || $operator === 'exact' || $operator === 'on') {
$result = '=';
}
if ($operator === 'contains') {
$result = 'like';
}
if ($operator === 'isnt') {
$result = '!=';
}
if ($operator === 'greater' || $operator === 'after') {
$result = '>';
}
if ($operator === 'lesser' || $operator === 'before') {
$result = '<';
}
if ($this->filter['inclusion'] === 'exclude') {
if ($result === '=') {
return '!=';
} elseif ($result === '!=') {
return '=';
} elseif ($result === '>') {
return '<=';
} elseif ($result === '<') {
return '>=';
} elseif ($result === 'like') {
return 'not like';
}
}
return $result;
}
private function value() : string
{
if ($this->filter['operator'] === 'contains') {
return '%' . $this->filter['operand'] . '%';
}
if ($this->filter['database_column'] === 'cached_date') {
try {
$date = \DateTime::createFromFormat('U', $this->filter['operand']);
} catch (\Throwable $e) {
$date = new \DateTime();
}
return $date->format('Y-m-d');
}
if (\in_array($this->filter['database_column'], ['wc_gross_sales', 'wc_refunded_amount', 'wc_net_sales', 'wc_earnings_per_visitor', 'wc_average_order_volume'])) {
return \strval(\floatval($this->filter['operand']) * 100);
}
return $this->filter['operand'];
}
}
IAWP/Rows/Pages.php 0000644 00000025147 14760033122 0010015 0 ustar 00 joinSub($this->query(\true), 'page_rows', function (JoinClause $join) {
$join->on('page_rows.id', '=', 'views.resource_id');
});
}
protected function fetch_rows() : array
{
$rows = $this->query()->get()->all();
return \array_map(function (object $row) {
return Page::from_row($row);
}, $rows);
}
private function has_wp_comments_table() : bool
{
if (\is_bool(self::$has_wp_comments_table)) {
return self::$has_wp_comments_table;
}
global $wpdb;
self::$has_wp_comments_table = Database::has_table($wpdb->prefix . 'comments');
return self::$has_wp_comments_table;
}
private function query(?bool $skip_pagination = \false) : Builder
{
if ($skip_pagination) {
$this->number_of_rows = null;
}
$views_table = Query::get_table_name(Query::VIEWS);
$sessions_table = Query::get_table_name(Query::SESSIONS);
$resources_table = Query::get_table_name(Query::RESOURCES);
$orders_table = Query::get_table_name(Query::ORDERS);
$database_sort_columns = ['title' => 'cached_title', 'url' => 'cached_url', 'author' => 'cached_author', 'type' => 'cached_type_label', 'date' => 'cached_date', 'category' => 'cached_category'];
$sort_column = $this->sort_configuration->column();
foreach ($database_sort_columns as $key => $value) {
if ($sort_column === $key) {
$sort_column = $value;
}
}
$orders_query = Illuminate_Builder::new();
$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) {
$join->on('orders.view_id', '=', 'views.id');
})->leftJoin($orders_query->raw($sessions_table . ' AS sessions'), function (JoinClause $join) {
$join->on('views.session_id', '=', 'sessions.session_id');
})->where('orders.is_included_in_analytics', '=', \true)->whereBetween('orders.created_at', $this->get_current_period_iso_range())->groupBy('orders.view_id');
$pages_query = Illuminate_Builder::new();
$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) {
foreach (Form::get_forms() as $form) {
$query->selectRaw("SUM(IF(form_submissions.form_id = ?, form_submissions.form_submissions, 0)) AS {$form->submissions_column()}", [$form->id()]);
}
})->from($views_table, 'views')->leftJoin($pages_query->raw($sessions_table . ' AS sessions'), function (JoinClause $join) {
$join->on('views.session_id', '=', 'sessions.session_id');
})->leftJoin($pages_query->raw($resources_table . ' AS resources'), function (JoinClause $join) {
$join->on('views.resource_id', '=', 'resources.id');
})->leftJoin($pages_query->raw($views_table . ' AS initial_view'), function (JoinClause $join) {
$join->on('sessions.initial_view_id', '=', 'initial_view.id');
})->leftJoin($pages_query->raw($views_table . ' AS final_view'), function (JoinClause $join) {
$join->on('sessions.final_view_id', '=', 'final_view.id');
})->leftJoin($pages_query->raw(Tables::clicks() . ' AS clicks'), function (JoinClause $join) {
$join->on('clicks.view_id', '=', 'views.id');
})->leftJoinSub($orders_query, 'the_orders', function (JoinClause $join) {
$join->on('the_orders.view_id', '=', 'views.id');
})->tap(Query_Taps::tap_authored_content_check(\false))->when($this->has_wp_comments_table(), function (Builder $query) {
$query->selectRaw('IFNULL(comments.comments, 0) AS comments');
$query->leftJoinSub($this->get_comments_query(), 'comments', 'comments.resource_id', '=', 'resources.id');
}, function (Builder $query) {
$query->selectRaw('0 AS comments');
})->leftJoinSub($this->get_form_submissions_query(), 'form_submissions', function (JoinClause $join) {
$join->on('form_submissions.view_id', '=', 'views.id');
})->whereBetween('views.viewed_at', $this->get_current_period_iso_range())->when(!$this->appears_to_be_for_real_time_analytics(), function (Builder $query) {
$query->whereBetween('sessions.created_at', $this->get_current_period_iso_range());
})->when(\count($this->filters) > 0, function (Builder $query) {
foreach ($this->filters as $filter) {
if (!$this->is_a_calculated_column($filter->column())) {
$filter->apply_to_query($query);
}
}
})->groupBy('resources.id')->having('views', '>', 0)->when(!$this->is_using_a_calculated_column(), function (Builder $query) use($sort_column) {
$query->when($this->sort_configuration->is_column_nullable(), function (Builder $query) use($sort_column) {
$query->orderByRaw("CASE WHEN {$sort_column} IS NULL THEN 1 ELSE 0 END");
})->orderBy($sort_column, $this->sort_configuration->direction())->orderBy('cached_title')->when(\is_int($this->number_of_rows), function (Builder $query) {
$query->limit($this->number_of_rows);
});
});
$previous_period_query = Illuminate_Builder::new();
$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');
$outer_query = Illuminate_Builder::new();
$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) {
foreach (Form::get_forms() as $form) {
$query->selectRaw("IF(visitors = 0, 0, ({$form->submissions_column()} / visitors) * 100) AS {$form->conversion_rate_column()}");
}
})->when(\count($this->filters) > 0, function (Builder $query) {
foreach ($this->filters as $filter) {
if ($this->is_a_calculated_column($filter->column())) {
$filter->apply_to_query($query);
}
}
})->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) {
$query->when($this->sort_configuration->is_column_nullable(), function (Builder $query) use($sort_column) {
$query->orderByRaw("CASE WHEN {$sort_column} IS NULL THEN 1 ELSE 0 END");
})->orderBy($sort_column, $this->sort_configuration->direction())->orderBy('cached_title')->when(\is_int($this->number_of_rows), function (Builder $query) {
$query->limit($this->number_of_rows);
});
});
return $outer_query;
}
private function get_comments_query() : Builder
{
global $wpdb;
$comments_table = $wpdb->prefix . 'comments';
$resources_table = Query::get_table_name(Query::RESOURCES);
$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');
return $comments_query;
}
}
IAWP/Rows/Referrers.php 0000644 00000017207 14760033122 0010713 0 ustar 00 joinSub($this->query(\true), 'referrer_rows', function (JoinClause $join) {
$join->on('referrer_rows.referrer_id', '=', 'sessions.referrer_id');
});
}
protected function fetch_rows() : array
{
$rows = $this->query()->get()->all();
return \array_map(function ($row) {
return new Referrer($row);
}, $rows);
}
private function query(?bool $skip_pagination = \false) : Builder
{
if ($skip_pagination) {
$this->number_of_rows = null;
}
$views_table = Query::get_table_name(Query::VIEWS);
$sessions_table = Query::get_table_name(Query::SESSIONS);
$orders_table = Query::get_table_name(Query::ORDERS);
$referrers_table = Query::get_table_name(Query::REFERRERS);
$orders_query = Illuminate_Builder::new();
$orders_query->select(['orders.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')->where('orders.is_included_in_analytics', '=', \true)->whereBetween('orders.created_at', $this->get_current_period_iso_range())->groupBy('orders.view_id');
$referrers_query = Illuminate_Builder::new();
$referrers_query->select('sessions.referrer_id', 'referrer', 'type AS referrer_type', 'domain')->selectRaw('COUNT(DISTINCT views.id) AS views')->selectRaw('COUNT(DISTINCT sessions.visitor_id) AS visitors')->selectRaw('COUNT(DISTINCT sessions.session_id) AS sessions')->selectRaw('ROUND(AVG( TIMESTAMPDIFF(SECOND, sessions.created_at, sessions.ended_at))) AS average_session_duration')->selectRaw('COUNT(DISTINCT IF(sessions.final_view_id IS NULL, sessions.session_id, NULL)) AS bounces')->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(the_orders.wc_refunds), 0) AS wc_refunds')->selectRaw('IFNULL(SUM(form_submissions.form_submissions), 0) AS form_submissions')->tap(function (Builder $query) {
foreach (Form::get_forms() as $form) {
$query->selectRaw("SUM(IF(form_submissions.form_id = ?, form_submissions.form_submissions, 0)) AS {$form->submissions_column()}", [$form->id()]);
}
})->from($views_table, 'views')->leftJoin($referrers_query->raw($sessions_table . ' AS sessions'), function (JoinClause $join) {
$join->on('views.session_id', '=', 'sessions.session_id');
})->leftJoin($referrers_query->raw($referrers_table . ' AS referrers'), function (JoinClause $join) {
$join->on('sessions.referrer_id', '=', 'referrers.id');
})->leftJoin($referrers_query->raw(Tables::clicks() . ' AS clicks'), function (JoinClause $join) {
$join->on('clicks.view_id', '=', 'views.id');
})->leftJoinSub($orders_query, 'the_orders', function (JoinClause $join) {
$join->on('the_orders.view_id', '=', 'views.id');
})->leftJoinSub($this->get_form_submissions_query(), 'form_submissions', function (JoinClause $join) {
$join->on('form_submissions.view_id', '=', 'views.id');
})->whereBetween('views.viewed_at', $this->get_current_period_iso_range())->when(!$this->appears_to_be_for_real_time_analytics(), function (Builder $query) {
$query->whereBetween('sessions.created_at', $this->get_current_period_iso_range());
})->tap(Query_Taps::tap_authored_content_check())->when(\count($this->filters) > 0, function (Builder $query) {
foreach ($this->filters as $filter) {
if (!$this->is_a_calculated_column($filter->column())) {
$filter->apply_to_query($query);
}
}
})->groupBy('sessions.referrer_id')->having('views', '>', 0)->when(!$this->is_using_a_calculated_column(), function (Builder $query) {
$query->when($this->sort_configuration->is_column_nullable(), function (Builder $query) {
$query->orderByRaw("CASE WHEN {$this->sort_configuration->column()} IS NULL THEN 1 ELSE 0 END");
})->orderBy($this->sort_configuration->column(), $this->sort_configuration->direction())->orderBy('referrer')->when(\is_int($this->number_of_rows), function (Builder $query) {
$query->limit($this->number_of_rows);
});
});
$previous_period_query = Illuminate_Builder::new();
$previous_period_query->select(['sessions.referrer_id'])->selectRaw('SUM(sessions.total_views) AS previous_period_views')->selectRaw('COUNT(DISTINCT sessions.visitor_id) AS previous_period_visitors')->from($sessions_table, 'sessions')->whereBetween('sessions.created_at', $this->get_previous_period_iso_range())->groupBy('sessions.referrer_id');
$outer_query = Illuminate_Builder::new();
$outer_query->selectRaw('referrers.*')->selectRaw('IF(sessions = 0, 0, views / sessions) AS views_per_session')->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('ROUND(CAST(wc_gross_sales - wc_refunded_amount AS SIGNED)) AS wc_net_sales')->selectRaw('IF(visitors = 0, 0, (wc_orders / visitors) * 100) AS wc_conversion_rate')->selectRaw('IF(visitors = 0, 0, (wc_gross_sales - wc_refunded_amount) / 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) {
foreach (Form::get_forms() as $form) {
$query->selectRaw("IF(visitors = 0, 0, ({$form->submissions_column()} / visitors) * 100) AS {$form->conversion_rate_column()}");
}
})->when(\count($this->filters) > 0, function (Builder $query) {
foreach ($this->filters as $filter) {
if ($this->is_a_calculated_column($filter->column())) {
$filter->apply_to_query($query);
}
}
})->fromSub($referrers_query, 'referrers')->leftJoinSub($previous_period_query, 'previous_period_stats', 'referrers.referrer_id', '=', 'previous_period_stats.referrer_id')->when($this->is_using_a_calculated_column(), function (Builder $query) {
$query->when($this->sort_configuration->is_column_nullable(), function (Builder $query) {
$query->orderByRaw("CASE WHEN {$this->sort_configuration->column()} IS NULL THEN 1 ELSE 0 END");
})->orderBy($this->sort_configuration->column(), $this->sort_configuration->direction())->orderBy('referrer')->when(\is_int($this->number_of_rows), function (Builder $query) {
$query->limit($this->number_of_rows);
});
});
return $outer_query;
}
}
IAWP/Rows/Rows.php 0000644 00000006606 14760033122 0007707 0 ustar 00 date_range = $date_range;
$this->number_of_rows = $number_of_rows;
$this->filters = $filters ?? [];
$this->sort_configuration = $sort_configuration ?? new Sort_Configuration('visitors');
}
protected abstract function fetch_rows() : array;
public abstract function attach_filters(Builder $query) : void;
public function rows()
{
if (\is_array($this->rows)) {
return $this->rows;
}
$this->rows = $this->fetch_rows();
return $this->rows;
}
/**
* @return string[]
*/
protected function calculated_columns() : array
{
$calculated_columns = ['comments', 'exit_percent', 'views_per_session', 'views_growth', 'visitors_growth', 'bounce_rate', 'wc_net_sales', 'wc_conversion_rate', 'wc_earnings_per_visitor', 'wc_average_order_volume', 'form_conversion_rate'];
foreach (Form::get_forms() as $form) {
$calculated_columns[] = $form->conversion_rate_column();
}
return $calculated_columns;
}
protected function is_a_calculated_column(string $column_name) : bool
{
return \in_array($column_name, $this->calculated_columns());
}
protected function is_using_a_calculated_column() : bool
{
$is_using_a_calculated_column = \false;
foreach ($this->filters as $filter) {
if (\in_array($filter->column(), $this->calculated_columns())) {
$is_using_a_calculated_column = \true;
}
}
if (\in_array($this->sort_configuration->column(), $this->calculated_columns())) {
$is_using_a_calculated_column = \true;
}
return $is_using_a_calculated_column;
}
protected function get_current_period_iso_range() : array
{
return [$this->date_range->iso_start(), $this->date_range->iso_end()];
}
protected function appears_to_be_for_real_time_analytics() : bool
{
$difference_in_seconds = $this->date_range->end()->getTimestamp() - $this->date_range->start()->getTimestamp();
$one_hour_in_seconds = 3600;
return $difference_in_seconds < $one_hour_in_seconds;
}
protected function get_previous_period_iso_range() : array
{
return [$this->date_range->previous_period()->iso_start(), $this->date_range->previous_period()->iso_end()];
}
protected function get_form_submissions_query() : Builder
{
$form_submissions_table = Query::get_table_name(Query::FORM_SUBMISSIONS);
return Illuminate_Builder::new()->select(['form_id', 'view_id'])->selectRaw('COUNT(*) AS form_submissions')->from($form_submissions_table, 'form_submissions')->whereBetween('created_at', $this->get_current_period_iso_range())->groupBy(['form_id', 'view_id']);
}
}
IAWP/Statistics/Intervals/Daily.php 0000644 00000001456 14760033122 0013164 0 ustar 00 setTime(0, 0, 0);
return $date_time;
}
public function get_label_for(\DateTime $date_time) : array
{
return ['tick' => $this->format($date_time, 'M j'), 'tooltipLabel' => $this->format($date_time, 'F jS (l)')];
}
}
IAWP/Statistics/Intervals/Hourly.php 0000644 00000002176 14760033122 0013404 0 ustar 00 setTime(\intval($date_time->format('G')), 0, 0);
return $date_time;
}
public function get_label_for(\DateTime $date_time) : array
{
$date_format = 'F jS';
$time_format = \IAWPSCOPED\iawp()->get_option('time_format', 'g:i a');
$in_one_hour = (clone $date_time)->add(new \DateInterval('PT1H'));
return ['tick' => $this->format($date_time, $time_format), 'tooltipLabel' => $this->format($date_time, $time_format) . " - " . $this->format($in_one_hour, $time_format) . $this->format($date_time, ' (' . $date_format . ')')];
}
}
IAWP/Statistics/Intervals/Interval.php 0000644 00000001573 14760033122 0013706 0 ustar 00 id() === $interval->id();
}
protected function format(\DateTime $date_time, string $format)
{
return \wp_date($format, $date_time->getTimestamp(), $date_time->getTimezone());
}
}
IAWP/Statistics/Intervals/Intervals.php 0000644 00000002653 14760033122 0014071 0 ustar 00 id() === $interval_id) {
return $interval;
}
}
return new \IAWP\Statistics\Intervals\Daily();
}
public static function default_for(int $days) : \IAWP\Statistics\Intervals\Interval
{
if ($days <= 3) {
return new \IAWP\Statistics\Intervals\Hourly();
} elseif ($days <= 84) {
return new \IAWP\Statistics\Intervals\Daily();
} elseif ($days <= 182) {
return new \IAWP\Statistics\Intervals\Weekly();
} else {
return new \IAWP\Statistics\Intervals\Monthly();
}
}
// public static function create_interval(?string $interval_id): Interval
// {
// // Switch case...
// }
}
IAWP/Statistics/Intervals/Monthly.php 0000644 00000001622 14760033122 0013547 0 ustar 00 setDate(\intval($date_time->format('Y')), \intval($date_time->format('m')), 1);
$date_time->setTime(0, 0, 0);
return $date_time;
}
public function get_label_for(\DateTime $date_time) : array
{
return ['tick' => $this->format($date_time, 'F'), 'tooltipLabel' => $this->format($date_time, 'F Y')];
}
}
IAWP/Statistics/Intervals/Weekly.php 0000644 00000002505 14760033122 0013356 0 ustar 00 setTime(0, 0, 0);
$start_of_week = \intval(\get_option('iawp_dow', 0));
$day_of_week = \intval($date_time->format('w'));
$days_to_subtract = $day_of_week - $start_of_week;
if ($days_to_subtract < 0) {
$days_to_subtract = 7 - \abs($days_to_subtract);
}
$interval_to_subtract = new \DateInterval('P' . $days_to_subtract . "D");
$date_time->sub($interval_to_subtract);
return $date_time;
}
public function get_label_for(\DateTime $date_time) : array
{
$in_six_days = (clone $date_time)->add(new \DateInterval('P6D'));
return ['tick' => $this->format($date_time, 'M j'), 'tooltipLabel' => $this->format($date_time, 'F jS') . ' - ' . $this->format($in_six_days, 'F jS')];
}
}
IAWP/Statistics/Campaign_Statistics.php 0000644 00000000334 14760033122 0014076 0 ustar 00 selectRaw('COUNT(DISTINCT link_rules.link_rule_id, clicks.click_target_id) AS total_table_rows')->from($this->tables::link_rules(), 'link_rules')->leftJoin($this->tables::clicked_links() . ' AS clicked_links', 'clicked_links.link_rule_id', '=', 'link_rules.link_rule_id')->leftJoin($this->tables::clicks() . ' AS clicks', 'clicks.click_id', '=', 'clicked_links.click_id')->leftJoin($this->tables::click_targets() . ' AS click_targets', 'click_targets.click_target_id', '=', 'clicks.click_target_id')->when(!\is_null($this->rows), function (Builder $query) {
$this->rows->attach_filters($query);
})->tap(Query_Taps::tap_authored_content_for_clicks())->whereBetween('clicks.created_at', [$this->date_range->iso_start(), $this->date_range->iso_end()]);
return $query->value('total_table_rows');
}
protected function make_statistic_instances() : array
{
return [$this->make_statistic(['id' => 'clicks', 'name' => \__('Clicks', 'independent-analytics'), 'plugin_group' => 'general'])];
}
protected function query(Date_Range $range, ?Rows $rows = null, bool $is_grouped_by_date_interval = \false)
{
$utc_offset = Timezone::utc_offset();
$site_offset = Timezone::site_offset();
$query = Illuminate_Builder::new()->selectRaw('COUNT(DISTINCT clicks.click_id) AS clicks')->from($this->tables::link_rules(), 'link_rules')->leftJoin($this->tables::clicked_links() . ' AS clicked_links', 'clicked_links.link_rule_id', '=', 'link_rules.link_rule_id')->leftJoin($this->tables::clicks() . ' AS clicks', 'clicks.click_id', '=', 'clicked_links.click_id')->leftJoin($this->tables::click_targets() . ' AS click_targets', 'click_targets.click_target_id', '=', 'clicks.click_target_id')->when(!\is_null($rows), function (Builder $query) use($rows) {
$rows->attach_filters($query);
})->tap(Query_Taps::tap_authored_content_for_clicks())->whereBetween('clicks.created_at', [$range->iso_start(), $range->iso_end()])->when($is_grouped_by_date_interval, function (Builder $query) use($utc_offset, $site_offset) {
if ($this->chart_interval->id() === 'daily') {
$query->selectRaw("DATE(CONVERT_TZ(clicks.created_at, '{$utc_offset}', '{$site_offset}')) AS date");
} elseif ($this->chart_interval->id() === 'monthly') {
$query->selectRaw("DATE_FORMAT(CONVERT_TZ(clicks.created_at, '{$utc_offset}', '{$site_offset}'), '%Y-%m-01 00:00:00') AS date");
} elseif ($this->chart_interval->id() === 'weekly') {
$day_of_week = \IAWPSCOPED\iawp()->get_option('iawp_dow', 0) + 1;
$query->selectRaw("\n IF (\n DAYOFWEEK(CONVERT_TZ(clicks.created_at, '{$utc_offset}', '{$site_offset}')) - {$day_of_week} < 0,\n DATE_FORMAT(SUBDATE(CONVERT_TZ(clicks.created_at, '{$utc_offset}', '{$site_offset}'), DAYOFWEEK(CONVERT_TZ(clicks.created_at, '{$utc_offset}', '{$site_offset}')) - {$day_of_week} + 7), '%Y-%m-%d 00:00:00'),\n DATE_FORMAT(SUBDATE(CONVERT_TZ(clicks.created_at, '{$utc_offset}', '{$site_offset}'), DAYOFWEEK(CONVERT_TZ(clicks.created_at, '{$utc_offset}', '{$site_offset}')) - {$day_of_week}), '%Y-%m-%d 00:00:00')\n ) AS date\n ");
} else {
$query->selectRaw("DATE_FORMAT(CONVERT_TZ(clicks.created_at, '{$utc_offset}', '{$site_offset}'), '%Y-%m-%d %H:00:00') AS date");
}
$query->groupByRaw("date");
});
$results = \array_map(function (object $statistic) : object {
return $this->clean_up_raw_statistic_row($statistic);
}, $query->get()->all());
if (!$is_grouped_by_date_interval) {
return $results[0];
}
return $results;
}
}
IAWP/Statistics/Country_Statistics.php 0000644 00000000332 14760033122 0014020 0 ustar 00 id = $attributes['id'];
$this->name = $attributes['name'];
$this->plugin_group = $attributes['plugin_group'];
$this->plugin_group_header = $attributes['plugin_group_header'] ?? null;
$this->icon = $attributes['icon'] ?? null;
$this->statistic = $attributes['statistic'] ?? 0;
$this->previous_period_statistic = $attributes['previous_period_statistic'] ?? 0;
$this->unfiltered_statistic = $attributes['unfiltered_statistic'] ?? null;
$this->statistic_over_time = $attributes['statistic_over_time'];
$this->is_visible_in_dashboard_widget = $attributes['is_visible_in_dashboard_widget'] ?? \false;
$this->format = $attributes['format'] ?? null;
$this->is_growth_good = $attributes['is_growth_good'] ?? \true;
$this->is_subgroup_plugin_enabled = $attributes['is_subgroup_plugin_active'] ?? \true;
$this->requires_pro = $attributes['requires_pro'] ?? \false;
}
public function is_enabled() : bool
{
if ($this->requires_pro === \true && \IAWPSCOPED\iawp_is_free()) {
return \false;
}
return \true;
}
public function id() : string
{
return $this->id;
}
public function name() : string
{
return $this->name;
}
public function icon() : ?string
{
return $this->icon;
}
public function plugin_group() : string
{
return $this->plugin_group;
}
public function plugin_group_header() : ?string
{
return $this->plugin_group_header;
}
public function is_visible_in_dashboard_widget() : bool
{
return $this->is_visible_in_dashboard_widget;
}
public function statistic_over_time() : array
{
return $this->statistic_over_time;
}
public function is_group_plugin_enabled() : bool
{
switch ($this->plugin_group) {
case "ecommerce":
return \IAWPSCOPED\iawp()->is_ecommerce_support_enabled();
case "forms":
return \IAWPSCOPED\iawp()->is_form_submission_support_enabled();
default:
return \true;
}
}
public function is_subgroup_plugin_enabled() : bool
{
return $this->is_subgroup_plugin_enabled;
}
public function is_visible() : bool
{
$options = Dashboard_Options::getInstance();
return \in_array($this->id(), $options->visible_quick_stats());
}
public function is_member_of_plugin_group(string $plugin_group) : bool
{
return $this->plugin_group === $plugin_group;
}
public function formatted_value() : string
{
return $this->format_value($this->statistic);
}
public function value()
{
return $this->statistic;
}
public function formatted_unfiltered_value() : ?string
{
if (\is_null($this->unfiltered_statistic)) {
return null;
}
return $this->format_value($this->unfiltered_statistic);
}
/**
* Growth can be good or bad depending on the quick stat. This allows it to be calculated on a
* at the individual quick stat level.
*
* The default behavior is "up" and "good" so you can tweak either of those as needed
*
* @return string
*/
public function growth_html_class() : string
{
$html_classes = [];
$has_growth = $this->growth() >= 0;
if (!$has_growth) {
$html_classes[] = 'down';
}
if ($has_growth && !$this->is_growth_good || !$has_growth && $this->is_growth_good) {
$html_classes[] = 'bad';
}
return \implode(' ', $html_classes);
}
public function formatted_growth() : string
{
$growth = $this->growth();
return Number_Formatter::percent(\absint($growth));
}
public function growth()
{
if ($this->statistic == 0 && $this->previous_period_statistic != 0) {
return -100;
} elseif ($this->statistic == 0 || $this->previous_period_statistic == 0) {
return 0;
}
$percent_growth = ($this->statistic / $this->previous_period_statistic - 1) * 100;
return \round($percent_growth, 0);
}
private function format_value($value) : string
{
switch ($this->format) {
case 'time':
return Number_Formatter::second_to_minute_timestamp($value);
case 'percent':
return Number_Formatter::percent($value, 2);
case 'decimal':
return Number_Formatter::decimal($value, 2);
case 'currency':
return Currency::format($value, \false);
case 'rounded-currency':
return Currency::format($value, \true);
default:
return Number_Formatter::integer($value);
}
}
}
IAWP/Statistics/Statistics.php 0000644 00000056106 14760033122 0012307 0 ustar 00 date_range = $date_range;
$this->rows = $rows;
$this->chart_interval = $chart_interval ?? Intervals::default_for($date_range->number_of_days());
if (\is_null($rows)) {
$this->statistics = $this->query($this->date_range);
$this->previous_period_statistics = $this->query($this->date_range->previous_period());
$this->statistics_grouped_by_date_interval = $this->query($this->date_range, null, \true);
} else {
$this->statistics = $this->query($this->date_range, $rows);
$this->previous_period_statistics = $this->query($this->date_range->previous_period(), $rows);
$this->statistics_grouped_by_date_interval = $this->query($this->date_range, $rows, \true);
$this->unfiltered_statistics = $this->query($this->date_range);
$this->previous_period_unfiltered_statistic = $this->query($this->date_range->previous_period());
$this->unfiltered_statistics_grouped_by_date_interval = $this->query($this->date_range, null, \true);
}
$this->statistic_instances = $this->make_statistic_instances();
$this->statistic_instances = \array_filter($this->statistic_instances, function (\IAWP\Statistics\Statistic $statistic) {
return $statistic->is_enabled();
});
}
/**
* @return Statistic[]
*/
public function get_statistics() : array
{
return $this->statistic_instances;
}
public function get_grouped_statistics()
{
// This whole thing is a bit of a mess...
return Collection::make($this->statistic_instances)->groupBy(function (\IAWP\Statistics\Statistic $item, int $key) {
return Plugin_Group::get_plugin_group($item->plugin_group())->name();
})->map(function (Collection $group, $plugin_group) {
$items = $group->map(function (\IAWP\Statistics\Statistic $item) {
if (!$item->is_group_plugin_enabled()) {
return null;
}
return ['id' => $item->id(), 'name' => $item->name()];
})->filter();
if ($items->isEmpty()) {
return null;
}
return ['name' => $plugin_group, 'items' => $items->toArray()];
})->filter()->values()->toArray();
}
public function get_statistic(string $statistic_id) : ?\IAWP\Statistics\Statistic
{
foreach ($this->statistic_instances as $statistic_instance) {
if ($statistic_instance->id() == $statistic_id) {
return $statistic_instance;
}
}
return null;
}
public function has_filters() : bool
{
return !\is_null($this->rows);
}
public function chart_interval() : Interval
{
return $this->chart_interval;
}
/**
* I'm sure there's more we could do here. If you get a result back where there isn't a full
* page of results or where you're not paginating, then you can just count up the rows...
*
* @return int|null
*/
public function total_number_of_rows() : ?int
{
$sessions_table = Query::get_table_name(Query::SESSIONS);
$views_table = Query::get_table_name(Query::VIEWS);
$column = $this->total_table_rows_column() ?? $this->required_column();
$query = Illuminate_Builder::new()->selectRaw("COUNT(DISTINCT {$column}) AS total_table_rows")->from("{$sessions_table} AS sessions")->join("{$views_table} AS views", function (JoinClause $join) {
$join->on('sessions.session_id', '=', 'views.session_id');
})->tap(Query_Taps::tap_authored_content_check(\true))->when(!\is_null($this->rows), function (Builder $query) {
$this->rows->attach_filters($query);
})->whereBetween('sessions.created_at', [$this->date_range->iso_start(), $this->date_range->iso_end()])->whereBetween('views.viewed_at', [$this->date_range->iso_start(), $this->date_range->iso_end()]);
return $query->value('total_table_rows');
}
/**
* Define which id column to use to count up the total table rows. This is only required
* for classes that don't have a required column and don't override required_column
*
* @return string|null
*/
protected function total_table_rows_column() : ?string
{
return null;
}
/**
* Statistics can require that a column exists in order to be included. As an example, geos
* requires visitors.country_code and campaigns requires sessions.campaign_id
*
* @return string|null
*/
protected function required_column() : ?string
{
return null;
}
/**
* @return Statistic[]
*/
protected function make_statistic_instances() : array
{
$statistics = [$this->make_statistic(['id' => 'visitors', 'name' => \__('Visitors', 'independent-analytics'), 'plugin_group' => 'general', 'is_visible_in_dashboard_widget' => \true]), $this->make_statistic(['id' => 'views', 'name' => \__('Views', 'independent-analytics'), 'plugin_group' => 'general', 'is_visible_in_dashboard_widget' => \true]), $this->make_statistic(['id' => 'sessions', 'name' => \__('Sessions', 'independent-analytics'), 'plugin_group' => 'general']), $this->make_statistic(['id' => 'average_session_duration', 'name' => \__('Average Session Duration', 'independent-analytics'), 'plugin_group' => 'general', 'format' => 'time']), $this->make_statistic(['id' => 'bounce_rate', 'name' => \__('Bounce Rate', 'independent-analytics'), 'plugin_group' => 'general', 'format' => 'percent', 'is_growth_good' => \false, 'compute' => function (object $statistics) {
return Calculations::percentage($statistics->bounces, $statistics->sessions);
}]), $this->make_statistic(['id' => 'views_per_session', 'name' => \__('Views Per Session', 'independent-analytics'), 'plugin_group' => 'general', 'format' => 'decimal', 'compute' => function (object $statistics) {
return Calculations::divide($statistics->total_views, $statistics->sessions, 2);
}]), $this->make_statistic(['id' => 'clicks', 'name' => \__('Clicks', 'independent-analytics'), 'plugin_group' => 'general', 'requires_pro' => \true]), $this->make_statistic(['id' => 'wc_orders', 'name' => \__('Orders', 'independent-analytics'), 'plugin_group' => 'ecommerce', 'icon' => $this->get_ecommerce_icon()]), $this->make_statistic(['id' => 'wc_gross_sales', 'name' => \__('Gross Sales', 'independent-analytics'), 'plugin_group' => 'ecommerce', 'icon' => $this->get_ecommerce_icon(), 'format' => 'rounded-currency']), $this->make_statistic(['id' => 'wc_refunds', 'name' => \__('Refunds', 'independent-analytics'), 'plugin_group' => 'ecommerce', 'icon' => $this->get_ecommerce_icon()]), $this->make_statistic(['id' => 'wc_refunded_amount', 'name' => \__('Refunded Amount', 'independent-analytics'), 'plugin_group' => 'ecommerce', 'icon' => $this->get_ecommerce_icon(), 'format' => 'rounded-currency']), $this->make_statistic(['id' => 'wc_net_sales', 'name' => \__('Total Sales', 'independent-analytics'), 'plugin_group' => 'ecommerce', 'icon' => $this->get_ecommerce_icon(), 'format' => 'rounded-currency']), $this->make_statistic(['id' => 'wc_conversion_rate', 'name' => \__('Conversion Rate', 'independent-analytics'), 'plugin_group' => 'ecommerce', 'icon' => $this->get_ecommerce_icon(), 'format' => 'percent']), $this->make_statistic(['id' => 'wc_earnings_per_visitor', 'name' => \__('Earnings Per Visitor', 'independent-analytics'), 'plugin_group' => 'ecommerce', 'icon' => $this->get_ecommerce_icon(), 'format' => 'currency']), $this->make_statistic(['id' => 'wc_average_order_volume', 'name' => \__('Average Order Volume', 'independent-analytics'), 'plugin_group' => 'ecommerce', 'icon' => $this->get_ecommerce_icon(), 'format' => 'rounded-currency']), $this->make_statistic(['id' => 'form_submissions', 'name' => \__('Form Submissions', 'independent-analytics'), 'plugin_group' => 'forms']), $this->make_statistic(['id' => 'form_conversion_rate', 'name' => \__('Form Conversion Rate', 'independent-analytics'), 'plugin_group' => 'forms', 'format' => 'percent', 'compute' => function (object $statistics) {
return Calculations::percentage($statistics->form_submissions, $statistics->visitors, 2);
}])];
foreach (Form::get_forms() as $form) {
if (!$form->is_plugin_active()) {
continue;
}
$statistics[] = $this->make_statistic(['id' => 'form_submissions_for_' . $form->id(), 'name' => \sprintf(\_x('%s Submissions', 'Title of the contact form', 'independent-analytics'), $form->title()), 'plugin_group' => 'forms', 'is_subgroup_plugin_active' => $form->is_plugin_active(), 'plugin_group_header' => $form->plugin_name(), 'icon' => $form->icon()]);
$statistics[] = $this->make_statistic(['id' => 'form_conversion_rate_for_' . $form->id(), 'name' => \sprintf(\_x('%s Conversion Rate', 'Title of the contact form', 'independent-analytics'), $form->title()), 'plugin_group' => 'forms', 'is_subgroup_plugin_active' => $form->is_plugin_active(), 'plugin_group_header' => $form->plugin_name(), 'icon' => $form->icon(), 'format' => 'percent', 'compute' => function (object $statistics) use($form) {
$form_submission_id = 'form_submissions_for_' . $form->id();
return Calculations::percentage($statistics->{$form_submission_id}, $statistics->visitors, 2);
}]);
}
return $statistics;
}
protected function make_statistic(array $attributes) : \IAWP\Statistics\Statistic
{
$statistic_id = $attributes['id'];
if (!\array_key_exists('compute', $attributes)) {
$attributes['compute'] = function ($statistics, $statistic_id) {
return $statistics->{$statistic_id};
};
}
$attributes['statistic'] = $attributes['compute']($this->statistics, $statistic_id);
$attributes['previous_period_statistic'] = $attributes['compute']($this->previous_period_statistics, $statistic_id);
$attributes['statistic_over_time'] = $this->fill_in_partial_day_range($this->statistics_grouped_by_date_interval, $attributes);
$attributes['unfiltered_statistic'] = $this->has_filters() ? $attributes['compute']($this->unfiltered_statistics, $statistic_id) : null;
return new \IAWP\Statistics\Statistic($attributes);
}
protected function query(Date_Range $range, ?Rows $rows = null, bool $is_grouped_by_date_interval = \false)
{
$utc_offset = Timezone::utc_offset();
$site_offset = Timezone::site_offset();
$sessions_table = Query::get_table_name(Query::SESSIONS);
$views_table = Query::get_table_name(Query::VIEWS);
$orders_table = Query::get_table_name(Query::ORDERS);
$form_submissions_table = Query::get_table_name(Query::FORM_SUBMISSIONS);
$form_submissions_query = Illuminate_Builder::new()->select(['form_id', 'session_id'])->selectRaw('COUNT(*) AS form_submissions')->from($form_submissions_table, 'form_submissions')->whereBetween('created_at', [$range->iso_start(), $range->iso_end()])->groupBy(['form_id', 'session_id']);
$session_statistics = Illuminate_Builder::new();
$session_statistics->select('sessions.session_id')->selectRaw('COUNT(DISTINCT views.id) AS views')->selectRaw('COUNT(DISTINCT clicks.click_id) AS clicks')->selectRaw('COUNT(DISTINCT orders.order_id) AS orders')->selectRaw('IFNULL(CAST(SUM(orders.total) AS SIGNED), 0) AS gross_sales')->selectRaw('IFNULL(CAST(SUM(orders.total_refunded) AS SIGNED), 0) AS total_refunded')->selectRaw('IFNULL(CAST(SUM(orders.total_refunds) AS SIGNED), 0) AS total_refunds')->selectRaw('IFNULL(CAST(SUM(orders.total - orders.total_refunded) AS SIGNED), 0) AS net_sales')->from("{$sessions_table} AS sessions")->join("{$views_table} AS views", function (JoinClause $join) {
$join->on('sessions.session_id', '=', 'views.session_id');
})->leftJoin("{$orders_table} AS orders", function (JoinClause $join) {
$join->on('views.id', '=', 'orders.initial_view_id')->where('orders.is_included_in_analytics', '=', \true);
})->leftJoin("{$this->tables::clicks()} AS clicks", function (JoinClause $join) {
$join->on('views.id', '=', 'clicks.view_id');
})->tap(Query_Taps::tap_authored_content_check(\true))->when(!\is_null($rows), function (Builder $query) use($rows) {
$rows->attach_filters($query);
})->whereBetween('sessions.created_at', [$range->iso_start(), $range->iso_end()])->whereBetween('views.viewed_at', [$range->iso_start(), $range->iso_end()])->groupBy('sessions.session_id')->when(!\is_null($this->required_column()), function (Builder $query) {
$query->whereNotNull($this->required_column());
});
$statistics = Illuminate_Builder::new();
$statistics->selectRaw('IFNULL(CAST(SUM(sessions.total_views) AS SIGNED), 0) AS total_views')->selectRaw('IFNULL(CAST(SUM(session_statistics.views) AS SIGNED), 0) AS views')->selectRaw('COUNT(DISTINCT sessions.visitor_id) AS visitors')->selectRaw('COUNT(DISTINCT sessions.session_id) AS sessions')->selectRaw('IFNULL(CAST(SUM(session_statistics.clicks) AS SIGNED), 0) AS clicks')->selectRaw('IFNULL(CAST(AVG(TIMESTAMPDIFF(SECOND, sessions.created_at, sessions.ended_at)) AS SIGNED), 0) AS average_session_duration')->selectRaw('COUNT(DISTINCT IF(sessions.final_view_id IS NULL, sessions.session_id, NULL)) AS bounces')->selectRaw('IFNULL(CAST(SUM(session_statistics.orders) AS SIGNED), 0) AS wc_orders')->selectRaw('IFNULL(CAST(SUM(session_statistics.gross_sales) AS SIGNED), 0) AS wc_gross_sales')->selectRaw('IFNULL(CAST(SUM(session_statistics.total_refunds) AS SIGNED), 0) AS wc_refunds')->selectRaw('IFNULL(CAST(SUM(session_statistics.total_refunded) AS SIGNED), 0) AS wc_refunded_amount')->selectRaw('IFNULL(CAST(SUM(session_statistics.net_sales) AS SIGNED), 0) AS wc_net_sales')->selectRaw('IFNULL(SUM(form_submissions.form_submissions), 0) AS form_submissions')->tap(function (Builder $query) {
foreach (Form::get_forms() as $form) {
$query->selectRaw('IFNULL(SUM(IF(form_submissions.form_id = ?, form_submissions.form_submissions, 0)), 0) AS ' . $form->submissions_column(), [$form->id()]);
}
})->from("{$sessions_table} AS sessions")->joinSub($session_statistics, 'session_statistics', function (JoinClause $join) {
$join->on('sessions.session_id', '=', 'session_statistics.session_id');
})->leftJoinSub($form_submissions_query, 'form_submissions', 'sessions.session_id', '=', 'form_submissions.session_id')->whereBetween('sessions.created_at', [$range->iso_start(), $range->iso_end()])->when($is_grouped_by_date_interval, function (Builder $query) use($utc_offset, $site_offset) {
if ($this->chart_interval->id() === 'daily') {
$query->selectRaw("DATE(CONVERT_TZ(sessions.created_at, '{$utc_offset}', '{$site_offset}')) AS date");
} elseif ($this->chart_interval->id() === 'monthly') {
$query->selectRaw("DATE_FORMAT(CONVERT_TZ(sessions.created_at, '{$utc_offset}', '{$site_offset}'), '%Y-%m-01 00:00:00') AS date");
} elseif ($this->chart_interval->id() === 'weekly') {
$day_of_week = \IAWPSCOPED\iawp()->get_option('iawp_dow', 0) + 1;
$query->selectRaw("\n IF (\n DAYOFWEEK(CONVERT_TZ(sessions.created_at, '{$utc_offset}', '{$site_offset}')) - {$day_of_week} < 0,\n DATE_FORMAT(SUBDATE(CONVERT_TZ(sessions.created_at, '{$utc_offset}', '{$site_offset}'), DAYOFWEEK(CONVERT_TZ(sessions.created_at, '{$utc_offset}', '{$site_offset}')) - {$day_of_week} + 7), '%Y-%m-%d 00:00:00'),\n DATE_FORMAT(SUBDATE(CONVERT_TZ(sessions.created_at, '{$utc_offset}', '{$site_offset}'), DAYOFWEEK(CONVERT_TZ(sessions.created_at, '{$utc_offset}', '{$site_offset}')) - {$day_of_week}), '%Y-%m-%d 00:00:00')\n ) AS date\n ");
} else {
$query->selectRaw("DATE_FORMAT(CONVERT_TZ(sessions.created_at, '{$utc_offset}', '{$site_offset}'), '%Y-%m-%d %H:00:00') AS date");
}
$query->groupByRaw("date");
});
$outer_query = Illuminate_Builder::new()->selectRaw('statistics.*')->selectRaw('IF(statistics.visitors = 0, 0, (statistics.wc_orders / statistics.visitors) * 100) AS wc_conversion_rate')->selectRaw('IF(statistics.visitors = 0, 0, (statistics.wc_gross_sales - statistics.wc_refunded_amount) / visitors) AS wc_earnings_per_visitor')->selectRaw('IF(statistics.wc_orders = 0, 0, ROUND(CAST(statistics.wc_gross_sales / statistics.wc_orders AS DECIMAL(10, 2)))) AS wc_average_order_volume')->fromSub($statistics, 'statistics');
$results = \array_map(function (object $statistic) : object {
return $this->clean_up_raw_statistic_row($statistic);
}, $outer_query->get()->all());
if (!$is_grouped_by_date_interval) {
return $results[0];
}
return $results;
}
protected function clean_up_raw_statistic_row(object $statistic) : object
{
if (\property_exists($statistic, 'wc_gross_sales')) {
$statistic->wc_gross_sales = \intval($statistic->wc_gross_sales);
}
if (\property_exists($statistic, 'wc_refunded_amount')) {
$statistic->wc_refunded_amount = \intval($statistic->wc_refunded_amount);
}
if (\property_exists($statistic, 'wc_net_sales')) {
$statistic->wc_net_sales = \intval($statistic->wc_net_sales);
}
if (\property_exists($statistic, 'wc_earnings_per_visitor')) {
$statistic->wc_earnings_per_visitor = \intval($statistic->wc_earnings_per_visitor);
}
foreach ($statistic as $key => $value) {
if (Str::startsWith($key, 'form_submissions')) {
$statistic->{$key} = \intval($value);
}
}
return $statistic;
}
/**
* @param array $partial_day_range
* @param array $attributes
*
* @return array
*/
private function fill_in_partial_day_range(array $partial_day_range, array $attributes) : array
{
$original_start = (clone $this->date_range->start())->setTimezone(Timezone::site_timezone());
$start = $this->chart_interval->calculate_start_of_interval_for($original_start);
$original_end = (clone $this->date_range->end())->setTimezone(Timezone::site_timezone());
$end = $this->chart_interval->calculate_start_of_interval_for($original_end);
$end->add(new DateInterval('PT1S'));
$is_problematic_timezone = \in_array(Timezone::site_timezone()->getName(), ['Asia/Beirut', 'America/Santiago', 'America/Havana', 'America/Asuncion']);
// Imagine a scenario where the offset for the start date is -4 and the offset for the
// end date is -3. In that case, the DatePeriod is actually going to have its end date
// short an hour, causing a date we care about to be chopped off the end. This code makes
// sure that the end date is still the day after the last date we care about, so it
// can get chopped off without consequence.
if ($is_problematic_timezone) {
$offset_difference = $end->getOffset() - $start->getOffset();
$interval = DateInterval::createFromDateString($offset_difference . ' seconds');
$end->add($interval);
}
$date_range = new DatePeriod($start, $this->chart_interval->date_interval(), $end);
$filled_in_data = [];
foreach ($date_range as $date) {
// If the timezone switches at midnight, there will be a date where there is no midnight. It'll be something
// like 1am instead. All dates after the day that switches will also be at 1am even though they have a
// midnight. This alters those back to midnight, so they can be matched against correctly.
if ($is_problematic_timezone && $date->format('H:i:s') === "01:00:00") {
$date->setTime(0, 0, 0);
}
$stat = $this->get_statistic_for_date($partial_day_range, $date, $attributes);
$filled_in_data[] = [$date, $stat];
}
return $filled_in_data;
}
/**
* @param array $partial_day_range
* @param DateTime $datetime_to_match
* @param array $attributes
*
* @return float|int
*/
private function get_statistic_for_date(array $partial_day_range, DateTime $datetime_to_match, array $attributes)
{
foreach ($partial_day_range as $day) {
$date = $day->date;
$value = $attributes['compute']($day, $attributes['id']);
try {
$datetime = new DateTime($date, Timezone::site_timezone());
} catch (Throwable $e) {
return 0;
}
// Intentionally using non-strict equality to see if two distinct DateTime objects represent the same time
if ($datetime == $datetime_to_match) {
if (\is_string($value)) {
if (\strpos($value, '.') !== \false) {
return \floatval($value);
} else {
return \intval($value);
}
}
return $value;
}
}
return 0;
}
private function get_ecommerce_icon() : ?string
{
if (\IAWPSCOPED\iawp()->is_woocommerce_support_enabled() && !\IAWPSCOPED\iawp()->is_surecart_support_enabled()) {
return 'woocommerce';
}
if (\IAWPSCOPED\iawp()->is_surecart_support_enabled() && !\IAWPSCOPED\iawp()->is_woocommerce_support_enabled()) {
return 'surecart';
}
return null;
}
}
IAWP/Tables/Columns/Column.php 0000644 00000010726 14760033122 0012110 0 ustar 00 id = $attributes['id'];
$this->name = $attributes['name'];
$this->plugin_group = $attributes['plugin_group'] ?? 'general';
$this->plugin_group_header = $attributes['plugin_group_header'] ?? null;
$this->visible = $attributes['visible'] ?? \false;
$this->type = $attributes['type'];
$this->exportable = $attributes['exportable'] ?? \true;
$this->options = $attributes['options'] ?? [];
$this->filter_placeholder = $attributes['filter_placeholder'] ?? '';
$this->unavailable_for = $attributes['unavailable_for'] ?? [];
$this->database_column = $attributes['database_column'] ?? null;
$this->is_nullable = $attributes['is_nullable'] ?? \false;
$this->is_plugin_active = $attributes['is_subgroup_plugin_active'] ?? \true;
$this->requires_pro = $attributes['requires_pro'] ?? \false;
}
public function is_enabled() : bool
{
if ($this->requires_pro === \true && \IAWPSCOPED\iawp_is_free()) {
return \false;
}
return \true;
}
public function is_enabled_for_group(Group $group) : bool
{
return !\in_array($group->id(), $this->unavailable_for);
}
public function is_group_dependent() : bool
{
return \count($this->unavailable_for) > 0;
}
public function id() : string
{
return $this->id;
}
public function name() : string
{
return $this->name;
}
public function plugin_group() : string
{
return $this->plugin_group;
}
public function database_column() : string
{
return !\is_null($this->database_column) ? $this->database_column : $this->id;
}
public function is_group_plugin_enabled() : bool
{
switch ($this->plugin_group) {
case "ecommerce":
return \IAWPSCOPED\iawp()->is_ecommerce_support_enabled();
case "forms":
return \IAWPSCOPED\iawp()->is_form_submission_support_enabled();
default:
return \true;
}
}
public function is_subgroup_plugin_enabled() : bool
{
return $this->is_plugin_active;
}
public function is_visible() : bool
{
return $this->visible;
}
public function is_member_of_plugin_group(string $plugin_group) : bool
{
return $this->plugin_group === $plugin_group;
}
public function plugin_group_header() : ?string
{
return $this->plugin_group_header;
}
public function type() : string
{
return $this->type;
}
/**
* @return string[]
*/
public function filter_operators() : array
{
switch ($this->type) {
case 'string':
return ['contains', 'exact'];
case 'date':
return ['before', 'after', 'on'];
case 'select':
return ['is', 'isnt'];
default:
// int
return ['greater', 'lesser', 'equal'];
}
}
public function is_valid_filter_operator(string $operator) : bool
{
return \in_array($operator, $this->filter_operators());
}
public function sort_direction() : string
{
$descending_types = ['int', 'date'];
return \in_array($this->type, $descending_types) ? 'desc' : 'asc';
}
public function set_visibility(bool $visible) : void
{
$this->visible = $visible;
}
public function exportable() : bool
{
return $this->exportable;
}
/**
* @return array List of possible options for this filter such as a list of authors or list of post categories
*/
public function options() : array
{
return $this->options;
}
public function filter_placeholder() : string
{
return $this->filter_placeholder;
}
public function is_nullable() : bool
{
return $this->is_nullable;
}
}
IAWP/Tables/Groups/Group.php 0000644 00000001661 14760033122 0011604 0 ustar 00 id = $id;
$this->singular = $singular;
$this->rows_class = $rows_class;
$this->statistics_class = $statistics_class;
}
public function id() : string
{
return $this->id;
}
public function singular() : string
{
return $this->singular;
}
/**
* @return class-string
*/
public function rows_class() : string
{
return $this->rows_class;
}
/**
* @return class-string
*/
public function statistics_class() : string
{
return $this->statistics_class;
}
}
IAWP/Tables/Groups/Groups.php 0000644 00000002547 14760033122 0011773 0 ustar 00 groups = $groups;
}
public function add(\IAWP\Tables\Groups\Group $group) : void
{
$this->groups[] = $group;
}
public function find_by_id(?string $id = null) : \IAWP\Tables\Groups\Group
{
if (\is_null($id)) {
return $this->default_group();
}
$array = \array_filter($this->groups(), function ($group) use($id) {
return $group->id() === $id;
});
$match = \reset($array);
return $match === \false ? $this->default_group() : $match;
}
/**
* Return an array of groups representing buttons one can select
*
* @return Group[]
*/
public function buttons() : array
{
if ($this->has_grouping_options()) {
return [];
} else {
return $this->groups();
}
}
public function has_grouping_options() : bool
{
return \count($this->groups()) > 1;
}
/**
* @return Group[]
*/
public function groups() : array
{
return $this->groups;
}
private function default_group() : \IAWP\Tables\Groups\Group
{
return $this->groups()[0];
}
}
IAWP/Tables/Table.php 0000644 00000056475 14760033122 0010275 0 ustar 00 visible_columns = Dashboard_Options::getInstance()->visible_columns();
$this->group = $this->groups()->find_by_id($group_id);
$this->is_new_group = $is_new_group;
$this->filters = new Filters();
}
protected abstract function groups() : Groups;
/**
* @return array
*/
protected abstract function local_columns() : array;
protected abstract function table_name() : string;
public function visible_column_ids()
{
$visible_columns = [];
foreach ($this->get_columns() as $column) {
if ($column->is_visible()) {
$visible_columns[] = $column->id();
}
}
return $visible_columns;
}
public function group() : Group
{
return $this->group;
}
public function column_picker_html() : string
{
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)]);
}
public function get_table_toolbar_markup()
{
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()]);
}
public function get_table_markup(string $sort_column, string $sort_direction)
{
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()]);
}
public function set_statistics(Statistics $statistics)
{
$this->statistics = $statistics;
}
public function get_row_data_attributes($row)
{
$html = '';
foreach ($this->get_columns() as $column) {
$id = $column->id();
$data_val = $row->{$id}();
$html .= ' data-' . \esc_attr($column->id()) . '="' . \esc_attr($data_val) . '"';
}
return $html;
}
public function get_cell_content($row, Column $column)
{
$column_id = $column->id();
if (\is_null($row->{$column_id}())) {
return '-';
}
if ($column_id == 'title' && $row->is_deleted()) {
return Security::string($row->{$column_id}()) . ' ' . \esc_html__('(deleted)', 'independent-analytics') . ' ';
} elseif ($column_id == 'views') {
$views = Number_Formatter::decimal($row->views());
// Getting a divide by zero error from the line below?
// It's likely an issue with $this->views which is an instance of Views. Make sure the queries there are working.
$views_percentage = Number_Formatter::percent($row->views() / $this->statistics->get_statistic('views')->value() * 100, 2);
return '' . Security::string($views) . ' (' . Security::string($views_percentage) . ') ';
} elseif ($column_id == 'visitors') {
$visitors = Number_Formatter::decimal($row->visitors());
$visitors_percentage = Number_Formatter::percent($row->visitors() / $this->statistics->get_statistic('visitors')->value() * 100, 2);
return '' . Security::string($visitors) . ' (' . Security::string($visitors_percentage) . ') ';
} elseif ($column_id == 'sessions') {
$sessions = Number_Formatter::decimal($row->sessions());
$sessions_percentage = Number_Formatter::percent($row->sessions() / $this->statistics->get_statistic('sessions')->value() * 100, 2);
return '' . Security::string($sessions) . ' (' . Security::string($sessions_percentage) . ') ';
} elseif ($column_id === 'entrances') {
$entrances = Number_Formatter::decimal($row->entrances());
$entrances_percentage = Number_Formatter::percent($row->entrances() / $this->statistics->get_statistic('sessions')->value() * 100, 2);
return '' . Security::string($entrances) . ' (' . Security::string($entrances_percentage) . ') ';
} elseif ($column_id === 'exits') {
$exits = Number_Formatter::decimal($row->exits());
$exits_percentage = Number_Formatter::percent($row->exits() / $this->statistics->get_statistic('sessions')->value() * 100, 2);
return '' . Security::string($exits) . ' (' . Security::string($exits_percentage) . ') ';
} elseif ($column_id === 'bounce_rate') {
return Security::string(Number_Formatter::percent($row->bounce_rate()));
} elseif ($column_id === 'average_session_duration' || $column_id === 'average_view_duration') {
return Number_Formatter::second_to_minute_timestamp($row->{$column_id}());
} 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')) {
return Number_Formatter::percent($row->{$column_id}(), 2);
} elseif ($column_id == 'url') {
if ($row->is_deleted()) {
return \urldecode(\esc_url($row->url()));
} else {
return '' . \urldecode(\esc_url($row->url())) . ' ';
}
} elseif ($column_id == 'author') {
return Security::html($row->avatar()) . ' ' . Security::string($row->author());
} elseif ($column_id == 'date') {
return Security::string(\date(WordPress_Site_Date_Format_Pattern::for_php(), \strtotime($row->date())));
} elseif ($column_id == 'type' && \method_exists($row, 'icon') && \method_exists($row, 'type')) {
return $row->icon(0) . ' ' . Security::string($row->type());
} elseif ($column_id == 'referrer' && $row->has_link()) {
return '' . Security::string($row->referrer()) . ' ';
} elseif ($column_id === 'device_type') {
return Icon_Directory_Factory::device_types()->find($row->device_type()) . Security::string($row->device_type());
} elseif ($column_id === 'browser') {
return Icon_Directory_Factory::browsers()->find($row->browser()) . Security::string($row->browser());
} elseif ($column_id === 'os') {
return Icon_Directory_Factory::operating_systems()->find($row->os()) . Security::string($row->os());
} elseif ($column_id === 'country') {
return Icon_Directory_Factory::flags()->find($row->country_code()) . Security::string($row->country());
} elseif ($column_id === 'wc_gross_sales' || $column_id === 'wc_refunded_amount' || $column_id === 'wc_net_sales' || $column_id === 'wc_average_order_volume') {
return Security::string(Currency::format($row->{$column_id}()));
} elseif ($column_id === 'wc_earnings_per_visitor') {
return Security::string(Currency::format($row->{$column_id}(), \false));
} elseif ($column_id === 'views_per_session') {
return Number_Formatter::decimal($row->{$column_id}(), 2);
} elseif ($column_id === 'link_target') {
$value = $row->{$column_id}();
if (!\is_string($value)) {
return $value;
}
$url = new URL($value);
if ($url->is_valid_url()) {
return '' . Security::string($value) . ' ';
}
return $value;
} else {
return Security::string($row->{$column_id}());
}
}
public function output_report_toolbar()
{
$options = Dashboard_Options::getInstance();
$start = $options->get_date_range()->start()->setTimezone(Timezone::site_timezone());
$end = $options->get_date_range()->end()->setTimezone(Timezone::site_timezone());
?>
filters()->get_condition_html($this->get_columns());
}
public function filters_condition_buttons_html(array $filters) : string
{
return $this->filters()->condition_buttons_html($filters);
}
public final function csv(array $rows, bool $is_dashboard_export = \false) : CSV
{
$columns = $this->get_columns();
$csv_header = [];
$csv_rows = [];
foreach ($columns as $column) {
if (!$this->include_column_in_csv($column, $is_dashboard_export)) {
continue;
}
$csv_header[] = $column->name();
}
foreach ($rows as $row) {
$csv_row = [];
foreach ($columns as $column) {
if (!$this->include_column_in_csv($column, $is_dashboard_export)) {
continue;
}
$column_id = $column->id();
$value = $row->{$column_id}();
// Todo - This logic is similar to the rendering logic for table cells. This should
// all be handled via the column class itself.
if (\is_null($value)) {
$csv_row[] = '-';
} elseif ($column_id === 'date') {
$csv_row[] = \date(WordPress_Site_Date_Format_Pattern::for_php(), \strtotime($value));
} elseif ($column_id === 'average_session_duration' || $column_id === 'average_view_duration') {
$csv_row[] = Number_Formatter::second_to_minute_timestamp($value);
} elseif ($column_id === 'views_per_session') {
$csv_row[] = Number_Formatter::decimal($value, 2);
} else {
$csv_row[] = $row->{$column_id}();
}
}
$csv_rows[] = $csv_row;
}
$csv = new CSV($csv_header, $csv_rows);
return $csv;
}
/**
* @param array[] $filters Raw filter associative arrays
*
* @return Filter[]
*/
public function sanitize_filters(array $filters) : array
{
return \array_values(\array_filter(\array_map(function ($filter) {
return $this->sanitize_filter($filter);
}, $filters)));
}
public function sanitize_filter(array $filter) : ?Filter
{
$column = $this->get_column($filter['column']);
if (\is_null($column)) {
return null;
}
$valid_inclusions = ['include', 'exclude'];
if (!\in_array($filter['inclusion'], $valid_inclusions)) {
return null;
}
if (!$column->is_valid_filter_operator($filter['operator'])) {
return null;
}
if (!$column->is_enabled_for_group($this->group())) {
return null;
}
$operand = \trim(Security::string($filter['operand']));
if (\strlen($operand) === 0) {
return null;
}
if ($column->database_column() === 'cached_url' && $filter['operator'] === 'exact') {
$url = new URL($filter['operand']);
if (!$url->is_valid_url()) {
$filter['operand'] = \site_url($filter['operand']);
}
}
// Link rules can be archived and then deleted by the user. That means that there's a very
// reasonable chance that a report is filtering by an id for a rule that's since been
// removed. We need to check and make sure that filters link rules still exist.
if ($column->id() === 'link_name') {
$match = \false;
foreach ($column->options() as $option) {
if ((int) $option[0] === (int) $filter['operand']) {
$match = \true;
}
}
if (!$match) {
return null;
}
}
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()]);
}
public function get_column(string $id) : ?Column
{
$matches = \array_filter($this->local_columns(), function (Column $column) use($id) {
return $column->id() === $id;
});
$column = \count($matches) === 1 ? \reset($matches) : null;
if (\is_null($column) || !$column->is_enabled()) {
return null;
}
return $column;
}
public function sanitize_sort_parameters(?string $sort_column = null, ?string $sort_direction = 'desc') : Sort_Configuration
{
if (\is_null($sort_column)) {
return new Sort_Configuration($this->default_sorting_column);
}
$column = $this->get_column($sort_column);
if (\is_null($column) || !$column->is_enabled_for_group($this->group)) {
return new Sort_Configuration($this->default_sorting_column);
}
return new Sort_Configuration($sort_column, $sort_direction, $column->is_nullable());
}
public function get_rendered_template(array $rows, bool $just_rows, string $sort_column, string $sort_direction)
{
if ($just_rows) {
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()]);
}
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()]);
}
protected function get_woocommerce_columns() : array
{
return [new Column(['id' => 'wc_orders', 'name' => \__('Orders', 'independent-analytics'), 'plugin_group' => 'ecommerce', 'type' => 'int']), new Column(['id' => 'wc_gross_sales', 'name' => \__('Gross Sales', 'independent-analytics'), 'plugin_group' => 'ecommerce', 'type' => 'int']), new Column(['id' => 'wc_refunds', 'name' => \__('Refunds', 'independent-analytics'), 'plugin_group' => 'ecommerce', 'type' => 'int']), new Column(['id' => 'wc_refunded_amount', 'name' => \__('Refunded Amount', 'independent-analytics'), 'plugin_group' => 'ecommerce', 'type' => 'int']), new Column(['id' => 'wc_net_sales', 'name' => \__('Total Sales', 'independent-analytics'), 'plugin_group' => 'ecommerce', 'type' => 'int']), 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'])];
}
protected function get_form_columns() : array
{
$columns = [new Column(['id' => 'form_submissions', 'name' => \__('Submissions', 'independent-analytics'), 'plugin_group' => 'forms', 'type' => 'int']), new Column(['id' => 'form_conversion_rate', 'name' => \__('Conversion Rate', 'independent-analytics'), 'plugin_group' => 'forms', 'type' => 'int'])];
foreach (Form::get_forms() as $form) {
$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']);
$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']);
}
return $columns;
}
private function include_column_in_csv(Column $column, bool $is_dashboard_export) : bool
{
if (!$column->is_visible() && $is_dashboard_export) {
return \false;
}
if (!$column->exportable() && !$is_dashboard_export) {
return \false;
}
if (!$column->is_group_plugin_enabled()) {
return \false;
}
return \true;
}
/**
* @return Column[]
*/
private function get_columns($show_disabled_columns = \false) : array
{
$columns_for_group = \array_filter($this->local_columns(), function (Column $column) {
return $column->is_enabled() && $column->is_enabled_for_group($this->group) && $column->is_subgroup_plugin_enabled();
});
if ($show_disabled_columns === \true) {
} else {
$columns_for_group = \array_filter($columns_for_group, function (Column $column) {
return $column->is_group_plugin_enabled();
});
}
if (\is_null($this->visible_columns) || \count($this->visible_columns) === 0) {
return $columns_for_group;
}
if (!$this->is_new_group) {
return \array_map(function ($column) {
$column->set_visibility(\in_array($column->id(), $this->visible_columns));
return $column;
}, $columns_for_group);
}
return \array_map(function ($column) {
if ($column->is_group_dependent()) {
$column->set_visibility(\true);
} elseif (!\in_array($column->id(), $this->visible_columns)) {
$column->set_visibility(\false);
}
return $column;
}, $columns_for_group);
}
/**
* Get the number of visible columns
*
* @return int
*/
private function visible_column_count() : int
{
$visible_columns = 0;
foreach ($this->get_columns() as $column) {
if ($column->is_visible()) {
$visible_columns++;
}
}
return $visible_columns;
}
private function filters()
{
return $this->filters;
}
}
IAWP/Tables/Table_Campaigns.php 0000644 00000005225 14760033122 0012242 0 ustar 00 'title', 'name' => \__('Landing Page', 'independent-analytics'), 'visible' => \true, 'type' => 'string']), new Column(['id' => 'utm_source', 'name' => \__('Source', 'independent-analytics'), 'visible' => \true, 'type' => 'string']), new Column(['id' => 'utm_medium', 'name' => \__('Medium', 'independent-analytics'), 'visible' => \true, 'type' => 'string']), new Column(['id' => 'utm_campaign', 'name' => \__('Campaign', 'independent-analytics'), 'visible' => \true, 'type' => 'string']), new Column(['id' => 'utm_term', 'name' => \__('Term', 'independent-analytics'), 'type' => 'string', 'is_nullable' => \true]), new Column(['id' => 'utm_content', 'name' => \__('Content', 'independent-analytics'), 'type' => 'string', 'is_nullable' => \true]), new Column(['id' => 'visitors', 'name' => \__('Visitors', 'independent-analytics'), 'visible' => \true, 'type' => 'int']), new Column(['id' => 'views', 'name' => \__('Views', 'independent-analytics'), 'visible' => \true, 'type' => 'int']), new Column(['id' => 'sessions', 'name' => \__('Sessions', 'independent-analytics'), 'type' => 'int']), new Column(['id' => 'average_session_duration', 'name' => \__('Session Duration', 'independent-analytics'), 'visible' => \true, 'type' => 'int', 'filter_placeholder' => 'Seconds']), new Column(['id' => 'views_per_session', 'name' => \__('Views Per Session', 'independent-analytics'), 'type' => 'int']), new Column(['id' => 'bounce_rate', 'name' => \__('Bounce Rate', 'independent-analytics'), 'visible' => \true, 'type' => 'int']), new Column(['id' => 'visitors_growth', 'name' => \__('Visitors Growth', 'independent-analytics'), 'type' => 'int', 'exportable' => \false]), new Column(['id' => 'views_growth', 'name' => \__('Views Growth', 'independent-analytics'), 'type' => 'int', 'exportable' => \false]), new Column(['id' => 'clicks', 'name' => \__('Clicks', 'independent-analytics'), 'type' => 'int', 'requires_pro' => \true])];
return \array_merge($columns, $this->get_woocommerce_columns(), $this->get_form_columns());
}
}
IAWP/Tables/Table_Clicks.php 0000644 00000002335 14760033122 0011547 0 ustar 00 'link_name', 'name' => \__('Link Pattern', 'independent-analytics'), 'visible' => \true, 'type' => 'select', 'options' => Link_Name_Filter_List::options(), 'database_column' => 'link_rules.link_rule_id']), new Column(['id' => 'link_target', 'name' => \__('Target', 'independent-analytics'), 'visible' => \true, 'type' => 'string']), new Column(['id' => 'link_clicks', 'name' => \__('Clicks', 'independent-analytics'), 'visible' => \true, 'type' => 'int'])];
return $columns;
}
}
IAWP/Tables/Table_Devices.php 0000644 00000006372 14760033122 0011726 0 ustar 00 'device_type', 'name' => \__('Type', 'independent-analytics'), 'visible' => \true, 'type' => 'select', 'options' => Device_Type_Filter_List::options(), 'database_column' => 'device_types.device_type_id', 'unavailable_for' => ['browser', 'os']]), new Column(['id' => 'os', 'name' => \__('Operating System', 'independent-analytics'), 'visible' => \true, 'type' => 'select', 'options' => Device_OS_Filter_List::options(), 'database_column' => 'device_oss.device_os_id', 'unavailable_for' => ['device_type', 'browser']]), new Column(['id' => 'browser', 'name' => \__('Browser', 'independent-analytics'), 'visible' => \true, 'type' => 'select', 'options' => Device_Browser_Filter_List::options(), 'database_column' => 'device_browsers.device_browser_id', 'unavailable_for' => ['device_type', 'os']]), new Column(['id' => 'visitors', 'name' => \__('Visitors', 'independent-analytics'), 'visible' => \true, 'type' => 'int']), new Column(['id' => 'views', 'name' => \__('Views', 'independent-analytics'), 'visible' => \true, 'type' => 'int']), new Column(['id' => 'sessions', 'name' => \__('Sessions', 'independent-analytics'), 'type' => 'int']), new Column(['id' => 'average_session_duration', 'name' => \__('Session Duration', 'independent-analytics'), 'visible' => \true, 'type' => 'int', 'filter_placeholder' => 'Seconds']), new Column(['id' => 'views_per_session', 'name' => \__('Views Per Session', 'independent-analytics'), 'type' => 'int']), new Column(['id' => 'bounce_rate', 'name' => \__('Bounce Rate', 'independent-analytics'), 'visible' => \true, 'type' => 'int']), new Column(['id' => 'visitors_growth', 'name' => \__('Visitors Growth', 'independent-analytics'), 'type' => 'int', 'exportable' => \false]), new Column(['id' => 'views_growth', 'name' => \__('Views Growth', 'independent-analytics'), 'type' => 'int', 'exportable' => \false]), new Column(['id' => 'clicks', 'name' => \__('Clicks', 'independent-analytics'), 'type' => 'int', 'requires_pro' => \true])];
return \array_merge($columns, $this->get_woocommerce_columns(), $this->get_form_columns());
}
}
IAWP/Tables/Table_Geo.php 0000644 00000005133 14760033122 0011050 0 ustar 00 'continent', 'name' => \__('Continent', 'independent-analytics'), 'type' => 'string']), new Column(['id' => 'country', 'name' => \__('Country', 'independent-analytics'), 'visible' => \true, 'type' => 'string']), new Column(['id' => 'subdivision', 'name' => \__('Subdivision', 'independent-analytics'), 'visible' => \true, 'type' => 'string', 'unavailable_for' => ['country']]), new Column(['id' => 'city', 'name' => \__('City', 'independent-analytics'), 'visible' => \true, 'type' => 'string', 'unavailable_for' => ['country']]), new Column(['id' => 'visitors', 'name' => \__('Visitors', 'independent-analytics'), 'visible' => \true, 'type' => 'int']), new Column(['id' => 'views', 'name' => \__('Views', 'independent-analytics'), 'visible' => \true, 'type' => 'int']), new Column(['id' => 'sessions', 'name' => \__('Sessions', 'independent-analytics'), 'type' => 'int']), new Column(['id' => 'average_session_duration', 'name' => \__('Session Duration', 'independent-analytics'), 'visible' => \true, 'type' => 'int', 'filter_placeholder' => 'Seconds']), new Column(['id' => 'views_per_session', 'name' => \__('Views Per Session', 'independent-analytics'), 'type' => 'int']), new Column(['id' => 'bounce_rate', 'name' => \__('Bounce Rate', 'independent-analytics'), 'visible' => \true, 'type' => 'int']), new Column(['id' => 'visitors_growth', 'name' => \__('Visitors Growth', 'independent-analytics'), 'type' => 'int', 'exportable' => \false]), new Column(['id' => 'views_growth', 'name' => \__('Views Growth', 'independent-analytics'), 'type' => 'int', 'exportable' => \false]), new Column(['id' => 'clicks', 'name' => \__('Clicks', 'independent-analytics'), 'type' => 'int', 'requires_pro' => \true])];
return \array_merge($columns, $this->get_woocommerce_columns(), $this->get_form_columns());
}
}
IAWP/Tables/Table_Pages.php 0000644 00000006635 14760033122 0011405 0 ustar 00 'title', 'name' => \__('Title', 'independent-analytics'), 'visible' => \true, 'type' => 'string', 'database_column' => 'cached_title']), new Column(['id' => 'visitors', 'name' => \__('Visitors', 'independent-analytics'), 'visible' => \true, 'type' => 'int']), new Column(['id' => 'views', 'name' => \__('Views', 'independent-analytics'), 'visible' => \true, 'type' => 'int']), new Column(['id' => 'sessions', 'name' => \__('Sessions', 'independent-analytics'), 'type' => 'int']), new Column(['id' => 'average_view_duration', 'name' => \__('View Duration', 'independent-analytics'), 'visible' => \true, 'type' => 'int', 'filter_placeholder' => 'Seconds']), new Column(['id' => 'bounce_rate', 'name' => \__('Bounce Rate', 'independent-analytics'), 'visible' => \true, 'type' => 'int']), new Column(['id' => 'visitors_growth', 'name' => \__('Visitors Growth', 'independent-analytics'), 'type' => 'int', 'exportable' => \false]), new Column(['id' => 'views_growth', 'name' => \__('Views Growth', 'independent-analytics'), 'type' => 'int', 'exportable' => \false]), new Column(['id' => 'entrances', 'name' => \__('Entrances', 'independent-analytics'), 'type' => 'int']), new Column(['id' => 'exits', 'name' => \__('Exits', 'independent-analytics'), 'type' => 'int']), new Column(['id' => 'exit_percent', 'name' => \__('Exit Rate', 'independent-analytics'), 'type' => 'int']), new Column(['id' => 'clicks', 'name' => \__('Clicks', 'independent-analytics'), 'type' => 'int', 'requires_pro' => \true]), new Column(['id' => 'url', 'name' => \__('URL', 'independent-analytics'), 'visible' => \true, 'type' => 'string', 'database_column' => 'cached_url']), new Column(['id' => 'author', 'name' => \__('Author', 'independent-analytics'), 'type' => 'select', 'options' => Author_Filter_List::options(), 'database_column' => 'cached_author_id', 'is_nullable' => \true]), new Column(['id' => 'type', 'name' => \__('Page Type', 'independent-analytics'), 'visible' => \true, 'type' => 'select', 'options' => Page_Type_Filter_List::options(), 'database_column' => 'cached_type', 'is_nullable' => \true]), new Column(['id' => 'date', 'name' => \__('Publish Date', 'independent-analytics'), 'type' => 'date', 'database_column' => 'cached_date', 'is_nullable' => \true]), new Column(['id' => 'category', 'name' => \__('Post Category', 'independent-analytics'), 'type' => 'select', 'options' => Category_Filter_List::options(), 'database_column' => 'cached_category', 'is_nullable' => \true]), new Column(['id' => 'comments', 'name' => \__('Comments', 'independent-analytics'), 'type' => 'int', 'is_nullable' => \true])];
return \array_merge($columns, $this->get_woocommerce_columns(), $this->get_form_columns());
}
}
IAWP/Tables/Table_Referrers.php 0000644 00000004400 14760033122 0012271 0 ustar 00 'referrer', 'name' => \__('Referrer', 'independent-analytics'), 'visible' => \true, 'type' => 'string']), new Column(['id' => 'referrer_type', 'name' => \__('Referrer Type', 'independent-analytics'), 'visible' => \true, 'type' => 'select', 'options' => Referrer_Type_Filter_List::options()]), new Column(['id' => 'visitors', 'name' => \__('Visitors', 'independent-analytics'), 'visible' => \true, 'type' => 'int']), new Column(['id' => 'views', 'name' => \__('Views', 'independent-analytics'), 'visible' => \true, 'type' => 'int']), new Column(['id' => 'sessions', 'name' => \__('Sessions', 'independent-analytics'), 'type' => 'int']), new Column(['id' => 'average_session_duration', 'name' => \__('Session Duration', 'independent-analytics'), 'visible' => \true, 'type' => 'int', 'filter_placeholder' => 'Seconds']), new Column(['id' => 'views_per_session', 'name' => \__('Views Per Session', 'independent-analytics'), 'type' => 'int']), new Column(['id' => 'bounce_rate', 'name' => \__('Bounce Rate', 'independent-analytics'), 'visible' => \true, 'type' => 'int']), new Column(['id' => 'visitors_growth', 'name' => \__('Visitors Growth', 'independent-analytics'), 'type' => 'int', 'exportable' => \false]), new Column(['id' => 'views_growth', 'name' => \__('Views Growth', 'independent-analytics'), 'type' => 'int', 'exportable' => \false]), new Column(['id' => 'clicks', 'name' => \__('Clicks', 'independent-analytics'), 'type' => 'int', 'requires_pro' => \true])];
return \array_merge($columns, $this->get_woocommerce_columns(), $this->get_form_columns());
}
}
IAWP/Utils/BladeOne.php 0000644 00000000376 14760033122 0010572 0 ustar 00 0) {
return 100;
} elseif ($denominator === 0.0) {
return 0;
}
return \round($numerator / $denominator, $precision);
}
public static function percentage(float $numerator, float $denominator, int $precision = 0)
{
if ($denominator === 0.0 && $numerator > 0) {
return 100;
} elseif ($denominator === 0.0) {
return 0;
}
return \round($numerator / $denominator * 100, $precision);
}
}
IAWP/Utils/CSV.php 0000644 00000001407 14760033122 0007550 0 ustar 00 header = $header;
$this->rows = $rows;
}
public function to_string() : string
{
$delimiter = ',';
$enclosure = '"';
$escape_character = '\\';
$f = \fopen('php://memory', 'r+');
\fputcsv($f, $this->header, $delimiter, $enclosure, $escape_character);
foreach ($this->rows as $row) {
\fputcsv($f, $row, $delimiter, $enclosure, $escape_character);
}
\rewind($f);
return \wp_kses(\stream_get_contents($f), 'strip');
}
}
IAWP/Utils/Currency.php 0000644 00000002136 14760033122 0010707 0 ustar 00 0];
} else {
$options = null;
}
$formatted_value = \strip_tags(\wc_price($amount_in_cents / 100, $options));
return $formatted_value;
}
if (\class_exists('\\SureCart\\Support\\Currency')) {
$currency_code = SureCart_Store::get_currency_code();
$formatted_value = \SureCart\Support\Currency::format($amount_in_cents, $currency_code);
return $round_to_whole_dollars ? Str::before($formatted_value, ".") : $formatted_value;
}
// Fallback
return \strval(\intval($amount_in_cents / 100));
}
}
IAWP/Utils/Device.php 0000644 00000010223 14760033122 0010310 0 ustar 00 detector = new DeviceDetector($_SERVER['HTTP_USER_AGENT']);
$cache = new \IAWP\Utils\Device_Cache();
$cache->load_from_file();
$this->detector->setCache($cache);
try {
@$this->detector->parse();
$this->type = $this->detect_type($this->detector);
$this->os = $this->detect_os($this->detector);
$this->browser = $this->detect_browser($this->detector);
} catch (Throwable $e) {
$this->type = null;
$this->os = null;
$this->browser = null;
}
$cache->save_to_file();
}
public function type_id() : ?int
{
if (!\is_string($this->type) || $this->type === '') {
return null;
}
$device_types_table = Query::get_table_name(Query::DEVICE_TYPES);
$id = Illuminate_Builder::new()->select('device_type_id')->from($device_types_table)->where('device_type', '=', $this->type)->value('device_type_id');
if (\is_null($id)) {
$id = Illuminate_Builder::new()->from($device_types_table)->insertGetId(['device_type' => $this->type], 'device_type_id');
}
return $id;
}
public function os_id() : ?int
{
if (!\is_string($this->os) || $this->os === '') {
return null;
}
$device_oss_table = Query::get_table_name(Query::DEVICE_OSS);
$id = Illuminate_Builder::new()->select('device_os_id')->from($device_oss_table)->where('device_os', '=', $this->os)->value('device_os_id');
if (\is_null($id)) {
$id = Illuminate_Builder::new()->from($device_oss_table)->insertGetId(['device_os' => $this->os], 'device_os_id');
}
return $id;
}
public function browser_id() : ?int
{
if (!\is_string($this->browser) || $this->browser === '') {
return null;
}
$device_browsers_table = Query::get_table_name(Query::DEVICE_BROWSERS);
$id = Illuminate_Builder::new()->select('device_browser_id')->from($device_browsers_table)->where('device_browser', '=', $this->browser)->value('device_browser_id');
if (\is_null($id)) {
$id = Illuminate_Builder::new()->from($device_browsers_table)->insertGetId(['device_browser' => $this->browser], 'device_browser_id');
}
return $id;
}
public function is_bot() : bool
{
return $this->detector->isBot();
}
private function detect_os(DeviceDetector $detector) : ?string
{
$os = $detector->getOs('name');
if ($os === "UNK") {
return null;
}
return $os;
}
private function detect_type(DeviceDetector $detector) : ?string
{
$detected_type = $detector->getDeviceName();
$type_mapping = ['Mobile' => ['smartphone', 'phablet'], 'Tablet' => ['tablet'], 'Desktop' => ['desktop'], 'Car' => ['car browser'], 'Console' => ['console'], 'TV' => ['tv'], 'Wearable' => ['wearable']];
foreach ($type_mapping as $type => $types) {
if (\in_array($detected_type, $types)) {
return $type;
}
}
return null;
}
private function detect_browser(DeviceDetector $detector) : ?string
{
$name = $detector->getClient('name');
if ($name === 'UNK' || \is_array($name)) {
return null;
}
if ($this->should_use_browser_name($name)) {
return $name;
}
return \ucwords(Browser::getBrowserFamily($name) ?? $name);
}
/**
* Should the browsers name be used instead of the browsers family name?
*
* @param string $name
*
* @return bool
*/
private function should_use_browser_name(string $name) : bool
{
$exceptions = ['Microsoft Edge'];
return \in_array($name, $exceptions);
}
}
IAWP/Utils/Device_Cache.php 0000644 00000004357 14760033122 0011406 0 ustar 00 cache[$id] ?? null;
}
/**
* @param string $id
* @return bool
*/
public function contains(string $id) : bool
{
return \array_key_exists($id, $this->cache);
}
/**
* @param string $id
* @param $data
* @param int $lifeTime
* @return bool
*/
public function save(string $id, $data, int $lifeTime = 0) : bool
{
$this->dirty = \true;
$this->cache[$id] = $data;
return \true;
}
/**
* @param string $id
* @return bool
*/
public function delete(string $id) : bool
{
$this->dirty = \true;
unset($this->cache[$id]);
return \true;
}
/**
* @return bool
*/
public function flushAll() : bool
{
$this->dirty = \true;
$this->cache = [];
return \true;
}
public function load_from_file()
{
if (!\file_exists($this->file())) {
$this->cache = [];
return;
}
$json = \file_get_contents($this->file());
if ($json === \false) {
$this->cache = [];
return;
}
$data = \json_decode($json, \true);
if ($data === null) {
$this->cache = [];
return;
}
$this->cache = $data;
}
public function save_to_file()
{
if ($this->dirty === \false) {
return;
}
$this->dirty = \false;
$contents = \json_encode($this->cache);
if ($contents === \false) {
\unlink($this->file());
return;
}
$response = \file_put_contents($this->file(), $contents);
if ($response === \false) {
\wp_mkdir_p(\IAWPSCOPED\iawp_temp_path_to(''));
\file_put_contents($this->file(), $contents);
}
}
private function file() : string
{
return \IAWPSCOPED\iawp_temp_path_to('device-detector.json');
}
}
IAWP/Utils/Dir.php 0000644 00000001165 14760033122 0007634 0 ustar 00 \__('Name cannot be empty.', 'independent-analytics'), 'empty-value' => \__('Value cannot be empty.', 'independent-analytics'), 'invalid-type' => \__('Invalid type.', 'independent-analytics'), 'class-number' => \__('Class cannot start with a number or special character.', 'independent-analytics'), 'class-space' => \__('Class cannot contain spaces.', 'independent-analytics'), 'class-characters' => \__('Class cannot contain special characters besides "-" and "_".', 'independent-analytics'), 'invalid-extension' => \__('Invalid Extension.', 'independent-analytics'), 'invalid-protocol' => \__('Invalid Protocol.', 'independent-analytics'), 'invalid-domain' => \__('Invalid domain.', 'independent-analytics'), 'invalid-subdirectory' => \__('Invalid characters in subdirectory.', 'independent-analytics')];
}
public static function validate(string $property, string $value, string $type)
{
if ($property == 'name') {
if (\trim($value) == '') {
return 'empty-name';
}
} elseif ($property == 'type') {
if (!\array_key_exists($value, Click_Tracking::types())) {
return 'invalid-type';
}
} elseif ($property == 'value') {
if (\trim($value) == '') {
return 'empty-value';
}
if ($type == 'class') {
if (!\preg_match('/[a-zA-Z]/', \substr($value, 0, 1))) {
return 'class-number';
} elseif (\preg_match('/\\s/', $value)) {
return 'class-space';
} elseif (\preg_match('/[^a-zA-Z0-9_-]/', $value)) {
return 'class-characters';
}
} elseif ($type == 'extension') {
if (!\in_array($value, Click_Tracking::extensions())) {
return 'invalid-extension';
}
} elseif ($type == 'protocol') {
if (!\in_array($value, Click_Tracking::protocols())) {
return 'invalid-protocol';
}
} elseif ($type == 'domain') {
if (!self::is_valid_domain($value)) {
return 'invalid-domain';
}
} elseif ($type == 'subdirectory') {
if (\preg_match("/[^A-Za-z0-9-._~!\$&'()*+,;=:@\\/]/", $value)) {
return 'invalid-subdirectory';
}
}
}
return \false;
}
public static function is_valid_domain(string $domain)
{
return \preg_match('/^(http[s]?\\:\\/\\/)?((\\w+)\\.)?(([\\w-]+)+)(\\.[\\w-]+){1,2}$/', $domain);
}
public static function sanitize_domain($domain)
{
$domain = \strpos($domain, 'http') !== 0 ? "http://{$domain}" : $domain;
$components = Uri::createFromString($domain);
return $components->getHost();
}
public static function sanitize_subdirectory($subdirectory)
{
return \sanitize_text_field(\trim($subdirectory, '/'));
}
}
IAWP/Utils/Number_Formatter.php 0000644 00000003013 14760033122 0012363 0 ustar 00 diff($now);
return $interval->format('%i:%S');
}
/**
* @param int|float $number
* @param int $decimals
*
* @return string
*/
public static function percent($number, int $decimals = 0) : string
{
if (\class_exists('\\NumberFormatter')) {
$formatter = new \NumberFormatter(\get_locale(), \NumberFormatter::PERCENT);
$formatter->setAttribute(\NumberFormatter::MAX_FRACTION_DIGITS, $decimals);
return $formatter->format($number / 100);
} else {
return \number_format_i18n($number, $decimals) . '%';
}
}
/**
* @param int|float $number
* @param int $decimals
*
* @return string
*/
public static function decimal($number, int $decimals = 0) : string
{
return \number_format_i18n($number, $decimals);
}
public static function integer($number) : string
{
if ($number < 100000) {
return \number_format_i18n($number, 0);
}
return Number::abbreviate($number, \false);
}
}
IAWP/Utils/Request.php 0000644 00000007574 14760033122 0010560 0 ustar 00 test('/^[a-zA-Z_]+$/')) {
return $user_defined_header;
}
return null;
}
public static function user_agent()
{
return $_SERVER['HTTP_USER_AGENT'];
}
public static function is_ip_address_blocked() : bool
{
$blocked_ips = \IAWPSCOPED\iawp()->get_option('iawp_blocked_ips', []);
// No address could be blocked
if (\count($blocked_ips) == 0) {
return \false;
}
$visitor_address = Factory::parseAddressString(self::ip());
// We cannot block invalid ip addresses
if ($visitor_address === null) {
return \false;
}
foreach ($blocked_ips as $blocked_ip) {
$blocked_range = Factory::parseRangeString($blocked_ip);
// We cannot check an ip address against an invalid range
if ($blocked_range === null) {
continue;
}
// If the address matches this particular blocked range, then the ip address is indeed blocked
if ($blocked_range->contains($visitor_address)) {
return \true;
}
}
return \false;
}
private static function scheme()
{
if (!empty($_SERVER['REQUEST_SCHEME']) && $_SERVER['REQUEST_SCHEME'] == 'https' || !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on' || !empty($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] == '443') {
return 'https';
} else {
return 'http';
}
}
private static function url()
{
if (!empty($_SERVER['HTTP_HOST']) && !empty($_SERVER['REQUEST_URI'])) {
return \esc_url_raw(self::scheme() . '://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']);
} else {
return null;
}
}
}
IAWP/Utils/Salt.php 0000644 00000002046 14760033122 0010020 0 ustar 00 ['class' => [], 'style' => []], 'select' => ['class' => []], 'option' => ['class' => [], 'value' => [], 'data-datatype' => []], 'input' => ['class' => [], 'type' => [], 'data-css' => [], 'data-dow' => [], 'data-format' => [], 'readonly'], 'button' => ['class' => []], 'span' => ['class' => [], 'style' => []]]);
}
public static function svg($html)
{
return \wp_kses($html, ['svg' => ['height' => [], 'width' => [], 'fill' => [], 'viewbox' => [], 'style' => []], 'path' => ['d' => []]]);
}
}
IAWP/Utils/Server.php 0000644 00000001561 14760033122 0010364 0 ustar 00 getOffset($date);
return $offset_in_seconds;
}
}
IAWP/Utils/URL.php 0000644 00000003201 14760033122 0007551 0 ustar 00 url = $url;
}
public function is_valid_url() : bool
{
$valid_url = \filter_var($this->url, \FILTER_VALIDATE_URL);
if (!$valid_url) {
return \false;
}
try {
// Recommend approach for uri validation: https://uri.thephpleague.com/uri/6.0/rfc3986/#uri-validation
$components = Uri::createFromString($this->url);
if (\is_null($components->getHost())) {
return \false;
}
return \true;
} catch (UriException $e) {
return \false;
}
}
public function get_domain() : ?string
{
if (!$this->is_valid_url()) {
return null;
}
return Uri::createFromString($this->url)->getHost();
}
public function get_extension() : ?string
{
if (!$this->is_valid_url()) {
return null;
}
$path = Uri::createFromString($this->url)->getPath();
$file = Str::afterLast($path, '/');
$extension = Str::afterLast($file, '.');
return $extension !== "" ? $extension : null;
}
public function get_path() : ?string
{
if (!$this->is_valid_url()) {
return null;
}
return Uri::createFromString($this->url)->getPath();
}
public static function new(string $url) : self
{
return new self($url);
}
}
IAWP/Utils/WordPress_Site_Date_Format_Pattern.php 0000644 00000003150 14760033122 0015770 0 ustar 00 'DD',
'D' => 'ddd',
'j' => 'D',
'l' => 'dddd',
'N' => 'E',
'S' => 'o',
'w' => 'e',
'z' => 'DDD',
'W' => 'W',
'F' => 'MMMM',
'm' => 'MM',
'M' => 'MMM',
'n' => 'M',
't' => '',
// no equivalent
'L' => '',
// no equivalent
'o' => 'YYYY',
'Y' => 'YYYY',
'y' => 'YY',
'a' => 'a',
'A' => 'A',
'B' => '',
// no equivalent
'g' => 'h',
'G' => 'H',
'h' => 'hh',
'H' => 'HH',
'i' => 'mm',
's' => 'ss',
'u' => 'SSS',
'e' => 'zz',
// deprecated since version 1.6.0 of moment.js
'I' => '',
// no equivalent
'O' => '',
// no equivalent
'P' => '',
// no equivalent
'T' => '',
// no equivalent
'Z' => '',
// no equivalent
'c' => '',
// no equivalent
'r' => '',
// no equivalent
'U' => 'X',
];
return \strtr($php_format, $replacements);
}
}
IAWP/Utils/WP_Async_Request.php 0000644 00000006756 14760033122 0012324 0 ustar 00 identifier = $this->prefix . '_' . $this->action;
\add_action('wp_ajax_' . $this->identifier, [$this, 'maybe_handle']);
\add_action('wp_ajax_nopriv_' . $this->identifier, [$this, 'maybe_handle']);
}
/**
* Handle
*
* Override this method to perform any actions required
* during the async request.
*/
protected abstract function handle();
/**
* Set data used during the request
*
* @param array $data Data.
*
* @return $this
*/
public function data($data)
{
$this->data = $data;
return $this;
}
/**
* Dispatch the async request
*
* @return array|\WP_Error
*/
public function dispatch()
{
$url = \add_query_arg($this->get_query_args(), $this->get_query_url());
$args = $this->get_post_args();
return \wp_remote_post(\esc_url_raw($url), $args);
}
/**
* Maybe handle
*
* Check for correct nonce and pass to handler.
*/
public function maybe_handle()
{
// Don't lock up other requests while processing
\session_write_close();
\check_ajax_referer($this->identifier, 'nonce');
$this->handle();
\wp_die();
}
/**
* Get query args
*
* @return array
*/
protected function get_query_args()
{
if (\property_exists($this, 'query_args')) {
return $this->query_args;
}
$args = ['action' => $this->identifier, 'nonce' => \wp_create_nonce($this->identifier)];
/*
* Filters the post arguments used during an async request.
*
* @param array $url
*/
return \apply_filters($this->identifier . '_query_args', $args);
}
/**
* Get query URL
*
* @return string
*/
protected function get_query_url()
{
if (\property_exists($this, 'query_url')) {
return $this->query_url;
}
$url = \admin_url('admin-ajax.php');
/*
* Filters the post arguments used during an async request.
*
* @param string $url
*/
return \apply_filters($this->identifier . '_query_url', $url);
}
/**
* Get post args
*
* @return array
*/
protected function get_post_args()
{
if (\property_exists($this, 'post_args')) {
return $this->post_args;
}
$args = ['timeout' => 0.01, 'blocking' => \false, 'body' => $this->data, 'cookies' => $_COOKIE, 'sslverify' => \apply_filters('https_local_ssl_verify', \false)];
/*
* Filters the post arguments used during an async request.
*
* @param array $args
*/
return \apply_filters($this->identifier . '_post_args', $args);
}
}
IAWP/Campaign_Builder.php 0000644 00000011323 14760033122 0011200 0 ustar 00 run('campaign-builder', ['campaigns' => $this->get_previously_created_campaigns()]);
}
public function create_campaign($path, $source, $medium, $campaign, $term, $content)
{
global $wpdb;
$has_errors = \false;
$path = \strlen($path) > 0 ? $path : '';
$path_error = null;
$source_error = null;
$medium_error = null;
$campaign_error = null;
$term = \strlen($term) > 0 ? $term : null;
$content = \strlen($content) > 0 ? $content : null;
$url = new URL(\site_url() . $path);
if (!$url->is_valid_url()) {
$has_errors = \true;
$path_error = 'path invalid';
}
if (\strlen($source) === 0) {
$has_errors = \true;
$source_error = 'Source is required';
}
if (\strlen($medium) === 0) {
$has_errors = \true;
$medium_error = 'Medium is required';
}
if (\strlen($campaign) === 0) {
$has_errors = \true;
$campaign_error = 'Campaign is required';
}
if ($has_errors) {
return \IAWPSCOPED\iawp_blade()->run('campaign-builder', ['path' => $path, 'path_error' => $path_error, 'utm_source' => $source, 'utm_source_error' => $source_error, 'utm_medium' => $medium, 'utm_medium_error' => $medium_error, 'utm_campaign' => $campaign, 'utm_campaign_error' => $campaign_error, 'utm_term' => $term, 'utm_content' => $content, 'campaigns' => $this->get_previously_created_campaigns()]);
}
$campaign_urls_table = \IAWP\Query::get_table_name(\IAWP\Query::CAMPAIGN_URLS);
$wpdb->insert($campaign_urls_table, ['path' => $path, 'utm_source' => $source, 'utm_medium' => $medium, 'utm_campaign' => $campaign, 'utm_term' => $term, 'utm_content' => $content, 'created_at' => (new \DateTime())->format('Y-m-d H:i:s')]);
$url = $this->build_url($path, $source, $medium, $campaign, $term, $content);
return \IAWPSCOPED\iawp_blade()->run('campaign-builder', ['path' => $path, 'utm_source' => $source, 'utm_medium' => $medium, 'utm_campaign' => $campaign, 'utm_term' => $term, 'utm_content' => $content, 'new_campaign_url' => $url, 'campaigns' => $this->get_previously_created_campaigns()]);
}
public function build_url($path, $source, $medium, $campaign, $term = null, $content = null) : string
{
$path = String_Util::str_starts_with($path, '/') ? \substr($path, 1) : $path;
$uri = Uri::createFromString(\trailingslashit(\site_url()) . $path);
$existing_query = $uri->getQuery();
if (\is_null($existing_query)) {
$existing_query = [];
} else {
\parse_str($existing_query, $existing_query);
}
$existing_query['utm_source'] = $source;
$existing_query['utm_medium'] = $medium;
$existing_query['utm_campaign'] = $campaign;
if (isset($term)) {
$existing_query['utm_term'] = $term;
}
if (isset($content)) {
$existing_query['utm_content'] = $content;
}
return $uri->withQuery(\http_build_query($existing_query));
}
private function get_previously_created_campaigns()
{
global $wpdb;
$campaign_urls_table = \IAWP\Query::get_table_name(\IAWP\Query::CAMPAIGN_URLS);
$results = $wpdb->get_results("\n SELECT * FROM {$campaign_urls_table} ORDER BY created_at DESC LIMIT 100\n ");
return \array_map(function ($result) {
$created_at = Carbon::parse($result->created_at)->diffForHumans();
return ['campaign_url_id' => $result->campaign_url_id, 'result' => \json_encode((array) $result), 'created_at' => $created_at, 'url' => $this->build_url($result->path, $result->utm_source, $result->utm_medium, $result->utm_campaign, $result->utm_term, $result->utm_content)];
}, $results);
}
public static function has_campaigns() : bool
{
$campaign_builder = new \IAWP\Campaign_Builder();
return \count($campaign_builder->get_previously_created_campaigns()) > 0;
}
public static function delete_campaign(string $campaign_url_id)
{
$campaign_urls_table = \IAWP\Query::get_table_name(\IAWP\Query::CAMPAIGN_URLS);
$delete_campaign = \IAWP\Illuminate_Builder::new();
$delete_campaign->from($campaign_urls_table)->where('campaign_url_id', '=', $campaign_url_id)->delete();
}
}
IAWP/Capability_Manager.php 0000644 00000007076 14760033122 0011540 0 ustar 00 \esc_html__('View analytics for authored content', 'independent-analytics'), 'iawp_read_only_access' => \esc_html__('View all analytics', 'independent-analytics'), 'iawp_full_access' => \esc_html__('View all analytics and edit settings', 'independent-analytics')];
}
public static function reset_capabilities() : void
{
$roles = \wp_roles()->roles;
$edits = [];
foreach ($roles as $role => $role_details) {
$edits[$role] = null;
}
self::edit_all_capabilities($edits);
}
/**
* Accepts an array of key value pairs where the key is the role and the value is the capability to use
*
* @param $capabilities
* @return void
*/
public static function edit_all_capabilities($capabilities) : void
{
foreach ($capabilities as $role => $capability) {
if ($role === 'administrator') {
continue;
}
$user_role = \get_role($role);
// For the role, remove all previous capabilities
foreach (self::all_capabilities() as $possible_capability => $label) {
$user_role->remove_cap($possible_capability);
}
if (\array_key_exists($capability, self::all_capabilities())) {
$user_role->add_cap($capability);
}
}
}
public static function can_view() : bool
{
return self::is_admin_user() || \current_user_can('iawp_read_only_authored_access') || \current_user_can('iawp_read_only_access') || \current_user_can('iawp_full_access');
}
public static function can_only_view_authored_analytics() : bool
{
return !self::is_admin_user() && \current_user_can('iawp_read_only_authored_access');
}
public static function can_view_all_analytics() : bool
{
return self::is_admin_user() || \current_user_can('iawp_read_only_access') || \current_user_can('iawp_full_access');
}
public static function can_edit() : bool
{
return self::is_admin_user() || \current_user_can('iawp_full_access');
}
/**
* Returns a capability string for admin menu pages. Admins can always see pages. Other roles
* can only see pages if they have the special capability applied.
*
* @return string
*/
public static function menu_page_capability_string() : string
{
if (self::is_admin_user()) {
return 'manage_options';
}
if (self::can_edit()) {
return 'iawp_full_access';
}
if (self::can_only_view_authored_analytics()) {
return 'iawp_read_only_authored_access';
}
if (self::can_view()) {
return 'iawp_read_only_access';
}
return 'manage_options';
}
public static function show_branded_ui() : bool
{
if (self::is_admin_user()) {
return \true;
}
if (\get_option('iawp_white_label') === '1') {
return \false;
}
return \true;
}
public static function show_white_labeled_ui() : bool
{
return !self::show_branded_ui();
}
/**
* @return bool
*/
private static function is_admin_user() : bool
{
if (\current_user_can('setup_network') || \in_array('administrator', \wp_get_current_user()->roles)) {
return \true;
}
return \false;
}
}
IAWP/Chart.php 0000644 00000005755 14760033122 0007070 0 ustar 00 statistics = $statistics;
$this->is_preview = $is_preview;
}
public function get_html() : string
{
$options = \IAWP\Dashboard_Options::getInstance();
$primary_statistic = $this->statistics->get_statistic($options->primary_chart_metric_id()) ?? $this->statistics->get_statistic('clicks') ?? $this->statistics->get_statistic('visitors');
$secondary_statistic = \is_string($options->secondary_chart_metric_id()) ? $this->statistics->get_statistic($options->secondary_chart_metric_id()) : null;
$labels = \array_map(function ($data_point) {
return Security::json_encode($this->statistics->chart_interval()->get_label_for($data_point[0]));
}, $primary_statistic->statistic_over_time());
$data = [];
foreach ($this->statistics->get_statistics() as $statistic) {
$data[$statistic->id()] = \array_map(function ($data_point) {
return $data_point[1];
}, $statistic->statistic_over_time());
}
$total_chart_statistics = 0;
foreach ($this->statistics->get_grouped_statistics() as $group) {
$total_chart_statistics += \count($group['items']);
}
return \IAWPSCOPED\iawp_blade()->run('chart', ['chart' => $this, 'intervals' => Intervals::all(), 'current_interval' => $this->statistics->chart_interval(), 'available_datasets' => $this->statistics->get_grouped_statistics(), 'primary_chart_metric_id' => $primary_statistic->id(), 'secondary_chart_metric_id' => \is_null($secondary_statistic) ? null : $secondary_statistic->id(), 'stimulus_values' => ['locale' => \get_bloginfo('language'), 'currency' => $this->get_currency_code(), 'is-preview' => $this->is_preview() ? '1' : '0', 'primary-chart-metric-id' => $primary_statistic->id(), 'primary-chart-metric-name' => $primary_statistic->name(), 'secondary-chart-metric-id' => \is_null($secondary_statistic) ? null : $secondary_statistic->id(), 'secondary-chart-metric-name' => \is_null($secondary_statistic) ? null : $secondary_statistic->name(), 'labels' => $labels, 'data' => $data, 'has-multiple-datasets' => $total_chart_statistics > 1 ? 1 : 0]]);
}
public function is_preview() : bool
{
return $this->is_preview;
}
public function encode_json(array $array) : string
{
return Security::json_encode($array);
}
private function get_currency_code() : ?string
{
if (\IAWPSCOPED\iawp()->is_woocommerce_support_enabled()) {
return get_woocommerce_currency();
}
if (\IAWPSCOPED\iawp()->is_surecart_support_enabled()) {
return SureCart_Store::get_currency_code();
}
return null;
}
}
IAWP/Chart_Geo.php 0000644 00000006462 14760033122 0007656 0 ustar 00 countries = $this->parse($geos);
$this->title = $title;
}
public function get_html()
{
$chart_data = \array_map(function ($country) {
return [$country['country_code'], $country['views'], $this->get_tooltip($country)];
}, $this->countries);
$dark_mode = \IAWPSCOPED\iawp()->get_option('iawp_dark_mode', '0');
\ob_start();
?>
$country) {
if ($geo->country_code() === $country['country_code']) {
$existing_country_index = $index;
}
}
if (\is_numeric($existing_country_index)) {
$countries[$existing_country_index]['views'] += $geo->views();
$countries[$existing_country_index]['visitors'] += $geo->visitors();
$countries[$existing_country_index]['sessions'] += $geo->sessions();
} else {
$countries[] = ['country_code' => $geo->country_code(), 'country' => $geo->country(), 'views' => $geo->views(), 'visitors' => $geo->visitors(), 'sessions' => $geo->sessions()];
}
}
return $countries;
}
private function get_tooltip($country) : string
{
\ob_start();
?>
run('click-tracking.menu', ['active_links' => Link_Rule_Finder::active_link_rules()->map(function ($link_rule) {
return $link_rule->to_array();
})->all(), 'inactive_links' => Link_Rule_Finder::inactive_link_rules()->map(function ($link_rule) {
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()
{
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')];
}
public static function extensions()
{
return ['aif', 'aifc', 'aiff', 'avi', 'csv', 'doc', 'docx', 'epub', 'exe', 'gif', 'jpeg', 'jpg', 'mov', 'mp3', 'mp4', 'm4a', 'pdf', 'png', 'ppt', 'pptx', 'psd', 'rtf', 'txt', 'wav', 'wmv', 'xls', 'xlsx', 'zip'];
}
public static function protocols()
{
return ['mailto', 'tel'];
}
}
IAWP/Cron_Job.php 0000644 00000003004 14760033122 0007503 0 ustar 00 name, function () {
if ($this->should_execute_handler()) {
$this->handle();
}
});
}
public function unschedule()
{
$scheduled_at_timestamp = \wp_next_scheduled($this->name);
if (\is_int($scheduled_at_timestamp)) {
\wp_unschedule_event($scheduled_at_timestamp, $this->name);
}
}
public function schedule()
{
$scheduled_at_timestamp = \wp_next_scheduled($this->name);
if (!\is_int($scheduled_at_timestamp)) {
\wp_schedule_event(\time() + 2, $this->interval, $this->name);
}
}
public function should_execute_handler() : bool
{
return \true;
}
public static function register_custom_intervals() : void
{
\add_filter('cron_schedules', function ($schedules) {
$schedules['monthly'] = ['interval' => \MONTH_IN_SECONDS, 'display' => \esc_html__('Once a Month', 'independent-analytics')];
$schedules['five_minutes'] = ['interval' => 300, 'display' => \esc_html__('Every 5 minutes', 'independent-analytics')];
$schedules['every_minute'] = ['interval' => 60, 'display' => \esc_html__('Every minute', 'independent-analytics')];
return $schedules;
});
}
}
IAWP/Cron_Manager.php 0000644 00000002254 14760033122 0010351 0 ustar 00 unschedule_daily_salt_refresh();
return;
}
$refresh_time = new \DateTime('tomorrow midnight', Timezone::site_timezone());
\wp_schedule_event($refresh_time->getTimestamp(), 'daily', 'iawp_refresh_salt');
}
public function unschedule_daily_salt_refresh()
{
$timestamp = \wp_next_scheduled('iawp_refresh_salt');
\wp_unschedule_event($timestamp, 'iawp_refresh_salt');
}
public function refresh_salt()
{
Salt::refresh_visitor_token_salt();
Config_File_Manager::recreate();
}
}
IAWP/Current_Traffic_Finder.php 0000644 00000002602 14760033122 0012362 0 ustar 00 date_range = $date_range;
}
public function fetch() : Current_Traffic
{
$views_table = \IAWP\Query::get_table_name(\IAWP\Query::VIEWS);
$sessions_table = \IAWP\Query::get_table_name(\IAWP\Query::SESSIONS);
$row = \IAWP\Illuminate_Builder::new()->from($views_table, 'views')->selectRaw('COUNT(DISTINCT (sessions.visitor_id)) AS visitor_count')->selectRaw('COUNT(DISTINCT (views.resource_id)) AS page_count')->selectRaw('COUNT(DISTINCT (sessions.referrer_id)) AS referrer_count')->selectRaw('COUNT(DISTINCT (sessions.country_id)) AS country_count')->selectRaw('COUNT(DISTINCT (sessions.campaign_id)) AS campaign_count')->selectRaw('COUNT(*) AS view_count')->leftJoin("{$sessions_table} AS sessions", function (JoinClause $join) {
$join->on('views.session_id', '=', 'sessions.session_id');
})->whereBetween('viewed_at', [$this->date_range->iso_start(), $this->date_range->iso_end()])->first();
return new Current_Traffic($row);
}
}
IAWP/Dashboard_Options.php 0000644 00000015374 14760033122 0011427 0 ustar 00 report = $this->fetch_current_report();
}
public function report_name() : ?string
{
if (\is_null($this->report->name ?? null)) {
return 'Report';
}
return $this->report->name;
}
public function visible_columns() : ?array
{
if (Request::get_post_array('columns')) {
return Request::get_post_array('columns');
}
if (\is_null($this->report) || \is_null($this->report->columns)) {
return null;
}
return \json_decode($this->report->columns, \true);
}
public function visible_quick_stats() : array
{
if (Request::get_post_array('quick_stats')) {
return Request::get_post_array('quick_stats');
}
$decoded_value = \json_decode($this->report->quick_stats ?? 'null', \true);
if (\is_array($decoded_value)) {
return $decoded_value;
}
if (\IAWP\Env::get_tab() === 'clicks') {
return ['clicks'];
}
return self::$default_visible_quick_stats;
}
public function primary_chart_metric_id() : string
{
if (Request::get_post_string('primary_chart_metric_id')) {
return Request::get_post_string('primary_chart_metric_id');
}
if (\is_null($this->report->primary_chart_metric_id ?? null)) {
return 'visitors';
}
return $this->report->primary_chart_metric_id;
}
public function secondary_chart_metric_id() : ?string
{
if (Request::get_post_string('secondary_chart_metric_id')) {
return Request::get_post_string('secondary_chart_metric_id');
}
if (\is_null($this->report->secondary_chart_metric_id ?? null)) {
return 'views';
}
return $this->report->secondary_chart_metric_id;
}
public function filters() : array
{
if (\is_null($this->report) || \is_null($this->report->filters)) {
return [];
}
$table_class = \IAWP\Env::get_table($this->report->type);
$table = new $table_class($this->report->group_name ?? null);
$filters = \json_decode($this->report->filters, \true);
return \is_null($filters) ? [] : $table->sanitize_filters($filters);
}
public function sort_column() : ?string
{
return $this->report->sort_column ?? null;
}
public function sort_direction() : ?string
{
return $this->report->sort_direction ?? null;
}
public function group() : ?string
{
return $this->report->group_name ?? null;
}
public function chart_interval() : ?Interval
{
if (\is_null($this->report->chart_interval ?? null)) {
return Intervals::default_for($this->get_date_range()->number_of_days());
}
return Intervals::find_by_id($this->report->chart_interval);
}
/**
* @return Date_Range
*/
public function get_date_range() : Date_Range
{
if ($this->has_exact_range()) {
try {
$start = new DateTime($this->start(), Timezone::site_timezone());
$end = new DateTime($this->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($this->relative_range_id());
}
public function start() : ?string
{
if (!$this->has_exact_range()) {
return null;
}
return $this->report->exact_start;
}
public function end() : ?string
{
if (!$this->has_exact_range()) {
return null;
}
return $this->report->exact_end;
}
/**
* Prefer exact range to relative range if both are provided
*/
public function relative_range_id() : ?string
{
$relative_range_id = $this->report->relative_range_id ?? null;
if (!$this->has_exact_range() && $relative_range_id === null) {
return 'LAST_THIRTY';
} elseif ($this->has_exact_range()) {
return null;
} elseif (Relative_Date_Range::is_valid_range($relative_range_id) === \false) {
return 'LAST_THIRTY';
}
return $relative_range_id;
}
public function maybe_redirect() : void
{
if (\IAWP\Env::get_page() !== 'independent-analytics') {
return;
}
if (empty($_GET['report']) && empty($_GET['tab'])) {
$favorite_report = \IAWP\Report_Finder::get_favorite();
if (\is_null($favorite_report)) {
return;
}
\wp_safe_redirect($favorite_report->url());
exit;
}
if (!empty($_GET['report']) && \is_null($this->report)) {
\wp_safe_redirect(\IAWPSCOPED\iawp_dashboard_url(['tab' => \IAWP\Env::get_tab()]));
exit;
}
if (!\is_null($this->report) && \IAWP\Env::get_tab() !== $this->report->type) {
\wp_safe_redirect(\IAWPSCOPED\iawp_dashboard_url(['tab' => $this->report->type, 'report' => $this->report->report_id]));
exit;
}
}
public function is_sidebar_collapsed() : bool
{
$is_sidebar_collapsed = \get_user_meta(\get_current_user_id(), 'iawp_is_sidebar_collapsed', \true) === '1';
return $is_sidebar_collapsed;
}
private function fetch_current_report() : ?object
{
$reports_table = \IAWP\Query::get_table_name(\IAWP\Query::REPORTS);
$report_id = \filter_input(\INPUT_GET, 'report', \FILTER_VALIDATE_INT);
if (!\is_int($report_id)) {
return null;
}
return \IAWP\Illuminate_Builder::new()->from($reports_table)->where('report_id', '=', $report_id)->first();
}
private function has_exact_range() : bool
{
return !\is_null($this->report->exact_start ?? null) && !\is_null($this->report->exact_end ?? null);
}
}
IAWP/Dashboard_Widget.php 0000644 00000002760 14760033122 0011212 0 ustar 00 is_enabled()) {
\add_action('wp_dashboard_setup', [$this, 'add_dashboard_widget']);
}
}
public function add_dashboard_widget()
{
if (\IAWP\Migrations\Migrations::is_migrating() || !\IAWP\Capability_Manager::can_view()) {
return;
}
\ob_start();
?>
get_html();
echo $stats->get_html();
}
private function is_enabled() : bool
{
return \get_option('iawp_disable_widget') !== '1';
}
}
IAWP/Database.php 0000644 00000012127 14760033122 0007522 0 ustar 00 get_charset_collate. As users move their site
* around, old tables might have one collation while newly created tables might have a different
* one.
*
* @internal
*/
class Database
{
private static $character_set = null;
private static $collation = null;
private static $user_privileges = null;
private static $required_privileges = ['SELECT', 'INSERT', 'UPDATE', 'DELETE', 'CREATE', 'ALTER', 'INDEX', 'DROP'];
public static function has_correct_database_privileges() : bool
{
return \count(self::missing_database_privileges()) === 0;
}
public static function missing_database_privileges() : array
{
return \array_diff(self::$required_privileges, self::user_privileges());
}
public static function is_missing_all_tables() : bool
{
global $wpdb;
$tables = \IAWP\Illuminate_Builder::new()->select('*')->from('INFORMATION_SCHEMA.TABLES')->where('TABLE_SCHEMA', '=', $wpdb->dbname)->where('TABLE_NAME', 'LIKE', $wpdb->prefix . 'independent_analytics_%');
$views_table = \IAWP\Query::get_table_name(\IAWP\Query::VIEWS);
$views_query = \IAWP\Illuminate_Builder::new()->selectRaw('0 AS number')->from($views_table);
try {
$views_query->doesntExist();
$missing_views_table = \false;
} catch (QueryException $exception) {
$missing_views_table = \true;
}
return $tables->doesntExist() && $missing_views_table;
}
public static function character_set() : string
{
if (\is_null(self::$character_set)) {
self::populate_character_set_and_collation();
}
return self::$character_set;
}
public static function collation() : string
{
if (\is_null(self::$collation)) {
self::populate_character_set_and_collation();
}
return self::$collation;
}
public static function has_table(string $table) : bool
{
global $wpdb;
$tables = $wpdb->get_row($wpdb->prepare("SHOW TABLES LIKE %s", $table));
return !\is_null($tables);
}
public static function has_index(string $table, string $index) : bool
{
global $wpdb;
if (!self::has_table($table)) {
return \false;
}
$row = $wpdb->get_row($wpdb->prepare("\n SHOW INDEX FROM {$table} WHERE Key_name = %s\n ", $index));
return !\is_null($row);
}
/**
* From MySQL: It is not possible to deny a privilege granted at a higher level by absence of that privilege at a lower level.
*
* @return string[]
*/
private static function user_privileges() : array
{
global $wpdb;
if (!\is_null(self::$user_privileges)) {
return self::$user_privileges;
}
$user = \IAWP\Illuminate_Builder::new()->selectRaw('CURRENT_USER() as user')->value('user');
$parts = \explode('@', $user);
$grantee = "'" . $parts[0] . "'@'" . $parts[1] . "'";
$global_privileges_query = \IAWP\Illuminate_Builder::new()->select('*')->from('information_schema.user_privileges')->where('grantee', '=', $grantee);
$global_privileges = \array_map(function ($record) {
return $record->PRIVILEGE_TYPE;
}, $global_privileges_query->get()->all());
$database_privileges_query = \IAWP\Illuminate_Builder::new()->select('*')->from('information_schema.schema_privileges')->where('grantee', '=', $grantee)->where('table_schema', '=', $wpdb->dbname);
$database_privileges = \array_map(function ($record) {
return $record->PRIVILEGE_TYPE;
}, $database_privileges_query->get()->all());
$privileges = \array_unique(\array_merge($global_privileges, $database_privileges), \SORT_REGULAR);
// If SELECT is missing, that means our query is broken and should be ignored
if (!\in_array('SELECT', $privileges)) {
self::$user_privileges = self::$required_privileges;
} else {
self::$user_privileges = $privileges;
}
return self::$user_privileges;
}
private static function populate_character_set_and_collation() : void
{
global $wpdb;
$query = \IAWP\Illuminate_Builder::new()->selectRaw('CCSA.CHARACTER_SET_NAME AS character_set_name')->selectRaw('CCSA.COLLATION_NAME AS collation_name')->from('information_schema.TABLES', 'THE_TABLES')->leftJoin('information_schema.COLLATION_CHARACTER_SET_APPLICABILITY AS CCSA', 'CCSA.COLLATION_NAME', '=', 'THE_TABLES.TABLE_COLLATION')->where('THE_TABLES.TABLE_SCHEMA', '=', $wpdb->dbname)->where('THE_TABLES.TABLE_NAME', '=', \IAWP\Query::get_table_name(\IAWP\Query::SESSIONS));
$result = $query->first();
self::$character_set = $result->character_set_name ?? null;
self::$collation = $result->collation_name ?? null;
if (\is_null(self::$character_set) || \is_null(self::$collation)) {
self::$character_set = $wpdb->charset;
self::$collation = $wpdb->collate;
}
}
}
IAWP/Database_Manager.php 0000644 00000003340 14760033122 0011151 0 ustar 00 delete_all_post_meta();
}
public function delete_all_data() : void
{
$this->delete_all_iawp_options();
$this->delete_all_iawp_user_metadata();
$this->delete_all_iawp_tables();
$this->delete_all_post_meta();
}
private function delete_all_iawp_options() : void
{
global $wpdb;
$options = $wpdb->get_results($wpdb->prepare("SELECT * FROM {$wpdb->options} WHERE option_name LIKE %s", 'iawp_%'));
foreach ($options as $option) {
\delete_option($option->option_name);
}
}
private function delete_all_iawp_user_metadata() : void
{
global $wpdb;
$metadata = $wpdb->get_results($wpdb->prepare("SELECT * FROM {$wpdb->usermeta} WHERE meta_key LIKE %s", 'iawp_%'));
foreach ($metadata as $metadata) {
\delete_user_meta($metadata->user_id, $metadata->meta_key);
}
}
private function delete_all_iawp_tables() : void
{
global $wpdb;
$prefix = $wpdb->prefix;
$rows = $wpdb->get_results($wpdb->prepare("SELECT table_name FROM information_schema.tables WHERE TABLE_SCHEMA = %s AND table_name LIKE %s", $wpdb->dbname, $prefix . 'independent_analytics_%'));
foreach ($rows as $row) {
$wpdb->query('DROP TABLE ' . $row->table_name);
}
}
private function delete_all_post_meta() : void
{
\delete_post_meta_by_key(Views_Column::$meta_key);
}
}
IAWP/Empty_Report_Option.php 0000644 00000000234 14760033122 0011773 0 ustar 00
condition_buttons_html($opts->filters());
?>
get_condition_html($columns);
?>
html_description());
?>
';
$html .= '' . \esc_html__('Include', 'independent-analytics') . ' ';
$html .= '' . \esc_html__('Exclude', 'independent-analytics') . ' ';
$html .= '';
return $html;
}
/**
* @param Column[] $columns
*
* @return void
*/
private function get_column_select(array $columns)
{
$plugin_groups = \IAWP\Plugin_Group::get_plugin_groups();
$column_sections = [];
foreach ($columns as $column) {
$plugin_group_id = $column->plugin_group();
$section_name = '';
$plugin_group = null;
foreach ($plugin_groups as $a_plugin_group) {
if ($a_plugin_group->id() === $plugin_group_id) {
$section_name = $a_plugin_group->name();
$plugin_group = $a_plugin_group;
}
}
if (!$plugin_group->has_active_group_plugins()) {
continue;
}
if (!\is_null($column->plugin_group_header())) {
$section_name = $plugin_group->name() . ' - ' . $column->plugin_group_header();
}
if (!\array_key_exists($section_name, $column_sections)) {
$column_sections[$section_name] = ['plugin_group' => $plugin_group, 'columns' => []];
}
\array_push($column_sections[$section_name]['columns'], $column);
}
echo \IAWPSCOPED\iawp_blade()->run('partials.filter-column-select', ['column_sections' => $column_sections]);
}
private function get_all_operator_selects()
{
$html = '';
foreach (self::get_data_types() as $data_type) {
$html .= '';
foreach (self::get_operators($data_type) as $key => $value) {
$html .= '' . \esc_html($value) . ' ';
}
$html .= ' ';
}
return $html;
}
private function get_all_operand_fields(array $columns)
{
$html = '';
foreach ($columns as $column) {
switch ($column->type()) {
case 'string':
$html .= ' ';
break;
case 'int':
$html .= ' ';
break;
case 'date':
$html .= ' ';
break;
case 'select':
$html .= '';
foreach ($column->options() as $option) {
$html .= '' . \esc_html($option[1]) . ' ';
}
$html .= ' ';
break;
}
}
return $html;
}
private function get_data_types()
{
return ['string', 'int', 'date', 'select'];
}
private function get_operators(string $data_type)
{
if ($data_type == 'string') {
return ['contains' => \esc_html__('Contains', 'independent-analytics'), 'exact' => \esc_html__('Exactly matches', 'independent-analytics')];
} elseif ($data_type == 'int') {
return ['greater' => \esc_html__('Greater than', 'independent-analytics'), 'lesser' => \esc_html__('Less than', 'independent-analytics'), 'equal' => \esc_html__('Equal to', 'independent-analytics')];
} elseif ($data_type == 'select') {
return ['is' => \esc_html__('Is', 'independent-analytics'), 'isnt' => \esc_html__('Isn\'t', 'independent-analytics')];
} elseif ($data_type == 'date') {
return ['before' => \esc_html__('Before', 'independent-analytics'), 'after' => \esc_html__('After', 'independent-analytics'), 'on' => \esc_html__('On', 'independent-analytics')];
} else {
return null;
}
}
}
IAWP/Geoposition.php 0000644 00000005045 14760033122 0010316 0 ustar 00 geoposition = $this->fetch_geoposition($ip);
}
public function valid_location() : bool
{
$required_values = [$this->continent(), $this->country_code(), $this->country(), $this->city()];
$null_values = \array_filter($required_values, function ($item) {
return \is_null($item);
});
return \count($null_values) === 0;
}
public function country_code() : ?string
{
return $this->geoposition['country']['iso_code'] ?? null;
}
/**
* Return an English city name
*
* @return string|null
*/
public function city() : ?string
{
$city = $this->geoposition['city']['names']['en'] ?? null;
if (\is_null($city)) {
return null;
}
return $this->strip_city_neighborhood_data($city);
}
/**
* Return an English subdivision name
*
* @return string|null
*/
public function subdivision() : ?string
{
return $this->geoposition['subdivisions'][0]['names']['en'] ?? null;
}
/**
* @return string|null
*/
public function country() : ?string
{
return $this->geoposition['country']['names']['en'] ?? null;
}
/**
* @return string|null
*/
public function continent() : ?string
{
return $this->geoposition['continent']['names']['en'] ?? null;
}
/**
* City names can occasionally contain neighborhood data in parentheses after the city name such
* as "Philadelphia (North Philadelphia)" in of "Philadelphia". This strips that extra
* neighborhood data, returning just the city name.
*
* @param $city_name
*
* @return string
*/
private function strip_city_neighborhood_data($city_name) : string
{
$position = \strpos($city_name, '(');
if ($position !== \false) {
$city_name = \substr($city_name, 0, $position);
}
return \trim($city_name);
}
private function fetch_geoposition(string $ip) : array
{
try {
$reader = new Reader(\IAWP\Geo_Database_Manager::path_to_database());
$geo = $reader->get($ip);
$reader->close();
return $geo;
} catch (\Throwable $e) {
return [];
}
}
}
IAWP/Geo_Database_Background_Job.php 0000644 00000001427 14760033122 0013246 0 ustar 00 download();
}
public static function maybe_dispatch() : void
{
$geo_database = new \IAWP\Geo_Database_Manager();
if ($geo_database->should_download()) {
$background_job = new self();
$background_job->dispatch();
}
}
}
IAWP/Geo_Database_Manager.php 0000644 00000007701 14760033122 0011750 0 ustar 00 should_download()) {
return;
}
\update_option('iawp_is_database_downloading', '1', \true);
$this->download_zip_database_and_extract();
if (!$this->is_existing_database_valid()) {
$this->download_raw_database();
} else {
}
\update_option('iawp_is_database_downloading', '0', \true);
$this->record_attempt();
}
public function should_download() : bool
{
if (!$this->has_attempt_interval_elapsed()) {
return \false;
}
if (\get_option('iawp_is_database_downloading', '0') === '1') {
return \false;
}
if ($this->is_existing_database_valid()) {
$this->record_attempt();
return \false;
}
return \true;
}
public function delete() : void
{
\wp_delete_file(self::path_to_database());
}
private function download_zip_database_and_extract() : void
{
\wp_remote_get($this->zip_download_url, ['stream' => \true, 'filename' => $this->path_to_database_zip(), 'timeout' => 60]);
try {
$zip = new ZipArchive();
if ($zip->open($this->path_to_database_zip()) === \true) {
$zip->extractTo(\IAWPSCOPED\iawp_upload_path_to('', \true));
$zip->close();
}
} catch (Throwable $e) {
// It's ok to fail
}
\wp_delete_file($this->path_to_database_zip());
}
private function download_raw_database() : void
{
\wp_remote_get($this->raw_download_url, ['stream' => \true, 'filename' => self::path_to_database(), 'timeout' => 60]);
}
private function is_existing_database_valid() : bool
{
if (!\file_exists(self::path_to_database())) {
return \false;
}
try {
return \verify_file_md5(self::path_to_database(), $this->database_checksum);
} catch (Throwable $e) {
return \false;
}
}
private function has_attempt_interval_elapsed() : bool
{
$last_attempted_at = $this->last_attempted_at();
$interval = new DateInterval('PT30M');
if (\is_null($last_attempted_at)) {
return \true;
}
$is_past_interval_time = $last_attempted_at->add($interval) < new DateTime('now', Timezone::utc_timezone());
if ($is_past_interval_time) {
return \true;
}
return \false;
}
private function last_attempted_at() : ?DateTime
{
$option_value = \get_option('iawp_geo_database_download_last_attempted_at', \false);
if (!$option_value) {
return null;
}
try {
return new DateTime($option_value, Timezone::utc_timezone());
} catch (Throwable $e) {
return null;
}
}
private function record_attempt() : void
{
$now = new DateTime('now', Timezone::utc_timezone());
$value = $now->format('Y-m-d\\TH:i:s');
\update_option('iawp_geo_database_download_last_attempted_at', $value, \true);
}
private function path_to_database_zip() : string
{
return \IAWPSCOPED\iawp_upload_path_to('iawp-geo-db.zip', \true);
}
public static function path_to_database() : string
{
return \IAWPSCOPED\iawp_upload_path_to('iawp-geo-db.mmdb', \true);
}
}
IAWP/Icon_Directory.php 0000644 00000003413 14760033122 0010730 0 ustar 00 directory = $directory;
$this->alt_text = $alt_text;
$this->files = $this->get_files_in_directory($directory);
}
public function find(string $icon) : string
{
$icon_url = $this->find_icon_url($icon);
if (\is_null($icon_url)) {
return '';
}
return ' ';
}
private function find_icon_url(string $icon) : ?string
{
$file_name = $this->convert_icon_name_to_file_name($icon);
if (\in_array($file_name, $this->files)) {
return $this->get_url_for_file($file_name);
}
if (\in_array('default.svg', $this->files)) {
return $this->get_url_for_file('default.svg');
}
return null;
}
private function convert_icon_name_to_file_name(string $string) : string
{
return \str_replace([' ', '/'], '-', \strtolower($string)) . '.svg';
}
private function get_url_for_file(string $file_name) : string
{
return \IAWPSCOPED\iawp_url_to($this->directory . $file_name) . '?version=' . \IAWP_VERSION;
}
private function get_files_in_directory(string $directory) : array
{
$files = \scandir(\IAWPSCOPED\iawp_path_to($directory));
if ($files === \false) {
return [];
}
$files = \array_diff($files, ['..', '.']);
$files = \array_values($files);
return $files;
}
}
IAWP/Icon_Directory_Factory.php 0000644 00000002646 14760033122 0012426 0 ustar 00 toSql());
$escape_mysql_format_percentages = \str_replace('%', '%%', $add_slashes);
$replace_question_marks = \str_replace('?', '%s', $escape_mysql_format_percentages);
if (\function_exists('IAWPSCOPED\\ray')) {
return ray(\vsprintf($replace_question_marks, $builder->getBindings()));
}
}
private static function make_connection() : Connection
{
global $wpdb;
$raw_host = $wpdb->dbhost;
$database_name = $wpdb->dbname;
$charset = $wpdb->dbcharset ?? 'utf8';
$username = $wpdb->dbuser;
$password = $wpdb->dbpassword;
$host_data = $wpdb->parse_db_host($raw_host);
list($host, $port, $socket, $is_ipv6) = $host_data;
if ($is_ipv6 && \extension_loaded('mysqlnd')) {
$host = "[{$host}]";
}
$charset_collate = $wpdb->determine_charset($charset, '');
$charset = $charset_collate['charset'];
// $collation = $charset_collate['collate'];
// Collation is no longer added due to issue with WP Rocket with testing 1.23.0. In the future,
// $connection_options should have the collation property added only if it's defined. It should
// not get set for empty strings.
$connection_options = ['driver' => 'mysql', 'database' => $database_name, 'username' => $username, 'password' => $password, 'charset' => $charset, 'prefix' => '', 'options' => self::ssl_options()];
// Ensures that we use an SSL database connection when WordPress is using one.
// WordPress does SSL, but not with certificate verification. We do the same.
if (self::should_use_ssl()) {
$connection_options['options'][PDO::MYSQL_ATTR_SSL_CA] = \true;
$connection_options['options'][PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT] = \false;
}
if (isset($socket)) {
$connection_options['unix_socket'] = $socket;
} else {
$connection_options['host'] = $host;
if (isset($port)) {
$connection_options['port'] = $port;
}
}
$capsule = new Capsule();
$capsule->addConnection($connection_options);
$capsule->setAsGlobal();
$capsule->bootEloquent();
$connection = $capsule->getConnection();
self::disable_mariadb_optimization($connection);
return $connection;
}
/**
* This disabled the lateral derived optimization for MariaDB users. This was cause slowdowns
* when filtering even with few views.
*
* https://mariadb.com/kb/en/lateral-derived-optimization/
*
* @param Connection $connection
*
* @return void
*/
private static function disable_mariadb_optimization(Connection $connection)
{
$pdo = $connection->getPdo();
$version = $pdo->query("SELECT VERSION() AS version")->fetchColumn();
if (\strpos(\strtolower($version), 'mariadb') === \false) {
return;
}
try {
$pdo->exec("SET optimizer_switch='split_materialized=off'");
} catch (\Throwable $exception) {
}
}
private static function ssl_options() : array
{
if (self::should_use_ssl()) {
if (!\defined('MYSQL_SSL_CA')) {
return [PDO::MYSQL_ATTR_SSL_CA => \true, PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT => \false];
}
return [PDO::MYSQL_ATTR_SSL_CA => \MYSQL_SSL_CA, PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT => \true];
}
if (self::should_use_ssl_without_certificate_verification()) {
return [PDO::MYSQL_ATTR_SSL_CA => \true, PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT => \false];
}
return [];
}
private static function should_use_ssl() : bool
{
if (!\defined('MYSQL_CLIENT_FLAGS')) {
return \false;
}
if (\MYSQL_CLIENT_FLAGS & \MYSQLI_CLIENT_SSL) {
return \true;
}
return \false;
}
private static function should_use_ssl_without_certificate_verification() : bool
{
if (!\defined('MYSQL_CLIENT_FLAGS')) {
return \false;
}
if (\MYSQL_CLIENT_FLAGS & \MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT) {
return \true;
}
return \false;
}
}
IAWP/Independent_Analytics.php 0000644 00000060143 14760033122 0012263 0 ustar 00 configure_carbon();
$this->settings = new \IAWP\Settings();
new \IAWP\REST_API();
new \IAWP\Dashboard_Widget();
new \IAWP\View_Counter();
new Submission_Listener();
Pruner::register_hook();
AJAX_Manager::getInstance();
if (!Migrations::is_migrating()) {
new \IAWP\Track_Resource_Changes();
Menu_Bar_Stats::register();
WooCommerce_Order::register_hooks();
SureCart_Order::register_hooks();
}
\IAWP\Cron_Job::register_custom_intervals();
$this->cron_manager = new \IAWP\Cron_Manager();
(new SureCart_Event_Sync_Job())->register_handler();
(new Click_Processing_Job())->register_handler();
if (\IAWPSCOPED\iawp_is_pro()) {
$this->email_reports = new Email_Reports();
new \IAWP\Campaign_Builder();
new WooCommerce_Referrer_Meta_Box();
}
\add_action('admin_enqueue_scripts', [$this, 'enqueue_scripts_and_styles'], 110);
// Called at 110 to dequeue other scripts
\add_action('wp_enqueue_scripts', [$this, 'enqueue_scripts_and_styles_front_end']);
\add_action('admin_menu', [$this, 'add_admin_menu_pages']);
\add_action('admin_init', [$this, 'remove_freemius_pricing_menu']);
\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']);
\IAWP_FS()->add_filter('pricing_url', [$this, 'change_freemius_pricing_url'], 10);
\IAWP_FS()->add_filter('show_deactivation_feedback_form', function () {
return \false;
});
\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']);
}
public function add_body_class($classes)
{
if (\get_option('iawp_dark_mode')) {
$classes .= ' iawp-dark-mode ';
}
$page = \IAWP\Env::get_page();
if (\is_string($page)) {
$classes .= " {$page} ";
}
return $classes;
}
/**
* At one point in time, there was a must-use plugin that was created. The plugin file and the
* option need to get cleaned up.
* @return void
*/
public function maybe_delete_mu_plugin()
{
$already_attempted = \get_option('iawp_attempted_to_delete_mu_plugin', '0');
if ($already_attempted === '1') {
return;
}
if (\get_option('iawp_must_use_directory_not_writable', '0') === '1') {
\delete_option('iawp_must_use_directory_not_writable');
}
$mu_plugin_file = \trailingslashit(\WPMU_PLUGIN_DIR) . 'iawp-performance-boost.php';
if (\file_exists($mu_plugin_file)) {
\unlink($mu_plugin_file);
}
\update_option('iawp_attempted_to_delete_mu_plugin', '1', \true);
}
public function load_textdomain()
{
\load_plugin_textdomain('independent-analytics', \false, \IAWP_LANGUAGES_DIRECTORY);
}
public function polylang_translations()
{
if (\function_exists('IAWPSCOPED\\pll_register_string')) {
pll_register_string('view_counter', 'Views:', 'Independent Analytics');
}
}
// Changes the URL for the "Upgrade" tab in the Account menu
public function change_freemius_pricing_url()
{
return 'https://independentwp.com/pricing/?utm_source=User+Dashboard&utm_medium=WP+Admin&utm_campaign=Upgrade+to+Pro&utm_content=Account';
}
public function add_admin_menu_pages()
{
$title = \IAWP\Capability_Manager::show_white_labeled_ui() ? \esc_html__('Analytics', 'independent-analytics') : 'Independent Analytics';
\add_menu_page($title, \esc_html__('Analytics', 'independent-analytics'), \IAWP\Capability_Manager::menu_page_capability_string(), 'independent-analytics', function () {
$analytics_page = new Analytics_Page();
$analytics_page->render();
}, $this->get_menu_icon(), 3);
if (\IAWP\Capability_Manager::can_edit()) {
\add_submenu_page('independent-analytics', \esc_html__('Settings', 'independent-analytics'), \esc_html__('Settings', 'independent-analytics'), \IAWP\Capability_Manager::menu_page_capability_string(), 'independent-analytics-settings', function () {
$settings_page = new Settings_Page();
$settings_page->render(\false);
});
}
if (\IAWPSCOPED\iawp_is_pro()) {
\add_submenu_page('independent-analytics', \esc_html__('Campaign Builder', 'independent-analytics'), \esc_html__('Campaign Builder', 'independent-analytics'), \IAWP\Capability_Manager::menu_page_capability_string(), 'independent-analytics-campaign-builder', function () {
$campaign_builder_page = new Campaign_Builder_Page();
$campaign_builder_page->render(\false);
});
if (\IAWP\Capability_Manager::can_edit()) {
\add_submenu_page('independent-analytics', \esc_html__('Click Tracking', 'independent-analytics'), \esc_html__('Click Tracking', 'independent-analytics'), \IAWP\Capability_Manager::menu_page_capability_string(), 'independent-analytics-click-tracking', function () {
$click_tracking_page = new Click_Tracking_Page();
$click_tracking_page->render(\false);
});
}
}
if (\IAWP\Capability_Manager::show_branded_ui()) {
\add_submenu_page('independent-analytics', \esc_html__('Help & Support', 'independent-analytics'), \esc_html__('Help & Support', 'independent-analytics'), \IAWP\Capability_Manager::menu_page_capability_string(), 'independent-analytics-support-center', function () {
$support_page = new Support_Page();
$support_page->render(\false);
});
}
if (\IAWP\Capability_Manager::show_branded_ui()) {
$menu_html = '';
$menu_html = $this->changelog_viewed_since_update() ? $menu_html . ' ' : $menu_html;
\add_submenu_page('independent-analytics', \esc_html__('Changelog', 'independent-analytics'), $menu_html, \IAWP\Capability_Manager::menu_page_capability_string(), 'independent-analytics-updates', function () {
$updates_page = new Updates_Page();
$updates_page->render(\false);
});
}
if (\IAWPSCOPED\iawp_is_free() && \IAWP\Capability_Manager::show_branded_ui()) {
\add_submenu_page('independent-analytics', \esc_html__('Upgrade to Pro →', 'independent-analytics'), '' . \esc_html__('Upgrade to Pro →', 'independent-analytics') . ' ', \IAWP\Capability_Manager::menu_page_capability_string(), \esc_url('https://independentwp.com/pricing/?utm_source=User+Dashboard&utm_medium=WP+Admin&utm_campaign=Upgrade+to+Pro&utm_content=Sidebar'));
}
}
// The menu link is removed in the SDK setup, but this makes it completely inaccessible
public function remove_freemius_pricing_menu()
{
\remove_submenu_page('independent-analytics', 'independent-analytics-pricing');
}
public function register_scripts_and_styles() : void
{
\wp_register_style('iawp-styles', \IAWPSCOPED\iawp_url_to('dist/styles/style.css'), [], \IAWP_VERSION);
\wp_register_style('iawp-dashboard-widget-styles', \IAWPSCOPED\iawp_url_to('dist/styles/dashboard_widget.css'), [], \IAWP_VERSION);
\wp_register_style('iawp-freemius-notice-styles', \IAWPSCOPED\iawp_url_to('dist/styles/freemius_notice_styles.css'), [], \IAWP_VERSION);
\wp_register_style('iawp-posts-menu-styles', \IAWPSCOPED\iawp_url_to('dist/styles/posts_menu.css'), [], \IAWP_VERSION);
\wp_register_script('iawp-javascript', \IAWPSCOPED\iawp_url_to('dist/js/index.js'), ['wp-i18n'], \IAWP_VERSION);
\wp_set_script_translations('iawp-javascript', 'independent-analytics');
\wp_register_script('iawp-dashboard-widget-javascript', \IAWPSCOPED\iawp_url_to('dist/js/dashboard_widget.js'), ['wp-i18n'], \IAWP_VERSION);
\wp_set_script_translations('iawp-dashboard-widget-javascript', 'independent-analytics');
\wp_register_script('iawp-layout-javascript', \IAWPSCOPED\iawp_url_to('dist/js/layout.js'), ['wp-i18n'], \IAWP_VERSION);
\wp_set_script_translations('iawp-layout-javascript', 'independent-analytics');
\wp_register_script('iawp-settings-javascript', \IAWPSCOPED\iawp_url_to('dist/js/settings.js'), ['wp-color-picker', 'wp-i18n'], \IAWP_VERSION);
\wp_set_script_translations('iawp-settings-javascript', 'independent-analytics');
\wp_register_script('iawp-click-tracking-menu-javascript', \IAWPSCOPED\iawp_url_to('dist/js/click-tracking-menu.js'), ['wp-i18n'], \IAWP_VERSION);
\wp_set_script_translations('iawp-click-tracking-menu-javascript', 'independent-analytics');
if (Menu_Bar_Stats::is_option_enabled()) {
\wp_register_style('iawp-front-end-styles', \IAWPSCOPED\iawp_url_to('dist/styles/menu_bar_stats.css'), [], \IAWP_VERSION);
}
if (\is_rtl()) {
\wp_register_style('iawp-styles-rtl', \IAWPSCOPED\iawp_url_to('dist/styles/rtl.css'), [], \IAWP_VERSION);
}
}
public function register_scripts_and_styles_front_end() : void
{
if (Menu_Bar_Stats::is_option_enabled()) {
\wp_register_style('iawp-front-end-styles', \IAWPSCOPED\iawp_url_to('dist/styles/menu_bar_stats.css'), [], \IAWP_VERSION);
}
}
public function enqueue_scripts_and_styles($hook)
{
$this->register_scripts_and_styles();
$page = \IAWP\Env::get_page();
$this->enqueue_translations();
$this->enqueue_nonces();
\wp_enqueue_style('iawp-freemius-notice-styles');
if (\is_string($page)) {
\wp_enqueue_style('iawp-styles');
\wp_enqueue_script('iawp-javascript');
\wp_enqueue_script('iawp-layout-javascript');
$this->dequeue_bad_actors();
$this->maybe_override_adminify_styles();
if (\is_rtl()) {
\wp_enqueue_style('iawp-styles-rtl');
}
}
if ($page === 'independent-analytics-settings') {
\wp_enqueue_style('wp-color-picker');
\wp_enqueue_script('iawp-settings-javascript');
} elseif ($page === 'independent-analytics-click-tracking') {
\wp_enqueue_script('iawp-click-tracking-menu-javascript');
} elseif ($hook === 'index.php') {
\wp_enqueue_script('iawp-dashboard-widget-javascript');
\wp_enqueue_style('iawp-dashboard-widget-styles');
} elseif ($hook === 'edit.php') {
\wp_enqueue_style('iawp-posts-menu-styles');
}
if (Menu_Bar_Stats::is_option_enabled()) {
\wp_enqueue_style('iawp-front-end-styles');
}
}
public function enqueue_scripts_and_styles_front_end()
{
if (Menu_Bar_Stats::is_option_enabled()) {
$this->register_scripts_and_styles_front_end();
\wp_enqueue_style('iawp-front-end-styles');
}
}
public function enqueue_translations()
{
\wp_register_script('iawp-translations', '');
\wp_enqueue_script('iawp-translations');
\wp_add_inline_script('iawp-translations', 'const iawpText = ' . \json_encode(['views' => \__('Views', 'independent-analytics'), 'exactDates' => \__('Apply Exact Dates', 'independent-analytics'), 'relativeDates' => \__('Apply Relative Dates', 'independent-analytics'), 'copied' => \__('Copied', 'independent-analytics'), 'exportingPages' => \__('Exporting Pages...', 'independent-analytics'), 'exportPages' => \__('Export Pages', 'independent-analytics'), 'exportingReferrers' => \__('Exporting Referrers...', 'independent-analytics'), 'exportReferrers' => \__('Export Referrers', 'independent-analytics'), 'exportingGeolocations' => \__('Exporting Geolocations...', 'independent-analytics'), 'exportGeolocations' => \__('Export Geolocations', 'independent-analytics'), 'exportingDevices' => \__('Exporting Devices...', 'independent-analytics'), 'exportDevices' => \__('Export Devices', 'independent-analytics'), 'exportingCampaigns' => \__('Exporting Campaigns...', 'independent-analytics'), 'exportCampaigns' => \__('Export Campaigns', 'independent-analytics'), 'exportingClicks' => \__('Exporting Clicks', 'independent-analytics'), 'exportClicks' => \__('Export Clicks', 'independent-analytics'), 'invalidReportArchive' => \__('This report archive is invalid. Please export your reports and try again.', 'independent-analytics'), 'openMobileMenu' => \__('Open menu', 'independent-analytics'), 'closeMobileMenu' => \__('Close menu', 'independent-analytics')]), 'before');
}
public function enqueue_nonces()
{
\wp_register_script('iawp-nonces', '');
\wp_enqueue_script('iawp-nonces');
\wp_add_inline_script('iawp-nonces', 'const iawpActions = ' . \json_encode(AJAX_Manager::getInstance()->get_action_signatures()), 'before');
}
public function get_option($name, $default)
{
$option = \get_option($name, $default);
return $option === '' ? $default : $option;
}
public function date_i18n(string $format, \DateTime $date) : string
{
return \date_i18n($format, $date->setTimezone(Timezone::site_timezone())->getTimestamp() + Timezone::site_offset_in_seconds($date));
}
public function plugin_action_links($links)
{
// Create the link
$settings_link = '' . \esc_html__('Analytics Dashboard', 'independent-analytics') . ' ';
// Add the link to the start of the array
\array_unshift($links, $settings_link);
return $links;
}
public function pagination_page_size()
{
return 50;
}
public function dequeue_bad_actors()
{
// https://wordpress.org/plugins/comment-link-remove/
\wp_dequeue_style('qc_clr_admin_style_css');
// https://wordpress.org/plugins/webappick-pdf-invoice-for-woocommerce/
\wp_dequeue_style('woo-invoice');
// https://wordpress.org/plugins/wp-media-files-name-rename/
\wp_dequeue_style('wpcmp_bootstrap_css');
// https://wordpress.org/plugins/morepuzzles/
\wp_dequeue_style('bscss');
\wp_dequeue_style('mypluginstyle');
}
public function maybe_override_adminify_styles()
{
if (\is_plugin_active('adminify/adminify.php')) {
$settings = \get_option('_wpadminify');
if ($settings) {
if (\array_key_exists('admin_ui', $settings)) {
if ($settings['admin_ui']) {
\wp_register_style('iawp-adminify-styles', \IAWPSCOPED\iawp_url_to('dist/styles/adminify.css'), [], \IAWP_VERSION);
\wp_enqueue_style('iawp-adminify-styles');
}
}
}
}
}
public function changelog_viewed_since_update() : bool
{
if (\number_format(\floatval(\IAWP_VERSION), 1) > \floatval($this->get_option('iawp_last_update_viewed', '0'))) {
return \true;
}
return \false;
}
public function is_form_submission_support_enabled() : bool
{
if (!\is_bool($this->is_form_submission_support_enabled)) {
$this->is_form_submission_support_enabled = \IAWPSCOPED\iawp_is_pro() && Form::has_active_form_plugin() && \IAWP\Capability_Manager::can_view_all_analytics();
}
return $this->is_form_submission_support_enabled;
}
public function is_woocommerce_support_enabled() : bool
{
if (!\is_bool($this->is_woocommerce_support_enabled)) {
$this->is_woocommerce_support_enabled = $this->actually_check_if_woocommerce_support_is_enabled();
}
return $this->is_woocommerce_support_enabled;
}
public function is_surecart_support_enabled() : bool
{
if (!\is_bool($this->is_surecart_support_enabled)) {
$this->is_surecart_support_enabled = $this->actually_check_if_surecart_support_is_enabled();
}
return $this->is_surecart_support_enabled;
}
public function is_ecommerce_support_enabled() : bool
{
return $this->is_woocommerce_support_enabled() || $this->is_surecart_support_enabled();
}
// This whitelists our plugin with the "Complianz" plugin
public function whitelist_script_tag_for_complianz($scripts)
{
$scripts[] = '/wp-json/iawp/search';
return $scripts;
}
// This is for compatibility with the "Lock and Protect System Folders" setting in the Security Optimizer plugin
public function whitelist_click_endpoint($whitelist)
{
if (\IAWPSCOPED\iawp_is_free()) {
return $whitelist;
}
$whitelist[] = 'iawp-click-endpoint.php';
return $whitelist;
}
private function actually_check_if_woocommerce_support_is_enabled() : bool
{
global $wpdb;
if (\IAWPSCOPED\iawp_is_free()) {
return \false;
}
if (\IAWP\Capability_Manager::can_only_view_authored_analytics()) {
return \false;
}
if (!\is_plugin_active('woocommerce/woocommerce.php')) {
return \false;
}
$table_name = $wpdb->prefix . 'wc_order_stats';
$order_stats_table = $wpdb->get_row($wpdb->prepare('
SELECT * FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = %s AND TABLE_NAME = %s
', $wpdb->dbname, $table_name));
if (\is_null($order_stats_table)) {
return \false;
}
return \true;
}
private function actually_check_if_surecart_support_is_enabled() : bool
{
if (\IAWPSCOPED\iawp_is_free()) {
return \false;
}
return \is_plugin_active('surecart/surecart.php');
}
private function get_menu_icon()
{
if (\is_null(\IAWP\Env::get_page())) {
return 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iNTEzcHgiIGhlaWdodD0iMjU0cHgiIHZpZXdCb3g9IjAgMCA1MTMgMjU0IiB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPgogICAgPHRpdGxlPkljb248L3RpdGxlPgogICAgPGcgaWQ9IlBhZ2UtMSIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiIGZpbGw9Im5vbmUiIGZpbGwtcnVsZT0iZXZlbm9kZCI+CiAgICAgICAgPGcgaWQ9Ik1lbnUtSWNvbiIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTEyNiwgLTIyOCkiIGZpbGw9IiNBN0FBQUQiPgogICAgICAgICAgICA8ZyBpZD0iV2hpdGUiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDgyLCA1NSkiPgogICAgICAgICAgICAgICAgPGcgaWQ9Ikljb24iIHRyYW5zZm9ybT0idHJhbnNsYXRlKDQ0LjUsIDE3MykiPgogICAgICAgICAgICAgICAgICAgIDxwb2x5Z29uIGlkPSJOZWNrLTMiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDQwMi44MDU3LCAxMDguNjEyNSkgcm90YXRlKDQ1KSB0cmFuc2xhdGUoLTQwMi44MDU3LCAtMTA4LjYxMjUpIiBwb2ludHM9IjM5MS4xNjkzNTYgNTYuMjQ4ODI1OSA0MTQuNDQyMDgzIDU2LjI0ODgyNTkgNDE0LjQ0MjA4MyAxNjAuOTc2MDk5IDM5MS4xNjkzNTYgMTYwLjk3NjA5OSI+PC9wb2x5Z29uPgogICAgICAgICAgICAgICAgICAgIDxwb2x5Z29uIGlkPSJOZWNrLTIiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDI1NiwgMTI1LjY3MjcpIHJvdGF0ZSgtNjApIHRyYW5zbGF0ZSgtMjU2LCAtMTI1LjY3MjcpIiBwb2ludHM9IjI0NC4zNjM2MzYgNzMuMzA5MDkwOSAyNjcuNjM2MzY0IDczLjMwOTA5MDkgMjY3LjYzNjM2NCAxNzguMDM2MzY0IDI0NC4zNjM2MzYgMTc4LjAzNjM2NCI+PC9wb2x5Z29uPgogICAgICAgICAgICAgICAgICAgIDxwb2x5Z29uIGlkPSJOZWNrLTEiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDEwOS41Njk0LCAxNDQuNjg1Mikgcm90YXRlKDQ1KSB0cmFuc2xhdGUoLTEwOS41Njk0LCAtMTQ0LjY4NTIpIiBwb2ludHM9Ijk3LjkzMjk5MjMgOTIuMzIxNTUzMiAxMjEuMjA1NzIgOTIuMzIxNTUzMiAxMjEuMjA1NzIgMTk3LjA0ODgyNiA5Ny45MzI5OTIzIDE5Ny4wNDg4MjYiPjwvcG9seWdvbj4KICAgICAgICAgICAgICAgICAgICA8Y2lyY2xlIGlkPSJQb2ludC00IiBjeD0iNDY4Ljk0NTQ1NSIgY3k9IjQzLjA1NDU0NTUiIHI9IjQzLjA1NDU0NTUiPjwvY2lyY2xlPgogICAgICAgICAgICAgICAgICAgIDxjaXJjbGUgaWQ9IlBvaW50LTMiIGN4PSIzMzYuMjkwOTA5IiBjeT0iMTczLjM4MTgxOCIgcj0iNDMuMDU0NTQ1NSI+PC9jaXJjbGU+CiAgICAgICAgICAgICAgICAgICAgPGNpcmNsZSBpZD0iUG9pbnQtMiIgY3g9IjE3NS43MDkwOTEiIGN5PSI3OS4xMjcyNzI3IiByPSI0My4wNTQ1NDU1Ij48L2NpcmNsZT4KICAgICAgICAgICAgICAgICAgICA8Y2lyY2xlIGlkPSJQb2ludC0xIiBjeD0iNDMuMDU0NTQ1NSIgY3k9IjIxMC42MTgxODIiIHI9IjQzLjA1NDU0NTUiPjwvY2lyY2xlPgogICAgICAgICAgICAgICAgPC9nPgogICAgICAgICAgICA8L2c+CiAgICAgICAgPC9nPgogICAgPC9nPgo8L3N2Zz4=';
} else {
return 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iNTEzcHgiIGhlaWdodD0iMjU0cHgiIHZpZXdCb3g9IjAgMCA1MTMgMjU0IiB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPgogICAgPHRpdGxlPkljb248L3RpdGxlPgogICAgPGcgaWQ9IlBhZ2UtMSIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiIGZpbGw9Im5vbmUiIGZpbGwtcnVsZT0iZXZlbm9kZCI+CiAgICAgICAgPGcgaWQ9Ik1lbnUtSWNvbiIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTc3NSwgLTIyOSkiIGZpbGw9IiNGRkZGRkYiPgogICAgICAgICAgICA8ZyBpZD0iV2hpdGUtQ29weSIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNzMxLCA1NikiPgogICAgICAgICAgICAgICAgPGcgaWQ9Ikljb24iIHRyYW5zZm9ybT0idHJhbnNsYXRlKDQ0LjUsIDE3MykiPgogICAgICAgICAgICAgICAgICAgIDxwb2x5Z29uIGlkPSJOZWNrLTMiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDQwMi44MDU3LCAxMDguNjEyNSkgcm90YXRlKDQ1KSB0cmFuc2xhdGUoLTQwMi44MDU3LCAtMTA4LjYxMjUpIiBwb2ludHM9IjM5MS4xNjkzNTYgNTYuMjQ4ODI1OSA0MTQuNDQyMDgzIDU2LjI0ODgyNTkgNDE0LjQ0MjA4MyAxNjAuOTc2MDk5IDM5MS4xNjkzNTYgMTYwLjk3NjA5OSI+PC9wb2x5Z29uPgogICAgICAgICAgICAgICAgICAgIDxwb2x5Z29uIGlkPSJOZWNrLTIiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDI1NiwgMTI1LjY3MjcpIHJvdGF0ZSgtNjApIHRyYW5zbGF0ZSgtMjU2LCAtMTI1LjY3MjcpIiBwb2ludHM9IjI0NC4zNjM2MzYgNzMuMzA5MDkwOSAyNjcuNjM2MzY0IDczLjMwOTA5MDkgMjY3LjYzNjM2NCAxNzguMDM2MzY0IDI0NC4zNjM2MzYgMTc4LjAzNjM2NCI+PC9wb2x5Z29uPgogICAgICAgICAgICAgICAgICAgIDxwb2x5Z29uIGlkPSJOZWNrLTEiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDEwOS41Njk0LCAxNDQuNjg1Mikgcm90YXRlKDQ1KSB0cmFuc2xhdGUoLTEwOS41Njk0LCAtMTQ0LjY4NTIpIiBwb2ludHM9Ijk3LjkzMjk5MjMgOTIuMzIxNTUzMiAxMjEuMjA1NzIgOTIuMzIxNTUzMiAxMjEuMjA1NzIgMTk3LjA0ODgyNiA5Ny45MzI5OTIzIDE5Ny4wNDg4MjYiPjwvcG9seWdvbj4KICAgICAgICAgICAgICAgICAgICA8Y2lyY2xlIGlkPSJQb2ludC00IiBjeD0iNDY4Ljk0NTQ1NSIgY3k9IjQzLjA1NDU0NTUiIHI9IjQzLjA1NDU0NTUiPjwvY2lyY2xlPgogICAgICAgICAgICAgICAgICAgIDxjaXJjbGUgaWQ9IlBvaW50LTMiIGN4PSIzMzYuMjkwOTA5IiBjeT0iMTczLjM4MTgxOCIgcj0iNDMuMDU0NTQ1NSI+PC9jaXJjbGU+CiAgICAgICAgICAgICAgICAgICAgPGNpcmNsZSBpZD0iUG9pbnQtMiIgY3g9IjE3NS43MDkwOTEiIGN5PSI3OS4xMjcyNzI3IiByPSI0My4wNTQ1NDU1Ij48L2NpcmNsZT4KICAgICAgICAgICAgICAgICAgICA8Y2lyY2xlIGlkPSJQb2ludC0xIiBjeD0iNDMuMDU0NTQ1NSIgY3k9IjIxMC42MTgxODIiIHI9IjQzLjA1NDU0NTUiPjwvY2lyY2xlPgogICAgICAgICAgICAgICAgPC9nPgogICAgICAgICAgICA8L2c+CiAgICAgICAgPC9nPgogICAgPC9nPgo8L3N2Zz4=';
}
}
private function configure_carbon()
{
$locale = \get_locale();
// Carbon will throw an error if de_DE_Formal is used
if ('de_de_formal' === \strtolower($locale)) {
$locale = 'de_DE';
}
Carbon::setLocale($locale);
}
}
IAWP/Interrupt.php 0000644 00000003225 14760033122 0010011 0 ustar 00 template = $template;
}
public function render(?array $options = null) : void
{
if ($this->is_admin_page()) {
\add_action('admin_enqueue_scripts', [$this, 'enqueue_styles']);
}
\add_action('admin_menu', function () use($options) {
$title = \IAWP\Capability_Manager::show_white_labeled_ui() ? \esc_html__('Analytics', 'independent-analytics') : 'Independent Analytics';
\add_menu_page($title, \esc_html__('Analytics', 'independent-analytics'), \IAWP\Capability_Manager::menu_page_capability_string(), 'independent-analytics', function () use($options) {
$this->render_page($options);
}, 'dashicons-analytics', 3);
});
}
public function enqueue_styles()
{
\wp_register_style('iawp-styles', \IAWPSCOPED\iawp_url_to('dist/styles/style.css'), [], \IAWP_VERSION);
\wp_enqueue_style('iawp-styles');
}
private function is_admin_page() : bool
{
$page = $_GET['page'] ?? null;
return \is_admin() && $page === 'independent-analytics';
}
private function render_page(?array $options) : void
{
if (\is_null($options)) {
$options = [];
}
?>
run('partials.interrupt-header');
?>
run($this->template, $options);
?>
'Google', 'type' => 'Search', 'domains' => ['www.google.com', 'www.google.ad', 'www.google.ae', 'www.google.com.af', 'www.google.com.ag', 'www.google.com.ai', 'www.google.al', 'www.google.am', 'www.google.co.ao', 'www.google.com.ar', 'www.google.as', 'www.google.at', 'www.google.com.au', 'www.google.az', 'www.google.ba', 'www.google.com.bd', 'www.google.be', 'www.google.bf', 'www.google.bg', 'www.google.com.bh', 'www.google.bi', 'www.google.bj', 'www.google.com.bn', 'www.google.com.bo', 'www.google.com.br', 'www.google.bs', 'www.google.bt', 'www.google.co.bw', 'www.google.by', 'www.google.com.bz', 'www.google.ca', 'www.google.cd', 'www.google.cf', 'www.google.cg', 'www.google.ch', 'www.google.ci', 'www.google.co.ck', 'www.google.cl', 'www.google.cm', 'www.google.cn', 'www.google.com.co', 'www.google.co.cr', 'www.google.com.cu', 'www.google.cv', 'www.google.com.cy', 'www.google.cz', 'www.google.de', 'www.google.dj', 'www.google.dk', 'www.google.dm', 'www.google.com.do', 'www.google.dz', 'www.google.com.ec', 'www.google.ee', 'www.google.com.eg', 'www.google.es', 'www.google.com.et', 'www.google.fi', 'www.google.com.fj', 'www.google.fm', 'www.google.fr', 'www.google.ga', 'www.google.ge', 'www.google.gg', 'www.google.com.gh', 'www.google.com.gi', 'www.google.gl', 'www.google.gm', 'www.google.gr', 'www.google.com.gt', 'www.google.gy', 'www.google.com.hk', 'www.google.hn', 'www.google.hr', 'www.google.ht', 'www.google.hu', 'www.google.co.id', 'www.google.ie', 'www.google.co.il', 'www.google.im', 'www.google.co.in', 'www.google.iq', 'www.google.is', 'www.google.it', 'www.google.je', 'www.google.com.jm', 'www.google.jo', 'www.google.co.jp', 'www.google.co.ke', 'www.google.com.kh', 'www.google.ki', 'www.google.kg', 'www.google.co.kr', 'www.google.com.kw', 'www.google.kz', 'www.google.la', 'www.google.com.lb', 'www.google.li', 'www.google.lk', 'www.google.co.ls', 'www.google.lt', 'www.google.lu', 'www.google.lv', 'www.google.com.ly', 'www.google.co.ma', 'www.google.md', 'www.google.me', 'www.google.mg', 'www.google.mk', 'www.google.ml', 'www.google.com.mm', 'www.google.mn', 'www.google.ms', 'www.google.com.mt', 'www.google.mu', 'www.google.mv', 'www.google.mw', 'www.google.com.mx', 'www.google.com.my', 'www.google.co.mz', 'www.google.com.na', 'www.google.com.ng', 'www.google.com.ni', 'www.google.ne', 'www.google.nl', 'www.google.no', 'www.google.com.np', 'www.google.nr', 'www.google.nu', 'www.google.co.nz', 'www.google.com.om', 'www.google.com.pa', 'www.google.com.pe', 'www.google.com.pg', 'www.google.com.ph', 'www.google.com.pk', 'www.google.pl', 'www.google.pn', 'www.google.com.pr', 'www.google.ps', 'www.google.pt', 'www.google.com.py', 'www.google.com.qa', 'www.google.ro', 'www.google.ru', 'www.google.rw', 'www.google.com.sa', 'www.google.com.sb', 'www.google.sc', 'www.google.se', 'www.google.com.sg', 'www.google.sh', 'www.google.si', 'www.google.sk', 'www.google.com.sl', 'www.google.sn', 'www.google.so', 'www.google.sm', 'www.google.sr', 'www.google.st', 'www.google.com.sv', 'www.google.td', 'www.google.tg', 'www.google.co.th', 'www.google.com.tj', 'www.google.tl', 'www.google.tm', 'www.google.tn', 'www.google.to', 'www.google.com.tr', 'www.google.tt', 'www.google.com.tw', 'www.google.co.tz', 'www.google.com.ua', 'www.google.co.ug', 'www.google.co.uk', 'www.google.com.uy', 'www.google.co.uz', 'www.google.com.vc', 'www.google.co.ve', 'www.google.vg', 'www.google.co.vi', 'www.google.com.vn', 'www.google.vu', 'www.google.ws', 'www.google.rs', 'www.google.co.za', 'www.google.co.zm', 'www.google.co.zw', 'www.google.cat', 'com.google.android.gm']], ['name' => 'Google Ads', 'type' => 'Ad', 'domains' => ['googleads.iawp']], ['name' => 'Google Display Network', 'type' => 'Ad', 'domains' => ['googleads.g.doubleclick.net']], ['name' => 'Google Docs', 'type' => 'Referrer', 'domains' => ['docs.google.com']], ['name' => 'Google Lens', 'type' => 'Search', 'domains' => ['lens.google.com']], ['name' => 'Gmail', 'type' => 'Referrer', 'domains' => ['mail.google.com']], ['name' => 'Yahoo', 'type' => 'Search', 'domains' => ['search.yahoo.com', 'at.search.yahoo.com', 'au.search.yahoo.com', 'be.search.yahoo.com', 'br.search.yahoo.com', 'ca.search.yahoo.com', 'ch.search.yahoo.com', 'de.search.yahoo.com', 'es.search.yahoo.com', 'espanol.search.yahoo.com', 'fi.search.yahoo.com', 'fr.search.yahoo.com', 'gr.search.yahoo.com', 'hk.search.yahoo.com', 'id.search.yahoo.com', 'ie.search.yahoo.com', 'il.search.yahoo.com', 'in.search.yahoo.com', 'it.search.yahoo.com', 'malaysia.search.yahoo.com', 'nl.search.yahoo.com', 'no.search.yahoo.com', 'pe.search.yahoo.com', 'ph.search.yahoo.com', 'pl.search.yahoo.com', 'qc.search.yahoo.com', 'r.search.yahoo.com', 'ro.search.yahoo.com', 'ru.search.yahoo.com', 'se.search.yahoo.com', 'sg.search.yahoo.com', 'th.search.yahoo.com', 'tr.search.yahoo.com', 'tw.search.yahoo.com', 'ua.search.yahoo.com', 'vn.search.yahoo.com', 'za.search.yahoo.com', 'uk.search.yahoo.com', 'us.search.yahoo.com', 'search.yahoo.co.jp', 'co.search.yahoo.com']], ['name' => 'Bing', 'type' => 'Search', 'domains' => ['bing.com', 'www.bing.com', 'cn.bing.com']], ['name' => 'Yandex', 'type' => 'Search', 'domains' => ['yandex.com', 'yandex.ru', 'yandex.ua', 'yandex.by', 'yandex.kz', 'yandex.uz', 'yandex.com.tr', 'yandex.fr', 'yandex.az', 'yandex.com.ge', 'yandex.com.am', 'yandex.co.il', 'yandex.lv', 'yandex.lt', 'yandex.ee', 'yandex.md', 'yandex.tm', 'yandex.tj']], ['name' => 'DuckDuckGo', 'type' => 'Search', 'domains' => ['duckduckgo.com']], ['name' => 'Ecosia', 'type' => 'Search', 'domains' => ['www.ecosia.org']], ['name' => 'Qwant', 'type' => 'Search', 'domains' => ['www.qwant.com']], ['name' => 'AlohaFind', 'type' => 'Search', 'domains' => ['alohafind.com']], ['name' => 'Brave', 'type' => 'Search', 'domains' => ['search.brave.com']], ['name' => 'Presearch', 'type' => 'Search', 'domains' => ['presearch.com']], ['name' => 'Twitter', 'type' => 'Social', 'domains' => ['twitter.com', 't.co']], ['name' => 'Facebook', 'type' => 'Social', 'domains' => ['www.facebook.com', 'm.facebook.com', 'lm.facebook.com', 'l.facebook.com']], ['name' => 'Instagram', 'type' => 'Social', 'domains' => ['instagram.com', 'www.instagram.com', 'l.instagram.com', 'lm.instagram.com']], ['name' => 'TikTok', 'type' => 'Social', 'domains' => ['www.tiktok.com']], ['name' => 'LinkedIn', 'type' => 'Social', 'domains' => ['www.linkedin.com', 'com.linkedin.android']], ['name' => 'Pinterest', 'type' => 'Social', 'domains' => ['www.pinterest.com']], ['name' => 'YouTube', 'type' => 'Social', 'domains' => ['youtube.com', 'www.youtube.com', 'm.youtube.com']], ['name' => 'AOL Search', 'type' => 'Search', 'domains' => ['search.aol.com']], ['name' => 'ArtStation', 'type' => 'Social', 'domains' => ['www.artstation.com']], ['name' => 'Baidu', 'type' => 'Search', 'domains' => ['baidu.com', 'www.baidu.com', 'm.baidu.com']], ['name' => 'Bandcamp', 'type' => 'Social', 'domains' => ['bandcamp.com']], ['name' => 'Behance', 'type' => 'Social', 'domains' => ['www.behance.net']], ['name' => 'Bitbucket', 'type' => 'Social', 'domains' => ['bitbucket.org']], ['name' => 'CodePen', 'type' => 'Social', 'domains' => ['codepen.io']], ['name' => 'DeviantArt', 'type' => 'Social', 'domains' => ['www.deviantart.com']], ['name' => 'Discord', 'type' => 'Social', 'domains' => ['discord.com']], ['name' => 'Dribble', 'type' => 'Social', 'domains' => ['dribbble.com']], ['name' => 'Flickr', 'type' => 'Social', 'domains' => ['flickr.com']], ['name' => 'GitHub', 'type' => 'Social', 'domains' => ['gist.github.com', 'github.com']], ['name' => 'Goodreads', 'type' => 'Social', 'domains' => ['www.goodreads.com']], ['name' => 'Hacker News', 'type' => 'Social', 'domains' => ['news.ycombinator.com']], ['name' => 'Meetup', 'type' => 'Social', 'domains' => ['www.meetup.com']], ['name' => 'Mixcloud', 'type' => 'Social', 'domains' => ['www.mixcloud.com']], ['name' => 'Patreon', 'type' => 'Social', 'domains' => ['www.patreon.com']], ['name' => 'PayPal', 'type' => 'Referrer', 'domains' => ['www.paypal.com']], ['name' => 'Quora', 'type' => 'Social', 'domains' => ['bn.quora.com', 'www.quora.com']], ['name' => 'Tencent QQ', 'type' => 'Social', 'domains' => ['www.qq.com']], ['name' => 'Ravelry', 'type' => 'Social', 'domains' => ['www.ravelry.com']], ['name' => 'Reddit', 'type' => 'Social', 'domains' => ['out.reddit.com', 'www.reddit.com']], ['name' => 'Slack', 'type' => 'Social', 'domains' => ['slack.com']], ['name' => 'SlideShare', 'type' => 'Social', 'domains' => ['www.slideshare.net']], ['name' => 'Snapchat', 'type' => 'Social', 'domains' => ['www.snapchat.com']], ['name' => 'SoundCloud', 'type' => 'Social', 'domains' => ['soundcloud.com']], ['name' => 'Stack Overflow', 'type' => 'Social', 'domains' => ['stackoverflow.com']], ['name' => 'Startpage', 'type' => 'Search', 'domains' => ['www.startpage.com']], ['name' => 'StumbleUpon', 'type' => 'Social', 'domains' => ['www.stumbleupon.com']], ['name' => 'Telegram', 'type' => 'Social', 'domains' => ['telegram.org']], ['name' => 'Weibo', 'type' => 'Social', 'domains' => ['weibo.com']], ['name' => 'Tumblr', 'type' => 'Social', 'domains' => ['www.tumblr.com']], ['name' => 'Twitch', 'type' => 'Social', 'domains' => ['www.twitch.tv']], ['name' => 'Vimeo', 'type' => 'Social', 'domains' => ['vimeo.com']], ['name' => 'WeChat', 'type' => 'Social', 'domains' => ['www.wechat.com']], ['name' => 'WhatsApp', 'type' => 'Social', 'domains' => ['www.whatsapp.com']], ['name' => 'Udemy', 'type' => 'Social', 'domains' => ['www.udemy.com']], ['name' => '500px', 'type' => 'Social', 'domains' => ['500px.com']], ['name' => 'WordPress.org', 'type' => 'Social', 'domains' => ['wordpress.org', 'ru.wordpress.org', 'ca.wordpress.org', 'fr.wordpress.org', 'pl.wordpress.org', 'id.wordpress.org', 'ur.wordpress.org', 'bn.wordpress.org', 'ja.wordpress.org', 'pt.wordpress.org', 'it.wordpress.org', 'hy.wordpress.org', 'hi.wordpress.org', 'de.wordpress.org', 'ar.wordpress.org', 'es.wordpress.org', 'cn.wordpress.org', 'en-ca.wordpress.org', 'en-gb.wordpress.org']]];
public static function get_group_for(string $domain) : ?array
{
foreach (self::$referrers as $referrer) {
if (\in_array($domain, $referrer['domains'])) {
return ['domain' => \reset($referrer['domains']), 'type' => $referrer['type'], 'name' => $referrer['name']];
}
}
return null;
}
public static function referrers() : array
{
return self::$referrers;
}
public static function replace_known_referrers_table()
{
global $wpdb;
$referrer_groups_table = \IAWP\Query::get_table_name(\IAWP\Query::REFERRER_GROUPS);
$known_referrers = self::referrers();
$wpdb->query("DELETE FROM {$referrer_groups_table}");
foreach ($known_referrers as $group) {
foreach ($group['domains'] as $domain) {
$wpdb->insert($referrer_groups_table, ['name' => $group['name'], 'domain' => $group['domains'][0], 'domain_to_match' => $domain, 'type' => $group['type']]);
}
}
}
}
IAWP/Patch.php 0000644 00000003103 14760033122 0007047 0 ustar 00 email_reports->next_event_scheduled_at())) {
\IAWPSCOPED\iawp()->email_reports->schedule();
}
\update_option('iawp_patch_2_6_2_applied', '1', \true);
}
}
public static function patch_2_8_7_potential_duplicates()
{
global $wpdb;
$db_version = \get_option('iawp_db_version', '0');
$is_migrating = \get_option('iawp_is_migrating', '0') === '1';
$last_finished_step = \get_option('iawp_last_finished_migration_step', '0');
$has_error = \get_option('iawp_migration_error_query', null) !== null && \get_option('iawp_migration_error', null) !== null;
if ($db_version === '36' && $is_migrating && \in_array($last_finished_step, ['2', '3']) && $has_error) {
if ($last_finished_step === '3') {
$orders_table = \IAWP\Query::get_table_name(\IAWP\Query::ORDERS);
$wpdb->query("DROP INDEX orders_woocommerce_order_id_index ON {$orders_table}");
}
\delete_option('iawp_migration_error_original_error_message');
\delete_option('iawp_last_finished_migration_step');
\delete_option('iawp_migration_error');
\delete_option('iawp_migration_error_query');
\update_option('iawp_is_migrating', '0', \true);
}
}
}
IAWP/Payload_Validator.php 0000644 00000004776 14760033122 0011427 0 ustar 00 payload = $payload;
$this->signature = $signature;
}
public function is_valid() : bool
{
$signature = \md5(Salt::request_payload_salt() . $this->payload);
if ($signature !== $this->signature) {
return \false;
}
$decoded_payload = \json_decode($this->payload, \true);
if ($decoded_payload === null) {
return \false;
}
return \true;
}
public function payload() : ?array
{
if (!$this->is_valid()) {
return null;
}
return \json_decode($this->payload, \true);
}
public function resource() : ?array
{
if (!$this->is_valid()) {
return null;
}
$payload = $this->payload();
$query = \IAWP\Illuminate_Builder::new()->from(\IAWP\Tables::resources())->where('resource', '=', $payload['resource']);
switch ($payload['resource']) {
case 'singular':
$query->where('singular_id', '=', $payload['singular_id']);
break;
case 'author_archive':
$query->where('author_id', '=', $payload['author_id']);
break;
case 'date_archive':
$query->where('date_archive', '=', $payload['date_archive']);
break;
case 'post_type_archive':
$query->where('post_type', '=', $payload['post_type']);
break;
case 'term_archive':
$query->where('term_id', '=', $payload['term_id']);
break;
case 'search':
$query->where('search_query', '=', $payload['search_query']);
break;
case 'home':
break;
case '404':
$query->where('not_found_url', '=', $payload['not_found_url']);
break;
case 'virtual_page':
$query->where('virtual_page_id', '=', $payload['virtual_page_id']);
break;
}
$row = $query->first();
if (!\is_object($row)) {
return null;
}
return (array) $row;
}
public static function new(string $payload, string $signature)
{
return new self($payload, $signature);
}
}
IAWP/Plugin_Conflict_Detector.php 0000644 00000024262 14760033122 0012731 0 ustar 00 error = $this->run_conflict_check();
}
/**
* Did the health check pass?
*
* @return bool
*/
public function has_conflict() : bool
{
return !empty($this->error);
}
/**
* Returns the health check error, if any
*
* @return string|null
*/
public function get_error() : ?string
{
return $this->error;
}
/**
* @return string|null Returns a string error message if the health check fails
*/
private function run_conflict_check() : ?string
{
if (\is_plugin_active('disable-wp-rest-api/disable-wp-rest-api.php')) {
return \__('The "Disable WP REST API" plugin needs to be deactivated because Independent Analytics uses the REST API to record visits.', 'independent-analytics');
}
if (\is_plugin_active('all-in-one-wp-security-and-firewall/wp-security.php')) {
$settings = \get_option('aio_wp_security_configs', []);
if (\array_key_exists('aiowps_disallow_unauthorized_rest_requests', $settings)) {
if ($settings['aiowps_disallow_unauthorized_rest_requests'] == 1) {
return \__('The "All In One WP Security" plugin is blocking REST API requests, which Independent Analytics needs to record views. Please disable this setting via the WP Security > Miscellaneous menu.', 'independent-analytics');
}
}
}
if (\is_plugin_active('disable-json-api/disable-json-api.php')) {
$settings = \get_option('disable_rest_api_options', []);
if (\array_key_exists('roles', $settings)) {
if ($settings['roles']['none']['default_allow'] == \false) {
if ($settings['roles']['none']['allow_list']['/iawp/search'] == \false) {
return \__('The "Disable REST API" plugin is blocking REST API requests for unauthenticated users, which Independent Analytics needs to record views. Please enable the /iawp/search route, so Independent Analytics can track your visitors.', 'independent-analytics');
}
}
}
}
if (\is_plugin_active('disable-xml-rpc-api/disable-xml-rpc-api.php')) {
$settings = \get_option('dsxmlrpc-settings');
if (\array_key_exists('json-rest-api', $settings)) {
if ($settings['json-rest-api'] == 1) {
return \__('The "Disable XML-RPC-API" plugin is blocking REST API requests, which Independent Analytics needs to record views. Please visit the Security Settings menu and turn off the "Disable JSON REST API" option, so Independent Analytics can track your visitors.', 'independent-analytics');
}
}
}
if (\is_plugin_active('wpo-tweaks/wordpress-wpo-tweaks.php')) {
return \__('The "WPO Tweaks & Optimizations" plugin needs to be deactivated because it is disabling the REST API, which Independent Analytics uses to record visits.', 'independent-analytics');
}
if (\is_plugin_active('all-in-one-intranet/basic_all_in_one_intranet.php')) {
return \__('The "All-In-One Intranet" plugin needs to be deactivated because it is disabling the REST API, which Independent Analytics uses to record visits. You may want to try the "My Private Site" plugin instead.', 'independent-analytics');
}
if (\is_plugin_active('wp-security-hardening/wp-hardening.php')) {
$settings = \get_option('whp_fixer_option');
if (\array_key_exists('disable_json_api', $settings)) {
if ($settings['disable_json_api'] != 'off') {
return \__('The "WP Hardening" plugin is blocking the REST API, which Independent Analytics needs to record views. Please visit the WP Hardening > Security Fixers menu and turn off the "Disable WP API JSON" option, so Independent Analytics can track your visitors.', 'independent-analytics');
}
}
}
if (\is_plugin_active('wp-rest-api-authentication/miniorange-api-authentication.php')) {
$settings = \get_option('mo_api_authentication_protectedrestapi_route_whitelist');
if (\in_array('/iawp/search', $settings)) {
return \__('The "WordPress REST API Authentication" plugin is blocking the REST API, which Independent Analytics needs to record views. Please visit the miniOrange API Authentication > Protected REST APIs menu and uncheck the "/iawp/search" box to allow Independent Analytics to track your visitors.', 'independent-analytics');
}
}
if (\is_plugin_active('ninjafirewall/ninjafirewall.php')) {
$settings = \get_option('nfw_options');
if (\array_key_exists('no_restapi', $settings)) {
if ($settings['no_restapi'] == 1) {
return \__('The "NinjaFirewall" plugin is blocking the REST API, which Independent Analytics needs to record views. Please visit the NinjaFirewall > Firewall Policies menu and uncheck the "Block any access to the API" checkbox to allow Independent Analytics to track your visitors.', 'independent-analytics');
}
}
}
if (\is_plugin_active('wp-cerber/wp-cerber.php')) {
// This option has been renamed before. If there's an issue in here, check that it wasn't renamed again.
$settings = \get_option('cerber_configuration');
if ($settings === \false) {
$settings = \get_option('cerber-hardening');
}
if (\array_key_exists('norest', $settings)) {
if ($settings['norest'] === '1') {
if (!\in_array('iawp', $settings['restwhite'])) {
return \__('The "WP Cerber" plugin is blocking the REST API, which Independent Analytics needs to record views. Please visit the WP Cerber > Dashboard > Hardening menu and add "iawp" to your allowed namespaces. This will keep the REST API locked down while allowing requests for Independent Analytics.', 'independent-analytics');
}
}
}
}
if (\is_plugin_active('wp-simple-firewall/icwp-wpsf.php')) {
// This option has been renamed before. If there's an issue in here, check that it wasn't renamed again.
$settings = \get_option('icwp_wpsf_opts_all');
if ($settings === \false) {
$settings = \get_option('icwp_wpsf_opts_free');
}
if (\array_key_exists('lockdown', $settings)) {
if (\array_key_exists('disable_anonymous_restapi', $settings['lockdown'])) {
if ($settings['lockdown']['disable_anonymous_restapi'] == 'Y') {
if (\array_key_exists('api_namespace_exclusions', $settings['lockdown'])) {
if (!\in_array('iawp', $settings['lockdown']['api_namespace_exclusions'])) {
return \__('The "Shield Security" plugin is blocking the REST API, which Independent Analytics needs to record views. Please visit the Shield Security > Config > Lockdown menu and add "iawp" to your allowed namespaces. This will keep the REST API locked down while allowing requests for Independent Analytics.', 'independent-analytics');
}
}
}
}
}
}
if (\is_plugin_active('wp-hide-security-enhancer/wp-hide.php')) {
$settings = \get_option('wph_settings');
if (\array_key_exists('module_settings', $settings)) {
if (\array_key_exists('disable_json_rest_v2', $settings['module_settings'])) {
if ($settings['module_settings']['disable_json_rest_v2'] == 'yes') {
return \__('The "WP Hide" plugin is blocking the REST API, which Independent Analytics needs to record views. Please visit the WP Hide > Rewrite URLs menu and switch the "Disable JSON REST V2 service" option to "No."', 'independent-analytics');
}
}
if (\array_key_exists('block_json_rest', $settings['module_settings'])) {
if ($settings['module_settings']['block_json_rest'] == 'yes' || $settings['module_settings']['block_json_rest'] == 'non-logged-in') {
return \__('The "WP Hide" plugin is blocking the REST API, which Independent Analytics needs to record views. Please visit the WP Hide > Rewrite URLs menu and switch the "Block any JSON REST calls" option to "No."', 'independent-analytics');
}
}
}
}
if (\is_plugin_active('admin-site-enhancements/admin-site-enhancements.php')) {
$settings = \get_option('admin_site_enhancements');
if (\array_key_exists('disable_rest_api', $settings)) {
if ($settings['disable_rest_api']) {
return \__('The "Admin and Site Enhancements" plugin is blocking the REST API, which Independent Analytics needs to record views. Please visit the Tools > Enhancements menu, click on the "Disable Components" section, and deselect the "Disable REST API" setting to allow Independent Analytics to track your visitors.', 'independent-analytics');
}
}
}
return null;
}
public function plugin_requiring_logged_in_tracking()
{
if (\is_plugin_active('woocommerce/woocommerce.php')) {
return 'WooCommerce';
} elseif (\is_plugin_active('surecart/surecart.php')) {
return 'SureCart';
} elseif (\is_plugin_active('paid-memberships-pro/paid-memberships-pro.php')) {
return 'Paid Memberships Pro';
} elseif (\is_plugin_active('ultimate-member/ultimate-member.php')) {
return 'Ultimate Member';
} elseif (\is_plugin_active('simple-membership/simple-wp-membership.php')) {
return 'Simple WordPress Membership';
} elseif (\is_plugin_active('members/members.php')) {
return 'Members plugin';
}
return \false;
}
}
IAWP/Plugin_Group.php 0000644 00000012575 14760033122 0010437 0 ustar 00 id = $attributes['id'];
$this->name = $attributes['name'];
$this->requires_pro = $attributes['requires_pro'] ?? \false;
$this->has_active_group_plugins = $attributes['has_active_group_plugins'] ?? \true;
$this->upgrade_message = $attributes['upgrade_message'] ?? null;
$this->upgrade_link = $attributes['upgrade_link'] ?? null;
$this->activate_message = $attributes['activate_message'] ?? null;
$this->activate_link = $attributes['activate_link'] ?? null;
$this->no_tracked_data_message = $attributes['no_tracked_data_message'] ?? null;
}
public function id() : string
{
return $this->id;
}
public function name() : string
{
return $this->name;
}
public function requires_pro() : bool
{
return $this->requires_pro;
}
public function has_active_group_plugins() : bool
{
return $this->has_active_group_plugins;
}
public function upgrade_message() : ?string
{
return $this->upgrade_message;
}
public function upgrade_link() : ?string
{
return $this->upgrade_link;
}
public function activate_message() : ?string
{
return $this->activate_message;
}
public function activate_link() : ?string
{
return $this->activate_link;
}
public function no_tracked_data_message() : ?string
{
return $this->no_tracked_data_message;
}
public function has_tracked_data() : bool
{
global $wpdb;
$form_submissions_table = \IAWP\Query::get_table_name(\IAWP\Query::FORM_SUBMISSIONS);
switch ($this->id) {
case 'forms':
$value = $wpdb->get_var("SELECT EXISTS (SELECT 1 FROM {$form_submissions_table})");
return $value === "1";
default:
return \true;
}
}
public static function get_plugin_group(string $plugin_group_id) : \IAWP\Plugin_Group
{
$plugin_groups = self::get_plugin_groups();
foreach ($plugin_groups as $plugin_group) {
if ($plugin_group->id() == $plugin_group_id) {
return $plugin_group;
}
}
// Added to satisfy PHPStan
return $plugin_groups[0];
}
/**
* @return Plugin_Group[]
*/
public static function get_plugin_groups() : array
{
return [new self(['id' => 'general', 'name' => \__('General', 'independent-analytics')]), new self(['id' => 'ecommerce', 'name' => self::get_ecommerce_label(), 'requires_pro' => \true, 'has_active_group_plugins' => \IAWPSCOPED\iawp()->is_ecommerce_support_enabled(), 'upgrade_message' => \__('Upgrade to Independent Analytics Pro to get eCommerce stats.', 'independent-analytics'), 'upgrade_link' => 'https://independentwp.com/features/woocommerce-analytics/?utm_source=User+Dashboard&utm_medium=WP+Admin&utm_campaign=Stat+Toggle+Link', 'activate_message' => \__('Activate a supported eCommerce plugin to display these stats.', 'independent-analytics'), 'activate_link' => 'https://independentwp.com/knowledgebase/woocommerce/supported-ecommerce-plugins/']), new self(['id' => 'forms', 'name' => \__('Forms', 'independent-analytics'), 'requires_pro' => \true, 'has_active_group_plugins' => \IAWPSCOPED\iawp()->is_form_submission_support_enabled(), 'upgrade_message' => self::form_group_upgrade_message(), 'upgrade_link' => 'https://independentwp.com/features/form-tracking/?utm_source=User+Dashboard&utm_medium=WP+Admin&utm_campaign=Stat+Toggle+Link', 'activate_message' => \__('Activate a supported form plugin to display these stats.', 'independent-analytics'), 'activate_link' => 'https://independentwp.com/knowledgebase/form-tracking/track-form-submissions/', 'no_tracked_data_message' => \__('Your forms will show up here once a submission has been recorded.', 'independent-analytics')])];
}
private static function get_ecommerce_label() : string
{
if (\IAWPSCOPED\iawp()->is_woocommerce_support_enabled() && !\IAWPSCOPED\iawp()->is_surecart_support_enabled()) {
return 'WooCommerce';
}
if (\IAWPSCOPED\iawp()->is_surecart_support_enabled() && !\IAWPSCOPED\iawp()->is_woocommerce_support_enabled()) {
return 'SureCart';
}
return \__('eCommerce', 'independent-analytics');
}
private static function form_group_upgrade_message() : string
{
if (Form::has_active_form_plugin()) {
return \sprintf(\_x('Upgrade to Independent Analytics Pro to track %s submissions.', 'Plugin name e.g. WPForms submissions', 'independent-analytics'), Form::get_first_active_form_plugin_name());
}
return \__('Upgrade to Independent Analytics Pro to track form submissions.', 'independent-analytics');
}
}
IAWP/Plugin_Group_Option.php 0000644 00000000654 14760033122 0011762 0 ustar 00 prefix;
$reflection = new \ReflectionClass(static::class);
$constants = $reflection->getConstants();
if (\in_array($name, $constants)) {
return $prefix . 'independent_analytics_' . $name;
} else {
return null;
}
}
}
IAWP/Query_Taps.php 0000644 00000003376 14760033122 0010120 0 ustar 00 leftJoin($query->raw($resources_table . ' AS resources'), function (JoinClause $join) {
$join->on('views.resource_id', '=', 'resources.id');
});
}
$query->where('resources.cached_author_id', '=', \get_current_user_id());
};
}
public static function tap_authored_content_for_clicks()
{
return function (Builder $query) {
if (!\is_user_logged_in() || \IAWP\Capability_Manager::can_view_all_analytics()) {
return;
}
$views_table = \IAWP\Query::get_table_name(\IAWP\Query::VIEWS);
$query->leftJoin($query->raw($views_table . ' AS views'), function (JoinClause $join) {
$join->on('clicks.view_id', '=', 'views.id');
});
$resources_table = \IAWP\Query::get_table_name(\IAWP\Query::RESOURCES);
$query->leftJoin($query->raw($resources_table . ' AS resources'), function (JoinClause $join) {
$join->on('views.resource_id', '=', 'resources.id');
});
$query->where('resources.cached_author_id', '=', \get_current_user_id());
};
}
}
IAWP/Quick_Stats.php 0000644 00000002353 14760033122 0010250 0 ustar 00 statistics = $statistics;
$this->is_dashboard_widget = $is_dashboard_widget;
}
public function get_html() : string
{
$statistics = $this->statistics->get_statistics();
$visible_quick_stats_count = \count(\array_filter($statistics, function (Statistic $statistic) : bool {
return $statistic->is_visible() && $statistic->is_group_plugin_enabled();
}));
$quick_stats_html_class = "quick-stats total-of-{$visible_quick_stats_count}";
if ($this->statistics->has_filters()) {
$quick_stats_html_class .= ' filtered';
}
return \IAWPSCOPED\iawp_blade()->run('quick-stats', ['is_dashboard_widget' => $this->is_dashboard_widget, 'quick_stats_html_class' => $quick_stats_html_class, 'statistics' => $statistics, 'plugin_groups' => \IAWP\Plugin_Group::get_plugin_groups()]);
}
}
IAWP/Real_Time.php 0000644 00000014050 14760033122 0007654 0 ustar 00 round_up_by_seconds($thirty_minutes_ago, 60);
$five_minutes_ago = new DateTime('-5 minutes');
$five_minutes_ago = $this->round_up_by_seconds($five_minutes_ago, 10);
$now = new DateTime();
$end_minutes = $this->round_up_by_seconds($now, 60);
$end_seconds = $this->round_up_by_seconds($now, 10);
$visitors_by_minute_date_range = new Exact_Date_Range($thirty_minutes_ago, $end_minutes, \false);
$visitors_by_minute_finder = new \IAWP\Visitors_Over_Time_Finder($visitors_by_minute_date_range, new Minute_Interval());
$visitors_by_minute = $visitors_by_minute_finder->fetch();
$visitors_by_second_date_range = new Exact_Date_Range($five_minutes_ago, $end_seconds, \false);
$visitors_by_second_finder = new \IAWP\Visitors_Over_Time_Finder($visitors_by_second_date_range, new Ten_Second_Interval());
$visitors_by_second = $visitors_by_second_finder->fetch();
$five_minute_date_range = new Exact_Date_Range($five_minutes_ago, new DateTime(), \false);
$current_traffic_finder = new \IAWP\Current_Traffic_Finder($five_minute_date_range);
$current_traffic = $current_traffic_finder->fetch();
$pages = new Pages($five_minute_date_range, 10);
$page_rows = \array_map(function ($row, $index) {
return ['id' => $row->id(), 'position' => $index + 1, 'title' => $row->title(), 'views' => $row->views(), 'subtitle' => $row->most_popular_subtitle()];
}, $pages->rows(), \array_keys($pages->rows()));
$referrers = new Referrers($five_minute_date_range, 10);
$referrer_rows = \array_map(function ($row, $index) {
return ['id' => $row->referrer(), 'position' => $index + 1, 'title' => $row->referrer(), 'views' => $row->views()];
}, $referrers->rows(), \array_keys($referrers->rows()));
$countries = new Countries($five_minute_date_range, 10);
$country_rows = \array_map(function ($row, $index) {
return ['id' => $row->country(), 'position' => $index + 1, 'title' => $row->country(), 'views' => $row->views(), 'flag' => \IAWP\Icon_Directory_Factory::flags()->find($row->country_code())];
}, $countries->rows(), \array_keys($countries->rows()));
$campaigns = new Campaigns($five_minute_date_range, 10);
$campaign_rows = \array_map(function ($row, $index) {
return ['id' => $row->params(), 'position' => $index + 1, 'title' => $row->utm_campaign(), 'views' => $row->views()];
}, $campaigns->rows(), \array_keys($campaigns->rows()));
$device_types = new Device_Types($five_minute_date_range, 10);
$device_rows = \array_map(function ($row, $index) {
return ['id' => $row->device_type(), 'position' => $index + 1, 'title' => $row->device_type(), 'views' => $row->views()];
}, $device_types->rows(), \array_keys($device_types->rows()));
$visitor_message = $this->get_visitor_count_message($current_traffic->get_visitor_count());
$page_message = $this->get_count_message($current_traffic->get_page_count(), \__('Page', 'independent-analytics'), \__('Pages', 'independent-analytics'));
$referrer_message = $this->get_count_message($current_traffic->get_referrer_count(), \__('Referrer', 'independent-analytics'), \__('Referrers', 'independent-analytics'));
$country_message = $this->get_count_message($current_traffic->get_country_count(), \__('Country', 'independent-analytics'), \__('Countries', 'independent-analytics'));
return ['visitor_message' => $visitor_message, 'page_message' => $page_message, 'referrer_message' => $referrer_message, 'country_message' => $country_message, 'chart_data' => ['minute_interval_visitors' => $visitors_by_minute->visitors, 'minute_interval_views' => $visitors_by_minute->views, 'minute_interval_labels_short' => $visitors_by_minute->interval_labels_short, 'minute_interval_labels_full' => $visitors_by_minute->interval_labels_full, 'second_interval_visitors' => $visitors_by_second->visitors, 'second_interval_views' => $visitors_by_second->views, 'second_interval_labels_short' => $visitors_by_second->interval_labels_short, 'second_interval_labels_full' => $visitors_by_second->interval_labels_full], 'lists' => ['pages' => ['title' => \__('Active Pages', 'independent-analytics'), 'entries' => $page_rows], 'referrers' => ['title' => \__('Active Referrers', 'independent-analytics'), 'entries' => $referrer_rows], 'countries' => ['title' => \__('Active Countries', 'independent-analytics'), 'entries' => $country_rows], 'campaigns' => ['title' => \__('Active Campaigns', 'independent-analytics'), 'entries' => $campaign_rows], 'device_types' => ['title' => \__('Device Types', 'independent-analytics'), 'entries' => $device_rows]]];
}
public function render_real_time_analytics()
{
echo \IAWPSCOPED\iawp_blade()->run('real_time', $this->get_real_time_analytics());
}
private function get_count_message(int $count, string $singular, string $plural) : string
{
return \number_format_i18n($count) . ' ' . \_n($singular, $plural, $count);
}
private function get_visitor_count_message(int $count) : string
{
return $this->get_count_message($count, \__('Active Visitor', 'independent-analytics'), \__('Active Visitors', 'independent-analytics'));
}
private function round_up_by_seconds(DateTime $datetime, $precision_seconds) : DateTime
{
$datetime = clone $datetime;
$datetime->setTimestamp($precision_seconds * (int) \ceil($datetime->getTimestamp() / $precision_seconds));
return $datetime;
}
}
IAWP/Report.php 0000644 00000003740 14760033122 0007272 0 ustar 00 row = $row;
}
public function id() : int
{
return $this->row->report_id;
}
public function type() : string
{
return $this->row->type;
}
public function name() : string
{
return $this->row->name;
}
public function url() : string
{
if (!$this->is_saved_report()) {
return \IAWPSCOPED\iawp_dashboard_url(['tab' => $this->row->type]);
}
return \IAWPSCOPED\iawp_dashboard_url(['tab' => $this->row->type, 'report' => $this->row->report_id]);
}
public function is_saved_report() : bool
{
return \property_exists($this->row, 'report_id');
}
public function is_current() : bool
{
$report_id = \array_key_exists('report', $_GET) ? \sanitize_text_field($_GET['report']) : null;
return $this->id() === \intval($report_id);
}
public function is_favorite() : bool
{
if ($this->is_saved_report()) {
return \intval(\get_user_meta(\get_current_user_id(), 'iawp_favorite_report_id', \true)) === $this->id();
}
return \get_user_meta(\get_current_user_id(), 'iawp_favorite_report_type', \true) === $this->type();
}
public function to_array() : array
{
$array = (array) $this->row;
if (\array_key_exists('columns', $array) && !\is_null($array['columns'])) {
$array['columns'] = \json_decode($array['columns'], \true);
}
if (\array_key_exists('filters', $array) && !\is_null($array['filters'])) {
$array['filters'] = \json_decode($array['filters'], \true);
}
return $array;
}
public static function is_valid_report_type(string $type) : bool
{
return \in_array($type, self::$report_types);
}
}
IAWP/Report_Finder.php 0000644 00000016367 14760033122 0010572 0 ustar 00 \esc_html__('Pages', 'independent-analytics'), 'reports' => $this->fetch_page_reports()], ['name' => \esc_html__('Referrers', 'independent-analytics'), 'reports' => $this->fetch_referrer_reports()], ['name' => \esc_html__('Geographic', 'independent-analytics'), 'reports' => $this->fetch_geographic_reports()], ['name' => \esc_html__('Devices', 'independent-analytics'), 'reports' => $this->fetch_device_reports()], ['name' => \esc_html__('Campaigns', 'independent-analytics'), 'reports' => $this->fetch_campaign_reports()], ['name' => \esc_html__('Clicks', 'independent-analytics'), 'reports' => $this->fetch_click_reports()]];
}
/**
* @return Report[]
*/
public function fetch_page_reports() : array
{
return $this->by_type('views');
}
/**
* @return Report[]
*/
public function fetch_referrer_reports() : array
{
return $this->by_type('referrers');
}
/**
* @return Report[]
*/
public function fetch_geographic_reports() : array
{
return $this->by_type('geo');
}
/**
* @return Report[]
*/
public function fetch_device_reports() : array
{
return $this->by_type('devices');
}
/**
* @return Report[]
*/
public function fetch_campaign_reports() : array
{
return $this->by_type('campaigns');
}
/**
* @return Report[]
*/
public function fetch_click_reports() : array
{
return $this->by_type('clicks');
}
public function is_real_time() : bool
{
return \IAWP\Env::get_tab() === 'real-time';
}
public function is_settings_page() : bool
{
return \IAWP\Env::get_page() === 'independent-analytics-settings';
}
public function is_campaign_builder_page() : bool
{
return \IAWP\Env::get_page() === 'independent-analytics-campaign-builder';
}
public function is_page_report() : bool
{
return \IAWP\Env::get_tab() === 'views';
}
public function is_referrer_report() : bool
{
return \IAWP\Env::get_tab() === 'referrers';
}
public function is_geographic_report() : bool
{
return \IAWP\Env::get_tab() === 'geo';
}
public function is_device_report() : bool
{
return \IAWP\Env::get_tab() === 'devices';
}
public function is_campaign_report() : bool
{
return \IAWP\Env::get_tab() === 'campaigns';
}
public function is_click_report() : bool
{
return \IAWP\Env::get_tab() === 'clicks';
}
public function is_saved_report() : bool
{
$report = $this->current();
if (\is_null($report)) {
return \false;
}
return $report->is_saved_report();
}
public function current() : ?\IAWP\Report
{
$report_id = \array_key_exists('report', $_GET) ? \sanitize_text_field($_GET['report']) : null;
if (\is_null($report_id)) {
return self::get_base_report_for_current_tab();
}
$report = self::by_id($report_id);
if (\is_null($report)) {
return self::get_base_report_for_current_tab();
}
return $report;
}
/**
* @param array $ids
*
* @return array|Report[]|null
*/
public function by_ids(array $ids) : ?array
{
$reports_table = \IAWP\Query::get_table_name(\IAWP\Query::REPORTS);
$rows = \IAWP\Illuminate_Builder::new()->from($reports_table)->whereIn('report_id', $ids)->get()->toArray();
return \array_map(function ($row) {
return new \IAWP\Report($row);
}, $rows);
}
/**
* @param string $type
*
* @return Report[]
*/
public function by_type(string $type) : array
{
$reports_table = \IAWP\Query::get_table_name(\IAWP\Query::REPORTS);
$builder = \IAWP\Illuminate_Builder::new()->from($reports_table)->where('type', '=', $type)->orderByRaw('position IS NULL')->orderBy('position')->orderBy('report_id')->get()->escapeWhenCastingToString();
$rows = $builder->toArray();
return \array_map(function ($row) {
return new \IAWP\Report($row);
}, $rows);
}
public static function get_base_report_for_current_tab() : ?\IAWP\Report
{
return self::get_base_report_for_type(\IAWP\Env::get_tab());
}
public static function get_favorite() : ?\IAWP\Report
{
$raw_id = \get_user_meta(\get_current_user_id(), 'iawp_favorite_report_id', \true);
$id = \filter_var($raw_id, \FILTER_VALIDATE_INT);
if ($id !== \false) {
return self::by_id($id);
}
$raw_type = \get_user_meta(\get_current_user_id(), 'iawp_favorite_report_type', \true);
$type = \filter_var($raw_type, \FILTER_SANITIZE_FULL_SPECIAL_CHARS);
return self::get_base_report_for_type($type);
}
/**
* @param string|int $id
*
* @return Report|null
*/
public static function by_id($id) : ?\IAWP\Report
{
$id = (string) $id;
$reports_table = \IAWP\Query::get_table_name(\IAWP\Query::REPORTS);
if (!\ctype_digit($id)) {
return null;
}
$row = \IAWP\Illuminate_Builder::new()->from($reports_table)->where('report_id', '=', $id)->first();
if (\is_null($row)) {
return null;
}
return new \IAWP\Report($row);
}
public static function create_report(array $attributes) : \IAWP\Report
{
$reports_table = \IAWP\Query::get_table_name(\IAWP\Query::REPORTS);
if (\array_key_exists('columns', $attributes) && \is_array($attributes['columns'])) {
$attributes['columns'] = \json_encode($attributes['columns']);
}
if (\array_key_exists('filters', $attributes) && \is_array($attributes['filters'])) {
$attributes['filters'] = \json_encode($attributes['filters']);
}
$report_id = \IAWP\Illuminate_Builder::new()->from($reports_table)->insertGetId($attributes);
return self::by_id($report_id);
}
private static function get_base_report_for_type(string $type) : ?\IAWP\Report
{
switch ($type) {
case 'views':
return new \IAWP\Report((object) ['name' => \esc_html__('Pages', 'independent-analytics'), 'type' => 'views']);
case 'referrers':
return new \IAWP\Report((object) ['name' => \esc_html__('Referrers', 'independent-analytics'), 'type' => 'referrers']);
case 'geo':
return new \IAWP\Report((object) ['name' => \esc_html__('Geographic', 'independent-analytics'), 'type' => 'geo']);
case 'devices':
return new \IAWP\Report((object) ['name' => \esc_html__('Devices', 'independent-analytics'), 'type' => 'devices']);
case 'campaigns':
return new \IAWP\Report((object) ['name' => \esc_html__('Campaigns', 'independent-analytics'), 'type' => 'campaigns']);
case 'clicks':
return new \IAWP\Report((object) ['name' => \esc_html__('Clicks', 'independent-analytics'), 'type' => 'clicks']);
default:
return null;
}
}
}
IAWP/Report_Options_Parser.php 0000644 00000011210 14760033122 0012310 0 ustar 00 attributes = $attributes;
}
public function get_options_for_creating() : array
{
return \array_merge(['name' => $this->get_string_option('name'), 'type' => $this->get_string_option('type')], $this->get_options());
}
public function get_options_for_updating() : array
{
return $this->add_update_side_effects($this->get_options());
}
private function get_options() : array
{
return $this->strip_empty_options(['primary_chart_metric_id' => $this->get_string_option('primary_chart_metric_id'), 'secondary_chart_metric_id' => $this->get_string_option('secondary_chart_metric_id'), 'exact_start' => $this->get_string_option('exact_start'), 'exact_end' => $this->get_string_option('exact_end'), 'relative_range_id' => $this->get_string_option('relative_range_id'), 'columns' => $this->get_array_option('columns'), 'quick_stats' => $this->get_array_option('quick_stats'), 'filters' => $this->get_filters(), 'sort_column' => $this->get_string_option('sort_column'), 'sort_direction' => $this->get_string_option('sort_direction'), 'group_name' => $this->get_string_option('group_name'), 'chart_interval' => $this->get_string_option('chart_interval')]);
}
private function add_update_side_effects(array $options) : array
{
if (\array_key_exists('exact_start', $options) && !\is_null($options['exact_start']) && \array_key_exists('exact_end', $options) && !\is_null($options['exact_end'])) {
$options['relative_range_id'] = null;
$options['chart_interval'] = null;
}
if (\array_key_exists('relative_range_id', $options) && !\is_null($options['relative_range_id'])) {
$options['exact_start'] = null;
$options['exact_end'] = null;
$options['chart_interval'] = null;
}
return $options;
}
private function strip_empty_options(array $options) : array
{
return \array_filter($options, function ($option) {
return !$option instanceof \IAWP\Empty_Report_Option;
});
}
/**
* @param string $key
*
* @return null|string|Empty_Report_Option
*/
private function get_string_option(string $key, bool $is_nullable = \false)
{
if ($is_nullable && \array_key_exists($key, $this->attributes) && \is_null($this->attributes[$key])) {
return null;
}
if (!\array_key_exists($key, $this->attributes) || !\is_string($this->attributes[$key])) {
return new \IAWP\Empty_Report_Option();
}
return \sanitize_text_field($this->attributes[$key]);
}
/**
* @param string $key
*
* @return array|Empty_Report_Option
*/
private function get_array_option(string $key)
{
if (!\array_key_exists($key, $this->attributes) || !\is_array($this->attributes[$key])) {
return new \IAWP\Empty_Report_Option();
}
foreach ($this->attributes[$key] as $visible_dataset) {
if (!\is_string($visible_dataset)) {
return new \IAWP\Empty_Report_Option();
}
}
return \array_map(function ($item) {
return \sanitize_text_field($item);
}, $this->attributes[$key]);
}
/**
* @return array|array[]|Empty_Report_Option
*/
private function get_filters()
{
if (!\array_key_exists('filters', $this->attributes) || !\is_array($this->attributes['filters'])) {
return new \IAWP\Empty_Report_Option();
}
foreach ($this->attributes['filters'] as $filter) {
if (!\is_array($filter)) {
return new \IAWP\Empty_Report_Option();
}
if (\array_keys($filter) !== ['inclusion', 'column', 'operator', 'operand']) {
return new \IAWP\Empty_Report_Option();
}
foreach ($filter as $value) {
if (!\is_string($value)) {
return new \IAWP\Empty_Report_Option();
}
}
}
return \array_map(function ($filter) {
return ['inclusion' => \sanitize_text_field($filter['inclusion']), 'column' => \sanitize_text_field($filter['column']), 'operator' => \sanitize_text_field($filter['operator']), 'operand' => \sanitize_text_field($filter['operand'])];
}, $this->attributes['filters']);
}
public static function from_json(string $json) : \IAWP\Report_Options_Parser
{
return new \IAWP\Report_Options_Parser(\json_decode(\stripslashes($json), \true));
}
}
IAWP/Resource_Identifier.php 0000644 00000013740 14760033122 0011751 0 ustar 00 type = $type;
$this->meta_key = $meta_key;
$this->meta_value = $meta_value;
}
/**
* @return string
*/
public function type() : string
{
return $this->type;
}
/**
* @return string|null
*/
public function meta_key() : ?string
{
return $this->meta_key;
}
/**
* @return int|string|null
*/
public function meta_value()
{
return $this->meta_value;
}
/**
* @return bool
*/
public function has_meta() : bool
{
return !\is_null($this->meta_key) && !\is_null($this->meta_value);
}
/**
* @return self|null
*/
public static function for_resource_being_viewed() : ?self
{
if (self::is_searchiq_results()) {
$type = 'search';
$meta_key = 'search_query';
$meta_value = \get_query_var(\get_option('_siq_search_query_param_name', 'q'));
} elseif (\is_string(self::get_virtual_page_id())) {
$type = 'virtual_page';
$meta_key = 'virtual_page_id';
$meta_value = self::get_virtual_page_id();
} elseif (\is_singular()) {
$type = 'singular';
$meta_key = 'singular_id';
$meta_value = \get_queried_object_id();
} elseif (\is_author()) {
$type = 'author_archive';
$meta_key = 'author_id';
$meta_value = \get_queried_object_id();
} elseif (\is_date()) {
$type = 'date_archive';
$meta_key = 'date_archive';
$meta_value = self::get_date_archive_date();
} elseif (\is_post_type_archive()) {
$type = 'post_type_archive';
$meta_key = 'post_type';
$meta_value = \get_queried_object()->name;
} elseif (\is_category() || \is_tag() || \is_tax()) {
$type = 'term_archive';
$meta_key = 'term_id';
$meta_value = \get_queried_object_id();
} elseif (\is_search()) {
$type = 'search';
$meta_key = 'search_query';
$meta_value = \get_search_query();
} elseif (\is_home()) {
$type = 'home';
$meta_key = null;
$meta_value = null;
} elseif (\is_404()) {
$path = Request::path_relative_to_site_url();
if (\is_null($path)) {
return null;
}
$type = '404';
$meta_key = 'not_found_url';
$meta_value = $path;
} else {
return null;
}
return new self($type, $meta_key, $meta_value);
}
/**
* @return self|null
*/
public static function for_resource_being_edited() : ?self
{
if (!\is_admin()) {
return null;
}
$screen = \get_current_screen();
// Check if the current screen is post editing page
if (!\is_null($screen) && $screen->base === 'post') {
$singular_id = \get_the_ID();
if (\is_int($singular_id)) {
$singular_id = \strval($singular_id);
} else {
return null;
}
return new self('singular', 'singular_id', $singular_id);
}
return null;
}
public static function for_post_id(int $post_id) : ?self
{
return new self('singular', 'singular_id', $post_id);
}
private static function get_virtual_page_id() : ?string
{
if (\is_404()) {
return null;
}
$post = \get_post();
if (\IAWPSCOPED\iawp()->is_woocommerce_support_enabled() && is_checkout() && is_wc_endpoint_url('order-received')) {
return 'wc_checkout_success';
}
if (\IAWPSCOPED\iawp()->is_surecart_support_enabled() && $post->post_type === 'sc_product' && \property_exists($post, 'sc_id')) {
return 'sc_product_' . $post->sc_id;
}
if (\IAWPSCOPED\iawp()->is_surecart_support_enabled() && $post->post_type === 'sc_collection' && \property_exists($post, 'sc_id')) {
return 'sc_collection_' . $post->sc_id;
}
if (\IAWPSCOPED\iawp()->is_surecart_support_enabled() && $post->post_type === 'sc_upsell' && \property_exists($post, 'sc_id')) {
return 'sc_upsell_' . $post->sc_id;
}
// TODO - What's the pro slug?
if (\is_plugin_active('clickwhale/clickwhale.php') && \property_exists($post, 'linkpage') && \is_array($post->linkpage)) {
return 'clickwhale_link_page_' . $post->linkpage['id'];
}
return null;
}
/**
* Build a date archive string with the year and possibly a month and date
*
* Examples would be "2023", "2023-01", or "2023-01-21"
*
* @return mixed|string
*/
private static function get_date_archive_date()
{
$str = \get_query_var('year');
if (\is_month() || \is_day()) {
$month = \get_query_var('monthnum');
$str = $str . '-' . \str_pad($month, 2, '0', \STR_PAD_LEFT);
}
if (\is_day()) {
$day = \get_query_var('day');
$str = $str . '-' . \str_pad($day, 2, '0', \STR_PAD_LEFT);
}
return $str;
}
private static function is_searchiq_results()
{
if (!\is_plugin_active('searchiq/searchiq.php')) {
return \false;
}
if (\get_query_var(\get_option('_siq_search_query_param_name', 'q')) !== '') {
$post = \get_post(\get_queried_object_id());
if (\has_shortcode($post->post_content, 'siq_ajax_search')) {
return \true;
}
}
return \false;
}
}
IAWP/REST_API.php 0000644 00000035574 14760033122 0007277 0 ustar 00 block_user_role()) {
return;
}
// Don't track post or page previews
if (\is_preview()) {
return;
}
$payload = [];
$current_resource = \IAWP\Resource_Identifier::for_resource_being_viewed();
if (\is_null($current_resource)) {
return;
}
$payload['resource'] = $current_resource->type();
if ($current_resource->has_meta()) {
$payload[$current_resource->meta_key()] = $current_resource->meta_value();
}
$payload['page'] = \max(1, \get_query_var('paged'));
$data = ['payload' => $payload];
$data['signature'] = \md5(Salt::request_payload_salt() . \json_encode($data['payload']));
$track_view_url = \get_rest_url(null, '/iawp/search');
$track_click_url = \IAWPSCOPED\iawp_url_to('/iawp-click-endpoint.php');
$link_rules = Link_Rule_Finder::link_rules()->filter(function (Link_Rule $link_rule) {
return $link_rule->is_active();
})->map(function (Link_Rule $link_rule) {
return ['type' => $link_rule->type(), 'value' => $link_rule->value()];
})->values();
$link_rules_json = \json_encode($link_rules);
?>
'POST', 'callback' => [$this, 'track_view'], 'permission_callback' => function () {
return \true;
}]);
}
public function track_view($request)
{
if (Device::getInstance()->is_bot() && !\defined('IAWP_TESTING')) {
return;
}
\IAWP\Migrations\Migrations::handle_migration_18_error();
\IAWP\Migrations\Migrations::handle_migration_22_error();
\IAWP\Migrations\Migrations::handle_migration_29_error();
\IAWP\Migrations\Migrations::create_or_migrate();
if (\IAWP\Migrations\Migrations::is_migrating()) {
return;
}
if (Request::is_ip_address_blocked()) {
return;
}
$visitor = Visitor::fetch_current_visitor();
$signature = \md5(Salt::request_payload_salt() . \json_encode($request['payload']));
$campaign = [];
if (\IAWPSCOPED\iawp_is_pro()) {
$campaign = ['utm_source' => $this->decode_or_nullify($request['utm_source']), 'utm_medium' => $this->decode_or_nullify($request['utm_medium']), 'utm_campaign' => $this->decode_or_nullify($request['utm_campaign']), 'utm_term' => $this->decode_or_nullify($request['utm_term']), 'utm_content' => $this->decode_or_nullify($request['utm_content'])];
}
if ($signature == $request['signature']) {
new \IAWP\View($request['payload'], $this->calculate_referrer_url($request), $visitor, $campaign);
return new \WP_REST_Response(['success' => \true], 200, ['X-IAWP' => 'iawp']);
} else {
return new \WP_REST_Response(['success' => \false], 200, ['X-IAWP' => 'iawp']);
}
}
private function calculate_referrer_url($request) : ?string
{
$referrer_url = $request['referrer_url'];
$url = new URL($referrer_url ?? '');
if (!\is_null($this->decode_or_nullify($request['gclid'])) && $url->get_domain() !== 'googleads.g.doubleclick.net') {
$referrer_url = 'https://googleads.iawp';
}
if (\is_null($referrer_url)) {
return null;
}
return $referrer_url;
}
private function decode_or_nullify($string)
{
if (!isset($string)) {
return null;
}
$safe_string = \trim(\urldecode($string));
$safe_string = \str_replace('+', ' ', $safe_string);
$safe_string = Security::string($safe_string);
if (\strlen($safe_string) === 0) {
return null;
}
return $safe_string;
}
private function block_user_role() : bool
{
$blocked_roles = \IAWPSCOPED\iawp()->get_option('iawp_blocked_roles', ['administrator']);
foreach (\wp_get_current_user()->roles as $visitor_role) {
if (\in_array($visitor_role, $blocked_roles)) {
return \true;
}
}
return \false;
}
}
IAWP/Settings.php 0000644 00000054521 14760033122 0007622 0 ustar 00 run('settings.index');
if (\IAWPSCOPED\iawp_is_pro()) {
$defaults = $this->email_report_colors();
$saved = \IAWPSCOPED\iawp()->get_option('iawp_email_report_colors', $defaults);
// There were 6 colors and now 9, so there is a saved value but 7-9 don't exist
$input_defaults = $defaults;
for ($i = 0; $i < \count($saved); $i++) {
$input_defaults[$i] = $saved[$i];
}
$interval = Interval_Factory::from_option();
echo \IAWPSCOPED\iawp_blade()->run('settings.email-reports', ['is_scheduled' => \wp_next_scheduled('iawp_send_email_report'), 'scheduled_date' => \IAWPSCOPED\iawp()->email_reports->next_email_at_for_humans(), 'interval' => \IAWPSCOPED\iawp()->get_option('iawp_email_report_interval', 'monthly'), 'time' => \IAWPSCOPED\iawp()->get_option('iawp_email_report_time', 9), 'emails' => \IAWPSCOPED\iawp()->get_option('iawp_email_report_email_addresses', []), 'from' => \IAWPSCOPED\iawp()->get_option('iawp_email_report_from_address', \get_option('admin_email')), 'default_colors' => $defaults, 'input_default' => $input_defaults, 'timestamp' => $interval->next_interval_start()->getTimestamp()]);
}
$ips = \IAWPSCOPED\iawp()->get_option('iawp_blocked_ips', []);
echo \IAWPSCOPED\iawp_blade()->run('settings.block-ips', ['current_ip' => Request::ip(), 'ip_is_blocked' => Request::is_ip_address_blocked(), 'ips' => $ips]);
echo \IAWPSCOPED\iawp_blade()->run('settings.block-by-role', ['roles' => \wp_roles()->roles, 'blocked' => \IAWPSCOPED\iawp()->get_option('iawp_blocked_roles', ['administrator'])]);
echo \IAWPSCOPED\iawp_blade()->run('settings.capabilities', ['editable_roles' => $this->get_editable_roles(), 'capabilities' => \IAWP\Capability_Manager::all_capabilities()]);
echo \IAWPSCOPED\iawp_blade()->run('settings.view-counter');
if (\IAWPSCOPED\iawp()->is_woocommerce_support_enabled()) {
echo \IAWPSCOPED\iawp_blade()->run('settings.woocommerce', ['statuses' => new WooCommerce_Status_Manager()]);
}
echo \IAWPSCOPED\iawp_blade()->run('settings.export-reports', ['report_finder' => new \IAWP\Report_Finder()]);
echo \IAWPSCOPED\iawp_blade()->run('settings.export-data');
echo \IAWPSCOPED\iawp_blade()->run('settings.pruner', ['pruner' => new Pruning_Scheduler()]);
echo \IAWPSCOPED\iawp_blade()->run('settings.delete', ['site_name' => \get_bloginfo('name'), 'site_url' => \site_url()]);
}
public function register_settings()
{
\add_settings_section('iawp-settings-section', \esc_html__('Basic Settings', 'independent-analytics'), function () {
}, 'independent-analytics-settings');
$args = ['type' => 'boolean', 'default' => \false, 'sanitize_callback' => 'rest_sanitize_boolean'];
\register_setting('iawp_settings', 'iawp_dark_mode', $args);
\add_settings_field('iawp_dark_mode', \esc_html__('Dark mode', 'independent-analytics'), [$this, 'dark_mode_callback'], 'independent-analytics-settings', 'iawp-settings-section', ['class' => 'dark-mode']);
\register_setting('iawp_settings', 'iawp_track_authenticated_users', $args);
\add_settings_field('iawp_track_authenticated_users', \esc_html__('Track logged in users', 'independent-analytics'), [$this, 'track_authenticated_users_callback'], 'independent-analytics-settings', 'iawp-settings-section', ['class' => 'logged-in']);
\register_setting('iawp_settings', 'iawp_disable_admin_toolbar_analytics', $args);
\add_settings_field('iawp_disable_admin_toolbar_analytics', \esc_html__('Admin toolbar stats', 'independent-analytics'), [$this, 'disable_admin_toolbar_analytics_callback'], 'independent-analytics-settings', 'iawp-settings-section');
\register_setting('iawp_settings', 'iawp_disable_widget', $args);
\add_settings_field('iawp_disable_widget', \esc_html__('Dashboard widget', 'independent-analytics'), [$this, 'disable_widget_callback'], 'independent-analytics-settings', 'iawp-settings-section');
\register_setting('iawp_settings', 'iawp_disable_views_column', $args);
\add_settings_field('iawp_disable_views_column', \esc_html__('Views column', 'independent-analytics'), [$this, 'disable_views_column_callback'], 'independent-analytics-settings', 'iawp-settings-section');
$args = ['type' => 'integer', 'default' => 0, 'sanitize_callback' => 'absint'];
\register_setting('iawp_settings', 'iawp_dow', $args);
\add_settings_field('iawp_dow', \esc_html__('First day of week', 'independent-analytics'), [$this, 'starting_dow_callback'], 'independent-analytics-settings', 'iawp-settings-section', ['class' => 'dow']);
$args = ['type' => 'boolean', 'default' => \false, 'sanitize_callback' => 'rest_sanitize_boolean'];
\register_setting('iawp_settings', 'iawp_refresh_salt', $args);
\add_settings_field('iawp_refresh_salt', \esc_html__('Salt refresh rate', 'independent-analytics'), [$this, 'refresh_salt_callback'], 'independent-analytics-settings', 'iawp-settings-section', ['class' => 'salt']);
}
public function dark_mode_callback()
{
echo \IAWPSCOPED\iawp_blade()->run('settings.dark-mode', ['dark_mode' => \IAWPSCOPED\iawp()->get_option('iawp_dark_mode', \false)]);
}
public function track_authenticated_users_callback()
{
echo \IAWPSCOPED\iawp_blade()->run('settings.track-authenticated-users', ['track_authenticated_users' => \IAWPSCOPED\iawp()->get_option('iawp_track_authenticated_users', \false)]);
}
public function disable_admin_toolbar_analytics_callback()
{
echo \IAWPSCOPED\iawp_blade()->run('settings.disable-admin-toolbar-analytics', ['value' => \IAWPSCOPED\iawp()->get_option('iawp_disable_admin_toolbar_analytics', \false)]);
}
public function disable_widget_callback()
{
echo \IAWPSCOPED\iawp_blade()->run('settings.disable-widget', ['value' => \IAWPSCOPED\iawp()->get_option('iawp_disable_widget', \false)]);
}
public function disable_views_column_callback() : void
{
echo \IAWPSCOPED\iawp_blade()->run('settings.disable-views-column', ['value' => \IAWPSCOPED\iawp()->get_option('iawp_disable_views_column', \false)]);
}
public function starting_dow_callback()
{
echo \IAWPSCOPED\iawp_blade()->run('settings.first-day-of-week', ['day_of_week' => \IAWPSCOPED\iawp()->get_option('iawp_dow', 0), 'days' => [0 => \esc_html__('Sunday', 'independent-analytics'), 1 => \esc_html__('Monday', 'independent-analytics'), 2 => \esc_html__('Tuesday', 'independent-analytics'), 3 => \esc_html__('Wednesday', 'independent-analytics'), 4 => \esc_html__('Thursday', 'independent-analytics'), 5 => \esc_html__('Friday', 'independent-analytics'), 6 => \esc_html__('Saturday', 'independent-analytics')]]);
}
public function refresh_salt_callback()
{
echo \IAWPSCOPED\iawp_blade()->run('settings.refresh-salt', ['refresh_salt' => \IAWPSCOPED\iawp()->get_option('iawp_refresh_salt', \false)]);
}
public function register_view_counter_settings()
{
\add_settings_section('iawp-view-counter-settings-section', \esc_html__('Public View Counter', 'independent-analytics'), function () {
}, 'independent-analytics-view-counter-settings');
$args = ['type' => 'boolean', 'default' => \false, 'sanitize_callback' => 'rest_sanitize_boolean'];
\register_setting('iawp_view_counter_settings', 'iawp_view_counter_enable', $args);
\add_settings_field('iawp_view_counter_enable', \esc_html__('Enable the view counter', 'independent-analytics'), [$this, 'view_counter_enable_callback'], 'independent-analytics-view-counter-settings', 'iawp-view-counter-settings-section', ['class' => 'enable']);
$args = ['type' => 'array', 'default' => [], 'sanitize_callback' => [$this, 'sanitize_view_counter_post_types']];
\register_setting('iawp_view_counter_settings', 'iawp_view_counter_post_types', $args);
\add_settings_field('iawp_view_counter_post_types', \esc_html__('Display on these post types', 'independent-analytics'), [$this, 'view_counter_post_types_callback'], 'independent-analytics-view-counter-settings', 'iawp-view-counter-settings-section', ['class' => 'post-types']);
// Position
$args = ['type' => 'string', 'default' => 'after', 'sanitize_callback' => [$this, 'sanitize_view_counter_position']];
\register_setting('iawp_view_counter_settings', 'iawp_view_counter_position', $args);
\add_settings_field('iawp_view_counter_position', \esc_html__('Show it in this location', 'independent-analytics'), [$this, 'view_counter_position_callback'], 'independent-analytics-view-counter-settings', 'iawp-view-counter-settings-section', ['class' => 'position']);
// Views to count
\register_setting('iawp_view_counter_settings', 'iawp_view_counter_views_to_count', ['type' => 'string', 'default' => 'total', 'sanitize_callback' => [$this, 'sanitize_view_counter_views_to_count']]);
\add_settings_field('iawp_view_counter_views_to_count', \esc_html__('Date range to count views', 'independent-analytics'), [$this, 'view_counter_views_to_count_callback'], 'independent-analytics-view-counter-settings', 'iawp-view-counter-settings-section', ['class' => 'views-to-count']);
// Exclude
$args = ['type' => 'string', 'default' => '', 'sanitize_callback' => [$this, 'sanitize_view_counter_exclude']];
\register_setting('iawp_view_counter_settings', 'iawp_view_counter_exclude', $args);
\add_settings_field('iawp_view_counter_exclude', \esc_html__('Exclude these pages', 'independent-analytics'), [$this, 'view_counter_exclude_callback'], 'independent-analytics-view-counter-settings', 'iawp-view-counter-settings-section', ['class' => 'exclude']);
// Label
$default = \function_exists('IAWPSCOPED\\pll__') ? pll__('Views:', 'independent-analytics') : \__('Views:', 'independent-analytics');
$args = ['type' => 'string', 'default' => $default, 'sanitize_callback' => 'sanitize_text_field'];
\register_setting('iawp_view_counter_settings', 'iawp_view_counter_label', $args);
\add_settings_field('iawp_view_counter_label', \esc_html__('Edit the label', 'independent-analytics'), [$this, 'view_counter_label_callback'], 'independent-analytics-view-counter-settings', 'iawp-view-counter-settings-section', ['class' => 'counter-label']);
// Hide Label
$args = ['type' => 'boolean', 'default' => \true, 'sanitize_callback' => 'rest_sanitize_boolean'];
\register_setting('iawp_view_counter_settings', 'iawp_view_counter_label_show', $args);
\add_settings_field('iawp_view_counter_label_show', \esc_html__('Display the label', 'independent-analytics'), [$this, 'view_counter_label_show_callback'], 'independent-analytics-view-counter-settings', 'iawp-view-counter-settings-section', ['class' => 'hide-label']);
// Icon
$args = ['type' => 'boolean', 'default' => \true, 'sanitize_callback' => 'rest_sanitize_boolean'];
\register_setting('iawp_view_counter_settings', 'iawp_view_counter_icon', $args);
\add_settings_field('iawp_view_counter_icon', \esc_html__('Display the icon', 'independent-analytics'), [$this, 'view_counter_icon_callback'], 'independent-analytics-view-counter-settings', 'iawp-view-counter-settings-section', ['class' => 'icon']);
// Private
\register_setting('iawp_view_counter_settings', 'iawp_view_counter_private', ['type' => 'boolean', 'default' => \false, 'sanitize_callback' => 'rest_sanitize_boolean']);
\add_settings_field('iawp_view_counter_private', \esc_html__('Make the view counter private?', 'independent-analytics'), [$this, 'view_counter_private_callback'], 'independent-analytics-view-counter-settings', 'iawp-view-counter-settings-section', ['class' => 'private']);
// Allow manual adjustment
\register_setting('iawp_view_counter_settings', 'iawp_view_counter_manual_adjustment', ['type' => 'boolean', 'default' => \false, 'sanitize_callback' => 'rest_sanitize_boolean']);
\add_settings_field('iawp_view_counter_manual_adjustment', \esc_html__('Allow manual adjustment?', 'independent-analytics'), [$this, 'view_counter_manual_adjustment_callback'], 'independent-analytics-view-counter-settings', 'iawp-view-counter-settings-section', ['class' => 'manual-adjustment']);
}
public function view_counter_enable_callback()
{
echo \IAWPSCOPED\iawp_blade()->run('settings.view-counter.enable', ['enable' => \IAWPSCOPED\iawp()->get_option('iawp_view_counter_enable', \false)]);
}
public function view_counter_post_types_callback()
{
$site_post_types = \get_post_types(['public' => \true], 'objects');
$counter = 0;
foreach ($site_post_types as $post_type) {
echo \IAWPSCOPED\iawp_blade()->run('settings.view-counter.post-types', ['counter' => $counter, 'post_type' => $post_type, 'saved' => \IAWPSCOPED\iawp()->get_option('iawp_view_counter_post_types', [])]);
$counter++;
}
?>
run('settings.view-counter.position', ['position' => \IAWPSCOPED\iawp()->get_option('iawp_view_counter_position', 'after')]);
}
public function view_counter_views_to_count_callback()
{
echo \IAWPSCOPED\iawp_blade()->run('settings.view-counter.views-to-count', ['value' => \IAWPSCOPED\iawp()->get_option('iawp_view_counter_views_to_count', 'total')]);
}
public function view_counter_exclude_callback()
{
echo \IAWPSCOPED\iawp_blade()->run('settings.view-counter.exclude', ['exclude' => \IAWPSCOPED\iawp()->get_option('iawp_view_counter_exclude', '')]);
}
public function view_counter_label_callback()
{
$default = \function_exists('IAWPSCOPED\\pll__') ? pll__('Views:', 'independent-analytics') : \__('Views:', 'independent-analytics');
echo \IAWPSCOPED\iawp_blade()->run('settings.view-counter.label', ['label' => \IAWPSCOPED\iawp()->get_option('iawp_view_counter_label', $default)]);
}
public function view_counter_label_show_callback()
{
echo \IAWPSCOPED\iawp_blade()->run('settings.view-counter.label-show', ['show' => \get_option('iawp_view_counter_label_show', \true)]);
}
public function view_counter_icon_callback()
{
echo \IAWPSCOPED\iawp_blade()->run('settings.view-counter.icon', ['icon' => \get_option('iawp_view_counter_icon', \true)]);
}
public function view_counter_private_callback()
{
echo \IAWPSCOPED\iawp_blade()->run('settings.view-counter.private', ['private' => \IAWPSCOPED\iawp()->get_option('iawp_view_counter_private', \false)]);
}
public function view_counter_manual_adjustment_callback()
{
echo \IAWPSCOPED\iawp_blade()->run('settings.view-counter.manual-adjustment', ['value' => \IAWPSCOPED\iawp()->get_option('iawp_view_counter_manual_adjustment', \false)]);
}
public function register_blocked_ip_settings()
{
\add_settings_section('iawp-blocked-ips-settings-section', \esc_html__('Block IP Addresses', 'independent-analytics'), function () {
}, 'iawp-blocked-ips-settings');
$args = ['type' => 'array', 'default' => [], 'sanitize_callback' => [$this, 'sanitize_blocked_ips']];
\register_setting('iawp_blocked_ip_settings', 'iawp_blocked_ips', $args);
}
public function register_email_report_settings()
{
\add_settings_section('iawp-email-report-settings-section', \esc_html__('Scheduled Email Reports', 'independent-analytics'), function () {
}, 'iawp-email-report-settings');
\register_setting('iawp_email_report_settings', 'iawp_email_report_interval', ['type' => 'string', 'default' => 'monthly', 'sanitize_callback' => [$this, 'sanitize_email_report_interval']]);
\register_setting('iawp_email_report_settings', 'iawp_email_report_time', ['type' => 'number', 'default' => 9, 'sanitize_callback' => [$this, 'sanitize_email_report_time']]);
\register_setting('iawp_email_report_settings', 'iawp_email_report_email_addresses', ['type' => 'array', 'default' => [], 'sanitize_callback' => [$this, 'sanitize_email_addresses']]);
\register_setting('iawp_email_report_settings', 'iawp_email_report_colors', ['type' => 'array', 'default' => $this->email_report_colors(), 'sanitize_callback' => [$this, 'sanitize_email_report_colors']]);
\register_setting('iawp_email_report_settings', 'iawp_email_report_from_address', ['type' => 'string', 'default' => \get_option('admin_email'), 'sanitize_callback' => [$this, 'sanitize_email_address']]);
}
public function register_block_by_role_settings()
{
\add_settings_section('iawp-block-by-role-settings-section', \esc_html__('Block by User Role', 'independent-analytics'), function () {
}, 'iawp-block-by-role-settings');
$args = ['type' => 'array', 'default' => ['administrator'], 'sanitize_callback' => [$this, 'sanitize_blocked_roles']];
\register_setting('iawp_block_by_role_settings', 'iawp_blocked_roles', $args);
}
public function sanitize_view_counter_post_types($user_input)
{
if (\is_null($user_input)) {
return [];
}
$site_post_types = \get_post_types(['public' => \true]);
$to_save = [];
foreach ($user_input as $post_type) {
if (\in_array($post_type, $site_post_types)) {
$to_save[] = $post_type;
}
}
return $to_save;
}
public function sanitize_view_counter_position($user_input)
{
if (\in_array($user_input, ['before', 'after', 'both'])) {
return $user_input;
} else {
return 'after';
}
}
public function sanitize_view_counter_views_to_count($user_input)
{
if (\in_array($user_input, ['total', 'today', 'yesterday', 'this_week', 'last_week', 'last_seven', 'last_thirty', 'last_sixty', 'last_ninety', 'this_month', 'last_month', 'last_three_months', 'last_six_months', 'last_twelve_months', 'this_year', 'last_year'])) {
return $user_input;
} else {
return 'total';
}
}
public function sanitize_view_counter_exclude($user_input)
{
$user_input = \explode(',', $user_input);
$to_save = [];
foreach ($user_input as $id) {
$save = \absint($id);
if ($save != 0) {
$to_save[] = $save;
}
}
$to_save = \implode(',', $to_save);
return $to_save;
}
public function sanitize_blocked_ips($ips)
{
$valid_ips = [];
foreach ($ips as $ip) {
$address = \IAWPSCOPED\IPLib\Factory::parseRangeString($ip);
// Skip invalid ip address ranges
if ($address === null) {
continue;
}
$valid_ips[] = $ip;
}
return $valid_ips;
}
public function sanitize_email_address($email)
{
$save = '';
$cleaned = \sanitize_email($email);
if (\is_email($cleaned)) {
$save = $cleaned;
}
return $save;
}
public function sanitize_email_addresses($emails)
{
$to_save = [];
foreach ($emails as $email) {
$cleaned = \sanitize_email($email);
if (\is_email($cleaned)) {
$to_save[] = $cleaned;
}
}
return $to_save;
}
public function sanitize_email_report_interval($input)
{
if (\in_array($input, ['monthly', 'weekly', 'daily'])) {
return $input;
} else {
return 'monthly';
}
}
public function sanitize_email_report_time($user_time)
{
$accepted_times = [];
for ($i = 0; $i < 24; $i++) {
$accepted_times[] = $i;
}
if (\in_array($user_time, $accepted_times)) {
return $user_time;
} else {
return 9;
}
}
public function sanitize_blocked_roles($blocked_roles)
{
$to_save = [];
$user_roles = \array_keys(\wp_roles()->roles);
foreach ($blocked_roles as $blocked) {
if (\in_array($blocked, $user_roles)) {
$to_save[] = $blocked;
}
}
return $to_save;
}
public function sanitize_email_report_colors($colors)
{
$to_save = [];
// No idea why WP sometimes returns an array, so this is for my sanity
if (\is_string($colors)) {
$colors = \explode(',', $colors);
}
foreach ($colors as $color) {
$to_save[] = \sanitize_hex_color($color);
}
return $to_save;
}
/**
* @return array
*/
private function get_editable_roles() : array
{
$editable_roles = [];
$wp_roles = \wp_roles()->roles;
\array_walk($wp_roles, function ($role, $role_key) use(&$editable_roles) {
if ($role_key === 'administrator') {
return;
}
$capability = null;
foreach (\IAWP\Capability_Manager::all_capabilities() as $key => $name) {
if (\array_key_exists($key, $role['capabilities'])) {
$capability = $key;
}
}
$editable_roles[] = ['key' => $role_key, 'name' => $role['name'], 'capability' => $capability];
});
return $editable_roles;
}
private function email_report_colors()
{
return ['#5123a0', '#fafafa', '#3a1e6b', '#fafafa', '#5123a0', '#a985e6', '#ece9f2', '#f7f5fa', '#ece9f2', '#dedae6'];
}
}
IAWP/Sort_Configuration.php 0000644 00000001762 14760033122 0011637 0 ustar 00 column = $column;
if (\in_array($direction, self::VALID_DIRECTIONS)) {
$this->direction = $direction;
}
$this->is_column_nullable = $is_column_nullable;
}
public function column() : string
{
return $this->column;
}
public function direction() : string
{
return $this->direction;
}
public function is_column_nullable() : bool
{
return $this->direction === self::ASCENDING && $this->is_column_nullable;
}
}
IAWP/Tables.php 0000644 00000001774 14760033122 0007236 0 ustar 00 prefix . 'independent_analytics_' . $name;
}
}
IAWP/Track_Resource_Changes.php 0000644 00000004506 14760033122 0012363 0 ustar 00 post_type)) {
return;
}
$post = \get_post($post_id);
if (\is_null($post) || $post->post_status === 'trash') {
return;
}
$row = (object) ['resource' => 'singular', 'singular_id' => $post_id];
$page = new Page_Singular($row);
$page->update_cache();
$campaigns_table = \IAWP\Query::get_table_name(\IAWP\Query::CAMPAIGNS);
$sessions_table = \IAWP\Query::get_table_name(\IAWP\Query::SESSIONS);
$views_table = \IAWP\Query::get_table_name(\IAWP\Query::VIEWS);
$resources_table = \IAWP\Query::get_table_name(\IAWP\Query::RESOURCES);
\IAWP\Illuminate_Builder::new()->from($campaigns_table, 'campaigns')->join("{$sessions_table} AS sessions", function (JoinClause $join) {
$join->on('sessions.campaign_id', '=', 'campaigns.campaign_id');
})->join("{$views_table} AS views", function (JoinClause $join) {
$join->on('views.id', '=', 'sessions.initial_view_id');
})->join("{$resources_table} AS resources", function (JoinClause $join) {
$join->on('resources.id', '=', 'views.resource_id');
})->where('resources.singular_id', '=', $post_id)->update(['campaigns.landing_page_title' => $page->title()]);
}
public function handle_updated_author($user_id)
{
$row = (object) ['resource' => 'author', 'author_id' => $user_id];
$page = new Page_Author_Archive($row);
$page->update_cache();
// TODO - This doesn't update resources where this author is attributed such as a singular
// where this author is the author. It'll have the old user data, such as the old name,
// until it's viewed.
}
}
IAWP/View.php 0000644 00000043224 14760033122 0006732 0 ustar 00 payload = $payload;
$this->referrer_url = \is_null($referrer_url) ? '' : \trim($referrer_url);
$this->visitor = $visitor;
$this->campaign_fields = $campaign_fields;
$this->viewed_at = $viewed_at instanceof \DateTime ? $viewed_at : new \DateTime();
$this->resource = $this->fetch_or_create_resource();
// If a resource can't be found or created, a view cannot be recorded
if (\is_null($this->resource)) {
return;
}
$this->session = $this->fetch_or_create_session();
$view_id = $this->create_view();
$this->link_with_previous_view($view_id);
$this->set_session_total_views();
$this->set_sessions_initial_view($view_id);
$this->set_sessions_final_view($view_id);
$this->update_postmeta($this->resource);
}
/**
* @return int ID of newly created session
*/
public function create_session() : int
{
$sessions_table = \IAWP\Query::get_table_name(\IAWP\Query::SESSIONS);
return \IAWP\Illuminate_Builder::new()->from($sessions_table)->insertGetId(['visitor_id' => $this->visitor->id(), 'referrer_id' => $this->fetch_or_create_referrer(), 'country_id' => $this->fetch_or_create_country(), 'city_id' => $this->fetch_or_create_city(), 'campaign_id' => $this->get_campaign(), 'device_type_id' => Device::getInstance()->type_id(), 'device_os_id' => Device::getInstance()->os_id(), 'device_browser_id' => Device::getInstance()->browser_id(), 'created_at' => $this->viewed_at()]);
}
public function fetch_or_create_country() : ?int
{
if (!$this->visitor->geoposition()->valid_location()) {
return null;
}
$countries_table = \IAWP\Query::get_table_name(\IAWP\Query::COUNTRIES);
$country_id = \IAWP\Illuminate_Builder::new()->from($countries_table)->where('country_code', '=', $this->visitor->geoposition()->country_code())->where('country', '=', $this->visitor->geoposition()->country())->where('continent', '=', $this->visitor->geoposition()->continent())->value('country_id');
if (!\is_null($country_id)) {
return $country_id;
}
\IAWP\Illuminate_Builder::new()->from($countries_table)->insertOrIgnore(['country_code' => $this->visitor->geoposition()->country_code(), 'country' => $this->visitor->geoposition()->country(), 'continent' => $this->visitor->geoposition()->continent()]);
return \IAWP\Illuminate_Builder::new()->from($countries_table)->where('country_code', '=', $this->visitor->geoposition()->country_code())->where('country', '=', $this->visitor->geoposition()->country())->where('continent', '=', $this->visitor->geoposition()->continent())->value('country_id');
}
public function fetch_or_create_city() : ?int
{
if (!$this->visitor->geoposition()->valid_location()) {
return null;
}
$country_id = $this->fetch_or_create_country();
$cities_table = \IAWP\Query::get_table_name(\IAWP\Query::CITIES);
$city_id = \IAWP\Illuminate_Builder::new()->from($cities_table)->where('country_id', $country_id)->where('subdivision', '=', $this->visitor->geoposition()->subdivision())->where('city', '=', $this->visitor->geoposition()->city())->value('city_id');
if (!\is_null($city_id)) {
return $city_id;
}
\IAWP\Illuminate_Builder::new()->from($cities_table)->insertOrIgnore(['country_id' => $country_id, 'subdivision' => $this->visitor->geoposition()->subdivision(), 'city' => $this->visitor->geoposition()->city()]);
return \IAWP\Illuminate_Builder::new()->from($cities_table)->where('country_id', $country_id)->where('subdivision', '=', $this->visitor->geoposition()->subdivision())->where('city', '=', $this->visitor->geoposition()->city())->value('city_id');
}
/**
* Fetch the last view, if any.
*
* @return int|null
*/
private function fetch_last_viewed_resource() : ?int
{
global $wpdb;
$views_table = \IAWP\Query::get_table_name(\IAWP\Query::VIEWS);
$session = $this->fetch_current_session();
if (\is_null($session)) {
return null;
}
$view = $wpdb->get_row($wpdb->prepare("\n SELECT * FROM {$views_table} WHERE session_id = %d ORDER BY viewed_at DESC LIMIT 1\n ", $session->session_id));
if (\is_null($view)) {
return null;
}
return $view->resource_id;
}
private function viewed_at() : string
{
return $this->viewed_at->format('Y-m-d\\TH:i:s');
}
private function link_with_previous_view($view_id) : void
{
global $wpdb;
$views_tables = \IAWP\Query::get_table_name(\IAWP\Query::VIEWS);
$sessions_tables = \IAWP\Query::get_table_name(\IAWP\Query::SESSIONS);
$session = \IAWP\Illuminate_Builder::new()->from($sessions_tables)->where('session_id', '=', $this->session)->first();
if (\is_null($session)) {
return;
}
$final_view_id = $session->final_view_id;
$initial_view_id = $session->initial_view_id;
if (!\is_null($final_view_id)) {
$wpdb->update($views_tables, ['next_view_id' => $view_id, 'next_viewed_at' => $this->viewed_at()], ['id' => $final_view_id]);
} elseif (!\is_null($initial_view_id)) {
$wpdb->update($views_tables, ['next_view_id' => $view_id, 'next_viewed_at' => $this->viewed_at()], ['id' => $initial_view_id]);
}
}
private function set_session_total_views()
{
global $wpdb;
$sessions_table = \IAWP\Query::get_table_name(\IAWP\Query::SESSIONS);
$views_table = \IAWP\Query::get_table_name(\IAWP\Query::VIEWS);
$wpdb->query($wpdb->prepare("\n UPDATE {$sessions_table} AS sessions\n LEFT JOIN (\n SELECT\n session_id,\n COUNT(*) AS view_count\n FROM\n {$views_table} AS views\n WHERE\n views.session_id = %d\n GROUP BY\n session_id) AS view_counts ON sessions.session_id = view_counts.session_id\n SET\n sessions.total_views = COALESCE(view_counts.view_count, 0)\n WHERE sessions.session_id = %d\n ", $this->session, $this->session));
}
private function set_sessions_initial_view(int $view_id)
{
global $wpdb;
$sessions_table = \IAWP\Query::get_table_name(\IAWP\Query::SESSIONS);
$wpdb->query($wpdb->prepare("UPDATE {$sessions_table} SET initial_view_id = %d WHERE session_id = %d AND initial_view_id IS NULL", $view_id, $this->session));
}
private function set_sessions_final_view(int $view_id)
{
global $wpdb;
$sessions_table = \IAWP\Query::get_table_name(\IAWP\Query::SESSIONS);
$wpdb->query($wpdb->prepare("\n UPDATE {$sessions_table} AS sessions\n SET\n sessions.final_view_id = %d,\n sessions.ended_at = %s\n WHERE sessions.session_id = %d AND sessions.initial_view_id IS NOT NULL AND sessions.initial_view_id != %d\n ", $view_id, $this->viewed_at(), $this->session, $view_id));
}
private function create_view() : int
{
$views_table = \IAWP\Query::get_table_name(\IAWP\Query::VIEWS);
return \IAWP\Illuminate_Builder::new()->from($views_table)->insertGetId(['resource_id' => $this->resource->id(), 'viewed_at' => $this->viewed_at(), 'page' => $this->payload['page'], 'session_id' => $this->session]);
}
private function fetch_resource()
{
global $wpdb;
$resources_table = \IAWP\Query::get_table_name(\IAWP\Query::RESOURCES);
$query = '';
$payload_copy = \array_merge($this->payload);
unset($payload_copy['page']);
switch ($payload_copy['resource']) {
case 'singular':
$query = $wpdb->prepare("SELECT * FROM {$resources_table} WHERE resource = %s AND singular_id = %d", $payload_copy['resource'], $payload_copy['singular_id']);
break;
case 'author_archive':
$query = $wpdb->prepare("SELECT * FROM {$resources_table} WHERE resource = %s AND author_id = %d", $payload_copy['resource'], $payload_copy['author_id']);
break;
case 'date_archive':
$query = $wpdb->prepare("SELECT * FROM {$resources_table} WHERE resource = %s AND date_archive = %s", $payload_copy['resource'], $payload_copy['date_archive']);
break;
case 'post_type_archive':
$query = $wpdb->prepare("SELECT * FROM {$resources_table} WHERE resource = %s AND post_type = %s", $payload_copy['resource'], $payload_copy['post_type']);
break;
case 'term_archive':
$query = $wpdb->prepare("SELECT * FROM {$resources_table} WHERE resource = %s AND term_id = %s", $payload_copy['resource'], $payload_copy['term_id']);
break;
case 'search':
$query = $wpdb->prepare("SELECT * FROM {$resources_table} WHERE resource = %s AND search_query = %s", $payload_copy['resource'], $payload_copy['search_query']);
break;
case 'home':
$query = $wpdb->prepare("SELECT * FROM {$resources_table} WHERE resource = %s ", $payload_copy['resource']);
break;
case '404':
$query = $wpdb->prepare("SELECT * FROM {$resources_table} WHERE resource = %s AND not_found_url = %s", $payload_copy['resource'], $payload_copy['not_found_url']);
break;
case 'virtual_page':
$query = $wpdb->prepare("SELECT * FROM {$resources_table} WHERE resource = %s AND virtual_page_id = %s", $payload_copy['resource'], $payload_copy['virtual_page_id']);
break;
}
$resource = $wpdb->get_row($query);
if (\is_null($resource)) {
return null;
}
return $resource;
}
private function fetch_or_create_resource() : ?Page
{
global $wpdb;
$resources_table = \IAWP\Query::get_table_name(\IAWP\Query::RESOURCES);
$resource = $this->fetch_resource();
if (\is_null($resource)) {
$payload_copy = \array_merge($this->payload);
unset($payload_copy['page']);
$wpdb->insert($resources_table, $payload_copy);
$resource = $this->fetch_resource();
}
if (\is_null($resource)) {
return null;
}
$page = Page::from_row($resource);
$page->update_cache();
return $page;
}
/**
* @return int|null ID of the session that should be used for this view
*/
private function fetch_or_create_session() : ?int
{
$session = $this->fetch_current_session();
if (\is_null($session)) {
return $this->create_session();
}
$is_same_referrer = $this->fetch_or_create_referrer() === $session->referrer_id;
$is_same_resource = \intval($this->fetch_resource()->id) === $this->fetch_last_viewed_resource();
$same_as_previous_view = $is_same_referrer && $is_same_resource;
// The goal here is to prevent opening multiple tabs to the site from creating multiple sessions
if ($is_same_referrer) {
return $session->session_id;
}
// The goal here is to prevent a page refresh from creating another session
if ($this->is_internal_referrer($this->referrer_url) || $same_as_previous_view) {
return $session->session_id;
}
return $this->create_session();
}
/**
* @param string|null $referrer_url
*
* @return bool
*/
private function is_internal_referrer(?string $referrer_url) : bool
{
return !empty($referrer_url) && String_Util::str_starts_with(\strtolower($referrer_url), \strtolower(\site_url()));
}
private function fetch_referrer(array $referrer) : int
{
$referrers_table = \IAWP\Query::get_table_name(\IAWP\Query::REFERRERS);
$id = \IAWP\Illuminate_Builder::new()->select('id')->from($referrers_table)->where('domain', '=', $referrer['domain'])->value('id');
if (\is_null($id)) {
$id = \IAWP\Illuminate_Builder::new()->from($referrers_table)->insertGetId(['domain' => $referrer['domain'], 'type' => $referrer['type'], 'referrer' => $referrer['referrer']]);
}
return $id;
}
private function fetch_or_create_referrer() : int
{
$url = new URL($this->referrer_url);
if (!$url->is_valid_url() || $this->is_internal_referrer($this->referrer_url)) {
return $this->fetch_referrer(['domain' => '', 'type' => 'Direct', 'referrer' => 'Direct']);
} elseif (!\is_null(\IAWP\Known_Referrers::get_group_for($url->get_domain()))) {
$group = \IAWP\Known_Referrers::get_group_for($url->get_domain());
return $this->fetch_referrer(['domain' => $group['domain'], 'type' => $group['type'], 'referrer' => $group['name']]);
} else {
return $this->fetch_referrer(['domain' => $url->get_domain(), 'type' => 'Referrer', 'referrer' => $this->strip_www($url->get_domain())]);
}
}
private function strip_www(string $string) : string
{
if (\strpos($string, "www.") !== 0) {
return $string;
}
return \substr($string, 4);
}
private function get_campaign() : ?int
{
global $wpdb;
$required_fields = ['utm_source', 'utm_medium', 'utm_campaign'];
$valid = \true;
foreach ($required_fields as $field) {
if (!isset($this->campaign_fields[$field])) {
$valid = \false;
}
}
if (!$valid) {
return null;
}
$campaigns_table = \IAWP\Query::get_table_name(\IAWP\Query::CAMPAIGNS);
$campaign = $wpdb->get_row($wpdb->prepare("SELECT * FROM {$campaigns_table} WHERE landing_page_title = %s AND utm_source = %s AND utm_medium = %s AND utm_campaign = %s AND (utm_term = %s OR (%d = 0 AND utm_term IS NULL)) AND (utm_content = %s OR (%d = 0 AND utm_content IS NULL))", $this->resource->title(), $this->campaign_fields['utm_source'], $this->campaign_fields['utm_medium'], $this->campaign_fields['utm_campaign'], $this->campaign_fields['utm_term'], isset($this->campaign_fields['utm_term']) ? 1 : 0, $this->campaign_fields['utm_content'], isset($this->campaign_fields['utm_content']) ? 1 : 0));
if (!\is_null($campaign)) {
return $campaign->campaign_id;
}
$wpdb->insert($campaigns_table, ['landing_page_title' => $this->resource->title(), 'utm_source' => $this->campaign_fields['utm_source'], 'utm_medium' => $this->campaign_fields['utm_medium'], 'utm_campaign' => $this->campaign_fields['utm_campaign'], 'utm_term' => $this->campaign_fields['utm_term'], 'utm_content' => $this->campaign_fields['utm_content']]);
$campaign = $wpdb->get_row($wpdb->prepare("SELECT * FROM {$campaigns_table} WHERE landing_page_title = %s AND utm_source = %s AND utm_medium = %s AND utm_campaign = %s AND (utm_term = %s OR (%d = 0 AND utm_term IS NULL)) AND (utm_content = %s OR (%d = 0 AND utm_content IS NULL))", $this->resource->title(), $this->campaign_fields['utm_source'], $this->campaign_fields['utm_medium'], $this->campaign_fields['utm_campaign'], $this->campaign_fields['utm_term'], isset($this->campaign_fields['utm_term']) ? 1 : 0, $this->campaign_fields['utm_content'], isset($this->campaign_fields['utm_content']) ? 1 : 0));
if (!\is_null($campaign)) {
return $campaign->campaign_id;
}
return null;
}
private function fetch_current_session() : ?object
{
$sessions_table = \IAWP\Query::get_table_name(\IAWP\Query::SESSIONS);
$session = \IAWP\Illuminate_Builder::new()->from($sessions_table, 'sessions')->selectRaw('IFNULL(ended_at, created_at) AS latest_view_at')->selectRaw('sessions.*')->where('visitor_id', '=', $this->visitor->id())->havingRaw('latest_view_at > DATE_SUB(UTC_TIMESTAMP(), INTERVAL 30 MINUTE)')->orderBy('latest_view_at', 'DESC')->first();
return $session;
}
private function update_postmeta(Page $resource) : void
{
$singular_id = $resource->get_singular_id();
if ($singular_id === null) {
return;
}
$views_table = \IAWP\Query::get_table_name(\IAWP\Query::VIEWS);
$resources_table = \IAWP\Query::get_table_name(\IAWP\Query::RESOURCES);
$total_views = \IAWP\Illuminate_Builder::new()->selectRaw('COUNT(*) AS views')->from("{$resources_table} as resources")->join("{$views_table} AS views", function (JoinClause $join) {
$join->on('resources.id', '=', 'views.resource_id');
})->where('singular_id', '=', $singular_id)->value('views');
\update_post_meta($singular_id, Views_Column::$meta_key, $total_views);
}
}
IAWP/View_Counter.php 0000644 00000016741 14760033122 0010435 0 ustar 00 passes_checks()) {
return $content;
}
$position = \IAWPSCOPED\iawp()->get_option('iawp_view_counter_position', 'after');
$counter = $this->get_counter_html();
if ($position == 'before' || $position == 'both') {
$content = $counter . $content;
}
if ($position == 'after' || $position == 'both') {
$content .= $counter;
}
return $content;
}
public function get_counter_html($label = null, $icon = null, $range = null)
{
$current_resource = \IAWP\Resource_Identifier::for_resource_being_viewed();
// It's critical to check because this function is called erroneously by Gutenberg in the editor
if (\is_null($current_resource)) {
return;
}
// Get stats for individual posts in the loop if shortcode added to each post
global $post;
if ($post->ID != $current_resource->meta_value() && \is_main_query() && \in_the_loop()) {
$current_resource = \IAWP\Resource_Identifier::for_post_id($post->ID);
}
if (\is_null($range)) {
$range = \IAWPSCOPED\iawp()->get_option('iawp_view_counter_views_to_count', 'total');
}
$view_count = $this->get_view_count($current_resource, $range);
if (\IAWPSCOPED\iawp()->get_option('iawp_view_counter_manual_adjustment', \false)) {
$view_count += \intval(\get_post_meta($current_resource->meta_value(), 'iawp_view_counter_adjustment', \true));
}
$view_count = Number_Formatter::decimal($view_count);
if (\is_null($label)) {
if (!\get_option('iawp_view_counter_label_show', \true)) {
$label = '';
} else {
$default = \function_exists('IAWPSCOPED\\pll__') ? pll__('Views:', 'independent-analytics') : \__('Views:', 'independent-analytics');
$label = \IAWPSCOPED\iawp()->get_option('iawp_view_counter_label', $default);
}
}
if (\is_null($icon)) {
$icon = \get_option('iawp_view_counter_icon', \true);
}
if ($icon) {
$svg = ' ';
$label = $svg . ' ' . $label;
}
return '' . Security::svg($label) . ' ' . \esc_html($view_count) . '
';
}
public function add_shortcode()
{
\add_shortcode('iawp_view_counter', [$this, 'shortcode']);
}
public function shortcode($atts)
{
$a = \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);
return $this->get_counter_html($a['label'], $a['icon'], $a['range']);
}
public function maybe_add_meta_box() : void
{
if (!\IAWPSCOPED\iawp()->get_option('iawp_view_counter_manual_adjustment', \false)) {
return;
}
foreach (\IAWPSCOPED\iawp()->get_option('iawp_view_counter_post_types', []) as $screen) {
\add_meta_box('iawp-view-counter-adjustment', \esc_html__('View Counter Adjustment', 'independent-analytics'), [$this, 'render_meta_box_content'], $screen, 'side');
}
}
public function render_meta_box_content() : void
{
global $post;
echo '' . \esc_html__('Increase count by:', 'independent-analytics') . '
';
}
public function save_metabox_settings(int $post_id)
{
if (\array_key_exists('iawp_view_counter_adjustment', $_POST)) {
\update_post_meta($post_id, 'iawp_view_counter_adjustment', \absint($_POST['iawp_view_counter_adjustment']));
}
}
private function passes_checks() : bool
{
if (!\is_singular() || !\is_main_query()) {
return \false;
}
if (\IAWPSCOPED\iawp()->get_option('iawp_view_counter_enable', \false) == \false) {
return \false;
}
if (!\in_array(\get_post_type(), \IAWPSCOPED\iawp()->get_option('iawp_view_counter_post_types', []))) {
return \false;
}
if (\IAWPSCOPED\iawp()->get_option('iawp_view_counter_private', \false) && !\is_user_logged_in()) {
return \false;
}
$exclude = \IAWPSCOPED\iawp()->get_option('iawp_view_counter_exclude', '');
if ($exclude != '') {
$exclude = \explode(',', $exclude);
if (\in_array(\get_the_ID(), $exclude)) {
return \false;
}
}
return \true;
}
private function get_view_count(\IAWP\Resource_Identifier $resource, string $relative_range_id) : int
{
$relative_range_id = \strtoupper($relative_range_id);
if ($relative_range_id === 'TOTAL' || !\in_array($relative_range_id, Relative_Date_Range::range_ids())) {
$relative_range_id = 'ALL_TIME';
}
$resources_table = \IAWP\Query::get_table_name(\IAWP\Query::RESOURCES);
$views_table = \IAWP\Query::get_table_name(\IAWP\Query::VIEWS);
$relative_range = new Relative_Date_Range($relative_range_id);
$query = \IAWP\Illuminate_Builder::new()->selectRaw('COUNT(views.id) AS views')->from($resources_table, 'resources')->leftJoin("{$views_table} AS views", function (JoinClause $join) {
$join->on('resources.id', '=', 'views.resource_id');
})->where('resource', '=', $resource->type())->when($resource->has_meta(), function (Builder $query) use($resource) {
$query->where($resource->meta_key(), '=', $resource->meta_value());
})->whereBetween('viewed_at', [$relative_range->iso_start(), $relative_range->iso_end()])->groupBy('resources.id');
$views = $query->value('views');
return \is_null($views) ? 0 : $views;
}
}
IAWP/Visitors_Over_Time_Finder.php 0000644 00000003651 14760033122 0013102 0 ustar 00 date_range = $date_range;
$this->interval = $interval;
}
public function fetch()
{
$rows = $this->interval->fetch($this->date_range);
return $this->rows_to_class($rows);
}
private function rows_to_class(array $rows) : object
{
$date_interval = $this->interval->get_date_interval();
$date_period = new \DatePeriod($this->date_range->start(), $date_interval, $this->date_range->end());
$interval_data = [];
$visitors_data = [];
$views_data = [];
foreach ($date_period as $index => $date) {
$current_interval = $index;
$current_visitors = 0;
$current_views = 0;
foreach ($rows as $row) {
$row_interval = \intval($row->interval_ago);
$row_visitors = \intval($row->visitors);
$row_views = \intval($row->views);
if ($row_interval === $index) {
$current_interval = $row_interval;
$current_visitors = $row_visitors;
$current_views = $row_views;
break;
}
}
$interval_data[] = $current_interval;
$visitors_data[] = $current_visitors;
$views_data[] = $current_views;
}
return (object) ['visitors' => $visitors_data, 'views' => $views_data, 'interval_labels_short' => $this->interval->get_short_labels($interval_data), 'interval_labels_full' => $this->interval->get_full_labels($interval_data)];
}
}
IAWP/WP_Option_Cache_Bust.php 0000644 00000002634 14760033122 0011756 0 ustar 00 option_name = $option_name;
}
/**
* @param string|null $prefix
* @return string
*/
private function option_name(?string $prefix = null) : string
{
if (\is_string($prefix)) {
return $prefix . $this->option_name;
}
return $this->option_name;
}
/**
* @param $default_value
* @return mixed|null
*/
private function value($default_value)
{
global $wpdb;
$row = $wpdb->get_row($wpdb->prepare("SELECT option_value FROM {$wpdb->options} WHERE option_name = %s LIMIT 1", $this->option_name()));
if (\is_object($row)) {
$value = $row->option_value;
} else {
$value = $default_value;
}
return \apply_filters($this->option_name('option_'), \maybe_unserialize($value), $this->option_name());
}
/**
* @param string $option_name
* @return void
*/
public static function register(string $option_name)
{
$cache_bust = new self($option_name);
\add_filter($cache_bust->option_name('pre_option_'), function ($default_value) use($cache_bust) {
return $cache_bust->value($default_value);
});
}
}
dist/js/click-tracking-menu.js 0000644 00000176601 14760033122 0012321 0 ustar 00 !function(e,t,n,o,r){var i="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:"undefined"!=typeof window?window:"undefined"!=typeof global?global:{},a="function"==typeof i[o]&&i[o],l=a.cache||{},s="undefined"!=typeof module&&"function"==typeof module.require&&module.require.bind(module);function c(t,n){if(!l[t]){if(!e[t]){var r="function"==typeof i[o]&&i[o];if(!n&&r)return r(t,!0);if(a)return a(t,!0);if(s&&"string"==typeof t)return s(t);var u=Error("Cannot find module '"+t+"'");throw u.code="MODULE_NOT_FOUND",u}f.resolve=function(n){var o=e[t][1][n];return null!=o?o:n},f.cache={};var d=l[t]=new c.Module(t);e[t][0].call(d.exports,f,d,d.exports,this)}return l[t].exports;function f(e){var t=f.resolve(e);return!1===t?{}:c(t)}}c.isParcelRequire=!0,c.Module=function(e){this.id=e,this.bundle=c,this.exports={}},c.modules=e,c.cache=l,c.parent=a,c.register=function(t,n){e[t]=[function(e,t){t.exports=n},{}]},Object.defineProperty(c,"root",{get:function(){return i[o]}}),i[o]=c;for(var u=0;u0?(t.hideErrorMessages(e),e.after(t.errorMessages),t.errorMessages.find("."+n.data.error).addClass("visible"),e.find(".link-"+n.data.property).addClass("error"),e.find(".save-button").prop("disabled",!1),e.find(".cancel-button").prop("disabled",!1)):(n.data.shouldShowCacheMessage&&document.getElementById("click-tracking-cache-message-container").classList.add("show"),e.parent().is("#sortable-tracked-links-list")?e.replaceWith(n.data.html):(e.remove(),d("#sortable-tracked-links-list").prepend(n.data.html)),t.hideErrorMessages(e))})},archiveLinkRequest:function(e){var t=this,n=e.data("id"),o=(0,i._)((0,r._)({},iawpActions.archive_link),{id:n}),a=e.closest(".tracked-links-list").length>0;e.addClass("archiving"),jQuery.post(ajaxurl,o,function(n){(n=JSON.parse(n))&&(document.getElementById("click-tracking-cache-message-container").classList.add("show"),e.remove(),a?d("#archived-links-list").prepend(n):d("#sortable-tracked-links-list").prepend(n)),t.toggleEmptyMessage()})},deleteLinkRequest:function(e){var t=this,n=this,o=(0,i._)((0,r._)({},iawpActions.delete_link),{id:e});this.deleteButton.addClass("sending"),jQuery.post(ajaxurl,o,function(e){n.deleteButton.removeClass("sending"),d('.trackable-link[data-id="'+e.data.id+'"]').remove(),(0,s.default).close("delete-link-modal"),t.toggleEmptyMessage()}).fail(function(){})},changeVisibleInput:function(e,t){e.find(".value-container.visible").removeClass("visible"),e.find(".value-container."+t).addClass("visible")},enableEditing:function(e){e.addClass("is-editing"),this.focusOnInput(e.find(".link-name"))},cancelEditing:function(e){e.hasClass("blueprint-clone")?e.remove():e.removeClass("is-editing"),this.hideErrorMessages(e),this.errorMessages.remove(),this.toggleEmptyMessage()},toggleArchivedLinks:function(e){d("#archived-links").toggleClass("open");var t=e.text();e.text(e.data("alt-text")),e.data("alt-text",t)},addNewLinkToTable:function(){if(0===d("#tracked-links-list").find(".blueprint-clone").length){var e=d("#blueprint-link .trackable-link").clone();e.addClass("is-editing blueprint-clone"),d("#tracked-links-list").prepend(e),e.find(".link-name").focus(),this.toggleEmptyMessage()}},triggerSaveButton:function(e,t,n){t.hasClass("is-editing")&&"SELECT"!=n.get(0).tagName&&"Enter"==e.key&&t.find(".save-button").click()},focusOnInput:function(e){var t=e.focus().val();e.val("").val(t)},hideErrorMessages:function(e){e.find("input, select").removeClass("error"),this.errorMessages.find("p").removeClass("visible")},toggleEmptyMessage:function(){0===d("#tracked-links-list .trackable-link").length?d(".tracked-links-empty-message").addClass("show"):d(".tracked-links-empty-message").removeClass("show"),0===d("#archived-links-list .trackable-link").length?d(".archived-links-empty-message").addClass("show"):d(".archived-links-empty-message").removeClass("show")},sortLinks:function(e,t){var n=this,o=Array.from(t.target.querySelectorAll(".trackable-link")).map(function(e){return parseInt(e.dataset.id)}),a=(0,i._)((0,r._)({},iawpActions.sort_links),{ids:o});jQuery.post(ajaxurl,a,function(e){}).fail(function(){e.sort(n.moveArrayItem(e.toArray(),t.newIndex,t.oldIndex))})},moveArrayItem:function(e,t,n){var o=(0,a._)(e);if(t===n)return o;var r=o.splice(t,1)[0];return o.splice(n,0,r),o}};jQuery(function(e){f.setup()})},{"@swc/helpers/_/_object_spread":"kexvf","@swc/helpers/_/_object_spread_props":"c7x3p","@swc/helpers/_/_to_consumable_array":"4oNkS",micromodal:"Tlrpp",sortablejs:"9lkyr","@parcel/transformer-js/src/esmodule-helpers.js":"kPSB8"}],kexvf:[function(e,t,n){var o=e("@parcel/transformer-js/src/esmodule-helpers.js");o.defineInteropFlag(n),o.export(n,"_object_spread",function(){return i}),o.export(n,"_",function(){return i});var r=e("./_define_property.js");function i(e){for(var t=1;te.length)&&(t=e.length);for(var n=0,o=Array(t);ne.length)&&(t=e.length);for(var n=0,o=Array(t);n0&&this.registerTriggers.apply(this,r(i)),this.onClick=this.onClick.bind(this),this.onKeydown=this.onKeydown.bind(this)}return e=[{key:"registerTriggers",value:function(){for(var e=this,t=arguments.length,n=Array(t),o=0;o0&&void 0!==arguments[0]?arguments[0]:null;(this.activeElement=document.activeElement,this.modal.setAttribute("aria-hidden","false"),this.modal.classList.add(this.config.openClass),this.scrollBehaviour("disable"),this.addEventListeners(),this.config.awaitOpenAnimation)?this.modal.addEventListener("animationend",function t(){e.modal.removeEventListener("animationend",t,!1),e.setFocusToFirstNode()},!1):this.setFocusToFirstNode(),this.config.onShow(this.modal,this.activeElement,t)}},{key:"closeModal",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null,t=this.modal;if(this.modal.setAttribute("aria-hidden","true"),this.removeEventListeners(),this.scrollBehaviour("enable"),this.activeElement&&this.activeElement.focus&&this.activeElement.focus(),this.config.onClose(this.modal,this.activeElement,e),this.config.awaitCloseAnimation){var n=this.config.openClass;this.modal.addEventListener("animationend",function e(){t.classList.remove(n),t.removeEventListener("animationend",e,!1)},!1)}else t.classList.remove(this.config.openClass)}},{key:"closeModalById",value:function(e){this.modal=document.getElementById(e),this.modal&&this.closeModal()}},{key:"scrollBehaviour",value:function(e){if(this.config.disableScroll){var t=document.querySelector("body");switch(e){case"enable":Object.assign(t.style,{overflow:""});break;case"disable":Object.assign(t.style,{overflow:"hidden"})}}}},{key:"addEventListeners",value:function(){this.modal.addEventListener("touchstart",this.onClick),this.modal.addEventListener("click",this.onClick),document.addEventListener("keydown",this.onKeydown)}},{key:"removeEventListeners",value:function(){this.modal.removeEventListener("touchstart",this.onClick),this.modal.removeEventListener("click",this.onClick),document.removeEventListener("keydown",this.onKeydown)}},{key:"onClick",value:function(e){(e.target.hasAttribute(this.config.closeTrigger)||e.target.parentNode.hasAttribute(this.config.closeTrigger))&&(e.preventDefault(),e.stopPropagation(),this.closeModal(e))}},{key:"onKeydown",value:function(e){27===e.keyCode&&this.closeModal(e),9===e.keyCode&&this.retainFocus(e)}},{key:"getFocusableNodes",value:function(){return Array.apply(void 0,r(this.modal.querySelectorAll(a)))}},{key:"setFocusToFirstNode",value:function(){var e=this;if(!this.config.disableFocus){var t=this.getFocusableNodes();if(0!==t.length){var n=t.filter(function(t){return!t.hasAttribute(e.config.closeTrigger)});n.length>0&&n[0].focus(),0===n.length&&t[0].focus()}}}},{key:"retainFocus",value:function(e){var t=this.getFocusableNodes();if(0!==t.length){if(t=t.filter(function(e){return null!==e.offsetParent}),this.modal.contains(document.activeElement)){var n=t.indexOf(document.activeElement);e.shiftKey&&0===n&&(t[t.length-1].focus(),e.preventDefault()),!e.shiftKey&&t.length>0&&n===t.length-1&&(t[0].focus(),e.preventDefault())}else t[0].focus()}}}],o(n.prototype,e),t&&o(n,t),n}(),s=null,c=function(e){if(!document.getElementById(e))return console.warn("MicroModal: â—Seems like you have missed %c'".concat(e,"'"),"background-color: #f8f9fa;color: #50596c;font-weight: bold;","ID somewhere in your code. Refer example below to resolve it."),console.warn("%cExample:","background-color: #f8f9fa;color: #50596c;font-weight: bold;",'
')),!1},u=function(e,t){if(e.length<=0&&(console.warn("MicroModal: â—Please specify at least one %c'micromodal-trigger'","background-color: #f8f9fa;color: #50596c;font-weight: bold;","data attribute."),console.warn("%cExample:","background-color: #f8f9fa;color: #50596c;font-weight: bold;",' ')),!t)return!0;for(var n in t)c(n);return!0},{init:function(e){var t,n,o=Object.assign({},{openTrigger:"data-micromodal-trigger"},e),i=r(document.querySelectorAll("[".concat(o.openTrigger,"]"))),a=(t=o.openTrigger,n=[],i.forEach(function(e){var o=e.attributes[t].value;void 0===n[o]&&(n[o]=[]),n[o].push(e)}),n);if(!0!==o.debugMode||!1!==u(i,a))for(var c in a){var d=a[c];o.targetModal=c,o.triggers=r(d),s=new l(o)}},show:function(e,t){var n=t||{};n.targetModal=e,!0===n.debugMode&&!1===c(e)||(s&&s.removeEventListeners(),(s=new l(n)).showModal())},close:function(e){e?s.closeModalById(e):s.closeModal()}});"undefined"!=typeof window&&(window.MicroModal=d),n.default=d},{"@parcel/transformer-js/src/esmodule-helpers.js":"kPSB8"}],"9lkyr":[function(e,t,n){/**!
* Sortable 1.15.2
* @author RubaXa
* @author owenm
* @license MIT
*/var o=e("@parcel/transformer-js/src/esmodule-helpers.js");function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),n.push.apply(n,o)}return n}function i(e){for(var t=1;te.length)&&(t=e.length);for(var n=0,o=Array(t);n"===t[0]&&(t=t.substring(1)),e)try{if(e.matches)return e.matches(t);if(e.msMatchesSelector)return e.msMatchesSelector(t);if(e.webkitMatchesSelector)return e.webkitMatchesSelector(t)}catch(e){}return!1}}function _(e,t,n,o){if(e){var r;n=n||document;do{if(null!=t&&(">"===t[0]?e.parentNode===n&&y(e,t):y(e,t))||o&&e===n)return e;if(e===n)break}while(e=(r=e).host&&r!==document&&r.host.nodeType?r.host:r.parentNode)}return null}var w=/\s+/g;function E(e,t,n){if(e&&t){if(e.classList)e.classList[n?"add":"remove"](t);else{var o=(" "+e.className+" ").replace(w," ").replace(" "+t+" "," ");e.className=(o+(n?" "+t:"")).replace(w," ")}}}function k(e,t,n){var o=e&&e.style;if(o){if(void 0===n)return document.defaultView&&document.defaultView.getComputedStyle?n=document.defaultView.getComputedStyle(e,""):e.currentStyle&&(n=e.currentStyle),void 0===t?n:n[t];t in o||-1!==t.indexOf("webkit")||(t="-webkit-"+t),o[t]=n+("string"==typeof n?"":"px")}}function S(e,t){var n="";if("string"==typeof e)n=e;else do{var o=k(e,"transform");o&&"none"!==o&&(n=o+" "+n)}while(!t&&(e=e.parentNode))var r=window.DOMMatrix||window.WebKitCSSMatrix||window.CSSMatrix||window.MSCSSMatrix;return r&&new r(n)}function D(e,t,n){if(e){var o=e.getElementsByTagName(t),r=0,i=o.length;if(n)for(;r=i:r<=i))return o;if(o===C())break;o=I(o,!1)}return!1}function M(e,t,n,o){for(var r=0,i=0,a=e.children;i2&&void 0!==arguments[2]?arguments[2]:{},o=n.evt,r=function(e,t){if(null==e)return{};var n,o,r=function(e,t){if(null==e)return{};var n,o,r={},i=Object.keys(e);for(o=0;o=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(o=0;o=0)&&Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}(n,W);q.pluginEvent.bind(eY)(e,t,i({dragEl:V,parentEl:$,ghostEl:Z,rootEl:J,nextEl:ee,lastDownEl:et,cloneEl:en,cloneHidden:eo,dragStarted:em,putSortable:ec,activeSortable:eY.active,originalEvent:o,oldIndex:er,oldDraggableIndex:ea,newIndex:ei,newDraggableIndex:el,hideGhostForTarget:eL,unhideGhostForTarget:eF,cloneNowHidden:function(){eo=!0},cloneNowShown:function(){eo=!1},dispatchSortableEvent:function(e){G({sortable:t,name:e,originalEvent:o})}},r))};function G(e){U(i({putSortable:ec,cloneEl:en,targetEl:V,rootEl:J,oldIndex:er,oldDraggableIndex:ea,newIndex:ei,newDraggableIndex:el},e))}var Q,V,$,Z,J,ee,et,en,eo,er,ei,ea,el,es,ec,eu,ed,ef,eh,ep,eg,em,ev,eb,ey,e_,ew=!1,eE=!1,ek=[],eS=!1,eD=!1,eC=[],ex=!1,eO=[],eM="undefined"!=typeof document,ej=d||u?"cssFloat":"float",eT=eM&&!g&&!p&&"draggable"in document.createElement("div"),eA=function(){if(eM){if(u)return!1;var e=document.createElement("x");return e.style.cssText="pointer-events:auto","auto"===e.style.pointerEvents}}(),eI=function(e,t){var n=k(e),o=parseInt(n.width)-parseInt(n.paddingLeft)-parseInt(n.paddingRight)-parseInt(n.borderLeftWidth)-parseInt(n.borderRightWidth),r=M(e,0,t),i=M(e,1,t),a=r&&k(r),l=i&&k(i),s=a&&parseInt(a.marginLeft)+parseInt(a.marginRight)+x(r).width,c=l&&parseInt(l.marginLeft)+parseInt(l.marginRight)+x(i).width;if("flex"===n.display)return"column"===n.flexDirection||"column-reverse"===n.flexDirection?"vertical":"horizontal";if("grid"===n.display)return n.gridTemplateColumns.split(" ").length<=1?"vertical":"horizontal";if(r&&a.float&&"none"!==a.float){var u="left"===a.float?"left":"right";return i&&("both"===l.clear||l.clear===u)?"vertical":"horizontal"}return r&&("block"===a.display||"flex"===a.display||"table"===a.display||"grid"===a.display||s>=o&&"none"===n[ej]||i&&"none"===n[ej]&&s+c>o)?"vertical":"horizontal"},eN=function(e,t,n){var o=n?e.left:e.top,r=n?e.right:e.bottom,i=n?e.width:e.height,a=n?t.left:t.top,l=n?t.right:t.bottom,s=n?t.width:t.height;return o===a||r===l||o+i/2===a+s/2},eP=function(e,t){var n;return ek.some(function(o){var r=o[Y].options.emptyInsertThreshold;if(!(!r||j(o))){var i=x(o),a=e>=i.left-r&&e<=i.right+r,l=t>=i.top-r&&t<=i.bottom+r;if(a&&l)return n=o}}),n},eB=function(e){function t(e,n){return function(o,r,i,a){var l=o.options.group.name&&r.options.group.name&&o.options.group.name===r.options.group.name;if(null==e&&(n||l))return!0;if(null==e||!1===e)return!1;if(n&&"clone"===e)return e;if("function"==typeof e)return t(e(o,r,i,a),n)(o,r,i,a);var s=(n?o:r).options.group.name;return!0===e||"string"==typeof e&&e===s||e.join&&e.indexOf(s)>-1}}var n={},o=e.group;o&&"object"==a(o)||(o={name:o}),n.name=o.name,n.checkPull=t(o.pull,!0),n.checkPut=t(o.put),n.revertClone=o.revertClone,e.group=n},eL=function(){!eA&&Z&&k(Z,"display","none")},eF=function(){!eA&&Z&&k(Z,"display","")};eM&&!g&&document.addEventListener("click",function(e){if(eE)return e.preventDefault(),e.stopPropagation&&e.stopPropagation(),e.stopImmediatePropagation&&e.stopImmediatePropagation(),eE=!1,!1},!0);var eR=function(e){if(V){var t=eP((e=e.touches?e.touches[0]:e).clientX,e.clientY);if(t){var n={};for(var o in e)e.hasOwnProperty(o)&&(n[o]=e[o]);n.target=n.rootEl=t,n.preventDefault=void 0,n.stopPropagation=void 0,t[Y]._onDragOver(n)}}},eX=function(e){V&&V.parentNode[Y]._isOutsideThisEl(e.target)};function eY(e,t){if(!(e&&e.nodeType&&1===e.nodeType))throw"Sortable: `el` must be an HTMLElement, not ".concat(({}).toString.call(e));this.el=e,this.options=t=l({},t),e[Y]=this;var n,o,r={group:null,sort:!0,disabled:!1,store:null,handle:null,draggable:/^[uo]l$/i.test(e.nodeName)?">li":">*",swapThreshold:1,invertSwap:!1,invertedSwapThreshold:null,removeCloneOnHide:!0,direction:function(){return eI(e,this.options)},ghostClass:"sortable-ghost",chosenClass:"sortable-chosen",dragClass:"sortable-drag",ignore:"a, img",filter:null,preventOnFilter:!0,animation:0,easing:null,setData:function(e,t){e.setData("Text",t.textContent)},dropBubble:!1,dragoverBubble:!1,dataIdAttr:"data-id",delay:0,delayOnTouchOnly:!1,touchStartThreshold:(Number.parseInt?Number:window).parseInt(window.devicePixelRatio,10)||1,forceFallback:!1,fallbackClass:"sortable-fallback",fallbackOnBody:!1,fallbackTolerance:0,fallbackOffset:{x:0,y:0},supportPointer:!1!==eY.supportPointer&&"PointerEvent"in window&&!h,emptyInsertThreshold:5};for(var a in q.initializePlugins(this,e,r),r)a in t||(t[a]=r[a]);for(var s in eB(t),this)"_"===s.charAt(0)&&"function"==typeof this[s]&&(this[s]=this[s].bind(this));this.nativeDraggable=!t.forceFallback&&eT,this.nativeDraggable&&(this.options.touchStartThreshold=1),t.supportPointer?v(e,"pointerdown",this._onTapStart):(v(e,"mousedown",this._onTapStart),v(e,"touchstart",this._onTapStart)),this.nativeDraggable&&(v(e,"dragover",this),v(e,"dragenter",this)),ek.push(this.el),t.store&&t.store.get&&this.sort(t.store.get(this)||[]),l(this,(o=[],{captureAnimationState:function(){o=[],this.options.animation&&[].slice.call(this.el.children).forEach(function(e){if("none"!==k(e,"display")&&e!==eY.ghost){o.push({target:e,rect:x(e)});var t=i({},o[o.length-1].rect);if(e.thisAnimationDuration){var n=S(e,!0);n&&(t.top-=n.f,t.left-=n.e)}e.fromRect=t}})},addAnimationState:function(e){o.push(e)},removeAnimationState:function(e){o.splice(function(e,t){for(var n in e)if(e.hasOwnProperty(n)){for(var o in t)if(t.hasOwnProperty(o)&&t[o]===e[n][o])return Number(n)}return -1}(o,{target:e}),1)},animateAll:function(e){var t=this;if(!this.options.animation){clearTimeout(n),"function"==typeof e&&e();return}var r=!1,i=0;o.forEach(function(e){var n,o=0,a=e.target,l=a.fromRect,s=x(a),c=a.prevFromRect,u=a.prevToRect,d=e.rect,f=S(a,!0);f&&(s.top-=f.f,s.left-=f.e),a.toRect=s,a.thisAnimationDuration&&N(c,s)&&!N(l,s)&&(d.top-s.top)/(d.left-s.left)==(l.top-s.top)/(l.left-s.left)&&(n=t.options,o=Math.sqrt(Math.pow(c.top-d.top,2)+Math.pow(c.left-d.left,2))/Math.sqrt(Math.pow(c.top-u.top,2)+Math.pow(c.left-u.left,2))*n.animation),N(s,l)||(a.prevFromRect=l,a.prevToRect=s,o||(o=t.options.animation),t.animate(a,d,s,o)),o&&(r=!0,i=Math.max(i,o),clearTimeout(a.animationResetTimer),a.animationResetTimer=setTimeout(function(){a.animationTime=0,a.prevFromRect=null,a.fromRect=null,a.prevToRect=null,a.thisAnimationDuration=null},o),a.thisAnimationDuration=o)}),clearTimeout(n),r?n=setTimeout(function(){"function"==typeof e&&e()},i):"function"==typeof e&&e(),o=[]},animate:function(e,t,n,o){if(o){k(e,"transition",""),k(e,"transform","");var r=S(this.el),i=r&&r.a,a=r&&r.d,l=(t.left-n.left)/(i||1),s=(t.top-n.top)/(a||1);e.animatingX=!!l,e.animatingY=!!s,k(e,"transform","translate3d("+l+"px,"+s+"px,0)"),this.forRepaintDummy=e.offsetWidth,k(e,"transition","transform "+o+"ms"+(this.options.easing?" "+this.options.easing:"")),k(e,"transform","translate3d(0,0,0)"),"number"==typeof e.animated&&clearTimeout(e.animated),e.animated=setTimeout(function(){k(e,"transition",""),k(e,"transform",""),e.animated=!1,e.animatingX=!1,e.animatingY=!1},o)}}}))}function eH(e,t,n,o,r,i,a,l){var s,c,f=e[Y],h=f.options.onMove;return!window.CustomEvent||u||d?(s=document.createEvent("Event")).initEvent("move",!0,!0):s=new CustomEvent("move",{bubbles:!0,cancelable:!0}),s.to=t,s.from=e,s.dragged=n,s.draggedRect=o,s.related=r||t,s.relatedRect=i||x(t),s.willInsertAfter=l,s.originalEvent=a,e.dispatchEvent(s),h&&(c=h.call(f,s,a)),c}function eK(e){e.draggable=!1}function eq(){ex=!1}function eU(e){return setTimeout(e,0)}function eW(e){return clearTimeout(e)}eY.prototype={constructor:eY,_isOutsideThisEl:function(e){this.el.contains(e)||e===this.el||(ev=null)},_getDirection:function(e,t){return"function"==typeof this.options.direction?this.options.direction.call(this,e,t,V):this.options.direction},_onTapStart:function(e){if(e.cancelable){var t=this,n=this.el,o=this.options,r=o.preventOnFilter,i=e.type,a=e.touches&&e.touches[0]||e.pointerType&&"touch"===e.pointerType&&e,l=(a||e).target,s=e.target.shadowRoot&&(e.path&&e.path[0]||e.composedPath&&e.composedPath()[0])||l,c=o.filter;if(function(e){eO.length=0;for(var t=e.getElementsByTagName("input"),n=t.length;n--;){var o=t[n];o.checked&&eO.push(o)}}(n),!(V||/mousedown|pointerdown/.test(i)&&0!==e.button||o.disabled||s.isContentEditable||!this.nativeDraggable&&h&&l&&"SELECT"===l.tagName.toUpperCase()||(l=_(l,o.draggable,n,!1))&&l.animated)&&et!==l){if(er=T(l),ea=T(l,o.draggable),"function"==typeof c){if(c.call(this,e,l,this)){G({sortable:t,rootEl:s,name:"filter",targetEl:l,toEl:n,fromEl:n}),z("filter",t,{evt:e}),r&&e.cancelable&&e.preventDefault();return}}else if(c&&(c=c.split(",").some(function(o){if(o=_(s,o.trim(),n,!1))return G({sortable:t,rootEl:o,name:"filter",targetEl:l,fromEl:n,toEl:n}),z("filter",t,{evt:e}),!0}))){r&&e.cancelable&&e.preventDefault();return}(!o.handle||_(s,o.handle,n,!1))&&this._prepareDragStart(e,a,l)}}},_prepareDragStart:function(e,t,n){var o,r=this,i=r.el,a=r.options,l=i.ownerDocument;if(n&&!V&&n.parentNode===i){var s=x(n);if(J=i,$=(V=n).parentNode,ee=V.nextSibling,et=n,es=a.group,eY.dragged=V,ep=(eu={target:V,clientX:(t||e).clientX,clientY:(t||e).clientY}).clientX-s.left,eg=eu.clientY-s.top,this._lastX=(t||e).clientX,this._lastY=(t||e).clientY,V.style["will-change"]="all",o=function(){if(z("delayEnded",r,{evt:e}),eY.eventCanceled){r._onDrop();return}r._disableDelayedDragEvents(),!f&&r.nativeDraggable&&(V.draggable=!0),r._triggerDragStart(e,t),G({sortable:r,name:"choose",originalEvent:e}),E(V,a.chosenClass,!0)},a.ignore.split(",").forEach(function(e){D(V,e.trim(),eK)}),v(l,"dragover",eR),v(l,"mousemove",eR),v(l,"touchmove",eR),v(l,"mouseup",r._onDrop),v(l,"touchend",r._onDrop),v(l,"touchcancel",r._onDrop),f&&this.nativeDraggable&&(this.options.touchStartThreshold=4,V.draggable=!0),z("delayStart",this,{evt:e}),!a.delay||a.delayOnTouchOnly&&!t||this.nativeDraggable&&(d||u))o();else{if(eY.eventCanceled){this._onDrop();return}v(l,"mouseup",r._disableDelayedDrag),v(l,"touchend",r._disableDelayedDrag),v(l,"touchcancel",r._disableDelayedDrag),v(l,"mousemove",r._delayedDragTouchMoveHandler),v(l,"touchmove",r._delayedDragTouchMoveHandler),a.supportPointer&&v(l,"pointermove",r._delayedDragTouchMoveHandler),r._dragStartTimer=setTimeout(o,a.delay)}}},_delayedDragTouchMoveHandler:function(e){var t=e.touches?e.touches[0]:e;Math.max(Math.abs(t.clientX-this._lastX),Math.abs(t.clientY-this._lastY))>=Math.floor(this.options.touchStartThreshold/(this.nativeDraggable&&window.devicePixelRatio||1))&&this._disableDelayedDrag()},_disableDelayedDrag:function(){V&&eK(V),clearTimeout(this._dragStartTimer),this._disableDelayedDragEvents()},_disableDelayedDragEvents:function(){var e=this.el.ownerDocument;b(e,"mouseup",this._disableDelayedDrag),b(e,"touchend",this._disableDelayedDrag),b(e,"touchcancel",this._disableDelayedDrag),b(e,"mousemove",this._delayedDragTouchMoveHandler),b(e,"touchmove",this._delayedDragTouchMoveHandler),b(e,"pointermove",this._delayedDragTouchMoveHandler)},_triggerDragStart:function(e,t){t=t||"touch"==e.pointerType&&e,!this.nativeDraggable||t?this.options.supportPointer?v(document,"pointermove",this._onTouchMove):t?v(document,"touchmove",this._onTouchMove):v(document,"mousemove",this._onTouchMove):(v(V,"dragend",this),v(J,"dragstart",this._onDragStart));try{document.selection?eU(function(){document.selection.empty()}):window.getSelection().removeAllRanges()}catch(e){}},_dragStarted:function(e,t){if(ew=!1,J&&V){z("dragStarted",this,{evt:t}),this.nativeDraggable&&v(document,"dragover",eX);var n=this.options;e||E(V,n.dragClass,!1),E(V,n.ghostClass,!0),eY.active=this,e&&this._appendGhost(),G({sortable:this,name:"start",originalEvent:t})}else this._nulling()},_emulateDragOver:function(){if(ed){this._lastX=ed.clientX,this._lastY=ed.clientY,eL();for(var e=document.elementFromPoint(ed.clientX,ed.clientY),t=e;e&&e.shadowRoot&&(e=e.shadowRoot.elementFromPoint(ed.clientX,ed.clientY))!==t;)t=e;if(V.parentNode[Y]._isOutsideThisEl(e),t)do{if(t[Y]&&t[Y]._onDragOver({clientX:ed.clientX,clientY:ed.clientY,target:e,rootEl:t})&&!this.options.dragoverBubble)break;e=t}while(t=t.parentNode)eF()}},_onTouchMove:function(e){if(eu){var t=this.options,n=t.fallbackTolerance,o=t.fallbackOffset,r=e.touches?e.touches[0]:e,i=Z&&S(Z,!0),a=Z&&i&&i.a,l=Z&&i&&i.d,s=p&&e_&&A(e_),c=(r.clientX-eu.clientX+o.x)/(a||1)+(s?s[0]-eC[0]:0)/(a||1),u=(r.clientY-eu.clientY+o.y)/(l||1)+(s?s[1]-eC[1]:0)/(l||1);if(!eY.active&&!ew){if(n&&Math.max(Math.abs(r.clientX-this._lastX),Math.abs(r.clientY-this._lastY))w.right+10||e.clientY>y.bottom&&e.clientX>y.left:e.clientY>w.bottom+10||e.clientX>y.right&&e.clientY>y.top)&&!m.animated)){if(m===V)return en(!1);if(m&&a===e.target&&(l=m),l&&(n=x(l)),!1!==eH(J,a,V,t,l,n,e,!!l))return et(),m&&m.nextSibling?a.insertBefore(V,m.nextSibling):a.appendChild(V),$=a,eo(),en(!0)}else if(m&&(S=r,D=x(M(this.el,0,this.options,!0)),C=X(this.el,this.options,Z),S?e.clientXu+c*i/2:sd-ey)return-eb}else if(s>u+c*(1-r)/2&&sd-c*i/2)?s>u+c/2?1:-1:0}(e,l,n,r,L?1:s.swapThreshold,null==s.invertedSwapThreshold?s.swapThreshold:s.invertedSwapThreshold,eD,ev===l))){var K=T(V);do K-=N,A=$.children[K];while(A&&("none"===k(A,"display")||A===Z))}if(0===N||A===l)return en(!1);ev=l,eb=N;var q=l.nextElementSibling,U=!1,W=eH(J,a,V,t,l,n,e,U=1===N);if(!1!==W)return(1===W||-1===W)&&(U=1===W),ex=!0,setTimeout(eq,30),et(),U&&!q?a.appendChild(V):l.parentNode.insertBefore(V,U?q:l),R&&B(R,0,H-R.scrollTop),$=V.parentNode,void 0===I||eD||(ey=Math.abs(I-x(l)[F])),eo(),en(!0)}if(a.contains(V))return en(!1)}return!1}function Q(s,c){z(s,p,i({evt:e,isOwner:d,axis:r?"vertical":"horizontal",revert:o,dragRect:t,targetRect:n,canSort:f,fromSortable:h,target:l,completed:en,onMove:function(n,o){return eH(J,a,V,t,n,x(n),e,o)},changed:eo},c))}function et(){Q("dragOverAnimationCapture"),p.captureAnimationState(),p!==h&&h.captureAnimationState()}function en(t){return Q("dragOverCompleted",{insertion:t}),t&&(d?u._hideClone():u._showClone(p),p!==h&&(E(V,ec?ec.options.ghostClass:u.options.ghostClass,!1),E(V,s.ghostClass,!0)),ec!==p&&p!==eY.active?ec=p:p===eY.active&&ec&&(ec=null),h===p&&(p._ignoreWhileAnimating=l),p.animateAll(function(){Q("dragOverAnimationComplete"),p._ignoreWhileAnimating=null}),p!==h&&(h.animateAll(),h._ignoreWhileAnimating=null)),(l!==V||V.animated)&&(l!==a||l.animated)||(ev=null),s.dragoverBubble||e.rootEl||l===document||(V.parentNode[Y]._isOutsideThisEl(e.target),t||eR(e)),!s.dragoverBubble&&e.stopPropagation&&e.stopPropagation(),g=!0}function eo(){ei=T(V),el=T(V,s.draggable),G({sortable:p,name:"change",toEl:a,newIndex:ei,newDraggableIndex:el,originalEvent:e})}},_ignoreWhileAnimating:null,_offMoveEvents:function(){b(document,"mousemove",this._onTouchMove),b(document,"touchmove",this._onTouchMove),b(document,"pointermove",this._onTouchMove),b(document,"dragover",eR),b(document,"mousemove",eR),b(document,"touchmove",eR)},_offUpEvents:function(){var e=this.el.ownerDocument;b(e,"mouseup",this._onDrop),b(e,"touchend",this._onDrop),b(e,"pointerup",this._onDrop),b(e,"touchcancel",this._onDrop),b(document,"selectstart",this)},_onDrop:function(e){var t=this.el,n=this.options;if(ei=T(V),el=T(V,n.draggable),z("drop",this,{evt:e}),$=V&&V.parentNode,ei=T(V),el=T(V,n.draggable),eY.eventCanceled){this._nulling();return}ew=!1,eD=!1,eS=!1,clearInterval(this._loopId),clearTimeout(this._dragStartTimer),eW(this.cloneId),eW(this._dragStartId),this.nativeDraggable&&(b(document,"drop",this),b(t,"dragstart",this._onDragStart)),this._offMoveEvents(),this._offUpEvents(),h&&k(document.body,"user-select",""),k(V,"transform",""),e&&(em&&(e.cancelable&&e.preventDefault(),n.dropBubble||e.stopPropagation()),Z&&Z.parentNode&&Z.parentNode.removeChild(Z),(J===$||ec&&"clone"!==ec.lastPutMode)&&en&&en.parentNode&&en.parentNode.removeChild(en),V&&(this.nativeDraggable&&b(V,"dragend",this),eK(V),V.style["will-change"]="",em&&!ew&&E(V,ec?ec.options.ghostClass:this.options.ghostClass,!1),E(V,this.options.chosenClass,!1),G({sortable:this,name:"unchoose",toEl:$,newIndex:null,newDraggableIndex:null,originalEvent:e}),J!==$?(ei>=0&&(G({rootEl:$,name:"add",toEl:$,fromEl:J,originalEvent:e}),G({sortable:this,name:"remove",toEl:$,originalEvent:e}),G({rootEl:$,name:"sort",toEl:$,fromEl:J,originalEvent:e}),G({sortable:this,name:"sort",toEl:$,originalEvent:e})),ec&&ec.save()):ei!==er&&ei>=0&&(G({sortable:this,name:"update",toEl:$,originalEvent:e}),G({sortable:this,name:"sort",toEl:$,originalEvent:e})),eY.active&&((null==ei||-1===ei)&&(ei=er,el=ea),G({sortable:this,name:"end",toEl:$,originalEvent:e}),this.save()))),this._nulling()},_nulling:function(){z("nulling",this),J=V=$=Z=ee=en=et=eo=eu=ed=em=ei=el=er=ea=ev=eb=ec=es=eY.dragged=eY.ghost=eY.clone=eY.active=null,eO.forEach(function(e){e.checked=!0}),eO.length=ef=eh=0},handleEvent:function(e){switch(e.type){case"drop":case"dragend":this._onDrop(e);break;case"dragenter":case"dragover":V&&(this._onDragOver(e),e.dataTransfer&&(e.dataTransfer.dropEffect="move"),e.cancelable&&e.preventDefault());break;case"selectstart":e.preventDefault()}},toArray:function(){for(var e,t=[],n=this.el.children,o=0,r=n.length,i=this.options;o1&&(tr.forEach(function(e){r.addAnimationState({target:e,rect:tl?x(e):i}),R(e),e.fromRect=i,n.removeAnimationState(e)}),tl=!1,t=!this.options.removeCloneOnHide,tr.forEach(function(e,n){var r=o.children[e.sortableIndex+(t?Number(n):0)];r?o.insertBefore(e,r):o.appendChild(e)}))},dragOverCompleted:function(e){var t=e.sortable,n=e.isOwner,o=e.insertion,r=e.activeSortable,i=e.parentEl,a=e.putSortable,l=this.options;if(o){if(n&&r._hideClone(),ta=!1,l.animation&&tr.length>1&&(tl||!n&&!r.options.sort&&!a)){var s=x(tt,!1,!0,!0);tr.forEach(function(e){e!==tt&&(F(e,s),i.appendChild(e))}),tl=!0}if(!n){if(tl||td(),tr.length>1){var c=to;r._showClone(t),r.options.animation&&!to&&c&&ti.forEach(function(e){r.addAnimationState({target:e,rect:tn}),e.fromRect=tn,e.thisAnimationDuration=null})}else r._showClone(t)}}},dragOverAnimationCapture:function(e){var t=e.dragRect,n=e.isOwner,o=e.activeSortable;if(tr.forEach(function(e){e.thisAnimationDuration=null}),o.options.animation&&!n&&o.multiDrag.isMultiDrag){tn=l({},t);var r=S(tt,!0);tn.top-=r.f,tn.left-=r.e}},dragOverAnimationComplete:function(){tl&&(tl=!1,td())},drop:function(e){var t=e.originalEvent,n=e.rootEl,o=e.parentEl,r=e.sortable,i=e.dispatchSortableEvent,a=e.oldIndex,l=e.putSortable,s=l||this.sortable;if(t){var c=this.options,u=o.children;if(!ts){if(c.multiDragKey&&!this.multiDragKeyDown&&this._deselectMultiDrag(),E(tt,c.selectedClass,!~tr.indexOf(tt)),~tr.indexOf(tt))tr.splice(tr.indexOf(tt),1),e4=null,U({sortable:r,rootEl:n,name:"deselect",targetEl:tt,originalEvent:t});else{if(tr.push(tt),U({sortable:r,rootEl:n,name:"select",targetEl:tt,originalEvent:t}),t.shiftKey&&e4&&r.el.contains(e4)){var d,f,h=T(e4),p=T(tt);if(~h&&~p&&h!==p)for(p>h?(f=h,d=p):(f=p,d=h+1);f1){var g=x(tt),m=T(tt,":not(."+this.options.selectedClass+")");if(!ta&&c.animation&&(tt.thisAnimationDuration=null),s.captureAnimationState(),!ta&&(c.animation&&(tt.fromRect=g,tr.forEach(function(e){if(e.thisAnimationDuration=null,e!==tt){var t=tl?x(e):g;e.fromRect=t,s.addAnimationState({target:e,rect:t})}})),td(),tr.forEach(function(e){u[m]?o.insertBefore(e,u[m]):o.appendChild(e),m++}),a===T(tt))){var v=!1;tr.forEach(function(e){if(e.sortableIndex!==T(e)){v=!0;return}}),v&&(i("update"),i("sort"))}tr.forEach(function(e){R(e)}),s.animateAll()}te=s}(n===o||l&&"clone"!==l.lastPutMode)&&ti.forEach(function(e){e.parentNode&&e.parentNode.removeChild(e)})}},nullingGlobal:function(){this.isMultiDrag=ts=!1,ti.length=0},destroyGlobal:function(){this._deselectMultiDrag(),b(document,"pointerup",this._deselectMultiDrag),b(document,"mouseup",this._deselectMultiDrag),b(document,"touchend",this._deselectMultiDrag),b(document,"keydown",this._checkKeyDown),b(document,"keyup",this._checkKeyUp)},_deselectMultiDrag:function(e){if(!(void 0!==ts&&ts||te!==this.sortable||e&&_(e.target,this.options.draggable,this.sortable.el,!1))&&(!e||0===e.button))for(;tr.length;){var t=tr[0];E(t,this.options.selectedClass,!1),tr.shift(),U({sortable:this.sortable,rootEl:this.sortable.el,name:"deselect",targetEl:t,originalEvent:e})}},_checkKeyDown:function(e){e.key===this.options.multiDragKey&&(this.multiDragKeyDown=!0)},_checkKeyUp:function(e){e.key===this.options.multiDragKey&&(this.multiDragKeyDown=!1)}},l(e,{pluginName:"multiDrag",utils:{select:function(e){var t=e.parentNode[Y];!t||!t.options.multiDrag||~tr.indexOf(e)||(te&&te!==t&&(te.multiDrag._deselectMultiDrag(),te=t),E(e,t.options.selectedClass,!0),tr.push(e))},deselect:function(e){var t=e.parentNode[Y],n=tr.indexOf(e);t&&t.options.multiDrag&&~n&&(E(e,t.options.selectedClass,!1),tr.splice(n,1))}},eventProperties:function(){var e,t=this,n=[],o=[];return tr.forEach(function(e){var r;n.push({multiDragElement:e,index:e.sortableIndex}),r=tl&&e!==tt?-1:tl?T(e,":not(."+t.options.selectedClass+")"):T(e),o.push({multiDragElement:e,index:r})}),{items:function(e){if(Array.isArray(e))return s(e)}(e=tr)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(e)||function(e,t){if(e){if("string"==typeof e)return s(e,void 0);var n=Object.prototype.toString.call(e).slice(8,-1);if("Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return s(e,void 0)}}(e)||function(){throw TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}(),clones:[].concat(ti),oldIndicies:n,newIndicies:o}},optionListeners:{multiDragKey:function(e){return"ctrl"===(e=e.toLowerCase())?e="Control":e.length>1&&(e=e.charAt(0).toUpperCase()+e.substr(1)),e}}})}function tu(e,t){ti.forEach(function(n,o){var r=t.children[n.sortableIndex+(e?Number(o):0)];r?t.insertBefore(n,r):t.appendChild(n)})}function td(){tr.forEach(function(e){e!==tt&&e.parentNode&&e.parentNode.removeChild(e)})}eY.mount(new function(){function e(){for(var e in this.defaults={scroll:!0,forceAutoScrollFallback:!1,scrollSensitivity:30,scrollSpeed:10,bubbleScroll:!0},this)"_"===e.charAt(0)&&"function"==typeof this[e]&&(this[e]=this[e].bind(this))}return e.prototype={dragStarted:function(e){var t=e.originalEvent;this.sortable.nativeDraggable?v(document,"dragover",this._handleAutoScroll):this.options.supportPointer?v(document,"pointermove",this._handleFallbackAutoScroll):t.touches?v(document,"touchmove",this._handleFallbackAutoScroll):v(document,"mousemove",this._handleFallbackAutoScroll)},dragOverCompleted:function(e){var t=e.originalEvent;this.options.dragOverBubble||t.rootEl||this._handleAutoScroll(t)},drop:function(){this.sortable.nativeDraggable?b(document,"dragover",this._handleAutoScroll):(b(document,"pointermove",this._handleFallbackAutoScroll),b(document,"touchmove",this._handleFallbackAutoScroll),b(document,"mousemove",this._handleFallbackAutoScroll)),e2(),e1(),clearTimeout(Q),Q=void 0},nulling:function(){e$=eG=ez=e0=eZ=eQ=eV=null,eJ.length=0},_handleFallbackAutoScroll:function(e){this._handleAutoScroll(e,!0)},_handleAutoScroll:function(e,t){var n=this,o=(e.touches?e.touches[0]:e).clientX,r=(e.touches?e.touches[0]:e).clientY,i=document.elementFromPoint(o,r);if(e$=e,t||this.options.forceAutoScrollFallback||d||u||h){e8(e,this.options,i,t);var a=I(i,!0);e0&&(!eZ||o!==eQ||r!==eV)&&(eZ&&e2(),eZ=setInterval(function(){var i=I(document.elementFromPoint(o,r),!0);i!==a&&(a=i,e1()),e8(e,n.options,i,t)},10),eQ=o,eV=r)}else{if(!this.options.bubbleScroll||I(i,!0)===C()){e1();return}e8(e,this.options,I(i,!1),!1)}}},l(e,{pluginName:"scroll",initializeByDefault:!0})}),eY.mount(e9,e5),n.default=eY},{"@parcel/transformer-js/src/esmodule-helpers.js":"kPSB8"}]},["1pQVs"],"1pQVs","parcelRequirec571"); dist/js/dashboard_widget.js 0000644 00001275446 14760033122 0011774 0 ustar 00 !function(t,e,r,n,i){var a="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:"undefined"!=typeof window?window:"undefined"!=typeof global?global:{},o="function"==typeof a[n]&&a[n],s=o.cache||{},l="undefined"!=typeof module&&"function"==typeof module.require&&module.require.bind(module);function u(e,r){if(!s[e]){if(!t[e]){var i="function"==typeof a[n]&&a[n];if(!r&&i)return i(e,!0);if(o)return o(e,!0);if(l&&"string"==typeof e)return l(e);var c=Error("Cannot find module '"+e+"'");throw c.code="MODULE_NOT_FOUND",c}f.resolve=function(r){var n=t[e][1][r];return null!=n?n:r},f.cache={};var h=s[e]=new u.Module(e);t[e][0].call(h.exports,f,h,h.exports,this)}return s[e].exports;function f(t){var e=f.resolve(t);return!1===e?{}:u(e)}}u.isParcelRequire=!0,u.Module=function(t){this.id=t,this.bundle=u,this.exports={}},u.modules=t,u.cache=s,u.parent=o,u.register=function(e,r){t[e]=[function(t,e){e.exports=r},{}]},Object.defineProperty(u,"root",{get:function(){return a[n]}}),a[n]=u;for(var c=0;c0}},{key:"bindings",get:function(){return Array.from(this.unorderedBindings).sort(function(t,e){var r=t.index,n=e.index;return rn?1:0})}}]),t}(),y=function(){function t(e){(0,a._)(this,t),this.application=e,this.eventListenerMaps=new Map,this.started=!1}return(0,o._)(t,[{key:"start",value:function(){this.started||(this.started=!0,this.eventListeners.forEach(function(t){return t.connect()}))}},{key:"stop",value:function(){this.started&&(this.started=!1,this.eventListeners.forEach(function(t){return t.disconnect()}))}},{key:"eventListeners",get:function(){return Array.from(this.eventListenerMaps.values()).reduce(function(t,e){return t.concat(Array.from(e.values()))},[])}},{key:"bindingConnected",value:function(t){this.fetchEventListenerForBinding(t).bindingConnected(t)}},{key:"bindingDisconnected",value:function(t){var e=arguments.length>1&&void 0!==arguments[1]&&arguments[1];this.fetchEventListenerForBinding(t).bindingDisconnected(t),e&&this.clearEventListenersForBinding(t)}},{key:"handleError",value:function(t,e){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};this.application.handleError(t,"Error ".concat(e),r)}},{key:"clearEventListenersForBinding",value:function(t){var e=this.fetchEventListenerForBinding(t);e.hasBindings()||(e.disconnect(),this.removeMappedEventListenerFor(t))}},{key:"removeMappedEventListenerFor",value:function(t){var e=t.eventTarget,r=t.eventName,n=t.eventOptions,i=this.fetchEventListenerMapForEventTarget(e),a=this.cacheKey(r,n);i.delete(a),0==i.size&&this.eventListenerMaps.delete(e)}},{key:"fetchEventListenerForBinding",value:function(t){var e=t.eventTarget,r=t.eventName,n=t.eventOptions;return this.fetchEventListener(e,r,n)}},{key:"fetchEventListener",value:function(t,e,r){var n=this.fetchEventListenerMapForEventTarget(t),i=this.cacheKey(e,r),a=n.get(i);return a||(a=this.createEventListener(t,e,r),n.set(i,a)),a}},{key:"createEventListener",value:function(t,e,r){var n=new g(t,e,r);return this.started&&n.connect(),n}},{key:"fetchEventListenerMapForEventTarget",value:function(t){var e=this.eventListenerMaps.get(t);return e||(e=new Map,this.eventListenerMaps.set(t,e)),e}},{key:"cacheKey",value:function(t,e){var r=[t];return Object.keys(e).sort().forEach(function(t){r.push("".concat(e[t]?"":"!").concat(t))}),r.join(":")}}]),t}(),m={stop:function(t){var e=t.event;return t.value&&e.stopPropagation(),!0},prevent:function(t){var e=t.event;return t.value&&e.preventDefault(),!0},self:function(t){var e=t.event,r=t.value,n=t.element;return!r||n===e.target}},b=/^(?:(?:([^.]+?)\+)?(.+?)(?:\.(.+?))?(?:@(window|document))?->)?(.+?)(?:#([^:]+?))(?::(.+))?$/;function _(t){return t.replace(/(?:[_-])([a-z0-9])/g,function(t,e){return e.toUpperCase()})}function x(t){return _(t.replace(/--/g,"-").replace(/__/g,"_"))}function k(t){return t.charAt(0).toUpperCase()+t.slice(1)}function w(t){return t.replace(/([A-Z])/g,function(t,e){return"-".concat(e.toLowerCase())})}function M(t,e){return Object.prototype.hasOwnProperty.call(t,e)}var S=["meta","ctrl","alt","shift"],O=function(){function t(e,r,n,i){(0,a._)(this,t),this.element=e,this.index=r,this.eventTarget=n.eventTarget||e,this.eventName=n.eventName||function(t){var e=t.tagName.toLowerCase();if(e in A)return A[e](t)}(e)||E("missing event name"),this.eventOptions=n.eventOptions||{},this.identifier=n.identifier||E("missing identifier"),this.methodName=n.methodName||E("missing method name"),this.keyFilter=n.keyFilter||"",this.schema=i}return(0,o._)(t,[{key:"toString",value:function(){var t=this.keyFilter?".".concat(this.keyFilter):"",e=this.eventTargetName?"@".concat(this.eventTargetName):"";return"".concat(this.eventName).concat(t).concat(e,"->").concat(this.identifier,"#").concat(this.methodName)}},{key:"shouldIgnoreKeyboardEvent",value:function(t){if(!this.keyFilter)return!1;var e=this.keyFilter.split("+");if(this.keyFilterDissatisfied(t,e))return!0;var r=e.filter(function(t){return!S.includes(t)})[0];return!!r&&(M(this.keyMappings,r)||E("contains unknown key filter: ".concat(this.keyFilter)),this.keyMappings[r].toLowerCase()!==t.key.toLowerCase())}},{key:"shouldIgnoreMouseEvent",value:function(t){if(!this.keyFilter)return!1;var e=[this.keyFilter];return!!this.keyFilterDissatisfied(t,e)}},{key:"params",get:function(){var t={},e=RegExp("^data-".concat(this.identifier,"-(.+)-param$"),"i"),r=!0,n=!1,i=void 0;try{for(var a,o=Array.from(this.element.attributes)[Symbol.iterator]();!(r=(a=o.next()).done);r=!0){var s=a.value,l=s.name,u=s.value,c=l.match(e),h=c&&c[1];h&&(t[_(h)]=function(t){try{return JSON.parse(t)}catch(e){return t}}(u))}}catch(t){n=!0,i=t}finally{try{r||null==o.return||o.return()}finally{if(n)throw i}}return t}},{key:"eventTargetName",get:function(){var t;return(t=this.eventTarget)==window?"window":t==document?"document":void 0}},{key:"keyMappings",get:function(){return this.schema.keyMappings}},{key:"keyFilterDissatisfied",value:function(t,e){var r=(0,h._)(S.map(function(t){return e.includes(t)}),4),n=r[0],i=r[1],a=r[2],o=r[3];return t.metaKey!==n||t.ctrlKey!==i||t.altKey!==a||t.shiftKey!==o}}],[{key:"forToken",value:function(t,e){var r,n,i,a;return new this(t.element,t.index,(n=(r=t.content.trim().match(b)||[])[2],(i=r[3])&&!["keydown","keyup","keypress"].includes(n)&&(n+=".".concat(i),i=""),{eventTarget:"window"==(a=r[4])?window:"document"==a?document:void 0,eventName:n,eventOptions:r[7]?r[7].split(":").reduce(function(t,e){return Object.assign(t,(0,s._)({},e.replace(/^!/,""),!/^!/.test(e)))},{}):{},identifier:r[5],methodName:r[6],keyFilter:r[1]||i}),e)}}]),t}(),A={a:function(){return"click"},button:function(){return"click"},form:function(){return"submit"},details:function(){return"toggle"},input:function(t){return"submit"==t.getAttribute("type")?"click":"input"},select:function(){return"change"},textarea:function(){return"input"}};function E(t){throw Error(t)}var C=function(){function t(e,r){(0,a._)(this,t),this.context=e,this.action=r}return(0,o._)(t,[{key:"index",get:function(){return this.action.index}},{key:"eventTarget",get:function(){return this.action.eventTarget}},{key:"eventOptions",get:function(){return this.action.eventOptions}},{key:"identifier",get:function(){return this.context.identifier}},{key:"handleEvent",value:function(t){var e=this.prepareActionEvent(t);this.willBeInvokedByEvent(t)&&this.applyEventModifiers(e)&&this.invokeWithEvent(e)}},{key:"eventName",get:function(){return this.action.eventName}},{key:"method",get:function(){var t=this.controller[this.methodName];if("function"==typeof t)return t;throw Error('Action "'.concat(this.action,'" references undefined method "').concat(this.methodName,'"'))}},{key:"applyEventModifiers",value:function(t){var e=this.action.element,r=this.context.application.actionDescriptorFilters,n=this.context.controller,i=!0,a=!0,o=!1,s=void 0;try{for(var l,u=Object.entries(this.eventOptions)[Symbol.iterator]();!(a=(l=u.next()).done);a=!0){var c=(0,h._)(l.value,2),f=c[0],d=c[1];if(f in r){var p=r[f];i=i&&p({name:f,value:d,event:t,element:e,controller:n})}}}catch(t){o=!0,s=t}finally{try{a||null==u.return||u.return()}finally{if(o)throw s}}return i}},{key:"prepareActionEvent",value:function(t){return Object.assign(t,{params:this.action.params})}},{key:"invokeWithEvent",value:function(t){var e=t.target,r=t.currentTarget;try{this.method.call(this.controller,t),this.context.logDebugActivity(this.methodName,{event:t,target:e,currentTarget:r,action:this.methodName})}catch(e){var n=this.identifier,i=this.controller,a=this.element,o=this.index;this.context.handleError(e,'invoking action "'.concat(this.action,'"'),{identifier:n,controller:i,element:a,index:o,event:t})}}},{key:"willBeInvokedByEvent",value:function(t){var e=t.target;return!(t instanceof KeyboardEvent&&this.action.shouldIgnoreKeyboardEvent(t)||t instanceof MouseEvent&&this.action.shouldIgnoreMouseEvent(t))&&(this.element===e||(e instanceof Element&&this.element.contains(e)?this.scope.containsElement(e):this.scope.containsElement(this.action.element)))}},{key:"controller",get:function(){return this.context.controller}},{key:"methodName",get:function(){return this.action.methodName}},{key:"element",get:function(){return this.scope.element}},{key:"scope",get:function(){return this.context.scope}}]),t}(),P=function(){function t(e,r){var n=this;(0,a._)(this,t),this.mutationObserverInit={attributes:!0,childList:!0,subtree:!0},this.element=e,this.started=!1,this.delegate=r,this.elements=new Set,this.mutationObserver=new MutationObserver(function(t){return n.processMutations(t)})}return(0,o._)(t,[{key:"start",value:function(){this.started||(this.started=!0,this.mutationObserver.observe(this.element,this.mutationObserverInit),this.refresh())}},{key:"pause",value:function(t){this.started&&(this.mutationObserver.disconnect(),this.started=!1),t(),this.started||(this.mutationObserver.observe(this.element,this.mutationObserverInit),this.started=!0)}},{key:"stop",value:function(){this.started&&(this.mutationObserver.takeRecords(),this.mutationObserver.disconnect(),this.started=!1)}},{key:"refresh",value:function(){if(this.started){var t=new Set(this.matchElementsInTree()),e=!0,r=!1,n=void 0;try{for(var i,a=Array.from(this.elements)[Symbol.iterator]();!(e=(i=a.next()).done);e=!0){var o=i.value;t.has(o)||this.removeElement(o)}}catch(t){r=!0,n=t}finally{try{e||null==a.return||a.return()}finally{if(r)throw n}}var s=!0,l=!1,u=void 0;try{for(var c,h=Array.from(t)[Symbol.iterator]();!(s=(c=h.next()).done);s=!0){var f=c.value;this.addElement(f)}}catch(t){l=!0,u=t}finally{try{s||null==h.return||h.return()}finally{if(l)throw u}}}}},{key:"processMutations",value:function(t){var e=!0,r=!1,n=void 0;if(this.started)try{for(var i,a=t[Symbol.iterator]();!(e=(i=a.next()).done);e=!0){var o=i.value;this.processMutation(o)}}catch(t){r=!0,n=t}finally{try{e||null==a.return||a.return()}finally{if(r)throw n}}}},{key:"processMutation",value:function(t){"attributes"==t.type?this.processAttributeChange(t.target,t.attributeName):"childList"==t.type&&(this.processRemovedNodes(t.removedNodes),this.processAddedNodes(t.addedNodes))}},{key:"processAttributeChange",value:function(t,e){this.elements.has(t)?this.delegate.elementAttributeChanged&&this.matchElement(t)?this.delegate.elementAttributeChanged(t,e):this.removeElement(t):this.matchElement(t)&&this.addElement(t)}},{key:"processRemovedNodes",value:function(t){var e=!0,r=!1,n=void 0;try{for(var i,a=Array.from(t)[Symbol.iterator]();!(e=(i=a.next()).done);e=!0){var o=i.value,s=this.elementFromNode(o);s&&this.processTree(s,this.removeElement)}}catch(t){r=!0,n=t}finally{try{e||null==a.return||a.return()}finally{if(r)throw n}}}},{key:"processAddedNodes",value:function(t){var e=!0,r=!1,n=void 0;try{for(var i,a=Array.from(t)[Symbol.iterator]();!(e=(i=a.next()).done);e=!0){var o=i.value,s=this.elementFromNode(o);s&&this.elementIsActive(s)&&this.processTree(s,this.addElement)}}catch(t){r=!0,n=t}finally{try{e||null==a.return||a.return()}finally{if(r)throw n}}}},{key:"matchElement",value:function(t){return this.delegate.matchElement(t)}},{key:"matchElementsInTree",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.element;return this.delegate.matchElementsInTree(t)}},{key:"processTree",value:function(t,e){var r=!0,n=!1,i=void 0;try{for(var a,o=this.matchElementsInTree(t)[Symbol.iterator]();!(r=(a=o.next()).done);r=!0){var s=a.value;e.call(this,s)}}catch(t){n=!0,i=t}finally{try{r||null==o.return||o.return()}finally{if(n)throw i}}}},{key:"elementFromNode",value:function(t){if(t.nodeType==Node.ELEMENT_NODE)return t}},{key:"elementIsActive",value:function(t){return t.isConnected==this.element.isConnected&&this.element.contains(t)}},{key:"addElement",value:function(t){!this.elements.has(t)&&this.elementIsActive(t)&&(this.elements.add(t),this.delegate.elementMatched&&this.delegate.elementMatched(t))}},{key:"removeElement",value:function(t){this.elements.has(t)&&(this.elements.delete(t),this.delegate.elementUnmatched&&this.delegate.elementUnmatched(t))}}]),t}(),D=function(){function t(e,r,n){(0,a._)(this,t),this.attributeName=r,this.delegate=n,this.elementObserver=new P(e,this)}return(0,o._)(t,[{key:"element",get:function(){return this.elementObserver.element}},{key:"selector",get:function(){return"[".concat(this.attributeName,"]")}},{key:"start",value:function(){this.elementObserver.start()}},{key:"pause",value:function(t){this.elementObserver.pause(t)}},{key:"stop",value:function(){this.elementObserver.stop()}},{key:"refresh",value:function(){this.elementObserver.refresh()}},{key:"started",get:function(){return this.elementObserver.started}},{key:"matchElement",value:function(t){return t.hasAttribute(this.attributeName)}},{key:"matchElementsInTree",value:function(t){var e=this.matchElement(t)?[t]:[],r=Array.from(t.querySelectorAll(this.selector));return e.concat(r)}},{key:"elementMatched",value:function(t){this.delegate.elementMatchedAttribute&&this.delegate.elementMatchedAttribute(t,this.attributeName)}},{key:"elementUnmatched",value:function(t){this.delegate.elementUnmatchedAttribute&&this.delegate.elementUnmatchedAttribute(t,this.attributeName)}},{key:"elementAttributeChanged",value:function(t,e){this.delegate.elementAttributeValueChanged&&this.attributeName==e&&this.delegate.elementAttributeValueChanged(t,e)}}]),t}();function j(t,e,r){F(t,e).add(r)}function T(t,e,r){F(t,e).delete(r),I(t,e)}function F(t,e){var r=t.get(e);return r||(r=new Set,t.set(e,r)),r}function I(t,e){var r=t.get(e);null!=r&&0==r.size&&t.delete(e)}var L=function(){function t(){(0,a._)(this,t),this.valuesByKey=new Map}return(0,o._)(t,[{key:"keys",get:function(){return Array.from(this.valuesByKey.keys())}},{key:"values",get:function(){return Array.from(this.valuesByKey.values()).reduce(function(t,e){return t.concat(Array.from(e))},[])}},{key:"size",get:function(){return Array.from(this.valuesByKey.values()).reduce(function(t,e){return t+e.size},0)}},{key:"add",value:function(t,e){j(this.valuesByKey,t,e)}},{key:"delete",value:function(t,e){T(this.valuesByKey,t,e)}},{key:"has",value:function(t,e){var r=this.valuesByKey.get(t);return null!=r&&r.has(e)}},{key:"hasKey",value:function(t){return this.valuesByKey.has(t)}},{key:"hasValue",value:function(t){return Array.from(this.valuesByKey.values()).some(function(e){return e.has(t)})}},{key:"getValuesForKey",value:function(t){var e=this.valuesByKey.get(t);return e?Array.from(e):[]}},{key:"getKeysForValue",value:function(t){return Array.from(this.valuesByKey).filter(function(e){var r=(0,h._)(e,2);return(r[0],r[1]).has(t)}).map(function(t){var e=(0,h._)(t,2),r=e[0];return e[1],r})}}]),t}(),B=function(t){(0,c._)(r,t);var e=(0,p._)(r);function r(){var t;return(0,a._)(this,r),(t=e.call(this)).keysByValue=new Map,t}return(0,o._)(r,[{key:"values",get:function(){return Array.from(this.keysByValue.keys())}},{key:"add",value:function(t,e){(0,l._)((0,u._)(r.prototype),"add",this).call(this,t,e),j(this.keysByValue,e,t)}},{key:"delete",value:function(t,e){(0,l._)((0,u._)(r.prototype),"delete",this).call(this,t,e),T(this.keysByValue,e,t)}},{key:"hasValue",value:function(t){return this.keysByValue.has(t)}},{key:"getKeysForValue",value:function(t){var e=this.keysByValue.get(t);return e?Array.from(e):[]}}]),r}(L),R=function(){function t(e,r,n,i){(0,a._)(this,t),this._selector=r,this.details=i,this.elementObserver=new P(e,this),this.delegate=n,this.matchesByElement=new L}return(0,o._)(t,[{key:"started",get:function(){return this.elementObserver.started}},{key:"selector",get:function(){return this._selector},set:function(t){this._selector=t,this.refresh()}},{key:"start",value:function(){this.elementObserver.start()}},{key:"pause",value:function(t){this.elementObserver.pause(t)}},{key:"stop",value:function(){this.elementObserver.stop()}},{key:"refresh",value:function(){this.elementObserver.refresh()}},{key:"element",get:function(){return this.elementObserver.element}},{key:"matchElement",value:function(t){var e=this.selector;if(!e)return!1;var r=t.matches(e);return this.delegate.selectorMatchElement?r&&this.delegate.selectorMatchElement(t,this.details):r}},{key:"matchElementsInTree",value:function(t){var e=this,r=this.selector;if(!r)return[];var n=this.matchElement(t)?[t]:[],i=Array.from(t.querySelectorAll(r)).filter(function(t){return e.matchElement(t)});return n.concat(i)}},{key:"elementMatched",value:function(t){var e=this.selector;e&&this.selectorMatched(t,e)}},{key:"elementUnmatched",value:function(t){var e=this.matchesByElement.getKeysForValue(t),r=!0,n=!1,i=void 0;try{for(var a,o=e[Symbol.iterator]();!(r=(a=o.next()).done);r=!0){var s=a.value;this.selectorUnmatched(t,s)}}catch(t){n=!0,i=t}finally{try{r||null==o.return||o.return()}finally{if(n)throw i}}}},{key:"elementAttributeChanged",value:function(t,e){var r=this.selector;if(r){var n=this.matchElement(t),i=this.matchesByElement.has(r,t);n&&!i?this.selectorMatched(t,r):!n&&i&&this.selectorUnmatched(t,r)}}},{key:"selectorMatched",value:function(t,e){this.delegate.selectorMatched(t,e,this.details),this.matchesByElement.add(e,t)}},{key:"selectorUnmatched",value:function(t,e){this.delegate.selectorUnmatched(t,e,this.details),this.matchesByElement.delete(e,t)}}]),t}(),N=function(){function t(e,r){var n=this;(0,a._)(this,t),this.element=e,this.delegate=r,this.started=!1,this.stringMap=new Map,this.mutationObserver=new MutationObserver(function(t){return n.processMutations(t)})}return(0,o._)(t,[{key:"start",value:function(){this.started||(this.started=!0,this.mutationObserver.observe(this.element,{attributes:!0,attributeOldValue:!0}),this.refresh())}},{key:"stop",value:function(){this.started&&(this.mutationObserver.takeRecords(),this.mutationObserver.disconnect(),this.started=!1)}},{key:"refresh",value:function(){var t=!0,e=!1,r=void 0;if(this.started)try{for(var n,i=this.knownAttributeNames[Symbol.iterator]();!(t=(n=i.next()).done);t=!0){var a=n.value;this.refreshAttribute(a,null)}}catch(t){e=!0,r=t}finally{try{t||null==i.return||i.return()}finally{if(e)throw r}}}},{key:"processMutations",value:function(t){var e=!0,r=!1,n=void 0;if(this.started)try{for(var i,a=t[Symbol.iterator]();!(e=(i=a.next()).done);e=!0){var o=i.value;this.processMutation(o)}}catch(t){r=!0,n=t}finally{try{e||null==a.return||a.return()}finally{if(r)throw n}}}},{key:"processMutation",value:function(t){var e=t.attributeName;e&&this.refreshAttribute(e,t.oldValue)}},{key:"refreshAttribute",value:function(t,e){var r=this.delegate.getStringMapKeyForAttribute(t);if(null!=r){this.stringMap.has(t)||this.stringMapKeyAdded(r,t);var n=this.element.getAttribute(t);if(this.stringMap.get(t)!=n&&this.stringMapValueChanged(n,r,e),null==n){var i=this.stringMap.get(t);this.stringMap.delete(t),i&&this.stringMapKeyRemoved(r,t,i)}else this.stringMap.set(t,n)}}},{key:"stringMapKeyAdded",value:function(t,e){this.delegate.stringMapKeyAdded&&this.delegate.stringMapKeyAdded(t,e)}},{key:"stringMapValueChanged",value:function(t,e,r){this.delegate.stringMapValueChanged&&this.delegate.stringMapValueChanged(t,e,r)}},{key:"stringMapKeyRemoved",value:function(t,e,r){this.delegate.stringMapKeyRemoved&&this.delegate.stringMapKeyRemoved(t,e,r)}},{key:"knownAttributeNames",get:function(){return Array.from(new Set(this.currentAttributeNames.concat(this.recordedAttributeNames)))}},{key:"currentAttributeNames",get:function(){return Array.from(this.element.attributes).map(function(t){return t.name})}},{key:"recordedAttributeNames",get:function(){return Array.from(this.stringMap.keys())}}]),t}(),V=function(){function t(e,r,n){(0,a._)(this,t),this.attributeObserver=new D(e,r,this),this.delegate=n,this.tokensByElement=new L}return(0,o._)(t,[{key:"started",get:function(){return this.attributeObserver.started}},{key:"start",value:function(){this.attributeObserver.start()}},{key:"pause",value:function(t){this.attributeObserver.pause(t)}},{key:"stop",value:function(){this.attributeObserver.stop()}},{key:"refresh",value:function(){this.attributeObserver.refresh()}},{key:"element",get:function(){return this.attributeObserver.element}},{key:"attributeName",get:function(){return this.attributeObserver.attributeName}},{key:"elementMatchedAttribute",value:function(t){this.tokensMatched(this.readTokensForElement(t))}},{key:"elementAttributeValueChanged",value:function(t){var e=(0,h._)(this.refreshTokensForElement(t),2),r=e[0],n=e[1];this.tokensUnmatched(r),this.tokensMatched(n)}},{key:"elementUnmatchedAttribute",value:function(t){this.tokensUnmatched(this.tokensByElement.getValuesForKey(t))}},{key:"tokensMatched",value:function(t){var e=this;t.forEach(function(t){return e.tokenMatched(t)})}},{key:"tokensUnmatched",value:function(t){var e=this;t.forEach(function(t){return e.tokenUnmatched(t)})}},{key:"tokenMatched",value:function(t){this.delegate.tokenMatched(t),this.tokensByElement.add(t.element,t)}},{key:"tokenUnmatched",value:function(t){this.delegate.tokenUnmatched(t),this.tokensByElement.delete(t.element,t)}},{key:"refreshTokensForElement",value:function(t){var e=this.tokensByElement.getValuesForKey(t),r=this.readTokensForElement(t),n=Array.from({length:Math.max(e.length,r.length)},function(t,n){return[e[n],r[n]]}).findIndex(function(t){var e,r,n=(0,h._)(t,2);return e=n[0],r=n[1],!e||!r||e.index!=r.index||e.content!=r.content});return -1==n?[[],[]]:[e.slice(n),r.slice(n)]}},{key:"readTokensForElement",value:function(t){var e=this.attributeName;return(t.getAttribute(e)||"").trim().split(/\s+/).filter(function(t){return t.length}).map(function(r,n){return{element:t,attributeName:e,content:r,index:n}})}}]),t}(),z=function(){function t(e,r,n){(0,a._)(this,t),this.tokenListObserver=new V(e,r,this),this.delegate=n,this.parseResultsByToken=new WeakMap,this.valuesByTokenByElement=new WeakMap}return(0,o._)(t,[{key:"started",get:function(){return this.tokenListObserver.started}},{key:"start",value:function(){this.tokenListObserver.start()}},{key:"stop",value:function(){this.tokenListObserver.stop()}},{key:"refresh",value:function(){this.tokenListObserver.refresh()}},{key:"element",get:function(){return this.tokenListObserver.element}},{key:"attributeName",get:function(){return this.tokenListObserver.attributeName}},{key:"tokenMatched",value:function(t){var e=t.element,r=this.fetchParseResultForToken(t).value;r&&(this.fetchValuesByTokenForElement(e).set(t,r),this.delegate.elementMatchedValue(e,r))}},{key:"tokenUnmatched",value:function(t){var e=t.element,r=this.fetchParseResultForToken(t).value;r&&(this.fetchValuesByTokenForElement(e).delete(t),this.delegate.elementUnmatchedValue(e,r))}},{key:"fetchParseResultForToken",value:function(t){var e=this.parseResultsByToken.get(t);return e||(e=this.parseToken(t),this.parseResultsByToken.set(t,e)),e}},{key:"fetchValuesByTokenForElement",value:function(t){var e=this.valuesByTokenByElement.get(t);return e||(e=new Map,this.valuesByTokenByElement.set(t,e)),e}},{key:"parseToken",value:function(t){try{return{value:this.delegate.parseValueForToken(t)}}catch(t){return{error:t}}}}]),t}(),W=function(){function t(e,r){(0,a._)(this,t),this.context=e,this.delegate=r,this.bindingsByAction=new Map}return(0,o._)(t,[{key:"start",value:function(){this.valueListObserver||(this.valueListObserver=new z(this.element,this.actionAttribute,this),this.valueListObserver.start())}},{key:"stop",value:function(){this.valueListObserver&&(this.valueListObserver.stop(),delete this.valueListObserver,this.disconnectAllActions())}},{key:"element",get:function(){return this.context.element}},{key:"identifier",get:function(){return this.context.identifier}},{key:"actionAttribute",get:function(){return this.schema.actionAttribute}},{key:"schema",get:function(){return this.context.schema}},{key:"bindings",get:function(){return Array.from(this.bindingsByAction.values())}},{key:"connectAction",value:function(t){var e=new C(this.context,t);this.bindingsByAction.set(t,e),this.delegate.bindingConnected(e)}},{key:"disconnectAction",value:function(t){var e=this.bindingsByAction.get(t);e&&(this.bindingsByAction.delete(t),this.delegate.bindingDisconnected(e))}},{key:"disconnectAllActions",value:function(){var t=this;this.bindings.forEach(function(e){return t.delegate.bindingDisconnected(e,!0)}),this.bindingsByAction.clear()}},{key:"parseValueForToken",value:function(t){var e=O.forToken(t,this.schema);if(e.identifier==this.identifier)return e}},{key:"elementMatchedValue",value:function(t,e){this.connectAction(e)}},{key:"elementUnmatchedValue",value:function(t,e){this.disconnectAction(e)}}]),t}(),H=function(){function t(e,r){(0,a._)(this,t),this.context=e,this.receiver=r,this.stringMapObserver=new N(this.element,this),this.valueDescriptorMap=this.controller.valueDescriptorMap}return(0,o._)(t,[{key:"start",value:function(){this.stringMapObserver.start(),this.invokeChangedCallbacksForDefaultValues()}},{key:"stop",value:function(){this.stringMapObserver.stop()}},{key:"element",get:function(){return this.context.element}},{key:"controller",get:function(){return this.context.controller}},{key:"getStringMapKeyForAttribute",value:function(t){if(t in this.valueDescriptorMap)return this.valueDescriptorMap[t].name}},{key:"stringMapKeyAdded",value:function(t,e){var r=this.valueDescriptorMap[e];this.hasValue(t)||this.invokeChangedCallback(t,r.writer(this.receiver[t]),r.writer(r.defaultValue))}},{key:"stringMapValueChanged",value:function(t,e,r){var n=this.valueDescriptorNameMap[e];null!==t&&(null===r&&(r=n.writer(n.defaultValue)),this.invokeChangedCallback(e,t,r))}},{key:"stringMapKeyRemoved",value:function(t,e,r){var n=this.valueDescriptorNameMap[t];this.hasValue(t)?this.invokeChangedCallback(t,n.writer(this.receiver[t]),r):this.invokeChangedCallback(t,n.writer(n.defaultValue),r)}},{key:"invokeChangedCallbacksForDefaultValues",value:function(){var t=!0,e=!1,r=void 0;try{for(var n,i=this.valueDescriptors[Symbol.iterator]();!(t=(n=i.next()).done);t=!0){var a=n.value,o=a.key,s=a.name,l=a.defaultValue,u=a.writer;void 0==l||this.controller.data.has(o)||this.invokeChangedCallback(s,u(l),void 0)}}catch(t){e=!0,r=t}finally{try{t||null==i.return||i.return()}finally{if(e)throw r}}}},{key:"invokeChangedCallback",value:function(t,e,r){var n=this.receiver["".concat(t,"Changed")];if("function"==typeof n){var i=this.valueDescriptorNameMap[t];try{var a=i.reader(e),o=r;r&&(o=i.reader(r)),n.call(this.receiver,a,o)}catch(t){throw t instanceof TypeError&&(t.message='Stimulus Value "'.concat(this.context.identifier,".").concat(i.name,'" - ').concat(t.message)),t}}}},{key:"valueDescriptors",get:function(){var t=this.valueDescriptorMap;return Object.keys(t).map(function(e){return t[e]})}},{key:"valueDescriptorNameMap",get:function(){var t=this,e={};return Object.keys(this.valueDescriptorMap).forEach(function(r){var n=t.valueDescriptorMap[r];e[n.name]=n}),e}},{key:"hasValue",value:function(t){var e=this.valueDescriptorNameMap[t],r="has".concat(k(e.name));return this.receiver[r]}}]),t}(),U=function(){function t(e,r){(0,a._)(this,t),this.context=e,this.delegate=r,this.targetsByName=new L}return(0,o._)(t,[{key:"start",value:function(){this.tokenListObserver||(this.tokenListObserver=new V(this.element,this.attributeName,this),this.tokenListObserver.start())}},{key:"stop",value:function(){this.tokenListObserver&&(this.disconnectAllTargets(),this.tokenListObserver.stop(),delete this.tokenListObserver)}},{key:"tokenMatched",value:function(t){var e=t.element,r=t.content;this.scope.containsElement(e)&&this.connectTarget(e,r)}},{key:"tokenUnmatched",value:function(t){var e=t.element,r=t.content;this.disconnectTarget(e,r)}},{key:"connectTarget",value:function(t,e){var r,n=this;this.targetsByName.has(e,t)||(this.targetsByName.add(e,t),null===(r=this.tokenListObserver)||void 0===r||r.pause(function(){return n.delegate.targetConnected(t,e)}))}},{key:"disconnectTarget",value:function(t,e){var r,n=this;this.targetsByName.has(e,t)&&(this.targetsByName.delete(e,t),null===(r=this.tokenListObserver)||void 0===r||r.pause(function(){return n.delegate.targetDisconnected(t,e)}))}},{key:"disconnectAllTargets",value:function(){var t=!0,e=!1,r=void 0,n=!0,i=!1,a=void 0;try{for(var o,s=this.targetsByName.keys[Symbol.iterator]();!(n=(o=s.next()).done);n=!0){var l=o.value;try{for(var u,c=this.targetsByName.getValuesForKey(l)[Symbol.iterator]();!(t=(u=c.next()).done);t=!0){var h=u.value;this.disconnectTarget(h,l)}}catch(t){e=!0,r=t}finally{try{t||null==c.return||c.return()}finally{if(e)throw r}}}}catch(t){i=!0,a=t}finally{try{n||null==s.return||s.return()}finally{if(i)throw a}}}},{key:"attributeName",get:function(){return"data-".concat(this.context.identifier,"-target")}},{key:"element",get:function(){return this.context.element}},{key:"scope",get:function(){return this.context.scope}}]),t}();function K(t,e){return Array.from(Y(t).reduce(function(t,r){var n;return(Array.isArray(n=r[e])?n:[]).forEach(function(e){return t.add(e)}),t},new Set))}function Y(t){for(var e=[];t;)e.push(t),t=Object.getPrototypeOf(t);return e.reverse()}var X=function(){function t(e,r){(0,a._)(this,t),this.started=!1,this.context=e,this.delegate=r,this.outletsByName=new L,this.outletElementsByName=new L,this.selectorObserverMap=new Map,this.attributeObserverMap=new Map}return(0,o._)(t,[{key:"start",value:function(){var t=this;this.started||(this.outletDefinitions.forEach(function(e){t.setupSelectorObserverForOutlet(e),t.setupAttributeObserverForOutlet(e)}),this.started=!0,this.dependentContexts.forEach(function(t){return t.refresh()}))}},{key:"refresh",value:function(){this.selectorObserverMap.forEach(function(t){return t.refresh()}),this.attributeObserverMap.forEach(function(t){return t.refresh()})}},{key:"stop",value:function(){this.started&&(this.started=!1,this.disconnectAllOutlets(),this.stopSelectorObservers(),this.stopAttributeObservers())}},{key:"stopSelectorObservers",value:function(){this.selectorObserverMap.size>0&&(this.selectorObserverMap.forEach(function(t){return t.stop()}),this.selectorObserverMap.clear())}},{key:"stopAttributeObservers",value:function(){this.attributeObserverMap.size>0&&(this.attributeObserverMap.forEach(function(t){return t.stop()}),this.attributeObserverMap.clear())}},{key:"selectorMatched",value:function(t,e,r){var n=r.outletName,i=this.getOutlet(t,n);i&&this.connectOutlet(i,t,n)}},{key:"selectorUnmatched",value:function(t,e,r){var n=r.outletName,i=this.getOutletFromMap(t,n);i&&this.disconnectOutlet(i,t,n)}},{key:"selectorMatchElement",value:function(t,e){var r=e.outletName,n=this.selector(r),i=this.hasOutlet(t,r),a=t.matches("[".concat(this.schema.controllerAttribute,"~=").concat(r,"]"));return!!n&&i&&a&&t.matches(n)}},{key:"elementMatchedAttribute",value:function(t,e){var r=this.getOutletNameFromOutletAttributeName(e);r&&this.updateSelectorObserverForOutlet(r)}},{key:"elementAttributeValueChanged",value:function(t,e){var r=this.getOutletNameFromOutletAttributeName(e);r&&this.updateSelectorObserverForOutlet(r)}},{key:"elementUnmatchedAttribute",value:function(t,e){var r=this.getOutletNameFromOutletAttributeName(e);r&&this.updateSelectorObserverForOutlet(r)}},{key:"connectOutlet",value:function(t,e,r){var n,i=this;this.outletElementsByName.has(r,e)||(this.outletsByName.add(r,t),this.outletElementsByName.add(r,e),null===(n=this.selectorObserverMap.get(r))||void 0===n||n.pause(function(){return i.delegate.outletConnected(t,e,r)}))}},{key:"disconnectOutlet",value:function(t,e,r){var n,i=this;this.outletElementsByName.has(r,e)&&(this.outletsByName.delete(r,t),this.outletElementsByName.delete(r,e),null===(n=this.selectorObserverMap.get(r))||void 0===n||n.pause(function(){return i.delegate.outletDisconnected(t,e,r)}))}},{key:"disconnectAllOutlets",value:function(){var t=!0,e=!1,r=void 0;try{for(var n,i=this.outletElementsByName.keys[Symbol.iterator]();!(t=(n=i.next()).done);t=!0){var a=n.value,o=!0,s=!1,l=void 0,u=!0,c=!1,h=void 0;try{for(var f,d=this.outletElementsByName.getValuesForKey(a)[Symbol.iterator]();!(u=(f=d.next()).done);u=!0){var p=f.value;try{for(var v,g=this.outletsByName.getValuesForKey(a)[Symbol.iterator]();!(o=(v=g.next()).done);o=!0){var y=v.value;this.disconnectOutlet(y,p,a)}}catch(t){s=!0,l=t}finally{try{o||null==g.return||g.return()}finally{if(s)throw l}}}}catch(t){c=!0,h=t}finally{try{u||null==d.return||d.return()}finally{if(c)throw h}}}}catch(t){e=!0,r=t}finally{try{t||null==i.return||i.return()}finally{if(e)throw r}}}},{key:"updateSelectorObserverForOutlet",value:function(t){var e=this.selectorObserverMap.get(t);e&&(e.selector=this.selector(t))}},{key:"setupSelectorObserverForOutlet",value:function(t){var e=this.selector(t),r=new R(document.body,e,this,{outletName:t});this.selectorObserverMap.set(t,r),r.start()}},{key:"setupAttributeObserverForOutlet",value:function(t){var e=this.attributeNameForOutletName(t),r=new D(this.scope.element,e,this);this.attributeObserverMap.set(t,r),r.start()}},{key:"selector",value:function(t){return this.scope.outlets.getSelectorForOutletName(t)}},{key:"attributeNameForOutletName",value:function(t){return this.scope.schema.outletAttributeForScope(this.identifier,t)}},{key:"getOutletNameFromOutletAttributeName",value:function(t){var e=this;return this.outletDefinitions.find(function(r){return e.attributeNameForOutletName(r)===t})}},{key:"outletDependencies",get:function(){var t=new L;return this.router.modules.forEach(function(e){K(e.definition.controllerConstructor,"outlets").forEach(function(r){return t.add(r,e.identifier)})}),t}},{key:"outletDefinitions",get:function(){return this.outletDependencies.getKeysForValue(this.identifier)}},{key:"dependentControllerIdentifiers",get:function(){return this.outletDependencies.getValuesForKey(this.identifier)}},{key:"dependentContexts",get:function(){var t=this.dependentControllerIdentifiers;return this.router.contexts.filter(function(e){return t.includes(e.identifier)})}},{key:"hasOutlet",value:function(t,e){return!!this.getOutlet(t,e)||!!this.getOutletFromMap(t,e)}},{key:"getOutlet",value:function(t,e){return this.application.getControllerForElementAndIdentifier(t,e)}},{key:"getOutletFromMap",value:function(t,e){return this.outletsByName.getValuesForKey(e).find(function(e){return e.element===t})}},{key:"scope",get:function(){return this.context.scope}},{key:"schema",get:function(){return this.context.schema}},{key:"identifier",get:function(){return this.context.identifier}},{key:"application",get:function(){return this.context.application}},{key:"router",get:function(){return this.application.router}}]),t}(),q=function(){function t(e,r){var n=this;(0,a._)(this,t),this.logDebugActivity=function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};e=Object.assign({identifier:n.identifier,controller:n.controller,element:n.element},e),n.application.logDebugActivity(n.identifier,t,e)},this.module=e,this.scope=r,this.controller=new e.controllerConstructor(this),this.bindingObserver=new W(this,this.dispatcher),this.valueObserver=new H(this,this.controller),this.targetObserver=new U(this,this),this.outletObserver=new X(this,this);try{this.controller.initialize(),this.logDebugActivity("initialize")}catch(t){this.handleError(t,"initializing controller")}}return(0,o._)(t,[{key:"connect",value:function(){this.bindingObserver.start(),this.valueObserver.start(),this.targetObserver.start(),this.outletObserver.start();try{this.controller.connect(),this.logDebugActivity("connect")}catch(t){this.handleError(t,"connecting controller")}}},{key:"refresh",value:function(){this.outletObserver.refresh()}},{key:"disconnect",value:function(){try{this.controller.disconnect(),this.logDebugActivity("disconnect")}catch(t){this.handleError(t,"disconnecting controller")}this.outletObserver.stop(),this.targetObserver.stop(),this.valueObserver.stop(),this.bindingObserver.stop()}},{key:"application",get:function(){return this.module.application}},{key:"identifier",get:function(){return this.module.identifier}},{key:"schema",get:function(){return this.application.schema}},{key:"dispatcher",get:function(){return this.application.dispatcher}},{key:"element",get:function(){return this.scope.element}},{key:"parentElement",get:function(){return this.element.parentElement}},{key:"handleError",value:function(t,e){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};r=Object.assign({identifier:this.identifier,controller:this.controller,element:this.element},r),this.application.handleError(t,"Error ".concat(e),r)}},{key:"targetConnected",value:function(t,e){this.invokeControllerMethod("".concat(e,"TargetConnected"),t)}},{key:"targetDisconnected",value:function(t,e){this.invokeControllerMethod("".concat(e,"TargetDisconnected"),t)}},{key:"outletConnected",value:function(t,e,r){this.invokeControllerMethod("".concat(x(r),"OutletConnected"),t,e)}},{key:"outletDisconnected",value:function(t,e,r){this.invokeControllerMethod("".concat(x(r),"OutletDisconnected"),t,e)}},{key:"invokeControllerMethod",value:function(t){for(var e=arguments.length,r=Array(e>1?e-1:0),n=1;n0&&void 0!==arguments[0]?arguments[0]:document.documentElement,r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:ts,n=this;(0,a._)(this,t),this.logger=console,this.debug=!1,this.logDebugActivity=function(t,e){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};n.debug&&n.logFormattedMessage(t,e,r)},this.element=e,this.schema=r,this.dispatcher=new y(this),this.router=new to(this),this.actionDescriptorFilters=Object.assign({},m)}return(0,o._)(t,[{key:"start",value:function(){var t=this;return(0,i._)(function(){return(0,v._)(this,function(e){switch(e.label){case 0:return[4,new Promise(function(t){"loading"==document.readyState?document.addEventListener("DOMContentLoaded",function(){return t()}):t()})];case 1:return e.sent(),t.logDebugActivity("application","starting"),t.dispatcher.start(),t.router.start(),t.logDebugActivity("application","start"),[2]}})})()}},{key:"stop",value:function(){this.logDebugActivity("application","stopping"),this.dispatcher.stop(),this.router.stop(),this.logDebugActivity("application","stop")}},{key:"register",value:function(t,e){this.load({identifier:t,controllerConstructor:e})}},{key:"registerActionOption",value:function(t,e){this.actionDescriptorFilters[t]=e}},{key:"load",value:function(t){for(var e=this,r=arguments.length,n=Array(r>1?r-1:0),i=1;i1?r-1:0),i=1;i2&&void 0!==arguments[2]?arguments[2]:{};r=Object.assign({application:this},r),this.logger.groupCollapsed("".concat(t," #").concat(e)),this.logger.log("details:",Object.assign({},r)),this.logger.groupEnd()}}],[{key:"start",value:function(t,e){var r=new this(t,e);return r.start(),r}}]),t}();function tc(t,e,r){return t.application.getControllerForElementAndIdentifier(e,r)}function th(t,e,r){var n=tc(t,e,r);return n||((t.application.router.proposeToConnectScopeForElementAndIdentifier(e,r),n=tc(t,e,r))?n:void 0)}function tf(t,e){var r,n,i,a,o,s=(0,h._)(t,2);return n=(r={controller:e,token:s[0],typeDefinition:s[1]}).token,i=r.typeDefinition,a="".concat(w(n),"-value"),{type:o=function(t){var e=t.controller,r=t.token,n=t.typeDefinition,i=function(t){var e=t.controller,r=t.token,n=t.typeObject,i=null!=n.type,a=null!=n.default,o=td(n.type),s=tp(t.typeObject.default);if(i&&!a)return o;if(!i&&a)return s;if(o!==s){var l=e?"".concat(e,".").concat(r):r;throw Error('The specified default value for the Stimulus Value "'.concat(l,'" must match the defined type "').concat(o,'". The provided default value of "').concat(n.default,'" is of type "').concat(s,'".'))}if(i&&a)return o}({controller:e,token:r,typeObject:n}),a=tp(n),o=td(n),s=i||a||o;if(s)return s;var l=e?"".concat(e,".").concat(n):r;throw Error('Unknown value type "'.concat(l,'" for "').concat(r,'" value'))}(r),key:a,name:_(a),get defaultValue(){return function(t){var e=td(t);if(e)return tv[e];var r=M(t,"default"),n=M(t,"type");if(r)return t.default;if(n){var i=td(t.type);if(i)return tv[i]}return t}(i)},get hasCustomDefaultValue(){return void 0!==tp(i)},reader:tg[o],writer:ty[o]||ty.default}}function td(t){switch(t){case Array:return"array";case Boolean:return"boolean";case Number:return"number";case Object:return"object";case String:return"string"}}function tp(t){switch(void 0===t?"undefined":(0,d._)(t)){case"boolean":return"boolean";case"number":return"number";case"string":return"string"}return Array.isArray(t)?"array":"[object Object]"===Object.prototype.toString.call(t)?"object":void 0}var tv={get array(){return[]},boolean:!1,number:0,get object(){return{}},string:""},tg={array:function(t){var e=JSON.parse(t);if(!Array.isArray(e))throw TypeError('expected value of type "array" but instead got value "'.concat(t,'" of type "').concat(tp(e),'"'));return e},boolean:function(t){return!("0"==t||"false"==String(t).toLowerCase())},number:function(t){return Number(t.replace(/_/g,""))},object:function(t){var e=JSON.parse(t);if(null===e||"object"!=typeof e||Array.isArray(e))throw TypeError('expected value of type "object" but instead got value "'.concat(t,'" of type "').concat(tp(e),'"'));return e},string:function(t){return t}},ty={default:function(t){return"".concat(t)},array:tm,object:tm};function tm(t){return JSON.stringify(t)}var tb=function(){function t(e){(0,a._)(this,t),this.context=e}return(0,o._)(t,[{key:"application",get:function(){return this.context.application}},{key:"scope",get:function(){return this.context.scope}},{key:"element",get:function(){return this.scope.element}},{key:"identifier",get:function(){return this.scope.identifier}},{key:"targets",get:function(){return this.scope.targets}},{key:"outlets",get:function(){return this.scope.outlets}},{key:"classes",get:function(){return this.scope.classes}},{key:"data",get:function(){return this.scope.data}},{key:"initialize",value:function(){}},{key:"connect",value:function(){}},{key:"disconnect",value:function(){}},{key:"dispatch",value:function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},r=e.target,n=void 0===r?this.element:r,i=e.detail,a=e.prefix,o=void 0===a?this.identifier:a,s=e.bubbles,l=e.cancelable,u=new CustomEvent(o?"".concat(o,":").concat(t):t,{detail:void 0===i?{}:i,bubbles:void 0===s||s,cancelable:void 0===l||l});return n.dispatchEvent(u),u}}],[{key:"shouldLoad",get:function(){return!0}},{key:"afterLoad",value:function(t,e){}}]),t}();tb.blessings=[function(t){return K(t,"classes").reduce(function(t,e){var r;return Object.assign(t,(r={},(0,s._)(r,"".concat(e,"Class"),{get:function(){var t=this.classes;if(t.has(e))return t.get(e);var r=t.getAttributeName(e);throw Error('Missing attribute "'.concat(r,'"'))}}),(0,s._)(r,"".concat(e,"Classes"),{get:function(){return this.classes.getAll(e)}}),(0,s._)(r,"has".concat(k(e),"Class"),{get:function(){return this.classes.has(e)}}),r))},{})},function(t){return K(t,"targets").reduce(function(t,e){var r;return Object.assign(t,(r={},(0,s._)(r,"".concat(e,"Target"),{get:function(){var t=this.targets.find(e);if(t)return t;throw Error('Missing target element "'.concat(e,'" for "').concat(this.identifier,'" controller'))}}),(0,s._)(r,"".concat(e,"Targets"),{get:function(){return this.targets.findAll(e)}}),(0,s._)(r,"has".concat(k(e),"Target"),{get:function(){return this.targets.has(e)}}),r))},{})},function(t){var e,r=(e="values",Y(t).reduce(function(t,r){var n;return t.push.apply(t,(0,f._)((n=r[e])?Object.keys(n).map(function(t){return[t,n[t]]}):[])),t},[]));return r.reduce(function(t,e){var r,n,i,a,o,l;return Object.assign(t,(i=(n=tf(e,void 0)).key,a=n.name,o=n.reader,l=n.writer,r={},(0,s._)(r,a,{get:function(){var t=this.data.get(i);return null!==t?o(t):n.defaultValue},set:function(t){void 0===t?this.data.delete(i):this.data.set(i,l(t))}}),(0,s._)(r,"has".concat(k(a)),{get:function(){return this.data.has(i)||n.hasCustomDefaultValue}}),r))},{valueDescriptorMap:{get:function(){var t=this;return r.reduce(function(e,r){var n=tf(r,t.identifier),i=t.data.getAttributeNameForKey(n.key);return Object.assign(e,(0,s._)({},i,n))},{})}}})},function(t){return K(t,"outlets").reduce(function(t,e){var r,n;return Object.assign(t,(n=x(e),r={},(0,s._)(r,"".concat(n,"Outlet"),{get:function(){var t=this.outlets.find(e),r=this.outlets.getSelectorForOutletName(e);if(t){var n=th(this,t,e);if(n)return n;throw Error('The provided outlet element is missing an outlet controller "'.concat(e,'" instance for host controller "').concat(this.identifier,'"'))}throw Error('Missing outlet element "'.concat(e,'" for host controller "').concat(this.identifier,'". Stimulus couldn\'t find a matching outlet element using selector "').concat(r,'".'))}}),(0,s._)(r,"".concat(n,"Outlets"),{get:function(){var t=this,r=this.outlets.findAll(e);return r.length>0?r.map(function(r){var n=th(t,r,e);if(n)return n;console.warn('The provided outlet element is missing an outlet controller "'.concat(e,'" instance for host controller "').concat(t.identifier,'"'),r)}).filter(function(t){return t}):[]}}),(0,s._)(r,"".concat(n,"OutletElement"),{get:function(){var t=this.outlets.find(e),r=this.outlets.getSelectorForOutletName(e);if(t)return t;throw Error('Missing outlet element "'.concat(e,'" for host controller "').concat(this.identifier,'". Stimulus couldn\'t find a matching outlet element using selector "').concat(r,'".'))}}),(0,s._)(r,"".concat(n,"OutletElements"),{get:function(){return this.outlets.findAll(e)}}),(0,s._)(r,"has".concat(k(n),"Outlet"),{get:function(){return this.outlets.has(e)}}),r))},{})}],tb.targets=[],tb.outlets=[],tb.values={}},{"@swc/helpers/_/_async_to_generator":"6Tpxj","@swc/helpers/_/_class_call_check":"2HOGN","@swc/helpers/_/_create_class":"8oe8p","@swc/helpers/_/_define_property":"27c3O","@swc/helpers/_/_get":"6FgjI","@swc/helpers/_/_get_prototype_of":"4Pl3E","@swc/helpers/_/_inherits":"7gHjg","@swc/helpers/_/_sliced_to_array":"hefcy","@swc/helpers/_/_to_consumable_array":"4oNkS","@swc/helpers/_/_type_of":"2bRX5","@swc/helpers/_/_create_super":"a37Ru","@swc/helpers/_/_ts_generator":"lwj56","@parcel/transformer-js/src/esmodule-helpers.js":"kPSB8"}],"6Tpxj":[function(t,e,r){var n=t("@parcel/transformer-js/src/esmodule-helpers.js");function i(t,e,r,n,i,a,o){try{var s=t[a](o),l=s.value}catch(t){r(t);return}s.done?e(l):Promise.resolve(l).then(n,i)}function a(t){return function(){var e=this,r=arguments;return new Promise(function(n,a){var o=t.apply(e,r);function s(t){i(o,n,a,s,l,"next",t)}function l(t){i(o,n,a,s,l,"throw",t)}s(void 0)})}}n.defineInteropFlag(r),n.export(r,"_async_to_generator",function(){return a}),n.export(r,"_",function(){return a})},{"@parcel/transformer-js/src/esmodule-helpers.js":"kPSB8"}],kPSB8:[function(t,e,r){r.interopDefault=function(t){return t&&t.__esModule?t:{default:t}},r.defineInteropFlag=function(t){Object.defineProperty(t,"__esModule",{value:!0})},r.exportAll=function(t,e){return Object.keys(t).forEach(function(r){"default"===r||"__esModule"===r||Object.prototype.hasOwnProperty.call(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:function(){return t[r]}})}),e},r.export=function(t,e,r){Object.defineProperty(t,e,{enumerable:!0,get:r})}},{}],"2HOGN":[function(t,e,r){var n=t("@parcel/transformer-js/src/esmodule-helpers.js");function i(t,e){if(!(t instanceof e))throw TypeError("Cannot call a class as a function")}n.defineInteropFlag(r),n.export(r,"_class_call_check",function(){return i}),n.export(r,"_",function(){return i})},{"@parcel/transformer-js/src/esmodule-helpers.js":"kPSB8"}],"8oe8p":[function(t,e,r){var n=t("@parcel/transformer-js/src/esmodule-helpers.js");function i(t,e){for(var r=0;rt.length)&&(e=t.length);for(var r=0,n=Array(e);re.indexOf(n)&&(r[n]=t[n]);if(null!=t&&"function"==typeof Object.getOwnPropertySymbols)for(var i=0,n=Object.getOwnPropertySymbols(t);ie.indexOf(n[i])&&Object.prototype.propertyIsEnumerable.call(t,n[i])&&(r[n[i]]=t[n[i]]);return r}function u(t,e,r,n){var i,a=arguments.length,o=a<3?e:null===n?n=Object.getOwnPropertyDescriptor(e,r):n;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(t,e,r,n);else for(var s=t.length-1;s>=0;s--)(i=t[s])&&(o=(a<3?i(o):a>3?i(e,r,o):i(e,r))||o);return a>3&&o&&Object.defineProperty(e,r,o),o}function c(t,e){return function(r,n){e(r,n,t)}}function h(t,e,r,n,i,a){function o(t){if(void 0!==t&&"function"!=typeof t)throw TypeError("Function expected");return t}for(var s,l=n.kind,u="getter"===l?"get":"setter"===l?"set":"value",c=!e&&t?n.static?t:t.prototype:null,h=e||(c?Object.getOwnPropertyDescriptor(c,n.name):{}),f=!1,d=r.length-1;d>=0;d--){var p={};for(var v in n)p[v]="access"===v?{}:n[v];for(var v in n.access)p.access[v]=n.access[v];p.addInitializer=function(t){if(f)throw TypeError("Cannot add initializers after decoration has completed");a.push(o(t||null))};var g=(0,r[d])("accessor"===l?{get:h.get,set:h.set}:h[u],p);if("accessor"===l){if(void 0===g)continue;if(null===g||"object"!=typeof g)throw TypeError("Object expected");(s=o(g.get))&&(h.get=s),(s=o(g.set))&&(h.set=s),(s=o(g.init))&&i.unshift(s)}else(s=o(g))&&("field"===l?i.unshift(s):h[u]=s)}c&&Object.defineProperty(c,n.name,h),f=!0}function f(t,e,r){for(var n=arguments.length>2,i=0;i0&&i[i.length-1])&&(6===s[0]||2===s[0])){o=0;continue}if(3===s[0]&&(!i||s[1]>i[0]&&s[1]=t.length&&(t=void 0),{value:t&&t[n++],done:!t}}};throw TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")}function x(t,e){var r="function"==typeof Symbol&&t[Symbol.iterator];if(!r)return t;var n,i,a=r.call(t),o=[];try{for(;(void 0===e||e-- >0)&&!(n=a.next()).done;)o.push(n.value)}catch(t){i={error:t}}finally{try{n&&!n.done&&(r=a.return)&&r.call(a)}finally{if(i)throw i.error}}return o}function k(){for(var t=[],e=0;e1||s(t,e)})})}function s(t,e){try{var r;(r=i[t](e)).value instanceof S?Promise.resolve(r.value.v).then(l,u):c(a[0][2],r)}catch(t){c(a[0][3],t)}}function l(t){s("next",t)}function u(t){s("throw",t)}function c(t,e){t(e),a.shift(),a.length&&s(a[0][0],a[0][1])}}function A(t){var e,r;return e={},n("next"),n("throw",function(t){throw t}),n("return"),e[Symbol.iterator]=function(){return this},e;function n(n,i){e[n]=t[n]?function(e){return(r=!r)?{value:S(t[n](e)),done:!1}:i?i(e):e}:i}}function E(t){if(!Symbol.asyncIterator)throw TypeError("Symbol.asyncIterator is not defined.");var e,r=t[Symbol.asyncIterator];return r?r.call(t):(t=_(t),e={},n("next"),n("throw"),n("return"),e[Symbol.asyncIterator]=function(){return this},e);function n(r){e[r]=t[r]&&function(e){return new Promise(function(n,i){!function(t,e,r,n){Promise.resolve(n).then(function(e){t({value:e,done:r})},e)}(n,i,(e=t[r](e)).done,e.value)})}}}function C(t,e){return Object.defineProperty?Object.defineProperty(t,"raw",{value:e}):t.raw=e,t}var P=Object.create?function(t,e){Object.defineProperty(t,"default",{enumerable:!0,value:e})}:function(t,e){t.default=e};function D(t){if(t&&t.__esModule)return t;var e={};if(null!=t)for(var r in t)"default"!==r&&Object.prototype.hasOwnProperty.call(t,r)&&m(e,t,r);return P(e,t),e}function j(t){return t&&t.__esModule?t:{default:t}}function T(t,e,r,n){if("a"===r&&!n)throw TypeError("Private accessor was defined without a getter");if("function"==typeof e?t!==e||!n:!e.has(t))throw TypeError("Cannot read private member from an object whose class did not declare it");return"m"===r?n:"a"===r?n.call(t):n?n.value:e.get(t)}function F(t,e,r,n,i){if("m"===n)throw TypeError("Private method is not writable");if("a"===n&&!i)throw TypeError("Private accessor was defined without a setter");if("function"==typeof e?t!==e||!i:!e.has(t))throw TypeError("Cannot write private member to an object whose class did not declare it");return"a"===n?i.call(t,r):i?i.value=r:e.set(t,r),r}function I(t,e){if(null===e||"object"!=typeof e&&"function"!=typeof e)throw TypeError("Cannot use 'in' operator on non-object");return"function"==typeof t?e===t:t.has(e)}function L(t,e,r){if(null!=e){var n;if("object"!=typeof e&&"function"!=typeof e)throw TypeError("Object expected.");if(r){if(!Symbol.asyncDispose)throw TypeError("Symbol.asyncDispose is not defined.");n=e[Symbol.asyncDispose]}if(void 0===n){if(!Symbol.dispose)throw TypeError("Symbol.dispose is not defined.");n=e[Symbol.dispose]}if("function"!=typeof n)throw TypeError("Object not disposable.");t.stack.push({value:e,dispose:n,async:r})}else r&&t.stack.push({async:!0});return e}var B="function"==typeof SuppressedError?SuppressedError:function(t,e,r){var n=Error(r);return n.name="SuppressedError",n.error=t,n.suppressed=e,n};function R(t){function e(e){t.error=t.hasError?new B(e,t.error,"An error was suppressed during disposal."):e,t.hasError=!0}return function r(){for(;t.stack.length;){var n=t.stack.pop();try{var i=n.dispose&&n.dispose.call(n.value);if(n.async)return Promise.resolve(i).then(r,function(t){return e(t),r()})}catch(t){e(t)}}if(t.hasError)throw t.error}()}r.default={__extends:o,__assign:s,__rest:l,__decorate:u,__param:c,__metadata:v,__awaiter:g,__generator:y,__createBinding:m,__exportStar:b,__values:_,__read:x,__spread:k,__spreadArrays:w,__spreadArray:M,__await:S,__asyncGenerator:O,__asyncDelegator:A,__asyncValues:E,__makeTemplateObject:C,__importStar:D,__importDefault:j,__classPrivateFieldGet:T,__classPrivateFieldSet:F,__classPrivateFieldIn:I,__addDisposableResource:L,__disposeResources:R}},{"@swc/helpers/_/_type_of":"2bRX5","@parcel/transformer-js/src/esmodule-helpers.js":"kPSB8"}],"78XDv":[function(t,e,r){var n,i=t("@parcel/transformer-js/src/esmodule-helpers.js");i.defineInteropFlag(r),i.export(r,"default",function(){return m});var a=t("@swc/helpers/_/_assert_this_initialized"),o=t("@swc/helpers/_/_class_call_check"),s=t("@swc/helpers/_/_create_class"),l=t("@swc/helpers/_/_define_property"),u=t("@swc/helpers/_/_inherits"),c=t("@swc/helpers/_/_to_consumable_array"),h=t("@swc/helpers/_/_create_super"),f=t("@hotwired/stimulus"),d=t("../chart_plugins/corsair_plugin"),p=i.interopDefault(d),v=t("chart.js"),g=t("color"),y=i.interopDefault(g);(n=v.Chart).register.apply(n,(0,c._)(v.registerables));var m=function(t){(0,u._)(r,t);var e=(0,h._)(r);function r(){var t;return(0,o._)(this,r),t=e.apply(this,arguments),(0,l._)((0,a._)(t),"metricGroups",[{metrics:["views","visitors","sessions"],format:"int"},{metrics:["clicks"],format:"int"},{metrics:["average_session_duration"],format:"time"},{metrics:["bounce_rate"],format:"percent"},{metrics:["views_per_session"],format:"float"},{metrics:["wc_orders","wc_refunds"],format:"int"},{metrics:["wc_gross_sales","wc_refunded_amount","wc_net_sales"],format:"whole_currency"},{metrics:["wc_conversion_rate"],format:"percent"},{metrics:["wc_earnings_per_visitor"],format:"currency"},{metrics:["wc_average_order_volume"],format:"whole_currency"},{metrics:["form_submissions"],prefix_to_include:"form_submissions_for_",format:"int"},{metrics:["form_conversion_rate"],prefix_to_include:"form_conversion_rate_for_",format:"percent"}]),(0,l._)((0,a._)(t),"tooltipLabel",function(e){return"function"==typeof e.dataset.tooltipLabel?e.dataset.tooltipLabel(e):e.dataset.label+": "+t.formatValueForMetric(e.dataset.id,e.raw)}),t}return(0,s._)(r,[{key:"getLocale",value:function(){try{return new Intl.NumberFormat(this.localeValue),this.localeValue}catch(t){return"en-US"}}},{key:"hasSecondaryMetric",value:function(){return this.hasSecondaryChartMetricIdValue&&this.secondaryChartMetricIdValue&&"no_comparison"!==this.secondaryChartMetricIdValue}},{key:"tooltipTitle",value:function(t){return JSON.parse(t[0].label).tooltipLabel}},{key:"getGroupByMetricId",value:function(t){return this.metricGroups.find(function(e){return e.metrics.includes(t)||e.prefix_to_include&&t.startsWith(e.prefix_to_include)})}},{key:"formatValueForMetric",value:function(t,e){switch(this.getGroupByMetricId(t).format){case"whole_currency":return new Intl.NumberFormat(this.localeValue,{style:"currency",currency:this.currencyValue,currencyDisplay:"narrowSymbol",minimumFractionDigits:0,maximumFractionDigits:0}).format(e/100);case"currency":return new Intl.NumberFormat(this.localeValue,{style:"currency",currency:this.currencyValue,currencyDisplay:"narrowSymbol",minimumFractionDigits:2,maximumFractionDigits:2}).format(e/100);case"percent":return new Intl.NumberFormat(this.localeValue,{style:"percent",maximumFractionDigits:2}).format(e/100);case"time":var r=Math.floor(e/60),n=e%60;return r.toString().padStart(2,"0")+":"+n.toString().padStart(2,"0");case"int":return new Intl.NumberFormat(this.localeValue,{maximumFractionDigits:0}).format(e);case"float":return new Intl.NumberFormat(this.localeValue,{maximumFractionDigits:2}).format(e);default:return e}}},{key:"tickText",value:function(t){return JSON.parse(this.getLabelForValue(t)).tick}},{key:"updateMetricSelectWidth",value:function(t){var e=t.options[t.selectedIndex];this.adaptiveWidthSelectTarget[0].innerHTML=e.innerText,t.style.width=this.adaptiveWidthSelectTarget.getBoundingClientRect().width+"px",t.parentElement.classList.add("visible")}},{key:"hasSharedAxis",value:function(t,e){var r=this.getGroupByMetricId(t),n=this.getGroupByMetricId(e);return JSON.stringify(r)===JSON.stringify(n)}},{key:"connect",value:function(){this.isPreviewValue||(this.updateMetricSelectWidth(this.primaryMetricSelectTarget),1===this.hasMultipleDatasetsValue&&this.updateMetricSelectWidth(this.secondaryMetricSelectTarget)),this.createChart(),this.updateChart()}},{key:"changePrimaryMetric",value:function(t){var e=t.target;this.primaryChartMetricIdValue=e.value,this.primaryChartMetricNameValue=e.options[e.selectedIndex].innerText,this.updateMetricSelectWidth(e),this.updateChart(),Array.from(this.secondaryMetricSelectTarget.querySelectorAll("option")).forEach(function(t){t.toggleAttribute("disabled",t.value===e.value)}),document.dispatchEvent(new CustomEvent("iawp:changePrimaryChartMetric",{detail:{primaryChartMetricId:e.value}}))}},{key:"changeSecondaryMetric",value:function(t){var e=t.target,r=""!==e.value;r?(this.secondaryChartMetricIdValue=e.value,this.secondaryChartMetricNameValue=e.options[e.selectedIndex].innerText):(this.secondaryChartMetricIdValue="",this.secondaryChartMetricNameValue=""),this.updateMetricSelectWidth(e),this.updateChart(),Array.from(this.primaryMetricSelectTarget.querySelectorAll("option")).forEach(function(t){t.toggleAttribute("disabled",t.value===e.value)}),document.dispatchEvent(new CustomEvent("iawp:changeSecondaryChartMetric",{detail:{secondaryChartMetricId:r?e.value:null}}))}},{key:"updateChart",value:function(){var t=window.iawp_chart.data.datasets[0];t.id=this.primaryChartMetricIdValue,t.data=this.dataValue[this.primaryChartMetricIdValue],t.label=this.primaryChartMetricNameValue;var e=t.data.every(function(t){return 0===t});if(window.iawp_chart.options.scales.y.suggestedMax=e?10:null,window.iawp_chart.options.scales.y.beginAtZero="bounce_rate"!==t.id,window.iawp_chart.data.datasets.length>1&&window.iawp_chart.data.datasets.pop(),this.hasSecondaryMetric()){var r=this.secondaryChartMetricIdValue,n=this.secondaryChartMetricNameValue,i=this.dataValue[r],a=this.hasSharedAxis(this.primaryChartMetricIdValue,r)?"y":"defaultRight";window.iawp_chart.data.datasets.push(this.makeDataset(r,n,i,a,"rgba(246,157,10)"));var o=i.every(function(t){return 0===t});window.iawp_chart.options.scales.defaultRight.suggestedMax=o?10:null,window.iawp_chart.options.scales.defaultRight.beginAtZero="bounce_rate"!==r}window.iawp_chart.update()}},{key:"makeDataset",value:function(t,e,r,n,i){var a=arguments.length>5&&void 0!==arguments[5]&&arguments[5],o=(0,y.default)(i);return{id:t,label:e,data:r,borderColor:o.string(),backgroundColor:o.alpha(.1).string(),pointBackgroundColor:o.string(),tension:.4,yAxisID:n,fill:!0,order:a?1:0}}},{key:"shouldUseDarkMode",value:function(){return document.body.classList.contains("iawp-dark-mode")&&!this.isPreviewValue}},{key:"createChart",value:function(){var t=this;v.Chart.defaults.font.family='-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"';var e=document.getElementById("independent-analytics-chart"),r={type:"line",data:{labels:this.labelsValue,datasets:[this.makeDataset(this.primaryChartMetricIdValue,this.primaryChartMetricNameValue,this.dataValue[this.primaryChartMetricIdValue],"y","rgba(108,70,174)",!0)].filter(function(t){return null!==t})},options:{locale:this.getLocale(),interaction:{intersect:!1,mode:"index"},scales:{y:{grid:{color:this.shouldUseDarkMode()?"#676173":"#DEDAE6",borderColor:"#DEDAE6",tickColor:"#DEDAE6",display:!0,drawOnChartArea:!0,borderDash:[2,4]},beginAtZero:!0,suggestedMax:null,ticks:{color:this.shouldUseDarkMode()?"#ffffff":"#6D6A73",font:{size:14,weight:400},precision:0,callback:function(e,r,n){return t.formatValueForMetric(t.primaryChartMetricIdValue,e)}}},defaultRight:{position:"right",display:"auto",grid:{color:this.shouldUseDarkMode()?"#9a95a6":"#DEDAE6",borderColor:"#DEDAE6",tickColor:"#DEDAE6",display:!0,drawOnChartArea:!1,borderDash:[2,4]},beginAtZero:!0,suggestedMax:null,ticks:{color:this.shouldUseDarkMode()?"#ffffff":"#6D6A73",font:{size:14,weight:400},precision:0,callback:function(e,r,n){return t.hasSecondaryMetric()?t.formatValueForMetric(t.secondaryChartMetricIdValue,e):e}}},x:{grid:{borderColor:"#DEDAE6",tickColor:"#DEDAE6",display:!0,drawOnChartArea:!1},ticks:{color:this.shouldUseDarkMode()?"#ffffff":"#6D6A73",autoSkip:!0,autoSkipPadding:16,maxRotation:0,font:{size:14,weight:400},callback:this.tickText}}},plugins:{mode:String,legend:{display:!1},corsair:{dash:[2,4],color:"#777",width:1},tooltip:{itemSort:function(t,e){return t.datasetIndexs||ca){t.corsair={x:u,y:c,draw:!1},t.draw();return}t.corsair={x:u,y:c,draw:!0},t.draw()}},afterDatasetsDraw:function(t,e,r){if(!r.disabled){var n=t.ctx,i=t.chartArea,a=i.top,o=i.bottom;i.left,i.right;var s=t.corsair,l=s.x;s.y,s.draw&&(l=t.tooltip.caretX,n.lineWidth=r.width||0,n.setLineDash(r.dash||[]),n.strokeStyle=r.color||"black",n.save(),n.beginPath(),n.moveTo(l,o),n.lineTo(l,a),n.stroke(),n.restore(),n.setLineDash([]))}}}},{}],"1stGI":[function(t,e,r){/*!
* Chart.js v3.9.1
* https://www.chartjs.org
* (c) 2022 Chart.js Contributors
* Released under the MIT License
*/var n=t("@parcel/transformer-js/src/esmodule-helpers.js");n.defineInteropFlag(r),n.export(r,"defaults",function(){return m.d}),n.export(r,"Animation",function(){return k}),n.export(r,"Animations",function(){return M}),n.export(r,"ArcElement",function(){return en}),n.export(r,"BarController",function(){return z}),n.export(r,"BarElement",function(){return eb}),n.export(r,"BasePlatform",function(){return tS}),n.export(r,"BasicPlatform",function(){return tO}),n.export(r,"BubbleController",function(){return W}),n.export(r,"CategoryScale",function(){return eZ}),n.export(r,"Chart",function(){return t7}),n.export(r,"DatasetController",function(){return I}),n.export(r,"Decimation",function(){return ew}),n.export(r,"DomPlatform",function(){return tV}),n.export(r,"DoughnutController",function(){return H}),n.export(r,"Element",function(){return q}),n.export(r,"Filler",function(){return eF}),n.export(r,"Interaction",function(){return tp}),n.export(r,"Legend",function(){return eB}),n.export(r,"LineController",function(){return U}),n.export(r,"LineElement",function(){return eh}),n.export(r,"LinearScale",function(){return e2}),n.export(r,"LogarithmicScale",function(){return e3}),n.export(r,"PieController",function(){return Y}),n.export(r,"PointElement",function(){return ed}),n.export(r,"PolarAreaController",function(){return K}),n.export(r,"RadarController",function(){return X}),n.export(r,"RadialLinearScale",function(){return e7}),n.export(r,"Scale",function(){return tr}),n.export(r,"ScatterController",function(){return ta}),n.export(r,"SubTitle",function(){return ez}),n.export(r,"Ticks",function(){return Q}),n.export(r,"TimeScale",function(){return ro}),n.export(r,"TimeSeriesScale",function(){return rl}),n.export(r,"Title",function(){return eN}),n.export(r,"Tooltip",function(){return eG}),n.export(r,"_adapters",function(){return tu}),n.export(r,"_detectPlatform",function(){return tz}),n.export(r,"animator",function(){return b}),n.export(r,"controllers",function(){return to}),n.export(r,"elements",function(){return e_}),n.export(r,"layouts",function(){return tM}),n.export(r,"plugins",function(){return eJ}),n.export(r,"registerables",function(){return rc}),n.export(r,"registry",function(){return ti}),n.export(r,"scales",function(){return ru});var i=t("@swc/helpers/_/_assert_this_initialized"),a=t("@swc/helpers/_/_class_call_check"),o=t("@swc/helpers/_/_create_class"),s=t("@swc/helpers/_/_define_property"),l=t("@swc/helpers/_/_get"),u=t("@swc/helpers/_/_get_prototype_of"),c=t("@swc/helpers/_/_inherits"),h=t("@swc/helpers/_/_object_spread"),f=t("@swc/helpers/_/_object_spread_props"),d=t("@swc/helpers/_/_sliced_to_array"),p=t("@swc/helpers/_/_to_consumable_array"),v=t("@swc/helpers/_/_type_of"),g=t("@swc/helpers/_/_wrap_native_super"),y=t("@swc/helpers/_/_create_super"),m=t("./chunks/helpers.segment.mjs"),b=new(function(){function t(){(0,a._)(this,t),this._request=null,this._charts=new Map,this._running=!1,this._lastDate=void 0}return(0,o._)(t,[{key:"_notify",value:function(t,e,r,n){var i=e.listeners[n],a=e.duration;i.forEach(function(n){return n({chart:t,initial:e.initial,numSteps:a,currentStep:Math.min(r-e.start,a)})})}},{key:"_refresh",value:function(){var t=this;this._request||(this._running=!0,this._request=(0,m.r).call(window,function(){t._update(),t._request=null,t._running&&t._refresh()}))}},{key:"_update",value:function(){var t=this,e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:Date.now(),r=0;this._charts.forEach(function(n,i){if(n.running&&n.items.length){for(var a,o=n.items,s=o.length-1,l=!1;s>=0;--s)(a=o[s])._active?(a._total>n.duration&&(n.duration=a._total),a.tick(e),l=!0):(o[s]=o[o.length-1],o.pop());l&&(i.draw(),t._notify(i,n,e,"progress")),o.length||(n.running=!1,t._notify(i,n,e,"complete"),n.initial=!1),r+=o.length}}),this._lastDate=e,0===r&&(this._running=!1)}},{key:"_getAnims",value:function(t){var e=this._charts,r=e.get(t);return r||(r={running:!1,initial:!0,items:[],listeners:{complete:[],progress:[]}},e.set(t,r)),r}},{key:"listen",value:function(t,e,r){this._getAnims(t).listeners[e].push(r)}},{key:"add",value:function(t,e){var r;e&&e.length&&(r=this._getAnims(t).items).push.apply(r,(0,p._)(e))}},{key:"has",value:function(t){return this._getAnims(t).items.length>0}},{key:"start",value:function(t){var e=this._charts.get(t);e&&(e.running=!0,e.start=Date.now(),e.duration=e.items.reduce(function(t,e){return Math.max(t,e._duration)},0),this._refresh())}},{key:"running",value:function(t){if(!this._running)return!1;var e=this._charts.get(t);return!!e&&!!e.running&&!!e.items.length}},{key:"stop",value:function(t){var e=this._charts.get(t);if(e&&e.items.length){for(var r=e.items,n=r.length-1;n>=0;--n)r[n].cancel();e.items=[],this._notify(t,e,Date.now(),"complete")}}},{key:"remove",value:function(t){return this._charts.delete(t)}}]),t}()),_="transparent",x={boolean:function(t,e,r){return r>.5?e:t},color:function(t,e,r){var n=(0,m.c)(t||_),i=n.valid&&(0,m.c)(e||_);return i&&i.valid?i.mix(n,r).hexString():e},number:function(t,e,r){return t+(e-t)*r}},k=function(){function t(e,r,n,i){(0,a._)(this,t);var o=r[n];i=(0,m.a)([e.to,i,o,e.from]);var s=(0,m.a)([e.from,o,i]);this._active=!0,this._fn=e.fn||x[e.type||(void 0===s?"undefined":(0,v._)(s))],this._easing=m.e[e.easing]||m.e.linear,this._start=Math.floor(Date.now()+(e.delay||0)),this._duration=this._total=Math.floor(e.duration),this._loop=!!e.loop,this._target=r,this._prop=n,this._from=s,this._to=i,this._promises=void 0}return(0,o._)(t,[{key:"active",value:function(){return this._active}},{key:"update",value:function(t,e,r){if(this._active){this._notify(!1);var n=this._target[this._prop],i=r-this._start,a=this._duration-i;this._start=r,this._duration=Math.floor(Math.max(a,t.duration)),this._total+=i,this._loop=!!t.loop,this._to=(0,m.a)([t.to,e,n,t.from]),this._from=(0,m.a)([t.from,n,e])}}},{key:"cancel",value:function(){this._active&&(this.tick(Date.now()),this._active=!1,this._notify(!1))}},{key:"tick",value:function(t){var e,r=t-this._start,n=this._duration,i=this._prop,a=this._from,o=this._loop,s=this._to;if(this._active=a!==s&&(o||r1?2-e:e,e=this._easing(Math.min(1,Math.max(0,e))),this._target[i]=this._fn(a,s,e)}},{key:"wait",value:function(){var t=this._promises||(this._promises=[]);return new Promise(function(e,r){t.push({res:e,rej:r})})}},{key:"_notify",value:function(t){for(var e=t?"res":"rej",r=this._promises||[],n=0;n=0;--s){var s,l=a[s];if("$"!==l.charAt(0)){if("options"===l){n.push.apply(n,(0,p._)(this._animateOptions(t,e)));continue}var u=e[l],c=i[l],h=r.get(l);if(c){if(h&&c.active()){c.update(h,u,o);continue}c.cancel()}if(!h||!h.duration){t[l]=u;continue}i[l]=c=new k(h,t,l,u),n.push(c)}}return n}},{key:"update",value:function(t,e){if(0===this._properties.size){Object.assign(t,e);return}var r=this._createAnimations(t,e);if(r.length)return b.add(this._chart,r),!0}}]),t}();function S(t,e){var r=t&&t.options||{},n=r.reverse,i=void 0===r.min?e:0,a=void 0===r.max?e:0;return{start:n?a:i,end:n?i:a}}function O(t,e){var r,n,i=[],a=t._getSortedDatasetMetas(e);for(r=0,n=a.length;r3&&void 0!==arguments[3]?arguments[3]:{},l=t.keys,u="single"===s.mode;if(null!==e){for(n=0,i=l.length;n0||!r&&c<0)return u.index}}catch(t){a=!0,o=t}finally{try{i||null==l.return||l.return()}finally{if(a)throw o}}return null}function P(t,e){for(var r,n=t.chart,i=t._cachedMeta,a=n._stacks||(n._stacks={}),o=i.iScale,s=i.vScale,l=i.index,u=o.axis,c=s.axis,h="".concat(o.id,".").concat(s.id,".").concat(i.stack||i.type),f=e.length,d=0;d0&&a._parsed[t-1];if(!1===this._parsing)a._parsed=o,a._sorted=!0,i=o;else{for(r=0,i=(0,m.b)(o[t])?this.parseArrayData(a,o,t,e):(0,m.i)(o[t])?this.parseObjectData(a,o,t,e):this.parsePrimitiveData(a,o,t,e);re||y=0;--o)if(!b()){this.updateRangeFromParsed(p,t,s,d);break}}return p}},{key:"getAllParsedValues",value:function(t){var e,r,n,i=this._cachedMeta._parsed,a=[];for(e=0,r=i.length;e=0&&t1&&void 0!==arguments[1]?arguments[1]:"default",n=arguments.length>2?arguments[2]:void 0,i="active"===r,a=this._cachedDataOpts,o=t+"-"+r,s=a[o],l=this.enableOptionSharing&&(0,m.j)(n);if(s)return F(s,l);var u=this.chart.config,c=u.datasetElementScopeKeys(this._type,t),h=u.getOptionScopes(this.getDataset(),c),f=Object.keys(m.d.elements[t]),d=u.resolveNamedOptions(h,f,function(){return e.getContext(n,i)},i?["".concat(t,"Hover"),"hover",t,""]:[t,""]);return d.$shared&&(d.$shared=l,a[o]=Object.freeze(F(d,l))),d}},{key:"_resolveAnimations",value:function(t,e,r){var n,i=this.chart,a=this._cachedDataOpts,o="animation-".concat(e),s=a[o];if(s)return s;if(!1!==i.options.animation){var l=this.chart.config,u=l.datasetAnimationScopeKeys(this._type,e),c=l.getOptionScopes(this.getDataset(),u);n=l.createResolver(c,this.getContext(t,r,e))}var h=new M(i,n&&n.animations);return n&&n._cacheable&&(a[o]=Object.freeze(h)),h}},{key:"getSharedOptions",value:function(t){if(t.$shared)return this._sharedOptions||(this._sharedOptions=Object.assign({},t))}},{key:"includeOptions",value:function(t,e){return!e||T(t)||this.chart._animationsDisabled}},{key:"_getSharedOptions",value:function(t,e){var r=this.resolveDataElementOptions(t,e),n=this._sharedOptions,i=this.getSharedOptions(r),a=this.includeOptions(e,i)||i!==n;return this.updateSharedOptions(i,e,r),{sharedOptions:i,includeOptions:a}}},{key:"updateElement",value:function(t,e,r,n){T(n)?Object.assign(t,r):this._resolveAnimations(e,n).update(t,r)}},{key:"updateSharedOptions",value:function(t,e,r){t&&!T(e)&&this._resolveAnimations(void 0,e).update(t,r)}},{key:"_setStyle",value:function(t,e,r,n){t.active=n;var i=this.getStyle(e,n);this._resolveAnimations(e,r,n).update(t,{options:!n&&this.getSharedOptions(i)||i})}},{key:"removeHoverStyle",value:function(t,e,r){this._setStyle(t,r,"active",!1)}},{key:"setHoverStyle",value:function(t,e,r){this._setStyle(t,r,"active",!0)}},{key:"_removeDatasetHoverStyle",value:function(){var t=this._cachedMeta.dataset;t&&this._setStyle(t,void 0,"active",!1)}},{key:"_setDatasetHoverStyle",value:function(){var t=this._cachedMeta.dataset;t&&this._setStyle(t,void 0,"active",!0)}},{key:"_resyncElements",value:function(t){var e=this._data,r=this._cachedMeta.data,n=!0,i=!1,a=void 0;try{for(var o,s=this._syncList[Symbol.iterator]();!(n=(o=s.next()).done);n=!0){var l=(0,d._)(o.value,3),u=l[0],c=l[1],h=l[2];this[u](c,h)}}catch(t){i=!0,a=t}finally{try{n||null==s.return||s.return()}finally{if(i)throw a}}this._syncList=[];var f=r.length,p=e.length,v=Math.min(p,f);v&&this.parse(0,v),p>f?this._insertElements(f,p-f,t):p2)||void 0===arguments[2]||arguments[2],i=this._cachedMeta,a=i.data,o=t+e,s=function(t){for(t.length+=e,r=t.length-1;r>=o;r--)t[r]=t[r-e]};for(s(a),r=t;rMath.abs(s)&&(l=s,u=o),e[r.axis]=u,e._custom={barStart:l,barEnd:u,start:i,end:a,min:o,max:s}}else e[r.axis]=r.parse(t,n);return e}function B(t,e,r,n){var i,a,o,s,l=t.iScale,u=t.vScale,c=l.getLabels(),h=l===u,f=[];for(i=r,a=r+n;it.x,a="left",o="right"):(i=t.base=u?1:-1))*l,d===u&&(y-=r/2);var b,_=i.getPixelForDecimal(0),x=i.getPixelForDecimal(1);e=(y=Math.max(Math.min(y,Math.max(_,x)),Math.min(_,x)))+r}if(y===i.getPixelForValue(u)){var k=(0,m.s)(r)*i.getLineWidthForValue(u)/2;y+=k,r-=k}return{size:r,base:y,head:e,center:e+r/2}}},{key:"_calculateBarIndexPixels",value:function(t,e){var r,n,i=e.scale,a=this.options,o=a.skipNull,s=(0,m.v)(a.maxBarThickness,1/0);if(e.grouped){var l,u,c,h,f,d,p,v,g,y=o?this._getStackCount(t):e.stackCount,b="flex"===a.barThickness?(u=(l=e.pixels)[t],c=t>0?l[t-1]:null,h=t=0;--r)e=Math.max(e,t[r].size(this.resolveDataElementOptions(r))/2);return e>0&&e}},{key:"getLabelAndValue",value:function(t){var e=this._cachedMeta,r=e.xScale,n=e.yScale,i=this.getParsed(t),a=r.getLabelForValue(i.x),o=n.getLabelForValue(i.y),s=i._custom;return{label:e.label,value:"("+a+", "+o+(s?", "+s:"")+")"}}},{key:"update",value:function(t){var e=this._cachedMeta.data;this.updateElements(e,0,e.length,t)}},{key:"updateElements",value:function(t,e,r,n){for(var i="reset"===n,a=this._cachedMeta,o=a.iScale,s=a.vScale,l=this._getSharedOptions(e,n),u=l.sharedOptions,c=l.includeOptions,h=o.axis,f=s.axis,d=e;d0&&!isNaN(t)?m.T*(Math.abs(t)/e):0}},{key:"getLabelAndValue",value:function(t){var e=this._cachedMeta,r=this.chart,n=r.data.labels||[],i=(0,m.o)(e._parsed[t],r.options.locale);return{label:n[t]||"",value:i}}},{key:"getMaxBorderWidth",value:function(t){var e,r,n,i,a,o=0,s=this.chart;if(!t){for(e=0,r=s.data.datasets.length;e0&&this.getParsed(e-1),k=e;k0&&Math.abs(M[d]-x[d])>b,y&&(S.parsed=M,S.raw=u.data[k]),f&&(S.options=h||this.resolveDataElementOptions(k,w.active?"active":n)),_||this.updateElement(w,k,S,n),x=M}}},{key:"getMaxOverflow",value:function(){var t=this._cachedMeta,e=t.dataset,r=e.options&&e.options.borderWidth||0,n=t.data||[];return n.length?Math.max(r,n[0].size(this.resolveDataElementOptions(0)),n[n.length-1].size(this.resolveDataElementOptions(n.length-1)))/2:r}},{key:"draw",value:function(){var t=this._cachedMeta;t.dataset.updateControlPoints(this.chart.chartArea,t.iScale.axis),(0,l._)((0,u._)(r.prototype),"draw",this).call(this)}}]),r}(I);U.id="line",U.defaults={datasetElementType:"line",dataElementType:"point",showLine:!0,spanGaps:!1},U.overrides={scales:{_index_:{type:"category"},_value_:{type:"linear"}}};var K=function(t){(0,c._)(r,t);var e=(0,y._)(r);function r(t,n){var i;return(0,a._)(this,r),(i=e.call(this,t,n)).innerRadius=void 0,i.outerRadius=void 0,i}return(0,o._)(r,[{key:"getLabelAndValue",value:function(t){var e=this._cachedMeta,r=this.chart,n=r.data.labels||[],i=(0,m.o)(e._parsed[t].r,r.options.locale);return{label:n[t]||"",value:i}}},{key:"parseObjectData",value:function(t,e,r,n){return(0,m.y).bind(this)(t,e,r,n)}},{key:"update",value:function(t){var e=this._cachedMeta.data;this._updateRadius(),this.updateElements(e,0,e.length,t)}},{key:"getMinMax",value:function(){var t=this,e=this._cachedMeta,r={min:Number.POSITIVE_INFINITY,max:Number.NEGATIVE_INFINITY};return e.data.forEach(function(e,n){var i=t.getParsed(n).r;!isNaN(i)&&t.chart.getDataVisibility(n)&&(ir.max&&(r.max=i))}),r}},{key:"_updateRadius",value:function(){var t=this.chart,e=t.chartArea,r=t.options,n=Math.max(Math.min(e.right-e.left,e.bottom-e.top)/2,0),i=Math.max(r.cutoutPercentage?n/100*r.cutoutPercentage:1,0),a=(n-i)/t.getVisibleDatasetCount();this.outerRadius=n-a*this.index,this.innerRadius=this.outerRadius-a}},{key:"updateElements",value:function(t,e,r,n){var i,a="reset"===n,o=this.chart,s=o.options.animation,l=this._cachedMeta.rScale,u=l.xCenter,c=l.yCenter,h=l.getIndexAngle(0)-.5*m.P,f=h,d=360/this.countVisibleElements();for(i=0;i1){var o,s=Math.max(Math.abs(r[0].value),Math.abs(r[r.length-1].value));(s<1e-4||s>1e15)&&(n="scientific"),Math.abs(o=r.length>3?r[2].value-r[1].value:r[1].value-r[0].value)>=1&&t!==Math.floor(t)&&(o=t-Math.floor(t)),a=o}var l=Math.max(Math.min(-1*Math.floor((0,m.z)(Math.abs(a))),20),0),u={notation:n,minimumFractionDigits:l,maximumFractionDigits:l};return Object.assign(u,this.options.ticks.format),(0,m.o)(t,i,u)},logarithmic:function(t,e,r){if(0===t)return"0";var n=t/Math.pow(10,Math.floor((0,m.z)(t)));return 1===n||2===n||5===n?$.numeric.call(this,t,e,r):""}},Q={formatters:$};function G(t,e,r,n,i){var a,o,s,l=(0,m.v)(n,0),u=Math.min((0,m.v)(i,t.length),t.length),c=0;for(r=Math.ceil(r),i&&(r=(a=i-n)/Math.floor(a/r)),s=l;s<0;)s=Math.round(l+ ++c*r);for(o=Math.max(l,0);oi?i:n,i=a&&n>i?n:i,{min:(0,m.B)(n,(0,m.B)(i,n)),max:(0,m.B)(i,(0,m.B)(n,i))}}},{key:"getPadding",value:function(){return{left:this.paddingLeft||0,top:this.paddingTop||0,right:this.paddingRight||0,bottom:this.paddingBottom||0}}},{key:"getTicks",value:function(){return this.ticks}},{key:"getLabels",value:function(){var t=this.chart.data;return this.options.labels||(this.isHorizontal()?t.xLabels:t.yLabels)||t.labels||[]}},{key:"beforeLayout",value:function(){this._cache={},this._dataLimitsCached=!1}},{key:"beforeUpdate",value:function(){(0,m.C)(this.options.beforeUpdate,[this])}},{key:"update",value:function(t,e,r){var n=this.options,i=n.beginAtZero,a=n.grace,o=n.ticks,s=o.sampleSize;this.beforeUpdate(),this.maxWidth=t,this.maxHeight=e,this._margins=r=Object.assign({left:0,right:0,top:0,bottom:0},r),this.ticks=null,this._labelSizes=null,this._gridLineItems=null,this._labelItems=null,this.beforeSetDimensions(),this.setDimensions(),this.afterSetDimensions(),this._maxLength=this.isHorizontal()?this.width+r.left+r.right:this.height+r.top+r.bottom,this._dataLimitsCached||(this.beforeDataLimits(),this.determineDataLimits(),this.afterDataLimits(),this._range=(0,m.D)(this,a,i),this._dataLimitsCached=!0),this.beforeBuildTicks(),this.ticks=this.buildTicks()||[],this.afterBuildTicks();var l=sn)return function(t,e,r,n){var i,a=0,o=r[0];for(i=0,n=Math.ceil(n);ii)return l}return Math.max(i,1)}(i,e,n);if(a>0){var c,h,f,d,p=a>1?Math.round((s-o)/(a-1)):null;for(G(e,l,u,(0,m.k)(p)?0:o-p,o),f=0,d=a-1;f=s||a<=1||!this.isHorizontal()){this.labelRotation=o;return}var u=this._getLabelSizes(),c=u.widest.width,h=u.highest.height,f=(0,m.E)(this.chart.width-c,0,this.maxWidth);c+6>(t=n.offset?this.maxWidth/a:f/(a-1))&&(t=f/(a-(n.offset?.5:1)),e=this.maxHeight-tt(n.grid)-i.padding-te(n.title,this.chart.options.font),r=Math.sqrt(c*c+h*h),l=Math.max(o,Math.min(s,l=(0,m.F)(Math.min(Math.asin((0,m.E)((u.highest.height+6)/t,-1,1)),Math.asin((0,m.E)(e/r,-1,1))-Math.asin((0,m.E)(h/r,-1,1))))))),this.labelRotation=l}},{key:"afterCalculateLabelRotation",value:function(){(0,m.C)(this.options.afterCalculateLabelRotation,[this])}},{key:"afterAutoSkip",value:function(){}},{key:"beforeFit",value:function(){(0,m.C)(this.options.beforeFit,[this])}},{key:"fit",value:function(){var t={width:0,height:0},e=this.chart,r=this.options,n=r.ticks,i=r.title,a=r.grid,o=this._isVisible(),s=this.isHorizontal();if(o){var l=te(i,e.options.font);if(s?(t.width=this.maxWidth,t.height=tt(a)+l):(t.height=this.maxHeight,t.width=tt(a)+l),n.display&&this.ticks.length){var u=this._getLabelSizes(),c=u.first,h=u.last,f=u.widest,d=u.highest,p=2*n.padding,v=(0,m.t)(this.labelRotation),g=Math.cos(v),y=Math.sin(v);if(s){var b=n.mirror?0:y*f.width+g*d.height;t.height=Math.min(this.maxHeight,t.height+b+p)}else{var _=n.mirror?0:g*f.width+y*d.height;t.width=Math.min(this.maxWidth,t.width+_+p)}this._calculatePadding(c,h,y,g)}}this._handleMargins(),s?(this.width=this._length=e.width-this._margins.left-this._margins.right,this.height=t.height):(this.width=t.width,this.height=this._length=e.height-this._margins.top-this._margins.bottom)}},{key:"_calculatePadding",value:function(t,e,r,n){var i=this.options,a=i.ticks,o=a.align,s=a.padding,l=i.position,u=0!==this.labelRotation,c="top"!==l&&"x"===this.axis;if(this.isHorizontal()){var h=this.getPixelForTick(0)-this.left,f=this.right-this.getPixelForTick(this.ticks.length-1),d=0,p=0;u?c?(d=n*t.width,p=r*e.height):(d=r*t.height,p=n*e.width):"start"===o?p=e.width:"end"===o?d=t.width:"inner"!==o&&(d=t.width/2,p=e.width/2),this.paddingLeft=Math.max((d-h+s)*this.width/(this.width-h),0),this.paddingRight=Math.max((p-f+s)*this.width/(this.width-f),0)}else{var v=e.height/2,g=t.height/2;"start"===o?(v=0,g=t.height):"end"===o&&(v=e.height,g=0),this.paddingTop=v+s,this.paddingBottom=g+s}}},{key:"_handleMargins",value:function(){this._margins&&(this._margins.left=Math.max(this.paddingLeft,this._margins.left),this._margins.top=Math.max(this.paddingTop,this._margins.top),this._margins.right=Math.max(this.paddingRight,this._margins.right),this._margins.bottom=Math.max(this.paddingBottom,this._margins.bottom))}},{key:"afterFit",value:function(){(0,m.C)(this.options.afterFit,[this])}},{key:"isHorizontal",value:function(){var t=this.options,e=t.axis,r=t.position;return"top"===r||"bottom"===r||"x"===e}},{key:"isFullSize",value:function(){return this.options.fullSize}},{key:"_convertTicksToLabels",value:function(t){var e,r;for(this.beforeTickToLabelConversion(),this.generateTickLabels(t),e=0,r=t.length;ee){for(r=0;re.length-1?null:this.getPixelForValue(e[t].value)}},{key:"getPixelForDecimal",value:function(t){this._reversePixels&&(t=1-t);var e=this._startPixel+t*this._length;return(0,m.I)(this._alignToPixels?(0,m.J)(this.chart,e,0):e)}},{key:"getDecimalForPixel",value:function(t){var e=(t-this._startPixel)/this._length;return this._reversePixels?1-e:e}},{key:"getBasePixel",value:function(){return this.getPixelForValue(this.getBaseValue())}},{key:"getBaseValue",value:function(){var t=this.min,e=this.max;return t<0&&e<0?e:t>0&&e>0?t:0}},{key:"getContext",value:function(t){var e,r=this.ticks||[];if(t>=0&&to*n?o/r:s/n:s*n0}},{key:"_computeGridLineItems",value:function(t){var e,r,n,i,a,o,s,l,u,c,h,f,d=this.axis,p=this.chart,v=this.options,g=v.grid,y=v.position,b=g.offset,_=this.isHorizontal(),x=this.ticks.length+(b?1:0),k=tt(g),w=[],M=g.setContext(this.getContext()),S=M.drawBorder?M.borderWidth:0,O=S/2,A=function(t){return(0,m.J)(p,t,S)};if("top"===y)e=A(this.bottom),o=this.bottom-k,l=e-O,c=A(t.top)+O,f=t.bottom;else if("bottom"===y)e=A(this.top),c=t.top,f=A(t.bottom)-O,o=e+O,l=this.top+k;else if("left"===y)e=A(this.right),a=this.right-k,s=e-O,u=A(t.left)+O,h=t.right;else if("right"===y)e=A(this.left),u=t.left,h=A(t.right)-O,a=e+O,s=this.left+k;else if("x"===d){if("center"===y)e=A((t.top+t.bottom)/2+.5);else if((0,m.i)(y)){var E=Object.keys(y)[0],C=y[E];e=A(this.chart.scales[E].getPixelForValue(C))}c=t.top,f=t.bottom,l=(o=e+O)+k}else if("y"===d){if("center"===y)e=A((t.left+t.right)/2);else if((0,m.i)(y)){var P=Object.keys(y)[0],D=y[P];e=A(this.chart.scales[P].getPixelForValue(D))}s=(a=e-O)-k,u=t.left,h=t.right}var j=(0,m.v)(v.ticks.maxTicksLimit,x),T=Math.max(1,Math.ceil(x/j));for(r=0;rs+1e-6)))return l}(this,r,b))&&(i=(0,m.J)(p,n,I),_?a=s=u=h=i:o=l=c=f=i,w.push({tx1:a,ty1:o,tx2:s,ty2:l,x1:u,y1:c,x2:h,y2:f,width:I,color:L,borderDash:B,borderDashOffset:R,tickWidth:N,tickColor:V,tickBorderDash:z,tickBorderDashOffset:W}))}return this._ticksLength=x,this._borderValue=e,w}},{key:"_computeLabelItems",value:function(t){var e,r,n,i,a,o,s,l,u,c,h,f=this.axis,d=this.options,p=d.position,v=d.ticks,g=this.isHorizontal(),y=this.ticks,b=v.align,_=v.crossAlign,x=v.padding,k=v.mirror,w=tt(d.grid),M=w+x,S=k?-x:M,O=-(0,m.t)(this.labelRotation),A=[],E="middle";if("top"===p)a=this.bottom-S,o=this._getXAxisLabelAlignment();else if("bottom"===p)a=this.top+S,o=this._getXAxisLabelAlignment();else if("left"===p){var C=this._getYAxisLabelAlignment(w);o=C.textAlign,i=C.x}else if("right"===p){var P=this._getYAxisLabelAlignment(w);o=P.textAlign,i=P.x}else if("x"===f){if("center"===p)a=(t.top+t.bottom)/2+M;else if((0,m.i)(p)){var D=Object.keys(p)[0],j=p[D];a=this.chart.scales[D].getPixelForValue(j)+M}o=this._getXAxisLabelAlignment()}else if("y"===f){if("center"===p)i=(t.left+t.right)/2-M;else if((0,m.i)(p)){var T=Object.keys(p)[0],F=p[T];i=this.chart.scales[T].getPixelForValue(F)}o=this._getYAxisLabelAlignment(w).textAlign}"y"===f&&("start"===b?E="top":"end"===b&&(E="bottom"));var I=this._getLabelSizes();for(e=0,r=y.length;e=0?e.setContext(this.getContext(r)).lineWidth:0}},{key:"drawGrid",value:function(t){var e,r,n=this.options.grid,i=this.ctx,a=this._gridLineItems||(this._gridLineItems=this._computeGridLineItems(t)),o=function(t,e,r){r.width&&r.color&&(i.save(),i.lineWidth=r.width,i.strokeStyle=r.color,i.setLineDash(r.borderDash||[]),i.lineDashOffset=r.borderDashOffset,i.beginPath(),i.moveTo(t.x,t.y),i.lineTo(e.x,e.y),i.stroke(),i.restore())};if(n.display)for(e=0,r=a.length;e0&&this.getParsed(e-1),k=e;k0&&Math.abs(M[d]-x[d])>b,y&&(S.parsed=M,S.raw=u.data[k]),f&&(S.options=h||this.resolveDataElementOptions(k,w.active?"active":n)),_||this.updateElement(w,k,S,n),x=M}this.updateSharedOptions(h,n,c)}},{key:"getMaxOverflow",value:function(){var t=this._cachedMeta,e=t.data||[];if(!this.options.showLine){for(var r=0,n=e.length-1;n>=0;--n)r=Math.max(r,e[n].size(this.resolveDataElementOptions(n))/2);return r>0&&r}var i=t.dataset,a=i.options&&i.options.borderWidth||0;return e.length?Math.max(a,e[0].size(this.resolveDataElementOptions(0)),e[e.length-1].size(this.resolveDataElementOptions(e.length-1)))/2:a}}]),r}(I);ta.id="scatter",ta.defaults={datasetElementType:!1,dataElementType:"point",showLine:!1,fill:!1},ta.overrides={interaction:{mode:"point"},plugins:{tooltip:{callbacks:{title:function(){return""},label:function(t){return"("+t.label+", "+t.formattedValue+")"}}}},scales:{x:{type:"linear"},y:{type:"linear"}}};var to=Object.freeze({__proto__:null,BarController:z,BubbleController:W,DoughnutController:H,LineController:U,PolarAreaController:K,PieController:Y,RadarController:X,ScatterController:ta});function ts(){throw Error("This method is not implemented: Check that a complete date adapter is provided.")}var tl=function(){function t(e){(0,a._)(this,t),this.options=e||{}}return(0,o._)(t,[{key:"init",value:function(t){}},{key:"formats",value:function(){return ts()}},{key:"parse",value:function(t,e){return ts()}},{key:"format",value:function(t,e){return ts()}},{key:"add",value:function(t,e,r){return ts()}},{key:"diff",value:function(t,e,r){return ts()}},{key:"startOf",value:function(t,e,r){return ts()}},{key:"endOf",value:function(t,e){return ts()}}]),t}();tl.override=function(t){Object.assign(tl.prototype,t)};var tu={_date:tl};function tc(t,e,r,n,i){for(var a=t.getSortedVisibleDatasetMetas(),o=r[e],s=0,l=a.length;s0){var l=s[0].datasetIndex,u=t.getDatasetMeta(l).data;s=[];for(var c=0;c3&&void 0!==arguments[3]?arguments[3]:[""],i={$shared:!0},a=tJ(this._resolverCache,t,n),o=a.resolver,s=a.subPrefixes,l=o;if(function(t,e){var r=(0,m.ab)(t),n=r.isScriptable,i=r.isIndexable,a=!0,o=!1,s=void 0;try{for(var l,u=e[Symbol.iterator]();!(a=(l=u.next()).done);a=!0){var c=l.value,h=n(c),f=i(c),d=(f||h)&&t[c];if(h&&((0,m.a8)(d)||tZ(d))||f&&(0,m.b)(d))return!0}}catch(t){o=!0,s=t}finally{try{a||null==u.return||u.return()}finally{if(o)throw s}}return!1}(o,e)){i.$shared=!1,r=(0,m.a8)(r)?r():r;var u=this.createResolver(t,r,s);l=(0,m.a9)(o,r,u)}var c=!0,h=!1,f=void 0;try{for(var d,p=e[Symbol.iterator]();!(c=(d=p.next()).done);c=!0){var v=d.value;i[v]=l[v]}}catch(t){h=!0,f=t}finally{try{c||null==p.return||p.return()}finally{if(h)throw f}}return i}},{key:"createResolver",value:function(t,e){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:[""],n=arguments.length>3?arguments[3]:void 0,i=tJ(this._resolverCache,t,r).resolver;return(0,m.i)(e)?(0,m.a9)(i,e,void 0,n):i}}]),t}();function tJ(t,e,r){var n=t.get(e);n||(n=new Map,t.set(e,n));var i=r.join(),a=n.get(i);return a||(a={resolver:(0,m.aa)(e,r),subPrefixes:r.filter(function(t){return!t.toLowerCase().includes("hover")})},n.set(i,a)),a}var tZ=function(t){return(0,m.i)(t)&&Object.getOwnPropertyNames(t).reduce(function(e,r){return e||(0,m.a8)(t[r])},!1)},t0=["top","bottom","left","right","chartArea"];function t1(t,e){return"top"===t||"bottom"===t||-1===t0.indexOf(t)&&"x"===e}function t2(t,e){return function(r,n){return r[t]===n[t]?r[e]-n[e]:r[t]-n[t]}}function t5(t){var e=t.chart,r=e.options.animation;e.notifyPlugins("afterRender"),(0,m.C)(r&&r.onComplete,[t],e)}function t3(t){var e=t.chart,r=e.options.animation;(0,m.C)(r&&r.onProgress,[t],e)}function t6(t){return(0,m.a6)()&&"string"==typeof t?t=document.getElementById(t):t&&t.length&&(t=t[0]),t&&t.canvas&&(t=t.canvas),t}var t8={},t4=function(t){var e=t6(t);return Object.values(t8).filter(function(t){return t.canvas===e}).pop()},t7=function(){function t(e,r){var n=this;(0,a._)(this,t);var i=this.config=new tG(r),o=t6(e),s=t4(o);if(s)throw Error("Canvas is already in use. Chart with ID '"+s.id+"' must be destroyed before the canvas with ID '"+s.canvas.id+"' can be reused.");var l=i.createResolver(i.chartOptionScopes(),this.getContext());this.platform=new(i.platform||tz(o)),this.platform.updateConfig(i);var u=this.platform.acquireContext(o,l.aspectRatio),c=u&&u.canvas,h=c&&c.height,f=c&&c.width;if(this.id=(0,m.ad)(),this.ctx=u,this.canvas=c,this.width=f,this.height=h,this._options=l,this._aspectRatio=this.aspectRatio,this._layers=[],this._metasets=[],this._stacks=void 0,this.boxes=[],this.currentDevicePixelRatio=void 0,this.chartArea=void 0,this._active=[],this._lastEvent=void 0,this._listeners={},this._responsiveListeners=void 0,this._sortedMetasets=[],this.scales={},this._plugins=new tW,this.$proxies={},this._hiddenIndices={},this.attached=!1,this._animationsDisabled=void 0,this.$context=void 0,this._doResize=(0,m.ae)(function(t){return n.update(t)},l.resizeDelay||0),this._dataChanges=[],t8[this.id]=this,!u||!c){console.error("Failed to create chart: can't acquire context from the given item");return}b.listen(this,"complete",t5),b.listen(this,"progress",t3),this._initialize(),this.attached&&this.update()}return(0,o._)(t,[{key:"aspectRatio",get:function(){var t=this.options,e=t.aspectRatio,r=t.maintainAspectRatio,n=this.width,i=this.height,a=this._aspectRatio;return(0,m.k)(e)?r&&a?a:i?n/i:null:e}},{key:"data",get:function(){return this.config.data},set:function(t){this.config.data=t}},{key:"options",get:function(){return this._options},set:function(t){this.config.options=t}},{key:"_initialize",value:function(){return this.notifyPlugins("beforeInit"),this.options.responsive?this.resize():(0,m.af)(this,this.options.devicePixelRatio),this.bindEvents(),this.notifyPlugins("afterInit"),this}},{key:"clear",value:function(){return(0,m.ag)(this.canvas,this.ctx),this}},{key:"stop",value:function(){return b.stop(this),this}},{key:"resize",value:function(t,e){b.running(this)?this._resizeBeforeDraw={width:t,height:e}:this._resize(t,e)}},{key:"_resize",value:function(t,e){var r=this.options,n=this.canvas,i=r.maintainAspectRatio&&this.aspectRatio,a=this.platform.getMaximumSize(n,t,e,i),o=r.devicePixelRatio||this.platform.getDevicePixelRatio(),s=this.width?"resize":"attach";this.width=a.width,this.height=a.height,this._aspectRatio=this.aspectRatio,(0,m.af)(this,o,!0)&&(this.notifyPlugins("resize",{size:a}),(0,m.C)(r.onResize,[this,a],this),this.attached&&this._doResize(s)&&this.render())}},{key:"ensureScalesHaveIDs",value:function(){var t=this.options.scales||{};(0,m.Q)(t,function(t,e){t.id=e})}},{key:"buildOrUpdateScales",value:function(){var t=this,e=this.options,r=e.scales,n=this.scales,i=Object.keys(n).reduce(function(t,e){return t[e]=!1,t},{}),a=[];r&&(a=a.concat(Object.keys(r).map(function(t){var e=r[t],n=tU(t,e),i="r"===n,a="x"===n;return{options:e,dposition:i?"chartArea":a?"bottom":"left",dtype:i?"radialLinear":a?"category":"linear"}}))),(0,m.Q)(a,function(r){var a=r.options,o=a.id,s=tU(o,a),l=(0,m.v)(a.type,r.dtype);(void 0===a.position||t1(a.position,s)!==t1(r.dposition))&&(a.position=r.dposition),i[o]=!0;var u=null;o in n&&n[o].type===l?u=n[o]:n[(u=new(ti.getScale(l))({id:o,type:l,ctx:t.ctx,chart:t})).id]=u,u.init(a,e)}),(0,m.Q)(i,function(t,e){t||delete n[e]}),(0,m.Q)(n,function(e){tM.configure(t,e,e.options),tM.addBox(t,e)})}},{key:"_updateMetasets",value:function(){var t=this._metasets,e=this.data.datasets.length,r=t.length;if(t.sort(function(t,e){return t.index-e.index}),r>e){for(var n=e;nr.length&&delete this._stacks,e.forEach(function(e,n){0===r.filter(function(t){return t===e._dataset}).length&&t._destroyDatasetMeta(n)})}},{key:"buildOrUpdateControllers",value:function(){var t,e,r=[],n=this.data.datasets;for(this._removeUnreferencedMetasets(),t=0,e=n.length;t=e){var h=t[u];delete t[u],(r>0||c>e)&&(t[c+r]=h)}}}catch(t){a=!0,o=t}finally{try{i||null==l.return||l.return()}finally{if(a)throw o}}}(t,u,h)}}catch(t){n=!0,i=t}finally{try{r||null==o.return||o.return()}finally{if(n)throw i}}}},{key:"_getUniformDataChanges",value:function(){var t=this._dataChanges;if(t&&t.length){this._dataChanges=[];for(var e=this.data.datasets.length,r=function(e){return new Set(t.filter(function(t){return t[0]===e}).map(function(t,e){return e+","+t.splice(1).join(",")}))},n=r(0),i=1;i=0;--e)this._drawDataset(t[e]);this.notifyPlugins("afterDatasetsDraw")}}},{key:"_drawDataset",value:function(t){var e=this.ctx,r=t._clip,n=!r.disabled,i=this.chartArea,a={meta:t,index:t.index,cancelable:!0};!1!==this.notifyPlugins("beforeDatasetDraw",a)&&(n&&(0,m.L)(e,{left:!1===r.left?0:i.left-r.left,right:!1===r.right?this.width:i.right+r.right,top:!1===r.top?0:i.top-r.top,bottom:!1===r.bottom?this.height:i.bottom+r.bottom}),t.controller.draw(),n&&(0,m.N)(e),a.cancelable=!1,this.notifyPlugins("afterDatasetDraw",a))}},{key:"isPointInArea",value:function(t){return(0,m.$)(t,this.chartArea,this._minPadding)}},{key:"getElementsAtEventForMode",value:function(t,e,r,n){var i=tp.modes[e];return"function"==typeof i?i(this,t,r,n):[]}},{key:"getDatasetMeta",value:function(t){var e=this.data.datasets[t],r=this._metasets,n=r.filter(function(t){return t&&t._dataset===e}).pop();return n||(n={type:null,data:[],dataset:null,controller:null,hidden:null,xAxisID:null,yAxisID:null,order:e&&e.order||0,index:t,_dataset:e,_parsed:[],_sorted:!1},r.push(n)),n}},{key:"getContext",value:function(){return this.$context||(this.$context=(0,m.h)(null,{chart:this,type:"chart"}))}},{key:"getVisibleDatasetCount",value:function(){return this.getSortedVisibleDatasetMetas().length}},{key:"isDatasetVisible",value:function(t){var e=this.data.datasets[t];if(!e)return!1;var r=this.getDatasetMeta(t);return"boolean"==typeof r.hidden?!r.hidden:!e.hidden}},{key:"setDatasetVisibility",value:function(t,e){this.getDatasetMeta(t).hidden=!e}},{key:"toggleDataVisibility",value:function(t){this._hiddenIndices[t]=!this._hiddenIndices[t]}},{key:"getDataVisibility",value:function(t){return!this._hiddenIndices[t]}},{key:"_updateVisibility",value:function(t,e,r){var n=r?"show":"hide",i=this.getDatasetMeta(t),a=i.controller._resolveAnimations(void 0,n);(0,m.j)(e)?(i.data[e].hidden=!r,this.update()):(this.setDatasetVisibility(t,r),a.update(i,{visible:r}),this.update(function(e){return e.datasetIndex===t?n:void 0}))}},{key:"hide",value:function(t,e){this._updateVisibility(t,e,!1)}},{key:"show",value:function(t,e){this._updateVisibility(t,e,!0)}},{key:"_destroyDatasetMeta",value:function(t){var e=this._metasets[t];e&&e.controller&&e.controller._destroy(),delete this._metasets[t]}},{key:"_stop",value:function(){var t,e;for(this.stop(),b.remove(this),t=0,e=this.data.datasets.length;ti?(u=i/l,t.arc(a,o,l,r+u,n-u,!0)):t.arc(a,o,i,r+m.H,n-m.H),t.closePath(),t.clip()}function ee(t,e,r,n){return{x:r+t*Math.cos(e),y:n+t*Math.sin(e)}}function er(t,e,r,n,i,a){var o,s,l,u,c,h,f=e.x,d=e.y,p=e.startAngle,v=e.pixelMargin,g=e.innerRadius,y=Math.max(e.outerRadius+n+r-v,0),b=g>0?g+n+r+v:0,_=0,x=i-p;if(n){var k=y>0?y-n:0,w=((g>0?g-n:0)+k)/2;_=(x-(0!==w?x*w/(w+n):x))/2}var M=Math.max(.001,x*y-r/m.P)/y,S=(x-M)/2,O=p+S+_,A=i-S-_,E=(o=A-O,s=e.options.borderRadius,l=(0,m.al)(s,["outerStart","outerEnd","innerStart","innerEnd"]),c=Math.min(u=(y-b)/2,o*b/2),{outerStart:(h=function(t){var e=(y-Math.min(u,t))*o/2;return(0,m.E)(t,0,Math.min(u,e))})(l.outerStart),outerEnd:h(l.outerEnd),innerStart:(0,m.E)(l.innerStart,0,c),innerEnd:(0,m.E)(l.innerEnd,0,c)}),C=E.outerStart,P=E.outerEnd,D=E.innerStart,j=E.innerEnd,T=y-C,F=y-P,I=O+C/T,L=A-P/F,B=b+D,R=b+j,N=O+D/B,V=A-j/R;if(t.beginPath(),a){if(t.arc(f,d,y,I,L),P>0){var z=ee(F,L,f,d);t.arc(z.x,z.y,P,L,A+m.H)}var W=ee(R,A,f,d);if(t.lineTo(W.x,W.y),j>0){var H=ee(R,V,f,d);t.arc(H.x,H.y,j,A+m.H,V+Math.PI)}if(t.arc(f,d,b,A-j/b,O+D/b,!0),D>0){var U=ee(B,N,f,d);t.arc(U.x,U.y,D,N+Math.PI,O-m.H)}var K=ee(T,O,f,d);if(t.lineTo(K.x,K.y),C>0){var Y=ee(T,I,f,d);t.arc(Y.x,Y.y,C,O-m.H,I)}}else{t.moveTo(f,d);var X=Math.cos(I)*y+f,q=Math.sin(I)*y+d;t.lineTo(X,q);var $=Math.cos(L)*y+f,Q=Math.sin(L)*y+d;t.lineTo($,Q)}t.closePath()}Object.defineProperties(t7,{defaults:{enumerable:!0,value:m.d},instances:{enumerable:!0,value:t8},overrides:{enumerable:!0,value:m.U},registry:{enumerable:!0,value:ti},version:{enumerable:!0,value:"3.9.1"},getChart:{enumerable:!0,value:t4},register:{enumerable:!0,value:function(){for(var t=arguments.length,e=Array(t),r=0;r=m.T||(0,m.p)(a,l,u),v=(0,m.ak)(o,c+d,h+d);return p&&v}},{key:"getCenterPoint",value:function(t){var e=this.getProps(["x","y","startAngle","endAngle","innerRadius","outerRadius","circumference"],t),r=e.x,n=e.y,i=e.startAngle,a=e.endAngle,o=e.innerRadius,s=e.outerRadius,l=this.options,u=l.offset,c=l.spacing,h=(i+a)/2,f=(o+s+c+u)/2;return{x:r+Math.cos(h)*f,y:n+Math.sin(h)*f}}},{key:"tooltipPosition",value:function(t){return this.getCenterPoint(t)}},{key:"draw",value:function(t){var e=this.options,r=this.circumference,n=(e.offset||0)/2,i=(e.spacing||0)/2,a=e.circular;if(this.pixelMargin="inner"===e.borderAlign?.33:0,this.fullCircles=r>m.T?Math.floor(r/m.T):0,0!==r&&!(this.innerRadius<0)&&!(this.outerRadius<0)){t.save();var o,s,l,u,c,h=0;if(n){h=n/2;var f=(this.startAngle+this.endAngle)/2;t.translate(Math.cos(f)*h,Math.sin(f)*h),this.circumference>=m.P&&(h=n)}t.fillStyle=e.backgroundColor,t.strokeStyle=e.borderColor;var d=function(t,e,r,n,i){var a=e.fullCircles,o=e.startAngle,s=e.circumference,l=e.endAngle;if(a){er(t,e,r,n,o+m.T,i);for(var u=0;u2&&void 0!==arguments[2]?arguments[2]:e;t.lineCap=(0,m.v)(r.borderCapStyle,e.borderCapStyle),t.setLineDash((0,m.v)(r.borderDash,e.borderDash)),t.lineDashOffset=(0,m.v)(r.borderDashOffset,e.borderDashOffset),t.lineJoin=(0,m.v)(r.borderJoinStyle,e.borderJoinStyle),t.lineWidth=(0,m.v)(r.borderWidth,e.borderWidth),t.strokeStyle=(0,m.v)(r.borderColor,e.borderColor)}function ea(t,e,r){t.lineTo(r.x,r.y)}function eo(t,e){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},n=t.length,i=r.start,a=void 0===i?0:i,o=r.end,s=void 0===o?n-1:o,l=e.start,u=e.end,c=Math.max(a,l),h=Math.min(s,u);return{count:n,start:c,loop:e.loop,ilen:hu&&s>u)?n+h-c:h-c}}function es(t,e,r,n){var i,a,o,s=e.points,l=e.options,u=eo(s,r,n),c=u.count,h=u.start,f=u.loop,d=u.ilen,p=l.stepped?m.as:l.tension||"monotone"===l.cubicInterpolationMode?m.at:ea,v=n||{},g=v.move,y=void 0===g||g,b=v.reverse;for(i=0;i<=d;++i)(a=s[(h+(b?d-i:i))%c]).skip||(y?(t.moveTo(a.x,a.y),y=!1):p(t,o,a,b,l.stepped),o=a);return f&&p(t,o,a=s[(h+(b?d:0))%c],b,l.stepped),!!f}function el(t,e,r,n){var i,a,o,s,l,u,c=e.points,h=eo(c,r,n),f=h.count,d=h.start,p=h.ilen,v=n||{},g=v.move,y=v.reverse,m=0,b=0,_=function(t){return(d+(y?p-t:t))%f},x=function(){s!==l&&(t.lineTo(m,l),t.lineTo(m,s),t.lineTo(m,u))};for((void 0===g||g)&&(a=c[_(0)],t.moveTo(a.x,a.y)),i=0;i<=p;++i)if(!(a=c[_(i)]).skip){var k=a.x,w=a.y,M=0|k;M===o?(wl&&(l=w),m=(b*m+k)/++b):(x(),t.lineTo(k,w),o=M,b=0,s=l=w),u=w}x()}function eu(t){var e=t.options,r=e.borderDash&&e.borderDash.length;return t._decimated||t._loop||e.tension||"monotone"===e.cubicInterpolationMode||e.stepped||r?es:el}en.id="arc",en.defaults={borderAlign:"center",borderColor:"#fff",borderJoinStyle:void 0,borderRadius:0,borderWidth:2,offset:0,spacing:0,angle:void 0,circular:!0},en.defaultRoutes={backgroundColor:"backgroundColor"};var ec="function"==typeof Path2D,eh=function(t){(0,c._)(r,t);var e=(0,y._)(r);function r(t){var n;return(0,a._)(this,r),(n=e.call(this)).animated=!0,n.options=void 0,n._chart=void 0,n._loop=void 0,n._fullLoop=void 0,n._path=void 0,n._points=void 0,n._segments=void 0,n._decimated=!1,n._pointsUpdated=!1,n._datasetIndex=void 0,t&&Object.assign((0,i._)(n),t),n}return(0,o._)(r,[{key:"updateControlPoints",value:function(t,e){var r=this.options;if((r.tension||"monotone"===r.cubicInterpolationMode)&&!r.stepped&&!this._pointsUpdated){var n=r.spanGaps?this._loop:this._fullLoop;(0,m.am)(this._points,r,t,n,e),this._pointsUpdated=!0}}},{key:"points",get:function(){return this._points},set:function(t){this._points=t,delete this._segments,delete this._path,this._pointsUpdated=!1}},{key:"segments",get:function(){return this._segments||(this._segments=(0,m.an)(this,this.options.segment))}},{key:"first",value:function(){var t=this.segments,e=this.points;return t.length&&e[t[0].start]}},{key:"last",value:function(){var t=this.segments,e=this.points,r=t.length;return r&&e[t[r-1].end]}},{key:"interpolate",value:function(t,e){var r,n,i=this.options,a=t[e],o=this.points,s=(0,m.ao)(this,{property:e,start:a,end:a});if(s.length){var l=[],u=i.stepped?m.ap:i.tension||"monotone"===i.cubicInterpolationMode?m.aq:m.ar;for(r=0,n=s.length;r2&&void 0!==arguments[2]?arguments[2]:{},n=t.x!==r.x?-e:0,i=t.y!==r.y?-e:0,a=(t.x+t.w!==r.x+r.w?e:0)-n,o=(t.y+t.h!==r.y+r.h?e:0)-i;return{x:t.x+n,y:t.y+i,w:t.w+a,h:t.h+o,radius:t.radius}}ed.id="point",ed.defaults={borderWidth:1,hitRadius:1,hoverBorderWidth:1,hoverRadius:4,pointStyle:"circle",radius:3,rotation:0},ed.defaultRoutes={backgroundColor:"backgroundColor",borderColor:"borderColor"};var eb=function(t){(0,c._)(r,t);var e=(0,y._)(r);function r(t){var n;return(0,a._)(this,r),(n=e.call(this)).options=void 0,n.horizontal=void 0,n.base=void 0,n.width=void 0,n.height=void 0,n.inflateAmount=void 0,t&&Object.assign((0,i._)(n),t),n}return(0,o._)(r,[{key:"draw",value:function(t){var e,r,n,i,a,o,s,l,u,c,h,f,d,p,v,g,y,b,_,x=this.inflateAmount,k=this.options,w=k.borderColor,M=k.backgroundColor,S=(r=(e=ep(this)).right-e.left,n=e.bottom-e.top,i=r/2,a=n/2,o=this.options.borderWidth,s=this.borderSkipped,l=(0,m.aw)(o),u={t:ev(s.top,l.top,0,a),r:ev(s.right,l.right,0,i),b:ev(s.bottom,l.bottom,0,a),l:ev(s.left,l.left,0,i)},c=r/2,h=n/2,f=this.getProps(["enableBorderRadius"]).enableBorderRadius,d=this.options.borderRadius,p=(0,m.ax)(d),v=Math.min(c,h),g=this.borderSkipped,b={topLeft:ev(!(y=f||(0,m.i)(d))||g.top||g.left,p.topLeft,0,v),topRight:ev(!y||g.top||g.right,p.topRight,0,v),bottomLeft:ev(!y||g.bottom||g.left,p.bottomLeft,0,v),bottomRight:ev(!y||g.bottom||g.right,p.bottomRight,0,v)},{outer:{x:e.left,y:e.top,w:r,h:n,radius:b},inner:{x:e.left+u.l,y:e.top+u.t,w:r-u.l-u.r,h:n-u.t-u.b,radius:{topLeft:Math.max(0,b.topLeft-Math.max(u.t,u.l)),topRight:Math.max(0,b.topRight-Math.max(u.t,u.r)),bottomLeft:Math.max(0,b.bottomLeft-Math.max(u.b,u.l)),bottomRight:Math.max(0,b.bottomRight-Math.max(u.b,u.r))}}}),O=S.inner,A=S.outer,E=(_=A.radius).topLeft||_.topRight||_.bottomLeft||_.bottomRight?m.av:ey;t.save(),(A.w!==O.w||A.h!==O.h)&&(t.beginPath(),E(t,em(A,x,O)),t.clip(),E(t,em(O,-x,A)),t.fillStyle=w,t.fill("evenodd")),t.beginPath(),E(t,em(O,x)),t.fillStyle=M,t.fill(),t.restore()}},{key:"inRange",value:function(t,e,r){return eg(this,t,e,r)}},{key:"inXRange",value:function(t,e){return eg(this,t,null,e)}},{key:"inYRange",value:function(t,e){return eg(this,null,t,e)}},{key:"getCenterPoint",value:function(t){var e=this.getProps(["x","y","base","horizontal"],t),r=e.x,n=e.y,i=e.base,a=e.horizontal;return{x:a?(r+i)/2:r,y:a?n:(n+i)/2}}},{key:"getRange",value:function(t){return"x"===t?this.width/2:this.height/2}}]),r}((0,g._)(q));eb.id="bar",eb.defaults={borderSkipped:"start",borderWidth:0,borderRadius:0,inflateAmount:"auto",pointStyle:void 0},eb.defaultRoutes={backgroundColor:"backgroundColor",borderColor:"borderColor"};var e_=Object.freeze({__proto__:null,ArcElement:en,LineElement:eh,PointElement:ed,BarElement:eb});function ex(t){if(t._decimated){var e=t._data;delete t._decimated,delete t._data,Object.defineProperty(t,"data",{value:e})}}function ek(t){t.data.datasets.forEach(function(t){ex(t)})}var ew={id:"decimation",defaults:{algorithm:"min-max",enabled:!1},beforeElementsUpdate:function(t,e,r){if(!r.enabled){ek(t);return}var n=t.width;t.data.datasets.forEach(function(e,i){var a,o=e._data,s=e.indexAxis,l=t.getDatasetMeta(i),u=o||e.data;if("y"!==(0,m.a)([s,t.options.indexAxis])&&l.controller.supportsDecimation){var c=t.scales[l.xAxisID];if(("linear"===c.type||"time"===c.type)&&!t.options.parsing){var d,p,v,g,y,b,_,x,k,w=(p=u.length,v=0,b=(y=(g=l.iScale).getUserBounds()).min,_=y.max,x=y.minDefined,k=y.maxDefined,x&&(v=(0,m.E)((0,m.Z)(u,g.axis,b).lo,0,p-1)),d=k?(0,m.E)((0,m.Z)(u,g.axis,_).hi+1,v,p)-v:p-v,{start:v,count:d}),M=w.start,S=w.count;if(S<=(r.threshold||4*n)){ex(e);return}switch((0,m.k)(o)&&(e._data=u,delete e.data,Object.defineProperty(e,"data",{configurable:!0,enumerable:!0,get:function(){return this._decimated},set:function(t){this._data=t}})),r.algorithm){case"lttb":a=function(t,e,r,n,i){var a,o,s,l,u,c=i.samples||n;if(c>=r)return t.slice(e,e+r);var h=[],f=(r-2)/(c-2),d=0,p=e+r-1,v=e;for(a=0,h[d++]=t[v];as&&(s=l,o=t[m],u=m);h[d++]=o,v=u}return h[d++]=t[p],h}(u,M,S,n,r);break;case"min-max":a=function(t,e,r,n){var i,a,o,s,l,u,c,d,p,v,g=0,y=0,b=[],_=t[e].x,x=t[e+r-1].x-_;for(i=e;iv&&(v=s,c=i),g=(y*g+a.x)/++y;else{var w=i-1;if(!(0,m.k)(u)&&!(0,m.k)(c)){var M=Math.min(u,c),S=Math.max(u,c);M!==d&&M!==w&&b.push((0,f._)((0,h._)({},t[M]),{x:g})),S!==d&&S!==w&&b.push((0,f._)((0,h._)({},t[S]),{x:g}))}i>0&&w!==d&&b.push(t[w]),b.push(a),l=k,y=0,p=v=s,u=c=d=i}}return b}(u,M,S,n);break;default:throw Error("Unsupported decimation algorithm '".concat(r.algorithm,"'"))}e._decimated=a}}})},destroy:function(t){ek(t)}};function eM(t,e,r,n){if(!n){var i=e[t],a=r[t];return"angle"===t&&(i=(0,m.az)(i),a=(0,m.az)(a)),{property:t,start:i,end:a}}}function eS(t,e,r){for(;e>t;e--){var n=r[e];if(!isNaN(n.x)&&!isNaN(n.y))break}return e}function eO(t,e,r,n){return t&&e?n(t[r],e[r]):t?t[r]:e?e[r]:0}function eA(t,e){var r,n,i,a,o,s,l,u=[],c=!1;return(0,m.b)(t)?(c=!0,u=t):(i=void 0===(n=(r=t||{}).x)?null:n,o=void 0===(a=r.y)?null:a,s=e.points,l=[],e.segments.forEach(function(t){var e=t.start,r=t.end;r=eS(e,r,s);var n=s[e],a=s[r];null!==o?(l.push({x:n.x,y:o}),l.push({x:a.x,y:o})):null!==i&&(l.push({x:i,y:n.y}),l.push({x:i,y:a.y}))}),u=l),u.length?new eh({points:u,options:{tension:0},_loop:c,_fullLoop:c}):null}function eE(t){return t&&!1!==t.fill}var eC=function(){function t(e){(0,a._)(this,t),this.x=e.x,this.y=e.y,this.radius=e.radius}return(0,o._)(t,[{key:"pathSegment",value:function(t,e,r){var n=this.x,i=this.y,a=this.radius;return e=e||{start:0,end:m.T},t.arc(n,i,a,e.end,e.start,!0),!r.bounds}},{key:"interpolate",value:function(t){var e=this.x,r=this.y,n=this.radius,i=t.angle;return{x:e+Math.cos(i)*n,y:r+Math.sin(i)*n,angle:i}}}]),t}();function eP(t,e,r){var n,i,a,o,s,l,u,c,h=function(t){var e,r=t.chart,n=t.fill,i=t.line;if((0,m.g)(n))return(e=r.getDatasetMeta(n))&&r.isDatasetVisible(n)?e.dataset:null;if("stack"===n)return function(t){var e=t.scale,r=t.index,n=t.line,i=[],a=n.segments,o=n.points,s=function(t,e){for(var r=[],n=t.getMatchingVisibleMetas("line"),i=0;i=r)&&i):["origin","start","end","stack","shape"].indexOf(a)>=0&&a}(a,i,s),chart:t,axis:n.controller.options.indexAxis,scale:n.vScale,line:a}),n.$filler=o,l.push(o);for(i=0;i=0;--o){var s=i[o].$filler;s&&(s.line.updateControlPoints(a,s.axis),n&&s.fill&&eP(t.ctx,s,a))}},beforeDatasetsDraw:function(t,e,r){if("beforeDatasetsDraw"===r.drawTime)for(var n=t.getSortedVisibleDatasetMetas(),i=n.length-1;i>=0;--i){var a=n[i].$filler;eE(a)&&eP(t.ctx,a,t.chartArea)}},beforeDatasetDraw:function(t,e,r){var n=e.meta.$filler;eE(n)&&"beforeDatasetDraw"===r.drawTime&&eP(t.ctx,n,t.chartArea)},defaults:{propagate:!0,drawTime:"beforeDatasetDraw"}},eI=function(t,e){var r=t.boxHeight,n=void 0===r?e:r,i=t.boxWidth,a=void 0===i?e:i;return t.usePointStyle&&(n=Math.min(n,e),a=t.pointStyleWidth||Math.min(a,e)),{boxWidth:a,boxHeight:n,itemHeight:Math.max(e,n)}},eL=function(t){(0,c._)(r,t);var e=(0,y._)(r);function r(t){var n;return(0,a._)(this,r),(n=e.call(this))._added=!1,n.legendHitBoxes=[],n._hoveredItem=null,n.doughnutMode=!1,n.chart=t.chart,n.options=t.options,n.ctx=t.ctx,n.legendItems=void 0,n.columnSizes=void 0,n.lineWidths=void 0,n.maxHeight=void 0,n.maxWidth=void 0,n.top=void 0,n.bottom=void 0,n.left=void 0,n.right=void 0,n.height=void 0,n.width=void 0,n._margins=void 0,n.position=void 0,n.weight=void 0,n.fullSize=void 0,n}return(0,o._)(r,[{key:"update",value:function(t,e,r){this.maxWidth=t,this.maxHeight=e,this._margins=r,this.setDimensions(),this.buildLabels(),this.fit()}},{key:"setDimensions",value:function(){this.isHorizontal()?(this.width=this.maxWidth,this.left=this._margins.left,this.right=this.width):(this.height=this.maxHeight,this.top=this._margins.top,this.bottom=this.height)}},{key:"buildLabels",value:function(){var t=this,e=this.options.labels||{},r=(0,m.C)(e.generateLabels,[this.chart],this)||[];e.filter&&(r=r.filter(function(r){return e.filter(r,t.chart.data)})),e.sort&&(r=r.sort(function(r,n){return e.sort(r,n,t.chart.data)})),this.options.reverse&&r.reverse(),this.legendItems=r}},{key:"fit",value:function(){var t,e,r=this.options,n=this.ctx;if(!r.display){this.width=this.height=0;return}var i=r.labels,a=(0,m.O)(i.font),o=a.size,s=this._computeTitleHeight(),l=eI(i,o),u=l.boxWidth,c=l.itemHeight;n.font=a.string,this.isHorizontal()?(t=this.maxWidth,e=this._fitRows(s,o,u,c)+10):(e=this.maxHeight,t=this._fitCols(s,o,u,c)+10),this.width=Math.min(t,r.maxWidth||this.maxWidth),this.height=Math.min(e,r.maxHeight||this.maxHeight)}},{key:"_fitRows",value:function(t,e,r,n){var i=this.ctx,a=this.maxWidth,o=this.options.labels.padding,s=this.legendHitBoxes=[],l=this.lineWidths=[0],u=n+o,c=t;i.textAlign="left",i.textBaseline="middle";var h=-1,f=-u;return this.legendItems.forEach(function(t,d){var p=r+e/2+i.measureText(t.text).width;(0===d||l[l.length-1]+p+2*o>a)&&(c+=u,l[l.length-(d>0?0:1)]=0,f+=u,h++),s[d]={left:0,top:f,row:h,width:p,height:n},l[l.length-1]+=p+o}),c}},{key:"_fitCols",value:function(t,e,r,n){var i=this.ctx,a=this.maxHeight,o=this.options.labels.padding,s=this.legendHitBoxes=[],l=this.columnSizes=[],u=a-t,c=o,h=0,f=0,d=0,p=0;return this.legendItems.forEach(function(t,a){var v=r+e/2+i.measureText(t.text).width;a>0&&f+n+2*o>u&&(c+=h+o,l.push({width:h,height:f}),d+=h+o,p++,h=f=0),s[a]={left:d,top:f,col:p,width:v,height:n},h=Math.max(h,v),f+=n+o}),c+=h,l.push({width:h,height:f}),c}},{key:"adjustHitBoxes",value:function(){if(this.options.display){var t=this._computeTitleHeight(),e=this.legendHitBoxes,r=this.options,n=r.align,i=r.labels.padding,a=r.rtl,o=(0,m.aA)(a,this.left,this.width);if(this.isHorizontal()){var s=0,l=(0,m.S)(n,this.left+i,this.right-this.lineWidths[s]),u=!0,c=!1,h=void 0;try{for(var f,d=e[Symbol.iterator]();!(u=(f=d.next()).done);u=!0){var p=f.value;s!==p.row&&(s=p.row,l=(0,m.S)(n,this.left+i,this.right-this.lineWidths[s])),p.top+=this.top+t+i,p.left=o.leftForLtr(o.x(l),p.width),l+=p.width+i}}catch(t){c=!0,h=t}finally{try{u||null==d.return||d.return()}finally{if(c)throw h}}}else{var v=0,g=(0,m.S)(n,this.top+t+i,this.bottom-this.columnSizes[v].height),y=!0,b=!1,_=void 0;try{for(var x,k=e[Symbol.iterator]();!(y=(x=k.next()).done);y=!0){var w=x.value;w.col!==v&&(v=w.col,g=(0,m.S)(n,this.top+t+i,this.bottom-this.columnSizes[v].height)),w.top=g,w.left+=this.left+i,w.left=o.leftForLtr(o.x(w.left),w.width),g+=w.height+i}}catch(t){b=!0,_=t}finally{try{y||null==k.return||k.return()}finally{if(b)throw _}}}}}},{key:"isHorizontal",value:function(){return"top"===this.options.position||"bottom"===this.options.position}},{key:"draw",value:function(){if(this.options.display){var t=this.ctx;(0,m.L)(t,this),this._draw(),(0,m.N)(t)}}},{key:"_draw",value:function(){var t,e=this,r=this.options,n=this.columnSizes,i=this.lineWidths,a=this.ctx,o=r.align,s=r.labels,l=m.d.color,u=(0,m.aA)(r.rtl,this.left,this.width),c=(0,m.O)(s.font),h=s.color,f=s.padding,d=c.size,p=d/2;this.drawTitle(),a.textAlign=u.textAlign("left"),a.textBaseline="middle",a.lineWidth=.5,a.font=c.string;var v=eI(s,d),g=v.boxWidth,y=v.boxHeight,b=v.itemHeight,_=function(t,e,r){if(!(isNaN(g)||g<=0||isNaN(y))&&!(y<0)){a.save();var n=(0,m.v)(r.lineWidth,1);if(a.fillStyle=(0,m.v)(r.fillStyle,l),a.lineCap=(0,m.v)(r.lineCap,"butt"),a.lineDashOffset=(0,m.v)(r.lineDashOffset,0),a.lineJoin=(0,m.v)(r.lineJoin,"miter"),a.lineWidth=n,a.strokeStyle=(0,m.v)(r.strokeStyle,l),a.setLineDash((0,m.v)(r.lineDash,[])),s.usePointStyle){var i={radius:y*Math.SQRT2/2,pointStyle:r.pointStyle,rotation:r.rotation,borderWidth:n},o=u.xPlus(t,g/2);(0,m.aE)(a,i,o,e+p,s.pointStyleWidth&&g)}else{var c=e+Math.max((d-y)/2,0),h=u.leftForLtr(t,g),f=(0,m.ax)(r.borderRadius);a.beginPath(),Object.values(f).some(function(t){return 0!==t})?(0,m.av)(a,{x:h,y:c,w:g,h:y,radius:f}):a.rect(h,c,g,y),a.fill(),0!==n&&a.stroke()}a.restore()}},x=function(t,e,r){(0,m.M)(a,r.text,t,e+b/2,c,{strikethrough:r.hidden,textAlign:u.textAlign(r.textAlign)})},k=this.isHorizontal(),w=this._computeTitleHeight();t=k?{x:(0,m.S)(o,this.left+f,this.right-i[0]),y:this.top+f+w,line:0}:{x:this.left+f,y:(0,m.S)(o,this.top+w+f,this.bottom-n[0].height),line:0},(0,m.aB)(this.ctx,r.textDirection);var M=b+f;this.legendItems.forEach(function(l,c){a.strokeStyle=l.fontColor||h,a.fillStyle=l.fontColor||h;var d=a.measureText(l.text).width,v=u.textAlign(l.textAlign||(l.textAlign=s.textAlign)),y=g+p+d,b=t.x,S=t.y;u.setWidth(e.width),k?c>0&&b+y+f>e.right&&(S=t.y+=M,t.line++,b=t.x=(0,m.S)(o,e.left+f,e.right-i[t.line])):c>0&&S+M>e.bottom&&(b=t.x=b+n[t.line].width+f,t.line++,S=t.y=(0,m.S)(o,e.top+w+f,e.bottom-n[t.line].height)),_(u.x(b),S,l),b=(0,m.aC)(v,b+g+p,k?b+y:e.right,r.rtl),x(u.x(b),S,l),k?t.x+=y+f:t.y+=M}),(0,m.aD)(this.ctx,r.textDirection)}},{key:"drawTitle",value:function(){var t,e,r=this.options,n=r.title,i=(0,m.O)(n.font),a=(0,m.K)(n.padding);if(n.display){var o=(0,m.aA)(r.rtl,this.left,this.width),s=this.ctx,l=n.position,u=i.size/2,c=a.top+u,h=this.left,f=this.width;if(this.isHorizontal())f=(e=Math).max.apply(e,(0,p._)(this.lineWidths)),t=this.top+c,h=(0,m.S)(r.align,h,this.right-f);else{var d=this.columnSizes.reduce(function(t,e){return Math.max(t,e.height)},0);t=c+(0,m.S)(r.align,this.top,this.bottom-d-r.labels.padding-this._computeTitleHeight())}var v=(0,m.S)(l,h,h+f);s.textAlign=o.textAlign((0,m.R)(l)),s.textBaseline="middle",s.strokeStyle=n.color,s.fillStyle=n.color,s.font=i.string,(0,m.M)(s,n.text,v,t,i)}}},{key:"_computeTitleHeight",value:function(){var t=this.options.title,e=(0,m.O)(t.font),r=(0,m.K)(t.padding);return t.display?e.lineHeight+r.height:0}},{key:"_getLegendItemAt",value:function(t,e){var r,n,i;if((0,m.ak)(t,this.left,this.right)&&(0,m.ak)(e,this.top,this.bottom)){for(r=0,i=this.legendHitBoxes;r-1?t.split("\n"):t}function eK(t,e){var r=t.chart.ctx,n=t.body,i=t.footer,a=t.title,o=e.boxWidth,s=e.boxHeight,l=(0,m.O)(e.bodyFont),u=(0,m.O)(e.titleFont),c=(0,m.O)(e.footerFont),h=a.length,f=i.length,d=n.length,p=(0,m.K)(e.padding),v=p.height,g=0,y=n.reduce(function(t,e){return t+e.before.length+e.lines.length+e.after.length},0);y+=t.beforeBody.length+t.afterBody.length,h&&(v+=h*u.lineHeight+(h-1)*e.titleSpacing+e.titleMarginBottom),y&&(v+=d*(e.displayColors?Math.max(s,l.lineHeight):l.lineHeight)+(y-d)*l.lineHeight+(y-1)*e.bodySpacing),f&&(v+=e.footerMarginTop+f*c.lineHeight+(f-1)*e.footerSpacing);var b=0,_=function(t){g=Math.max(g,r.measureText(t).width+b)};return r.save(),r.font=u.string,(0,m.Q)(t.title,_),r.font=l.string,(0,m.Q)(t.beforeBody.concat(t.afterBody),_),b=e.displayColors?o+2+e.boxPadding:0,(0,m.Q)(n,function(t){(0,m.Q)(t.before,_),(0,m.Q)(t.lines,_),(0,m.Q)(t.after,_)}),b=0,r.font=c.string,(0,m.Q)(t.footer,_),r.restore(),{width:g+=p.width,height:v}}function eY(t,e,r){var n,i,a,o,s,l,u,c,h,f=r.yAlign||e.yAlign||((n=r.y)<(i=r.height)/2?"top":n>t.height-i/2?"bottom":"center");return{xAlign:r.xAlign||e.xAlign||(a=r.x,o=r.width,s=t.width,u=(l=t.chartArea).left,c=l.right,h="center","center"===f?h=a<=(u+c)/2?"left":"right":a<=o/2?h="left":a>=s-o/2&&(h="right"),function(t,e,r,n){var i=n.x,a=n.width,o=r.caretSize+r.caretPadding;if("left"===t&&i+a+o>e.width||"right"===t&&i-a-o<0)return!0}(h,t,e,r)&&(h="center"),h),yAlign:f}}function eX(t,e,r,n){var i,a,o,s,l=t.caretSize,u=t.caretPadding,c=t.cornerRadius,h=r.xAlign,f=r.yAlign,d=l+u,p=(0,m.ax)(c),v=p.topLeft,g=p.topRight,y=p.bottomLeft,b=p.bottomRight,_=(i=e.x,a=e.width,"right"===h?i-=a:"center"===h&&(i-=a/2),i),x=(o=e.y,s=e.height,"top"===f?o+=d:"bottom"===f?o-=s+d:o-=s/2,o);return"center"===f?"left"===h?_+=d:"right"===h&&(_-=d):"left"===h?_-=Math.max(v,y)+l:"right"===h&&(_+=Math.max(g,b)+l),{x:(0,m.E)(_,0,n.width-e.width),y:(0,m.E)(x,0,n.height-e.height)}}function eq(t,e,r){var n=(0,m.K)(r.padding);return"center"===e?t.x+t.width/2:"right"===e?t.x+t.width-n.right:t.x+n.left}function e$(t,e){var r=e&&e.dataset&&e.dataset.tooltip&&e.dataset.tooltip.callbacks;return r?t.override(r):t}var eQ=function(t){(0,c._)(r,t);var e=(0,y._)(r);function r(t){var n;return(0,a._)(this,r),(n=e.call(this)).opacity=0,n._active=[],n._eventPosition=void 0,n._size=void 0,n._cachedAnimations=void 0,n._tooltipItems=[],n.$animations=void 0,n.$context=void 0,n.chart=t.chart||t._chart,n._chart=n.chart,n.options=t.options,n.dataPoints=void 0,n.title=void 0,n.beforeBody=void 0,n.body=void 0,n.afterBody=void 0,n.footer=void 0,n.xAlign=void 0,n.yAlign=void 0,n.x=void 0,n.y=void 0,n.height=void 0,n.width=void 0,n.caretX=void 0,n.caretY=void 0,n.labelColors=void 0,n.labelPointStyles=void 0,n.labelTextColors=void 0,n}return(0,o._)(r,[{key:"initialize",value:function(t){this.options=t,this._cachedAnimations=void 0,this.$context=void 0}},{key:"_resolveAnimations",value:function(){var t=this._cachedAnimations;if(t)return t;var e=this.chart,r=this.options.setContext(this.getContext()),n=r.enabled&&e.options.animation&&r.animations,i=new M(this.chart,n);return n._cacheable&&(this._cachedAnimations=Object.freeze(i)),i}},{key:"getContext",value:function(){var t,e;return this.$context||(this.$context=(t=this.chart.getContext(),e=this._tooltipItems,(0,m.h)(t,{tooltip:this,tooltipItems:e,type:"tooltip"})))}},{key:"getTitle",value:function(t,e){var r=e.callbacks,n=r.beforeTitle.apply(this,[t]),i=r.title.apply(this,[t]),a=r.afterTitle.apply(this,[t]),o=[];return o=eH(o,eU(n)),o=eH(o,eU(i)),o=eH(o,eU(a))}},{key:"getBeforeBody",value:function(t,e){return eH([],eU(e.callbacks.beforeBody.apply(this,[t])))}},{key:"getBody",value:function(t,e){var r=this,n=e.callbacks,i=[];return(0,m.Q)(t,function(t){var e={before:[],lines:[],after:[]},a=e$(n,t);eH(e.before,eU(a.beforeLabel.call(r,t))),eH(e.lines,a.label.call(r,t)),eH(e.after,eU(a.afterLabel.call(r,t))),i.push(e)}),i}},{key:"getAfterBody",value:function(t,e){return eH([],eU(e.callbacks.afterBody.apply(this,[t])))}},{key:"getFooter",value:function(t,e){var r=e.callbacks,n=r.beforeFooter.apply(this,[t]),i=r.footer.apply(this,[t]),a=r.afterFooter.apply(this,[t]),o=[];return o=eH(o,eU(n)),o=eH(o,eU(i)),o=eH(o,eU(a))}},{key:"_createItems",value:function(t){var e,r,n=this,i=this._active,a=this.chart.data,o=[],s=[],l=[],u=[];for(e=0,r=i.length;e0&&e.stroke()}},{key:"_updateAnimationTarget",value:function(t){var e=this.chart,r=this.$animations,n=r&&r.x,i=r&&r.y;if(n||i){var a=eW[t.position].call(this,this._active,this._eventPosition);if(!a)return;var o=this._size=eK(this,t),s=Object.assign({},a,this._size),l=eY(e,t,s),u=eX(t,s,l,e);(n._to!==u.x||i._to!==u.y)&&(this.xAlign=l.xAlign,this.yAlign=l.yAlign,this.width=o.width,this.height=o.height,this.caretX=a.x,this.caretY=a.y,this._resolveAnimations().update(this,u))}}},{key:"_willRender",value:function(){return!!this.opacity}},{key:"draw",value:function(t){var e=this.options.setContext(this.getContext()),r=this.opacity;if(r){this._updateAnimationTarget(e);var n={width:this.width,height:this.height},i={x:this.x,y:this.y};r=.001>Math.abs(r)?0:r;var a=(0,m.K)(e.padding),o=this.title.length||this.beforeBody.length||this.body.length||this.afterBody.length||this.footer.length;e.enabled&&o&&(t.save(),t.globalAlpha=r,this.drawBackground(i,t,n,e),(0,m.aB)(t,e.textDirection),i.y+=a.top,this.drawTitle(i,t,e),this.drawBody(i,t,e),this.drawFooter(i,t,e),(0,m.aD)(t,e.textDirection),t.restore())}}},{key:"getActiveElements",value:function(){return this._active||[]}},{key:"setActiveElements",value:function(t,e){var r=this,n=this._active,i=t.map(function(t){var e=t.datasetIndex,n=t.index,i=r.chart.getDatasetMeta(e);if(!i)throw Error("Cannot find a dataset at index "+e);return{datasetIndex:e,element:i.data[n],index:n}}),a=!(0,m.ai)(n,i),o=this._positionChanged(i,e);(a||o)&&(this._active=i,this._eventPosition=e,this._ignoreReplayEvents=!0,this.update(!0))}},{key:"handleEvent",value:function(t,e){var r=!(arguments.length>2)||void 0===arguments[2]||arguments[2];if(e&&this._ignoreReplayEvents)return!1;this._ignoreReplayEvents=!1;var n=this.options,i=this._active||[],a=this._getActiveElements(t,i,e,r),o=this._positionChanged(a,t),s=e||!(0,m.ai)(a,i)||o;return s&&(this._active=a,(n.enabled||n.external)&&(this._eventPosition={x:t.x,y:t.y},this.update(!0,e))),s}},{key:"_getActiveElements",value:function(t,e,r,n){var i=this.options;if("mouseout"===t.type)return[];if(!n)return e;var a=this.chart.getElementsAtEventForMode(t,i.mode,i,r);return i.reverse&&a.reverse(),a}},{key:"_positionChanged",value:function(t,e){var r=this.caretX,n=this.caretY,i=eW[this.options.position].call(this,t,e);return!1!==i&&(r!==i.x||n!==i.y)}}]),r}((0,g._)(q));eQ.positioners=eW;var eG={id:"tooltip",_element:eQ,positioners:eW,afterInit:function(t,e,r){r&&(t.tooltip=new eQ({chart:t,options:r}))},beforeUpdate:function(t,e,r){t.tooltip&&t.tooltip.initialize(r)},reset:function(t,e,r){t.tooltip&&t.tooltip.initialize(r)},afterDraw:function(t){var e=t.tooltip;if(e&&e._willRender()){var r={tooltip:e};if(!1===t.notifyPlugins("beforeTooltipDraw",r))return;e.draw(t.ctx),t.notifyPlugins("afterTooltipDraw",r)}},afterEvent:function(t,e){if(t.tooltip){var r=e.replay;t.tooltip.handleEvent(e.event,r,e.inChartArea)&&(e.changed=!0)}},defaults:{enabled:!0,external:null,position:"average",backgroundColor:"rgba(0,0,0,0.8)",titleColor:"#fff",titleFont:{weight:"bold"},titleSpacing:2,titleMarginBottom:6,titleAlign:"left",bodyColor:"#fff",bodySpacing:2,bodyFont:{},bodyAlign:"left",footerColor:"#fff",footerSpacing:2,footerMarginTop:6,footerFont:{weight:"bold"},footerAlign:"left",padding:6,caretPadding:2,caretSize:5,cornerRadius:6,boxHeight:function(t,e){return e.bodyFont.size},boxWidth:function(t,e){return e.bodyFont.size},multiKeyBackground:"#fff",displayColors:!0,boxPadding:0,borderColor:"rgba(0,0,0,0)",borderWidth:0,animation:{duration:400,easing:"easeOutQuart"},animations:{numbers:{type:"number",properties:["x","y","width","height","caretX","caretY"]},opacity:{easing:"linear",duration:200}},callbacks:{beforeTitle:m.aF,title:function(t){if(t.length>0){var e=t[0],r=e.chart.data.labels,n=r?r.length:0;if(this&&this.options&&"dataset"===this.options.mode)return e.dataset.label||"";if(e.label)return e.label;if(n>0&&e.dataIndex=0&&te.length-1?null:this.getPixelForValue(e[t].value)}},{key:"getValueForPixel",value:function(t){return Math.round(this._startValue+this.getDecimalForPixel(t)*this._valueRange)}},{key:"getBasePixel",value:function(){return this.bottom}}]),r}(tr);function e0(t,e,r){var n=r.horizontal,i=r.minRotation,a=(0,m.t)(i),o=.75*e*(""+t).length;return Math.min(e/((n?Math.sin(a):Math.cos(a))||.001),o)}eZ.id="category",eZ.defaults={ticks:{callback:eZ.prototype.getLabelForValue}};var e1=function(t){(0,c._)(r,t);var e=(0,y._)(r);function r(t){var n;return(0,a._)(this,r),(n=e.call(this,t)).start=void 0,n.end=void 0,n._startValue=void 0,n._endValue=void 0,n._valueRange=0,n}return(0,o._)(r,[{key:"parse",value:function(t,e){return(0,m.k)(t)||("number"==typeof t||t instanceof Number)&&!isFinite(+t)?null:+t}},{key:"handleTickRangeOptions",value:function(){var t=this.options.beginAtZero,e=this.getUserBounds(),r=e.minDefined,n=e.maxDefined,i=this.min,a=this.max,o=function(t){return i=r?i:t},s=function(t){return a=n?a:t};if(t){var l=(0,m.s)(i),u=(0,m.s)(a);l<0&&u<0?s(0):l>0&&u>0&&o(0)}if(i===a){var c=1;(a>=Number.MAX_SAFE_INTEGER||i<=Number.MIN_SAFE_INTEGER)&&(c=Math.abs(.05*a)),s(a+c),t||o(i-c)}this.min=i,this.max=a}},{key:"getTickLimit",value:function(){var t,e=this.options.ticks,r=e.maxTicksLimit,n=e.stepSize;return n?(t=Math.ceil(this.max/n)-Math.floor(this.min/n)+1)>1e3&&(console.warn("scales.".concat(this.id,".ticks.stepSize: ").concat(n," would result generating up to ").concat(t," ticks. Limiting to 1000.")),t=1e3):(t=this.computeTickLimit(),r=r||11),r&&(t=Math.min(r,t)),t}},{key:"computeTickLimit",value:function(){return Number.POSITIVE_INFINITY}},{key:"buildTicks",value:function(){var t=this.options,e=t.ticks,r=this.getTickLimit(),n=function(t,e){var r,n,i,a,o=[],s=t.bounds,l=t.step,u=t.min,c=t.max,h=t.precision,f=t.count,d=t.maxTicks,p=t.maxDigits,v=t.includeBounds,g=l||1,y=d-1,b=e.min,_=e.max,x=!(0,m.k)(u),k=!(0,m.k)(c),w=!(0,m.k)(f),M=(_-b)/(p+1),S=(0,m.aI)((_-b)/y/g)*g;if(S<1e-14&&!x&&!k)return[{value:b},{value:_}];(a=Math.ceil(_/S)-Math.floor(b/S))>y&&(S=(0,m.aI)(a*S/y/g)*g),(0,m.k)(h)||(S=Math.ceil(S*(r=Math.pow(10,h)))/r),"ticks"===s?(n=Math.floor(b/S)*S,i=Math.ceil(_/S)*S):(n=b,i=_),x&&k&&l&&(0,m.aJ)((c-u)/l,S/1e3)?(a=Math.round(Math.min((c-u)/S,d)),S=(c-u)/a,n=u,i=c):w?(n=x?u:n,S=((i=k?c:i)-n)/(a=f-1)):(a=(i-n)/S,a=(0,m.aK)(a,Math.round(a),S/1e3)?Math.round(a):Math.ceil(a));var O=Math.max((0,m.aL)(S),(0,m.aL)(n));n=Math.round(n*(r=Math.pow(10,(0,m.k)(h)?O:h)))/r,i=Math.round(i*r)/r;var A=0;for(x&&(v&&n!==u?(o.push({value:u}),n0?r:null}},{key:"determineDataLimits",value:function(){var t=this.getMinMax(!0),e=t.min,r=t.max;this.min=(0,m.g)(e)?Math.max(0,e):null,this.max=(0,m.g)(r)?Math.max(0,r):null,this.options.beginAtZero&&(this._zero=!0),this.handleTickRangeOptions()}},{key:"handleTickRangeOptions",value:function(){var t=this.getUserBounds(),e=t.minDefined,r=t.maxDefined,n=this.min,i=this.max,a=function(t){return n=e?n:t},o=function(t){return i=r?i:t},s=function(t,e){return Math.pow(10,Math.floor((0,m.z)(t))+e)};n===i&&(n<=0?(a(1),o(10)):(a(s(n,-1)),o(s(i,1)))),n<=0&&a(s(i,-1)),i<=0&&o(s(n,1)),this._zero&&this.min!==this._suggestedMin&&n===s(this.min,0)&&a(s(n,-1)),this.min=n,this.max=i}},{key:"buildTicks",value:function(){var t=this.options,e=function(t,e){var r=Math.floor((0,m.z)(e.max)),n=Math.ceil(e.max/Math.pow(10,r)),i=[],a=(0,m.B)(t.min,Math.pow(10,Math.floor((0,m.z)(e.min)))),o=Math.floor((0,m.z)(a)),s=Math.floor(a/Math.pow(10,o)),l=o<0?Math.pow(10,Math.abs(o)):1;do i.push({value:a,major:e5(a)}),10==++s&&(s=1,l=++o>=0?1:l),a=Math.round(s*Math.pow(10,o)*l)/l;while(oi?{start:e-r,end:e}:{start:e,end:e+r}}function e4(t,e,r,n){var i=t.ctx;if(r)i.arc(t.xCenter,t.yCenter,e,0,m.T);else{var a=t.getPointPosition(0,e);i.moveTo(a.x,a.y);for(var o=1;oe.r&&(s=(n.end-e.r)/a,t.r=Math.max(t.r,e.r+s)),i.starte.b&&(l=(i.end-e.b)/o,t.b=Math.max(t.b,e.b+l))})(r,e,v,e8(g,f.x,p.w,0,180),e8(g,f.y,p.h,90,270))}t.setCenterPoint(e.l-r.l,r.r-e.r,e.t-r.t,r.b-e.b),t._pointLabelItems=function(t,e,r){for(var n=[],i=t._pointLabels.length,a=t.options,o=e6(a)/2,s=t.drawingArea,l=a.pointLabels.centerPointLabels?m.P/i:0,u=0;u270||v<90)&&(c-=h),c),b=0===v||180===v?"center":v<180?"left":"right",_=(f=p.x,d=g.w,"right"===b?f-=d:"center"===b&&(f-=d/2),f);n.push({x:p.x,y:y,textAlign:b,left:_,top:y,right:_+g.w,bottom:y+g.h})}return n}(t,n,i)}(this):this.setCenterPoint(0,0,0,0)}},{key:"setCenterPoint",value:function(t,e,r,n){this.xCenter+=Math.floor((t-e)/2),this.yCenter+=Math.floor((r-n)/2),this.drawingArea-=Math.min(this.drawingArea/2,Math.max(t,e,r,n))}},{key:"getIndexAngle",value:function(t){var e=m.T/(this._pointLabels.length||1),r=this.options.startAngle||0;return(0,m.az)(t*e+(0,m.t)(r))}},{key:"getDistanceFromCenterForValue",value:function(t){if((0,m.k)(t))return NaN;var e=this.drawingArea/(this.max-this.min);return this.options.reverse?(this.max-t)*e:(t-this.min)*e}},{key:"getValueForDistanceFromCenter",value:function(t){if((0,m.k)(t))return NaN;var e=t/(this.drawingArea/(this.max-this.min));return this.options.reverse?this.max-e:this.min+e}},{key:"getPointLabelContext",value:function(t){var e=this._pointLabels||[];if(t>=0&&t2&&void 0!==arguments[2]?arguments[2]:0,n=this.getIndexAngle(t)-m.H+r;return{x:Math.cos(n)*e+this.xCenter,y:Math.sin(n)*e+this.yCenter,angle:n}}},{key:"getPointPositionForValue",value:function(t,e){return this.getPointPosition(t,this.getDistanceFromCenterForValue(e))}},{key:"getBasePosition",value:function(t){return this.getPointPositionForValue(t||0,this.getBaseValue())}},{key:"getPointLabelPosition",value:function(t){var e=this._pointLabelItems[t];return{left:e.left,top:e.top,right:e.right,bottom:e.bottom}}},{key:"drawBackground",value:function(){var t=this.options,e=t.backgroundColor,r=t.grid.circular;if(e){var n=this.ctx;n.save(),n.beginPath(),e4(this,this.getDistanceFromCenterForValue(this._endValue),r,this._pointLabels.length),n.closePath(),n.fillStyle=e,n.fill(),n.restore()}}},{key:"drawGrid",value:function(){var t,e,r,n=this,i=this.ctx,a=this.options,o=a.angleLines,s=a.grid,l=this._pointLabels.length;if(a.pointLabels.display&&function(t,e){for(var r=t.ctx,n=t.options.pointLabels,i=e-1;i>=0;i--){var a=n.setContext(t.getPointLabelContext(i)),o=(0,m.O)(a.font),s=t._pointLabelItems[i],l=s.x,u=s.y,c=s.textAlign,h=s.left,f=s.top,d=s.right,p=s.bottom,v=a.backdropColor;if(!(0,m.k)(v)){var g=(0,m.ax)(a.borderRadius),y=(0,m.K)(a.backdropPadding);r.fillStyle=v;var b=h-y.left,_=f-y.top,x=d-h+y.width,k=p-f+y.height;Object.values(g).some(function(t){return 0!==t})?(r.beginPath(),(0,m.av)(r,{x:b,y:_,w:x,h:k,radius:g}),r.fill()):r.fillRect(b,_,x,k)}(0,m.M)(r,t._pointLabels[i],l,u+o.lineHeight/2,o,{color:a.color,textAlign:c,textBaseline:"middle"})}}(this,l),s.display&&this.ticks.forEach(function(t,r){if(0!==r){e=n.getDistanceFromCenterForValue(t.value);var i,a,o,u,c,h=s.setContext(n.getContext(r-1));i=e,a=n.ctx,o=h.circular,u=h.color,c=h.lineWidth,(o||l)&&u&&c&&!(i<0)&&(a.save(),a.strokeStyle=u,a.lineWidth=c,a.setLineDash(h.borderDash),a.lineDashOffset=h.borderDashOffset,a.beginPath(),e4(n,i,o,l),a.closePath(),a.stroke(),a.restore())}}),o.display){for(i.save(),t=l-1;t>=0;t--){var u=o.setContext(this.getPointLabelContext(t)),c=u.color,h=u.lineWidth;h&&c&&(i.lineWidth=h,i.strokeStyle=c,i.setLineDash(u.borderDash),i.lineDashOffset=u.borderDashOffset,e=this.getDistanceFromCenterForValue(a.ticks.reverse?this.min:this.max),r=this.getPointPosition(t,e),i.beginPath(),i.moveTo(this.xCenter,this.yCenter),i.lineTo(r.x,r.y),i.stroke())}i.restore()}}},{key:"drawBorder",value:function(){}},{key:"drawLabels",value:function(){var t,e,r=this,n=this.ctx,i=this.options,a=i.ticks;if(a.display){var o=this.getIndexAngle(0);n.save(),n.translate(this.xCenter,this.yCenter),n.rotate(o),n.textAlign="center",n.textBaseline="middle",this.ticks.forEach(function(o,s){if(0!==s||i.reverse){var l=a.setContext(r.getContext(s)),u=(0,m.O)(l.font);if(t=r.getDistanceFromCenterForValue(r.ticks[s].value),l.showLabelBackdrop){n.font=u.string,e=n.measureText(o.label).width,n.fillStyle=l.backdropColor;var c=(0,m.K)(l.backdropPadding);n.fillRect(-e/2-c.left,-t-u.size/2-c.top,e+c.width,u.size+c.height)}(0,m.M)(n,o.label,0,-t,u,{color:l.color})}}),n.restore()}}},{key:"drawTitle",value:function(){}}]),r}(e1);e7.id="radialLinear",e7.defaults={display:!0,animate:!0,position:"chartArea",angleLines:{display:!0,lineWidth:1,borderDash:[],borderDashOffset:0},grid:{circular:!1},startAngle:0,ticks:{showLabelBackdrop:!0,callback:Q.formatters.numeric},pointLabels:{backdropColor:void 0,backdropPadding:2,display:!0,font:{size:10},callback:function(t){return t},padding:5,centerPointLabels:!1}},e7.defaultRoutes={"angleLines.color":"borderColor","pointLabels.color":"color","ticks.color":"color"},e7.descriptors={angleLines:{_fallback:"grid"}};var e9={millisecond:{common:!0,size:1,steps:1e3},second:{common:!0,size:1e3,steps:60},minute:{common:!0,size:6e4,steps:60},hour:{common:!0,size:36e5,steps:24},day:{common:!0,size:864e5,steps:30},week:{common:!1,size:6048e5,steps:4},month:{common:!0,size:2628e6,steps:12},quarter:{common:!1,size:7884e6,steps:4},year:{common:!0,size:3154e7}},rt=Object.keys(e9);function re(t,e){return t-e}function rr(t,e){if((0,m.k)(e))return null;var r=t._adapter,n=t._parseOpts,i=n.parser,a=n.round,o=n.isoWeekday,s=e;return("function"==typeof i&&(s=i(s)),(0,m.g)(s)||(s="string"==typeof i?r.parse(s,i):r.parse(s)),null===s)?null:(a&&(s="week"===a&&((0,m.x)(o)||!0===o)?r.startOf(s,"isoWeek",o):r.startOf(s,a)),+s)}function rn(t,e,r,n){for(var i=rt.length,a=rt.indexOf(t);a=e?r[i]:r[a]]=!0}}else t[e]=!0}function ra(t,e,r){var n,i,a=[],o={},s=e.length;for(n=0;n=0&&(e[a].major=!0);return e}(t,a,o,r):a}var ro=function(t){(0,c._)(r,t);var e=(0,y._)(r);function r(t){var n;return(0,a._)(this,r),(n=e.call(this,t))._cache={data:[],labels:[],all:[]},n._unit="day",n._majorUnit=void 0,n._offsets={},n._normalized=!1,n._parseOpts=void 0,n}return(0,o._)(r,[{key:"init",value:function(t,e){var n=t.time||(t.time={}),i=this._adapter=new tu._date(t.adapters.date);i.init(e),(0,m.ac)(n.displayFormats,i.formats()),this._parseOpts={parser:n.parser,round:n.round,isoWeekday:n.isoWeekday},(0,l._)((0,u._)(r.prototype),"init",this).call(this,t),this._normalized=e.normalized}},{key:"parse",value:function(t,e){return void 0===t?null:rr(this,t)}},{key:"beforeLayout",value:function(){(0,l._)((0,u._)(r.prototype),"beforeLayout",this).call(this),this._cache={data:[],labels:[],all:[]}}},{key:"determineDataLimits",value:function(){var t=this.options,e=this._adapter,r=t.time.unit||"day",n=this.getUserBounds(),i=n.min,a=n.max,o=n.minDefined,s=n.maxDefined;function l(t){o||isNaN(t.min)||(i=Math.min(i,t.min)),s||isNaN(t.max)||(a=Math.max(a,t.max))}o&&s||(l(this._getLabelBounds()),("ticks"!==t.bounds||"labels"!==t.ticks.source)&&l(this.getMinMax(!1))),i=(0,m.g)(i)&&!isNaN(i)?i:+e.startOf(Date.now(),r),a=(0,m.g)(a)&&!isNaN(a)?a:+e.endOf(Date.now(),r)+1,this.min=Math.min(i,a-1),this.max=Math.max(i+1,a)}},{key:"_getLabelBounds",value:function(){var t=this.getLabelTimestamps(),e=Number.POSITIVE_INFINITY,r=Number.NEGATIVE_INFINITY;return t.length&&(e=t[0],r=t[t.length-1]),{min:e,max:r}}},{key:"buildTicks",value:function(){var t=this.options,e=t.time,r=t.ticks,n="labels"===r.source?this.getLabelTimestamps():this._generate();"ticks"===t.bounds&&n.length&&(this.min=this._userMin||n[0],this.max=this._userMax||n[n.length-1]);var i=this.min,a=this.max,o=(0,m.aN)(n,i,a);return this._unit=e.unit||(r.autoSkip?rn(e.minUnit,this.min,this.max,this._getLabelCapacity(i)):function(t,e,r,n,i){for(var a=rt.length-1;a>=rt.indexOf(r);a--){var o=rt[a];if(e9[o].common&&t._adapter.diff(i,n,o)>=e-1)return o}return rt[r?rt.indexOf(r):0]}(this,o.length,e.minUnit,this.min,this.max)),this._majorUnit=r.major.enabled&&"year"!==this._unit?function(t){for(var e=rt.indexOf(t)+1,r=rt.length;e1e5*l)throw Error(n+" and "+i+" are too far apart with stepSize of "+l+" "+s);var d="data"===a.ticks.source&&this.getDataTimestamps();for(t=f,e=0;t0?o:1}},{key:"getDataTimestamps",value:function(){var t,e,r=this._cache.data||[];if(r.length)return r;var n=this.getMatchingVisibleMetas();if(this._normalized&&n.length)return this._cache.data=n[0].controller.getAllParsedValues(this);for(t=0,e=n.length;t=t[d].pos&&e<=t[p].pos&&(d=(s=(0,m.Z)(t,"pos",e)).lo,p=s.hi),n=(l=t[d]).pos,a=l.time,i=(u=t[p]).pos,o=u.time):(e>=t[d].time&&e<=t[p].time&&(d=(c=(0,m.Z)(t,"time",e)).lo,p=c.hi),n=(h=t[d]).time,a=h.pos,i=(f=t[p]).time,o=f.pos);var v=i-n;return v?a+(o-a)*(e-n)/v:a}ro.id="time",ro.defaults={bounds:"data",adapters:{},time:{parser:!1,unit:!1,round:!1,isoWeekday:!1,minUnit:"millisecond",displayFormats:{}},ticks:{source:"auto",major:{enabled:!1}}};var rl=function(t){(0,c._)(r,t);var e=(0,y._)(r);function r(t){var n;return(0,a._)(this,r),(n=e.call(this,t))._table=[],n._minPos=void 0,n._tableRange=void 0,n}return(0,o._)(r,[{key:"initOffsets",value:function(){var t=this._getTimestampsForTable(),e=this._table=this.buildLookupTable(t);this._minPos=rs(e,this.min),this._tableRange=rs(e,this.max)-this._minPos,(0,l._)((0,u._)(r.prototype),"initOffsets",this).call(this,t)}},{key:"buildLookupTable",value:function(t){var e,r,n,i=this.min,a=this.max,o=[],s=[];for(e=0,r=t.length;e=i&&n<=a&&o.push(n);if(o.length<2)return[{time:i,pos:0},{time:a,pos:1}];for(e=0,r=o.length;e")+"->"+t);return s.add(t),e=e(a,o||n),s.delete(t),eD(t,e)&&(e=eT(i._scopes,i,t,e)),e}(r,l,e,n)),p(l)&&l.length&&(l=function(e,r,n,i){var a=n._proxy,o=n._context,s=n._subProxy,l=n._descriptors;if(I(o.index)&&i(e))r=r[o.index%r.length];else if(v(r[0])){var u=r,c=a._scopes.filter(function(t){return t!==u});r=[];var h=!0,f=!1,d=void 0;try{for(var p,g=u[Symbol.iterator]();!(h=(p=g.next()).done);h=!0){var y=p.value,m=eT(c,a,e,y);r.push(t(m,o,s&&s[e],l))}}catch(t){f=!0,d=t}finally{try{h||null==g.return||g.return()}finally{if(f)throw d}}}return r}(r,l,e,s.isIndexable)),eD(r,l)&&(l=t(l,a,o&&o[r],s)),l})},getOwnPropertyDescriptor:function(t,r){return t._descriptors.allKeys?Reflect.has(e,r)?{enumerable:!0,configurable:!0}:void 0:Reflect.getOwnPropertyDescriptor(e,r)},getPrototypeOf:function(){return Reflect.getPrototypeOf(e)},has:function(t,r){return Reflect.has(e,r)},ownKeys:function(){return Reflect.ownKeys(e)},set:function(t,r,n){return e[r]=n,delete t[r],!0}})}}),a.export(r,"aA",function(){return e9}),a.export(r,"aB",function(){return rt}),a.export(r,"aC",function(){return tO}),a.export(r,"aD",function(){return re}),a.export(r,"aE",function(){return ec}),a.export(r,"aF",function(){return h}),a.export(r,"aG",function(){return ta}),a.export(r,"aH",function(){return tt}),a.export(r,"aI",function(){return $}),a.export(r,"aJ",function(){return Z}),a.export(r,"aK",function(){return J}),a.export(r,"aL",function(){return tn}),a.export(r,"aM",function(){return eo}),a.export(r,"aN",function(){return tv}),a.export(r,"aO",function(){return tf}),a.export(r,"aP",function(){return t8}),a.export(r,"aQ",function(){return t7}),a.export(r,"aR",function(){return M}),a.export(r,"aS",function(){return O}),a.export(r,"aT",function(){return C}),a.export(r,"aU",function(){return P}),a.export(r,"aV",function(){return T}),a.export(r,"aW",function(){return ei}),a.export(r,"aX",function(){return ez}),a.export(r,"aY",function(){return eW}),a.export(r,"aZ",function(){return e$}),a.export(r,"a_",function(){return t_}),a.export(r,"aa",function(){return eC}),a.export(r,"ab",function(){return eP}),a.export(r,"ac",function(){return E}),a.export(r,"ad",function(){return f}),a.export(r,"ae",function(){return tw}),a.export(r,"af",function(){return e1}),a.export(r,"ag",function(){return el}),a.export(r,"ah",function(){return B}),a.export(r,"ai",function(){return w}),a.export(r,"aj",function(){return R}),a.export(r,"ak",function(){return th}),a.export(r,"al",function(){return ex}),a.export(r,"am",function(){return eU}),a.export(r,"an",function(){return ro}),a.export(r,"ao",function(){return ra}),a.export(r,"ap",function(){return e6}),a.export(r,"aq",function(){return e8}),a.export(r,"ar",function(){return e3}),a.export(r,"as",function(){return ep}),a.export(r,"at",function(){return ev}),a.export(r,"au",function(){return eu}),a.export(r,"av",function(){return ey}),a.export(r,"aw",function(){return ek}),a.export(r,"ax",function(){return ew}),a.export(r,"ay",function(){return ri}),a.export(r,"az",function(){return ts}),a.export(r,"b",function(){return p}),a.export(r,"b0",function(){return z}),a.export(r,"b1",function(){return W}),a.export(r,"b2",function(){return H}),a.export(r,"b3",function(){return K}),a.export(r,"b4",function(){return Y}),a.export(r,"b5",function(){return to}),a.export(r,"c",function(){return t4}),a.export(r,"d",function(){return en}),a.export(r,"e",function(){return tj}),a.export(r,"f",function(){return j}),a.export(r,"g",function(){return g}),a.export(r,"h",function(){return eE}),a.export(r,"i",function(){return v}),a.export(r,"j",function(){return I}),a.export(r,"k",function(){return d}),a.export(r,"l",function(){return ty}),a.export(r,"m",function(){return b}),a.export(r,"n",function(){return _}),a.export(r,"o",function(){return e7}),a.export(r,"p",function(){return tl}),a.export(r,"q",function(){return tA}),a.export(r,"r",function(){return tx}),a.export(r,"s",function(){return q}),a.export(r,"t",function(){return te}),a.export(r,"u",function(){return tm}),a.export(r,"v",function(){return m}),a.export(r,"w",function(){return tE}),a.export(r,"x",function(){return G}),a.export(r,"y",function(){return eB}),a.export(r,"z",function(){return X});var o=t("@swc/helpers/_/_class_call_check"),s=t("@swc/helpers/_/_create_class"),l=t("@swc/helpers/_/_define_property"),u=t("@swc/helpers/_/_to_consumable_array"),c=t("@swc/helpers/_/_type_of");function h(){}var f=(n=0,function(){return n++});function d(t){return null==t}function p(t){if(Array.isArray&&Array.isArray(t))return!0;var e=Object.prototype.toString.call(t);return"[object"===e.slice(0,7)&&"Array]"===e.slice(-6)}function v(t){return null!==t&&"[object Object]"===Object.prototype.toString.call(t)}var g=function(t){return("number"==typeof t||t instanceof Number)&&isFinite(+t)};function y(t,e){return g(t)?t:e}function m(t,e){return void 0===t?e:t}var b=function(t,e){return"string"==typeof t&&t.endsWith("%")?parseFloat(t)/100:t/e},_=function(t,e){return"string"==typeof t&&t.endsWith("%")?parseFloat(t)/100*e:+t};function x(t,e,r){if(t&&"function"==typeof t.call)return t.apply(r,e)}function k(t,e,r,n){var i,a,o;if(p(t)){if(a=t.length,n)for(i=a-1;i>=0;i--)e.call(r,t[i],i);else for(i=0;i=t}function tt(t,e,r){var n,i,a;for(n=0,i=t.length;nl&&u3&&void 0!==arguments[3]?arguments[3]:1e-6;return t>=Math.min(e,r)-n&&t<=Math.max(e,r)+n}function tf(t,e,r){r=r||function(r){return t[r]1;)r(n=a+i>>1)?a=n:i=n;return{lo:a,hi:i}}var td=function(t,e,r,n){return tf(t,r,n?function(n){return t[n][e]<=r}:function(n){return t[n][e]=r})};function tv(t,e,r){for(var n=0,i=t.length;nn&&t[i-1]>r;)i--;return n>0||i0||(tg.forEach(function(e){delete t[e]}),delete t._chartjs)}}function tb(t){var e,r,n=new Set;for(e=0,r=t.length;e=1?t:-(Math.sqrt(1-t*t)-1)},easeOutCirc:function(t){return Math.sqrt(1-(t-=1)*t)},easeInOutCirc:function(t){return(t/=.5)<1?-.5*(Math.sqrt(1-t*t)-1):.5*(Math.sqrt(1-(t-=2)*t)+1)},easeInElastic:function(t){return tC(t)?t:tP(t,.075,.3)},easeOutElastic:function(t){return tC(t)?t:tD(t,.075,.3)},easeInOutElastic:function(t){return tC(t)?t:t<.5?.5*tP(2*t,.1125,.45):.5+.5*tD(2*t-1,.1125,.45)},easeInBack:function(t){return t*t*(2.70158*t-1.70158)},easeOutBack:function(t){return(t-=1)*t*(2.70158*t+1.70158)+1},easeInOutBack:function(t){var e=1.70158;return(t/=.5)<1?t*t*(((e*=1.525)+1)*t-e)*.5:.5*((t-=2)*t*(((e*=1.525)+1)*t+e)+2)},easeInBounce:function(t){return 1-tj.easeOutBounce(1-t)},easeOutBounce:function(t){return t<.36363636363636365?7.5625*t*t:t<.7272727272727273?7.5625*(t-=.5454545454545454)*t+.75:t<.9090909090909091?7.5625*(t-=.8181818181818182)*t+.9375:7.5625*(t-=.9545454545454546)*t+.984375},easeInOutBounce:function(t){return t<.5?.5*tj.easeInBounce(2*t):.5*tj.easeOutBounce(2*t-1)+.5}};/*!
* @kurkle/color v0.2.1
* https://github.com/kurkle/color#readme
* (c) 2022 Jukka Kurkela
* Released under the MIT License
*/function tT(t){return t+.5|0}var tF=function(t,e,r){return Math.max(Math.min(t,r),e)};function tI(t){return tF(tT(2.55*t),0,255)}function tL(t){return tF(tT(255*t),0,255)}function tB(t){return tF(tT(t/2.55)/100,0,1)}function tR(t){return tF(tT(100*t),0,100)}var tN={0:0,1:1,2:2,3:3,4:4,5:5,6:6,7:7,8:8,9:9,A:10,B:11,C:12,D:13,E:14,F:15,a:10,b:11,c:12,d:13,e:14,f:15},tV=Array.from("0123456789ABCDEF"),tz=function(t){return tV[15&t]},tW=function(t){return tV[(240&t)>>4]+tV[15&t]},tH=function(t){return(240&t)>>4==(15&t)},tU=/^(hsla?|hwb|hsv)\(\s*([-+.e\d]+)(?:deg)?[\s,]+([-+.e\d]+)%[\s,]+([-+.e\d]+)%(?:[\s,]+([-+.e\d]+)(%)?)?\s*\)$/;function tK(t,e,r){var n=e*Math.min(r,1-r),i=function(e){var i=arguments.length>1&&void 0!==arguments[1]?arguments[1]:(e+t/30)%12;return r-n*Math.max(Math.min(i-3,9-i,1),-1)};return[i(0),i(8),i(4)]}function tY(t,e,r){var n=function(n){var i=arguments.length>1&&void 0!==arguments[1]?arguments[1]:(n+t/60)%6;return r-r*e*Math.max(Math.min(i,4-i,1),0)};return[n(5),n(3),n(1)]}function tX(t,e,r){var n,i=tK(t,1,.5);for(e+r>1&&(n=1/(e+r),e*=n,r*=n),n=0;n<3;n++)i[n]*=1-e-r,i[n]+=e;return i}function tq(t){var e,r,n,i=t.r/255,a=t.g/255,o=t.b/255,s=Math.max(i,a,o),l=Math.min(i,a,o),u=(s+l)/2;return s!==l&&(n=s-l,r=u>.5?n/(2-s-l):n/(s+l),e=60*(e=i===s?(a-o)/n+(a=3&&(e={r:t[0],g:t[1],b:t[2],a:255},t.length>3&&(e.a=tL(t[3]))):(e=t5(t,{r:0,g:0,b:0,a:1})).a=tL(e.a),e}var t6=function(){function t(e){if((0,o._)(this,t),e instanceof t)return e;var r,n,a,s,l=void 0===e?"undefined":(0,c._)(e);"object"===l?s=t3(e):"string"===l&&(n=e.length,"#"===e[0]&&(4===n||5===n?r={r:255&17*tN[e[1]],g:255&17*tN[e[2]],b:255&17*tN[e[3]],a:5===n?17*tN[e[4]]:255}:(7===n||9===n)&&(r={r:tN[e[1]]<<4|tN[e[2]],g:tN[e[3]]<<4|tN[e[4]],b:tN[e[5]]<<4|tN[e[6]],a:9===n?tN[e[7]]<<4|tN[e[8]]:255})),s=r||(i||((i=function(){var t,e,r,n,i,a={},o=Object.keys(tJ),s=Object.keys(tG);for(t=0;t>16&255,r>>8&255,255&r]}return a}()).transparent=[0,0,0,0]),(a=i[e.toLowerCase()])&&{r:a[0],g:a[1],b:a[2],a:4===a.length?a[3]:255})||("r"===e.charAt(0)?function(t){var e,r,n,i=tZ.exec(t),a=255;if(i){if(i[7]!==e){var o=+i[7];a=i[8]?tI(o):tF(255*o,0,255)}return e=+i[1],r=+i[3],n=+i[5],{r:e=255&(i[2]?tI(e):tF(e,0,255)),g:r=255&(i[4]?tI(r):tF(r,0,255)),b:n=255&(i[6]?tI(n):tF(n,0,255)),a:a}}}(e):function(t){var e,r=tU.exec(t),n=255;if(r){r[5]!==e&&(n=r[6]?tI(+r[5]):tL(+r[5]));var i=tQ(+r[2]),a=+r[3]/100,o=+r[4]/100;return{r:(e="hwb"===r[1]?t$(tX,i,a,o):"hsv"===r[1]?t$(tY,i,a,o):t$(tK,i,a,o))[0],g:e[1],b:e[2],a:n}}}(e))),this._rgb=s,this._valid=!!s}return(0,s._)(t,[{key:"valid",get:function(){return this._valid}},{key:"rgb",get:function(){var t=t5(this._rgb);return t&&(t.a=tB(t.a)),t},set:function(t){this._rgb=t3(t)}},{key:"rgbString",value:function(){var t;return this._valid?(t=this._rgb)&&(t.a<255?"rgba(".concat(t.r,", ").concat(t.g,", ").concat(t.b,", ").concat(tB(t.a),")"):"rgb(".concat(t.r,", ").concat(t.g,", ").concat(t.b,")")):void 0}},{key:"hexString",value:function(){var t,e,r,n;return this._valid?(r=tH((e=t=this._rgb).r)&&tH(e.g)&&tH(e.b)&&tH(e.a)?tz:tW,t?"#"+r(t.r)+r(t.g)+r(t.b)+((n=t.a)<255?r(n):""):void 0):void 0}},{key:"hslString",value:function(){return this._valid?function(t){if(t){var e=tq(t),r=e[0],n=tR(e[1]),i=tR(e[2]);return t.a<255?"hsla(".concat(r,", ").concat(n,"%, ").concat(i,"%, ").concat(tB(t.a),")"):"hsl(".concat(r,", ").concat(n,"%, ").concat(i,"%)")}}(this._rgb):void 0}},{key:"mix",value:function(t,e){if(t){var r,n=this.rgb,i=t.rgb,a=e===r?.5:e,o=2*a-1,s=n.a-i.a,l=((o*s==-1?o:(o+s)/(1+o*s))+1)/2;r=1-l,n.r=255&l*n.r+r*i.r+.5,n.g=255&l*n.g+r*i.g+.5,n.b=255&l*n.b+r*i.b+.5,n.a=a*n.a+(1-a)*i.a,this.rgb=n}return this}},{key:"interpolate",value:function(t,e){if(t){var r,n,i,a,o;this._rgb=(r=this._rgb,n=t._rgb,i=t1(tB(r.r)),a=t1(tB(r.g)),o=t1(tB(r.b)),{r:tL(t0(i+e*(t1(tB(n.r))-i))),g:tL(t0(a+e*(t1(tB(n.g))-a))),b:tL(t0(o+e*(t1(tB(n.b))-o))),a:r.a+e*(n.a-r.a)})}return this}},{key:"clone",value:function(){return new t(this.rgb)}},{key:"alpha",value:function(t){return this._rgb.a=tL(t),this}},{key:"clearer",value:function(t){var e=this._rgb;return e.a*=1-t,this}},{key:"greyscale",value:function(){var t=this._rgb,e=tT(.3*t.r+.59*t.g+.11*t.b);return t.r=t.g=t.b=e,this}},{key:"opaquer",value:function(t){var e=this._rgb;return e.a*=1+t,this}},{key:"negate",value:function(){var t=this._rgb;return t.r=255-t.r,t.g=255-t.g,t.b=255-t.b,this}},{key:"lighten",value:function(t){return t2(this._rgb,2,t),this}},{key:"darken",value:function(t){return t2(this._rgb,2,-t),this}},{key:"saturate",value:function(t){return t2(this._rgb,1,t),this}},{key:"desaturate",value:function(t){return t2(this._rgb,1,-t),this}},{key:"rotate",value:function(t){var e,r;return(r=tq(e=this._rgb))[0]=tQ(r[0]+t),r=t$(tK,r,void 0,void 0),e.r=r[0],e.g=r[1],e.b=r[2],this}}]),t}();function t8(t){if(t&&"object"==typeof t){var e=t.toString();return"[object CanvasPattern]"===e||"[object CanvasGradient]"===e}return!1}function t4(t){return t8(t)?t:new t6(t)}function t7(t){return t8(t)?t:new t6(t).saturate(.5).darken(.1).hexString()}var t9=Object.create(null),et=Object.create(null);function ee(t,e){if(!e)return t;for(var r=e.split("."),n=0,i=r.length;nn&&(n=a),n}function eo(t,e,r,n){var i,a,o,s,l,u=(n=n||{}).data=n.data||{},c=n.garbageCollect=n.garbageCollect||[];n.font!==e&&(u=n.data={},c=n.garbageCollect=[],n.font=e),t.save(),t.font=e;var h=0,f=r.length;for(i=0;ir.length){for(i=0;i0&&t.stroke()}}function eh(t,e,r){return r=r||.5,!e||t&&t.x>e.left-r&&t.xe.top-r&&t.y5&&void 0!==arguments[5]?arguments[5]:{},l=p(e)?e:[e],u=s.strokeWidth>0&&""!==s.strokeColor;for(t.save(),t.font=i.string,s.translation&&t.translate(s.translation[0],s.translation[1]),d(s.rotation)||t.rotate(s.rotation),s.color&&(t.fillStyle=s.color),s.textAlign&&(t.textAlign=s.textAlign),s.textBaseline&&(t.textBaseline=s.textBaseline),a=0;a1&&void 0!==arguments[1]?arguments[1]:[""],n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:t,i=arguments.length>3?arguments[3]:void 0,a=arguments.length>4&&void 0!==arguments[4]?arguments[4]:function(){return t[0]};return I(i)||(i=eI("_fallback",t)),new Proxy((e={},(0,l._)(e,Symbol.toStringTag,"Object"),(0,l._)(e,"_cacheable",!0),(0,l._)(e,"_scopes",t),(0,l._)(e,"_rootScopes",n),(0,l._)(e,"_fallback",i),(0,l._)(e,"_getTarget",a),(0,l._)(e,"override",function(e){return eC([e].concat((0,u._)(t)),r,n,i)}),e),{deleteProperty:function(e,r){return delete e[r],delete e._keys,delete t[0][r],!0},get:function(e,n){return ej(e,n,function(){return function(t,e,r,n){var i=!0,a=!1,o=void 0;try{for(var s,l,u=e[Symbol.iterator]();!(i=(l=u.next()).done);i=!0){var c=l.value;if(s=eI(c?c+F(t):t,r),I(s))return eD(t,s)?eT(r,n,t,s):s}}catch(t){a=!0,o=t}finally{try{i||null==u.return||u.return()}finally{if(a)throw o}}}(n,r,t,e)})},getOwnPropertyDescriptor:function(t,e){return Reflect.getOwnPropertyDescriptor(t._scopes[0],e)},getPrototypeOf:function(){return Reflect.getPrototypeOf(t[0])},has:function(t,e){return eL(t).includes(e)},ownKeys:function(t){return eL(t)},set:function(t,e,r){var n=t._storage||(t._storage=a());return t[e]=n[e]=r,delete t._keys,!0}})}function eP(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{scriptable:!0,indexable:!0},r=t._scriptable,n=void 0===r?e.scriptable:r,i=t._indexable,a=void 0===i?e.indexable:i,o=t._allKeys;return{allKeys:void 0===o?e.allKeys:o,scriptable:n,indexable:a,isScriptable:L(n)?n:function(){return n},isIndexable:L(a)?a:function(){return a}}}var eD=function(t,e){return v(e)&&"adapters"!==t&&(null===Object.getPrototypeOf(e)||e.constructor===Object)};function ej(t,e,r){if(Object.prototype.hasOwnProperty.call(t,e))return t[e];var n=r();return t[e]=n,n}function eT(t,e,r,n){var i,a=e._rootScopes,o=L(i=e._fallback)?i(r,n):i,s=(0,u._)(t).concat((0,u._)(a)),l=new Set;l.add(n);var c=eF(l,s,r,o||r,n);return!(null===c||I(o)&&o!==r&&null===(c=eF(l,s,o,c,n)))&&eC(Array.from(l),[""],a,o,function(){var t,i;return r in(t=e._getTarget())||(t[r]={}),p(i=t[r])&&v(n)?n:i})}function eF(t,e,r,n,i){for(;r;)r=function(t,e,r,n,i){var a=!0,o=!1,s=void 0;try{for(var l,u=e[Symbol.iterator]();!(a=(l=u.next()).done);a=!0){var c=l.value,h=!0===r?c:"string"==typeof r?j(c,r):void 0;if(h){t.add(h);var f,d=(f=h._fallback,L(f)?f(r,i):f);if(I(d)&&d!==r&&d!==n)return d}else if(!1===h&&I(n)&&r!==n)return null}}catch(t){o=!0,s=t}finally{try{a||null==u.return||u.return()}finally{if(o)throw s}}return!1}(t,e,r,n,i);return r}function eI(t,e){var r=!0,n=!1,i=void 0;try{for(var a,o=e[Symbol.iterator]();!(r=(a=o.next()).done);r=!0){var s=a.value;if(s){var l=s[t];if(I(l))return l}}}catch(t){n=!0,i=t}finally{try{r||null==o.return||o.return()}finally{if(n)throw i}}}function eL(t){var e=t._keys;return e||(e=t._keys=function(t){var e=new Set,r=!0,n=!1,i=void 0,a=!0,o=!1,s=void 0;try{for(var l,u=t[Symbol.iterator]();!(a=(l=u.next()).done);a=!0){var c=l.value;try{for(var h,f=Object.keys(c).filter(function(t){return!t.startsWith("_")})[Symbol.iterator]();!(r=(h=f.next()).done);r=!0){var d=h.value;e.add(d)}}catch(t){n=!0,i=t}finally{try{r||null==f.return||f.return()}finally{if(n)throw i}}}}catch(t){o=!0,s=t}finally{try{a||null==u.return||u.return()}finally{if(o)throw s}}return Array.from(e)}(t._scopes)),e}function eB(t,e,r,n){var i,a,o,s=t.iScale,l=this._parsing.key,u=void 0===l?"r":l,c=Array(n);for(i=0;i1&&void 0!==arguments[1]?arguments[1]:"x",a=eV(i),o=t.length,s=Array(o).fill(0),l=Array(o),u=eN(t,0);for(e=0;e2&&void 0!==arguments[2]?arguments[2]:"x",o=eV(a),s=t.length,l=eN(t,0),u=0;u0||l>0)&&(!r||!r.shadowRoot))n=s,i=l;else{var c=e.getBoundingClientRect();n=o.clientX-c.left,i=o.clientY-c.top,u=!0}return{x:n,y:i,box:u}}(t,r),u=l.x,c=l.y,h=l.box,f=o.left+(h&&s.left),d=o.top+(h&&s.top),p=e.width,v=e.height;return a&&(p-=o.width+s.width,v-=o.height+s.height),{x:Math.round((u-f)/p*r.width/n),y:Math.round((c-d)/v*r.height/n)}}var eZ=function(t){return Math.round(10*t)/10};function e0(t,e,r,n){var i=eq(t),a=eG(i,"margin"),o=eX(i.maxWidth,t,"clientWidth")||W,s=eX(i.maxHeight,t,"clientHeight")||W,l=function(t,e,r){var n,i;if(void 0===e||void 0===r){var a=eY(t);if(a){var o=a.getBoundingClientRect(),s=eq(a),l=eG(s,"border","width"),u=eG(s,"padding");e=o.width-u.width-l.width,r=o.height-u.height-l.height,n=eX(s.maxWidth,a,"clientWidth"),i=eX(s.maxHeight,a,"clientHeight")}else e=t.clientWidth,r=t.clientHeight}return{width:e,height:r,maxWidth:n||W,maxHeight:i||W}}(t,e,r),u=l.width,c=l.height;if("content-box"===i.boxSizing){var h=eG(i,"border","width"),f=eG(i,"padding");u-=f.width+h.width,c-=f.height+h.height}return u=Math.max(0,u-a.width),c=Math.max(0,n?Math.floor(u/n):c-a.height),u=eZ(Math.min(u,o,l.maxWidth)),c=eZ(Math.min(c,s,l.maxHeight)),u&&!c&&(c=eZ(u/2)),{width:u,height:c}}function e1(t,e,r){var n=e||1,i=Math.floor(t.height*n),a=Math.floor(t.width*n);t.height=i/n,t.width=a/n;var o=t.canvas;return o.style&&(r||!o.style.height&&!o.style.width)&&(o.style.height="".concat(t.height,"px"),o.style.width="".concat(t.width,"px")),(t.currentDevicePixelRatio!==n||o.height!==i||o.width!==a)&&(t.currentDevicePixelRatio=n,o.height=i,o.width=a,t.ctx.setTransform(n,0,0,n,0,0),!0)}var e2=function(){var t=!1;try{var e={get passive(){return t=!0,!1}};window.addEventListener("test",null,e),window.removeEventListener("test",null,e)}catch(t){}return t}();function e5(t,e){var r=e$(t,e),n=r&&r.match(/^(\d+)(\.\d+)?px$/);return n?+n[1]:void 0}function e3(t,e,r,n){return{x:t.x+r*(e.x-t.x),y:t.y+r*(e.y-t.y)}}function e6(t,e,r,n){return{x:t.x+r*(e.x-t.x),y:"middle"===n?r<.5?t.y:e.y:"after"===n?r<1?t.y:e.y:r>0?e.y:t.y}}function e8(t,e,r,n){var i={x:t.cp2x,y:t.cp2y},a={x:e.cp1x,y:e.cp1y},o=e3(t,i,r),s=e3(i,a,r),l=e3(a,e,r),u=e3(o,s,r),c=e3(s,l,r);return e3(u,c,r)}var e4=new Map;function e7(t,e,r){var n,i,a;return(i=e+JSON.stringify(n=(n=r)||{}),(a=e4.get(i))||(a=new Intl.NumberFormat(e,n),e4.set(i,a)),a).format(t)}function e9(t,e,r){var n;return t?(n=r,{x:function(t){return e+e+n-t},setWidth:function(t){n=t},textAlign:function(t){return"center"===t?t:"right"===t?"left":"right"},xPlus:function(t,e){return t-e},leftForLtr:function(t,e){return t-e}}):{x:function(t){return t},setWidth:function(t){},textAlign:function(t){return t},xPlus:function(t,e){return t+e},leftForLtr:function(t,e){return t}}}function rt(t,e){var r,n;("ltr"===e||"rtl"===e)&&(n=[(r=t.canvas.style).getPropertyValue("direction"),r.getPropertyPriority("direction")],r.setProperty("direction",e,"important"),t.prevTextDirection=n)}function re(t,e){void 0!==e&&(delete t.prevTextDirection,t.canvas.style.setProperty("direction",e[0],e[1]))}function rr(t){return"angle"===t?{between:tl,compare:to,normalize:ts}:{between:th,compare:function(t,e){return t-e},normalize:function(t){return t}}}function rn(t){var e=t.start,r=t.end,n=t.count;return{start:e%n,end:r%n,loop:t.loop&&(r-e+1)%n==0,style:t.style}}function ri(t,e,r){if(!r)return[t];for(var n,i,a,o=r.property,s=r.start,l=r.end,u=e.length,c=rr(o),h=c.compare,f=c.between,d=c.normalize,p=function(t,e,r){var n,i=r.property,a=r.start,o=r.end,s=rr(i),l=s.between,u=s.normalize,c=e.length,h=t.start,f=t.end,d=t.loop;if(d){for(h+=c,f+=c,n=0;ni&&t[a%e].skip;)a--;return{start:i,end:a%=e}}(r,i,a,n),s=o.start,l=o.end;if(!0===n)return rs(t,[{start:s,end:l,loop:a}],r,e);var u=l0){this.model=e||"rgb",n=s[this.model].channels;var c=Array.prototype.slice.call(t,0,n);this.color=S(c,n),this.valpha="number"==typeof t[n]?t[n]:1}else if("number"==typeof t)this.model="rgb",this.color=[t>>16&255,t>>8&255,255&t],this.valpha=1;else{this.valpha=1;var h=Object.keys(t);"alpha"in t&&(h.splice(h.indexOf("alpha"),1),this.valpha="number"==typeof t.alpha?t.alpha:0);var f=h.sort().join("");if(!(f in u))throw Error("Unable to parse color from object: "+JSON.stringify(t));this.model=u[f];var d=s[this.model].labels,p=[];for(r=0;rr?(e+.05)/(r+.05):(r+.05)/(e+.05)},level:function(t){var e=this.contrast(t);return e>=7?"AAA":e>=4.5?"AA":""},isDark:function(){var t=this.rgb().color;return(2126*t[0]+7152*t[1]+722*t[2])/1e4<128},isLight:function(){return!this.isDark()},negate:function(){for(var t=this.rgb(),e=0;e<3;e++)t.color[e]=255-t.color[e];return t},lighten:function(t){var e=this.hsl();return e.color[2]+=e.color[2]*t,e},darken:function(t){var e=this.hsl();return e.color[2]-=e.color[2]*t,e},saturate:function(t){var e=this.hsl();return e.color[1]+=e.color[1]*t,e},desaturate:function(t){var e=this.hsl();return e.color[1]-=e.color[1]*t,e},whiten:function(t){var e=this.hwb();return e.color[1]+=e.color[1]*t,e},blacken:function(t){var e=this.hwb();return e.color[2]+=e.color[2]*t,e},grayscale:function(){var t=this.rgb().color,e=.3*t[0]+.59*t[1]+.11*t[2];return y.rgb(e,e,e)},fade:function(t){return this.alpha(this.valpha-this.valpha*t)},opaquer:function(t){return this.alpha(this.valpha+this.valpha*t)},rotate:function(t){var e=this.hsl(),r=e.color[0];return r=(r=(r+t)%360)<0?360+r:r,e.color[0]=r,e},mix:function(t,e){if(!t||!t.rgb)throw Error('Argument to "mix" was not a Color instance, but rather an instance of '+(void 0===t?"undefined":(0,a._)(t)));var r=t.rgb(),n=this.rgb(),i=void 0===e?.5:e,o=2*i-1,s=r.alpha()-n.alpha(),l=((o*s==-1?o:(o+s)/(1+o*s))+1)/2,u=1-l;return y.rgb(l*r.red()+u*n.red(),l*r.green()+u*n.green(),l*r.blue()+u*n.blue(),r.alpha()*i+n.alpha()*(1-i))}};var m=!0,b=!1,_=void 0;try{for(var x,k=Object.keys(s)[Symbol.iterator]();!(m=(x=k.next()).done);m=!0)!function(){var t=x.value;if(!l.includes(t)){var e=s[t].channels;y.prototype[t]=function(){for(var e,r=arguments.length,n=Array(r),a=0;a0?new y(n,t):new y((0,i._)((e=s[this.model][t].raw(this.color),Array.isArray(e)?e:[e])).concat([this.valpha]),t)},y[t]=function(){for(var r=arguments.length,n=Array(r),i=0;i=4&&1!==t[3]&&(e=", "+t[3]),"hwb("+t[0]+", "+t[1]+"%, "+t[2]+"%"+e+")"},l.to.keyword=function(t){return o[t.slice(0,3)]}},{d7a6eeb7388b4bb:"9CRqC","248ce9e419a8df53":"7SGVb"}],"9CRqC":[function(t,e,r){e.exports={aliceblue:[240,248,255],antiquewhite:[250,235,215],aqua:[0,255,255],aquamarine:[127,255,212],azure:[240,255,255],beige:[245,245,220],bisque:[255,228,196],black:[0,0,0],blanchedalmond:[255,235,205],blue:[0,0,255],blueviolet:[138,43,226],brown:[165,42,42],burlywood:[222,184,135],cadetblue:[95,158,160],chartreuse:[127,255,0],chocolate:[210,105,30],coral:[255,127,80],cornflowerblue:[100,149,237],cornsilk:[255,248,220],crimson:[220,20,60],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgoldenrod:[184,134,11],darkgray:[169,169,169],darkgreen:[0,100,0],darkgrey:[169,169,169],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkseagreen:[143,188,143],darkslateblue:[72,61,139],darkslategray:[47,79,79],darkslategrey:[47,79,79],darkturquoise:[0,206,209],darkviolet:[148,0,211],deeppink:[255,20,147],deepskyblue:[0,191,255],dimgray:[105,105,105],dimgrey:[105,105,105],dodgerblue:[30,144,255],firebrick:[178,34,34],floralwhite:[255,250,240],forestgreen:[34,139,34],fuchsia:[255,0,255],gainsboro:[220,220,220],ghostwhite:[248,248,255],gold:[255,215,0],goldenrod:[218,165,32],gray:[128,128,128],green:[0,128,0],greenyellow:[173,255,47],grey:[128,128,128],honeydew:[240,255,240],hotpink:[255,105,180],indianred:[205,92,92],indigo:[75,0,130],ivory:[255,255,240],khaki:[240,230,140],lavender:[230,230,250],lavenderblush:[255,240,245],lawngreen:[124,252,0],lemonchiffon:[255,250,205],lightblue:[173,216,230],lightcoral:[240,128,128],lightcyan:[224,255,255],lightgoldenrodyellow:[250,250,210],lightgray:[211,211,211],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightsalmon:[255,160,122],lightseagreen:[32,178,170],lightskyblue:[135,206,250],lightslategray:[119,136,153],lightslategrey:[119,136,153],lightsteelblue:[176,196,222],lightyellow:[255,255,224],lime:[0,255,0],limegreen:[50,205,50],linen:[250,240,230],magenta:[255,0,255],maroon:[128,0,0],mediumaquamarine:[102,205,170],mediumblue:[0,0,205],mediumorchid:[186,85,211],mediumpurple:[147,112,219],mediumseagreen:[60,179,113],mediumslateblue:[123,104,238],mediumspringgreen:[0,250,154],mediumturquoise:[72,209,204],mediumvioletred:[199,21,133],midnightblue:[25,25,112],mintcream:[245,255,250],mistyrose:[255,228,225],moccasin:[255,228,181],navajowhite:[255,222,173],navy:[0,0,128],oldlace:[253,245,230],olive:[128,128,0],olivedrab:[107,142,35],orange:[255,165,0],orangered:[255,69,0],orchid:[218,112,214],palegoldenrod:[238,232,170],palegreen:[152,251,152],paleturquoise:[175,238,238],palevioletred:[219,112,147],papayawhip:[255,239,213],peachpuff:[255,218,185],peru:[205,133,63],pink:[255,192,203],plum:[221,160,221],powderblue:[176,224,230],purple:[128,0,128],rebeccapurple:[102,51,153],red:[255,0,0],rosybrown:[188,143,143],royalblue:[65,105,225],saddlebrown:[139,69,19],salmon:[250,128,114],sandybrown:[244,164,96],seagreen:[46,139,87],seashell:[255,245,238],sienna:[160,82,45],silver:[192,192,192],skyblue:[135,206,235],slateblue:[106,90,205],slategray:[112,128,144],slategrey:[112,128,144],snow:[255,250,250],springgreen:[0,255,127],steelblue:[70,130,180],tan:[210,180,140],teal:[0,128,128],thistle:[216,191,216],tomato:[255,99,71],turquoise:[64,224,208],violet:[238,130,238],wheat:[245,222,179],white:[255,255,255],whitesmoke:[245,245,245],yellow:[255,255,0],yellowgreen:[154,205,50]}},{}],"7SGVb":[function(t,e,r){var n=t("ce0bf6d0bc000d24"),i=Array.prototype.concat,a=Array.prototype.slice,o=e.exports=function(t){for(var e=[],r=0,o=t.length;r=0&&(t.splice instanceof Function||Object.getOwnPropertyDescriptor(t,t.length-1)&&"String"!==t.constructor.name))}},{}],b0bZu:[function(t,e,r){var n=t("739980f7990d3c32"),i=t("30ea0c7ee5f3dd94"),a={};Object.keys(n).forEach(function(t){a[t]={},Object.defineProperty(a[t],"channels",{value:n[t].channels}),Object.defineProperty(a[t],"labels",{value:n[t].labels});var e=i(t);Object.keys(e).forEach(function(r){var n,i,o=e[r];a[t][r]=(n=function(){for(var t=arguments.length,e=Array(t),r=0;r1&&(e=n);var i=o(e);if("object"==typeof i)for(var a=i.length,s=0;s1&&(e=n),o(e))},"conversion"in o&&(i.conversion=o.conversion),i)})}),e.exports=a},{"739980f7990d3c32":"bLCsr","30ea0c7ee5f3dd94":"B0afd"}],bLCsr:[function(t,e,r){var n=t("@swc/helpers/_/_sliced_to_array"),i=t("efc99055946c4df8"),a={},o=!0,s=!1,l=void 0;try{for(var u,c=Object.keys(i)[Symbol.iterator]();!(o=(u=c.next()).done);o=!0){var h=u.value;a[i[h]]=h}}catch(t){s=!0,l=t}finally{try{o||null==c.return||c.return()}finally{if(s)throw l}}var f={rgb:{channels:3,labels:"rgb"},hsl:{channels:3,labels:"hsl"},hsv:{channels:3,labels:"hsv"},hwb:{channels:3,labels:"hwb"},cmyk:{channels:4,labels:"cmyk"},xyz:{channels:3,labels:"xyz"},lab:{channels:3,labels:"lab"},lch:{channels:3,labels:"lch"},hex:{channels:1,labels:["hex"]},keyword:{channels:1,labels:["keyword"]},ansi16:{channels:1,labels:["ansi16"]},ansi256:{channels:1,labels:["ansi256"]},hcg:{channels:3,labels:["h","c","g"]},apple:{channels:3,labels:["r16","g16","b16"]},gray:{channels:1,labels:["gray"]}};e.exports=f;var d=!0,p=!1,v=void 0;try{for(var g,y=Object.keys(f)[Symbol.iterator]();!(d=(g=y.next()).done);d=!0){var m=g.value;if(!("channels"in f[m]))throw Error("missing channels property: "+m);if(!("labels"in f[m]))throw Error("missing channel labels property: "+m);if(f[m].labels.length!==f[m].channels)throw Error("channel and label counts mismatch: "+m);var b=f[m],_=b.channels,x=b.labels;delete f[m].channels,delete f[m].labels,Object.defineProperty(f[m],"channels",{value:_}),Object.defineProperty(f[m],"labels",{value:x})}}catch(t){p=!0,v=t}finally{try{d||null==y.return||y.return()}finally{if(p)throw v}}f.rgb.hsl=function(t){var e,r=t[0]/255,n=t[1]/255,i=t[2]/255,a=Math.min(r,n,i),o=Math.max(r,n,i),s=o-a;o===a?e=0:r===o?e=(n-i)/s:n===o?e=2+(i-r)/s:i===o&&(e=4+(r-n)/s),(e=Math.min(60*e,360))<0&&(e+=360);var l=(a+o)/2;return[e,100*(o===a?0:l<=.5?s/(o+a):s/(2-o-a)),100*l]},f.rgb.hsv=function(t){var e,r,n,i,a,o=t[0]/255,s=t[1]/255,l=t[2]/255,u=Math.max(o,s,l),c=u-Math.min(o,s,l),h=function(t){return(u-t)/6/c+.5};return 0===c?(i=0,a=0):(a=c/u,e=h(o),r=h(s),n=h(l),o===u?i=n-r:s===u?i=1/3+e-n:l===u&&(i=2/3+r-e),i<0?i+=1:i>1&&(i-=1)),[360*i,100*a,100*u]},f.rgb.hwb=function(t){var e=t[0],r=t[1],n=t[2];return[f.rgb.hsl(t)[0],1/255*Math.min(e,Math.min(r,n))*100,100*(n=1-1/255*Math.max(e,Math.max(r,n)))]},f.rgb.cmyk=function(t){var e=t[0]/255,r=t[1]/255,n=t[2]/255,i=Math.min(1-e,1-r,1-n);return[100*((1-e-i)/(1-i)||0),100*((1-r-i)/(1-i)||0),100*((1-n-i)/(1-i)||0),100*i]},f.rgb.keyword=function(t){var e=a[t];if(e)return e;var r=1/0,n=!0,o=!1,s=void 0;try{for(var l,u,c=Object.keys(i)[Symbol.iterator]();!(n=(u=c.next()).done);n=!0){var h=u.value,f=i[h],d=Math.pow(t[0]-f[0],2)+Math.pow(t[1]-f[1],2)+Math.pow(t[2]-f[2],2);d.04045?Math.pow((e+.055)/1.055,2.4):e/12.92)+.3576*(r=r>.04045?Math.pow((r+.055)/1.055,2.4):r/12.92)+.1805*(n=n>.04045?Math.pow((n+.055)/1.055,2.4):n/12.92)),100*(.2126*e+.7152*r+.0722*n),100*(.0193*e+.1192*r+.9505*n)]},f.rgb.lab=function(t){var e=f.rgb.xyz(t),r=e[0],n=e[1],i=e[2];return r/=95.047,n/=100,i/=108.883,r=r>.008856?Math.pow(r,1/3):7.787*r+16/116,[116*(n=n>.008856?Math.pow(n,1/3):7.787*n+16/116)-16,500*(r-n),200*(n-(i=i>.008856?Math.pow(i,1/3):7.787*i+16/116))]},f.hsl.rgb=function(t){var e,r,n,i=t[0]/360,a=t[1]/100,o=t[2]/100;if(0===a)return[n=255*o,n,n];e=o<.5?o*(1+a):o+a-o*a;for(var s=2*o-e,l=[0,0,0],u=0;u<3;u++)(r=i+-(1/3*(u-1)))<0&&r++,r>1&&r--,n=6*r<1?s+(e-s)*6*r:2*r<1?e:3*r<2?s+(e-s)*(2/3-r)*6:s,l[u]=255*n;return l},f.hsl.hsv=function(t){var e=t[0],r=t[1]/100,n=t[2]/100,i=r,a=Math.max(n,.01);n*=2,r*=n<=1?n:2-n,i*=a<=1?a:2-a;var o=(n+r)/2;return[e,100*(0===n?2*i/(a+i):2*r/(n+r)),100*o]},f.hsv.rgb=function(t){var e=t[0]/60,r=t[1]/100,n=t[2]/100,i=e-Math.floor(e),a=255*n*(1-r),o=255*n*(1-r*i),s=255*n*(1-r*(1-i));switch(n*=255,Math.floor(e)%6){case 0:return[n,s,a];case 1:return[o,n,a];case 2:return[a,n,s];case 3:return[a,o,n];case 4:return[s,a,n];case 5:return[n,a,o]}},f.hsv.hsl=function(t){var e,r,n=t[0],i=t[1]/100,a=t[2]/100,o=Math.max(a,.01);r=(2-i)*a;var s=(2-i)*o;return[n,100*(i*o/(s<=1?s:2-s)||0),100*(r/=2)]},f.hwb.rgb=function(t){var e,r,n,i,a=t[0]/360,o=t[1]/100,s=t[2]/100,l=o+s;l>1&&(o/=l,s/=l);var u=Math.floor(6*a),c=1-s;e=6*a-u,(1&u)!=0&&(e=1-e);var h=o+e*(c-o);switch(u){default:case 6:case 0:r=c,n=h,i=o;break;case 1:r=h,n=c,i=o;break;case 2:r=o,n=c,i=h;break;case 3:r=o,n=h,i=c;break;case 4:r=h,n=o,i=c;break;case 5:r=c,n=o,i=h}return[255*r,255*n,255*i]},f.cmyk.rgb=function(t){var e=t[0]/100,r=t[1]/100,n=t[2]/100,i=t[3]/100;return[255*(1-Math.min(1,e*(1-i)+i)),255*(1-Math.min(1,r*(1-i)+i)),255*(1-Math.min(1,n*(1-i)+i))]},f.xyz.rgb=function(t){var e,r,n,i=t[0]/100,a=t[1]/100,o=t[2]/100;return e=3.2406*i+-1.5372*a+-.4986*o,r=-.9689*i+1.8758*a+.0415*o,n=.0557*i+-.204*a+1.057*o,e=e>.0031308?1.055*Math.pow(e,1/2.4)-.055:12.92*e,r=r>.0031308?1.055*Math.pow(r,1/2.4)-.055:12.92*r,n=n>.0031308?1.055*Math.pow(n,1/2.4)-.055:12.92*n,[255*(e=Math.min(Math.max(0,e),1)),255*(r=Math.min(Math.max(0,r),1)),255*(n=Math.min(Math.max(0,n),1))]},f.xyz.lab=function(t){var e=t[0],r=t[1],n=t[2];return e/=95.047,r/=100,n/=108.883,e=e>.008856?Math.pow(e,1/3):7.787*e+16/116,[116*(r=r>.008856?Math.pow(r,1/3):7.787*r+16/116)-16,500*(e-r),200*(r-(n=n>.008856?Math.pow(n,1/3):7.787*n+16/116))]},f.lab.xyz=function(t){var e,r,n,i=t[0],a=t[1],o=t[2];e=a/500+(r=(i+16)/116),n=r-o/200;var s=Math.pow(r,3),l=Math.pow(e,3),u=Math.pow(n,3);return r=(s>.008856?s:(r-16/116)/7.787)*100,[e=(l>.008856?l:(e-16/116)/7.787)*95.047,r,n=(u>.008856?u:(n-16/116)/7.787)*108.883]},f.lab.lch=function(t){var e,r=t[0],n=t[1],i=t[2];return(e=360*Math.atan2(i,n)/2/Math.PI)<0&&(e+=360),[r,Math.sqrt(n*n+i*i),e]},f.lch.lab=function(t){var e=t[0],r=t[1],n=t[2]/360*2*Math.PI;return[e,r*Math.cos(n),r*Math.sin(n)]},f.rgb.ansi16=function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null,r=(0,n._)(t,3),i=r[0],a=r[1],o=r[2],s=null===e?f.rgb.hsv(t)[2]:e;if(0===(s=Math.round(s/50)))return 30;var l=30+(Math.round(o/255)<<2|Math.round(a/255)<<1|Math.round(i/255));return 2===s&&(l+=60),l},f.hsv.ansi16=function(t){return f.rgb.ansi16(f.hsv.rgb(t),t[2])},f.rgb.ansi256=function(t){var e=t[0],r=t[1],n=t[2];return e===r&&r===n?e<8?16:e>248?231:Math.round((e-8)/247*24)+232:16+36*Math.round(e/255*5)+6*Math.round(r/255*5)+Math.round(n/255*5)},f.ansi16.rgb=function(t){var e=t%10;if(0===e||7===e)return t>50&&(e+=3.5),[e=e/10.5*255,e,e];var r=(~~(t>50)+1)*.5;return[(1&e)*r*255,(e>>1&1)*r*255,(e>>2&1)*r*255]},f.ansi256.rgb=function(t){if(t>=232){var e,r=(t-232)*10+8;return[r,r,r]}return[Math.floor((t-=16)/36)/5*255,Math.floor((e=t%36)/6)/5*255,e%6/5*255]},f.rgb.hex=function(t){var e=(((255&Math.round(t[0]))<<16)+((255&Math.round(t[1]))<<8)+(255&Math.round(t[2]))).toString(16).toUpperCase();return"000000".substring(e.length)+e},f.hex.rgb=function(t){var e=t.toString(16).match(/[a-f0-9]{6}|[a-f0-9]{3}/i);if(!e)return[0,0,0];var r=e[0];3===e[0].length&&(r=r.split("").map(function(t){return t+t}).join(""));var n=parseInt(r,16);return[n>>16&255,n>>8&255,255&n]},f.rgb.hcg=function(t){var e,r=t[0]/255,n=t[1]/255,i=t[2]/255,a=Math.max(Math.max(r,n),i),o=Math.min(Math.min(r,n),i),s=a-o;return e=s<1?o/(1-s):0,[(s<=0?0:a===r?(n-i)/s%6:a===n?2+(i-r)/s:4+(r-n)/s)/6%1*360,100*s,100*e]},f.hsl.hcg=function(t){var e=t[1]/100,r=t[2]/100,n=r<.5?2*e*r:2*e*(1-r),i=0;return n<1&&(i=(r-.5*n)/(1-n)),[t[0],100*n,100*i]},f.hsv.hcg=function(t){var e=t[1]/100,r=t[2]/100,n=e*r,i=0;return n<1&&(i=(r-n)/(1-n)),[t[0],100*n,100*i]},f.hcg.rgb=function(t){var e=t[0]/360,r=t[1]/100,n=t[2]/100;if(0===r)return[255*n,255*n,255*n];var i=[0,0,0],a=e%1*6,o=a%1,s=1-o,l=0;switch(Math.floor(a)){case 0:i[0]=1,i[1]=o,i[2]=0;break;case 1:i[0]=s,i[1]=1,i[2]=0;break;case 2:i[0]=0,i[1]=1,i[2]=o;break;case 3:i[0]=0,i[1]=s,i[2]=1;break;case 4:i[0]=o,i[1]=0,i[2]=1;break;default:i[0]=1,i[1]=0,i[2]=s}return l=(1-r)*n,[(r*i[0]+l)*255,(r*i[1]+l)*255,(r*i[2]+l)*255]},f.hcg.hsv=function(t){var e=t[1]/100,r=e+t[2]/100*(1-e),n=0;return r>0&&(n=e/r),[t[0],100*n,100*r]},f.hcg.hsl=function(t){var e=t[1]/100,r=t[2]/100*(1-e)+.5*e,n=0;return r>0&&r<.5?n=e/(2*r):r>=.5&&r<1&&(n=e/(2*(1-r))),[t[0],100*n,100*r]},f.hcg.hwb=function(t){var e=t[1]/100,r=e+t[2]/100*(1-e);return[t[0],(r-e)*100,(1-r)*100]},f.hwb.hcg=function(t){var e=t[1]/100,r=1-t[2]/100,n=r-e,i=0;return n<1&&(i=(r-n)/(1-n)),[t[0],100*n,100*i]},f.apple.rgb=function(t){return[t[0]/65535*255,t[1]/65535*255,t[2]/65535*255]},f.rgb.apple=function(t){return[t[0]/255*65535,t[1]/255*65535,t[2]/255*65535]},f.gray.rgb=function(t){return[t[0]/100*255,t[0]/100*255,t[0]/100*255]},f.gray.hsl=function(t){return[0,0,t[0]]},f.gray.hsv=f.gray.hsl,f.gray.hwb=function(t){return[0,100,t[0]]},f.gray.cmyk=function(t){return[0,0,0,t[0]]},f.gray.lab=function(t){return[t[0],0,0]},f.gray.hex=function(t){var e=255&Math.round(t[0]/100*255),r=((e<<16)+(e<<8)+e).toString(16).toUpperCase();return"000000".substring(r.length)+r},f.rgb.gray=function(t){return[(t[0]+t[1]+t[2])/3/255*100]}},{"@swc/helpers/_/_sliced_to_array":"hefcy",efc99055946c4df8:"9CRqC"}],B0afd:[function(t,e,r){var n=t("22442592002c5ac3");e.exports=function(t){for(var e=function(t){var e=function(){for(var t={},e=Object.keys(n),r=e.length,i=0;i