service_name = 'umami'; $this->title = 'umami'; $this->icon = 'chart-line'; $this->defineFields(); $this->defineInstructions(); parent::__construct(); $this->defineTables(); } protected function defineFields(): void { $id = $this->addField('website_id', 'Website ID', 'text', 'manage_options'); $id->setHint('Found in your Umami dashboard under Settings->Websites'); $id->setRequired(); $id->makeSetupField(); $this->updateField('website_id', $id); $api_url = $this->addField('api_url', 'API URL', 'text', 'manage_options'); $api_url->setHint('Your Umami server URL. Leave blank if using umami.is cloud service.'); $api_url->makeAdvancedField(); $this->updateField('api_url', $api_url); $api_token = $this->addField('api_token', 'API Token (Optional)', 'text', 'manage_options'); $api_token->setSubType('password'); $api_token->setHint('Required only if you want to retrieve analytics data for dashboards.'); $api_token->makeAdvancedField(); $this->updateField('api_token', $api_token); } protected function defineInstructions():void { $this->instructions = [ 'Login to your umami.is account, select your website, and copy the website ID' ]; } protected function defineTables():void { //TODO: Once we have an actual umami setup, we can store the fetched data here for reference //Ideally, we have the type (term, user, post), WP ID, created_date, and count } protected function initialize(): void { // Add tracking script to frontend add_action('wp_head', [$this, 'renderTrackingScript'], 5); // Schedule data collection if API is configured if ($this->getApiToken()) { add_action('jvb_daily_umami_collection', [$this, 'collectDailyData']); if (!wp_next_scheduled('jvb_daily_umami_collection')) { wp_schedule_event(time(), 'daily', 'jvb_daily_umami_collection'); } } } public function renderTrackingScript():void { if (JVB_TESTING || !$this->isSetUp() || is_admin()) { return; } $script_url = $this->getTrackingScriptUrl(); if (!$this->getWebsiteID() || empty($script_url)) { return; } echo sprintf( '' . "\n", esc_attr(parse_url($script_url, PHP_URL_HOST)) ); $attributes = [ 'defer', sprintf( 'src="%s"', esc_url($script_url) ), sprintf( 'data-website-id="%s"', esc_attr($this->getWebsiteID()) ) ]; $tags = $this->getCurrentTag(); if (!empty($tags)) { $attributes[] = $tags; } echo sprintf( '', implode(' ', $attributes) ); $this->outputCustomEvent(); } protected function getCurrentTag():string { $contentTax = array_map('jvbCheckBase', Registrar::withFeature('is_content', 'term')); if (!empty($contentTax) && is_tax($contentTax)) { $tax = get_queried_object(); $reg = Registrar::getInstance($tax->taxonomy); return 'data-tag="'.$reg->getUmamiEvent().'"'; } $profiles = array_map('jvbCheckBase', Registrar::withFeature('profile_link')); if (!empty($profiles) && is_singular($profiles)) { $usr = get_queried_object(); $reg = Registrar::getInstance($usr->post_type); return 'data-tag="'.$reg->getUmamiEvent().'"'; } return ''; } protected function outputCustomEvent():void { $args = []; $event = false; $contentTax = array_map('jvbCheckBase', Registrar::withFeature('is_content', 'term')); if (!empty($contentTax) && is_tax($contentTax)) { $tax = get_queried_object(); $reg = Registrar::getInstance($tax->taxonomy); $event = $reg->getUmamiEvent(); $args = [ 'id' => $tax->term_id, ]; if ($reg->isOwnable()) { $owners = jvbGetTermOwners($tax->term_id); if (!empty($owners)) { $args['owners'] = $owners; } } } $profiles = array_map('jvbCheckBase', Registrar::withFeature('profile_link')); if (!empty($profiles) && is_singular($profiles)) { $usr = get_queried_object(); $reg = Registrar::getInstance($usr->post_type); $event = $reg->getUmamiEvent(); global $post; $args['id'] = get_the_ID(); $args['owner_id'] = $post->post_author; } if ($event && !empty($args)) { echo sprintf( '', $event, json_encode($args) ); } } /********************************************************* * UTILITY *********************************************************/ public function getWebsiteID(): string|false { return $this->loadCredentials()['website_id']??false; } protected function getApiUrl():string|false { $api = $this->loadCredentials()['api_url']; return empty($api) ? false : $api; } protected function getApiToken():string|false { $api = $this->loadCredentials()['api_token']; return empty($api) ? false : $api; } protected function getTrackingScriptUrl():string { if ($this->getApiUrl()) { return rtrim($this->getApiUrl(), '/').'/script.js'; } // Default to Umami cloud return 'https://cloud.umami.is/script.js'; } public function buildEvent(string $event, array $args = []):string { $base = 'data-umami-event'; $out = [ $base => esc_attr($event), ]; foreach ($args as $k => $v) { $out[$base.$k] = esc_attr(jvbNoBase($v)); } return $this->attributesToString($out); } protected function attributesToString(array $attributes):string { $strings = []; foreach ($attributes as $key => $value) { $strings[] = sprintf( '%s="%s"', $key, $value ); } return implode(' ', $strings); } protected function defineActions(): void { // TODO: Implement defineActions() method. } }