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 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);
}
}