| | |
| | | <?php |
| | | namespace JVBase\integrations\services; |
| | | use JVBase\integrations\Admin; |
| | | use JVBase\integrations\Instance; |
| | | use JVBase\Instance; |
| | | use JVBase\integrations\Integrations; |
| | | use JVBase\managers\Roles; |
| | | use JVBase\registrar\Registrar; |
| | | |
| | | if (!defined('ABSPATH')) { |
| | | exit; |
| | |
| | | class Umami extends Integrations |
| | | { |
| | | use Admin, Instance; |
| | | |
| | | protected function __construct() |
| | | { |
| | | $this->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(); |
| | | |
| | | $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_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.'); |
| | | } |
| | | protected function defineInstructions():void |
| | | { |
| | | $this->instructions = [ |
| | | 'Login to your <a href="https://cloud.umami.is/settings/websites" target="_blank">umami.is</a> 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 |
| | | { |
| | | // TODO: Implement initialize() method. |
| | | // 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( |
| | | '<link rel="preconnect" href="https://%s"/>' . "\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( |
| | | '<script %s></script>', |
| | | 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( |
| | | '<script defer>umami.track(event_name: %s, data: %s);</script>', |
| | | $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); |
| | | } |
| | | } |