fixed wp plugin
This commit is contained in:
parent
78ab65fccf
commit
3a7f791fa9
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,3 +1,4 @@
|
|||||||
.env
|
.env
|
||||||
deploy.sh
|
deploy.sh
|
||||||
/palanticshelper
|
/palanticshelper
|
||||||
|
*.zip
|
||||||
10
README.md
10
README.md
@ -9,6 +9,16 @@ While direct integration between the frontend script and tracker server is possi
|
|||||||
The WordPress plugin includes the helper functionality integrated into the PHP backend for seamless operation.
|
The WordPress plugin includes the helper functionality integrated into the PHP backend for seamless operation.
|
||||||
|
|
||||||
1. Copy the contents of the WordPress folder to your WordPress plugins directory
|
1. Copy the contents of the WordPress folder to your WordPress plugins directory
|
||||||
|
|
||||||
|
|
||||||
|
OR zip it and upload
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd wordpress
|
||||||
|
zip -r palantics-tracking-plugin.zip palantics-tracking-plugin/
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
2. Configure the tracker endpoint with your domain in the plugin settings
|
2. Configure the tracker endpoint with your domain in the plugin settings
|
||||||
3. Track click events by either:
|
3. Track click events by either:
|
||||||
- Wrapping elements in the Analysis block
|
- Wrapping elements in the Analysis block
|
||||||
|
|||||||
@ -1,133 +0,0 @@
|
|||||||
/**
|
|
||||||
* Tracking Block for Gutenberg with Popup Editor
|
|
||||||
*/
|
|
||||||
(function(blocks, element, blockEditor) {
|
|
||||||
var el = element.createElement;
|
|
||||||
var InnerBlocks = blockEditor.InnerBlocks;
|
|
||||||
var useBlockProps = blockEditor.useBlockProps;
|
|
||||||
var __ = wp.i18n.__;
|
|
||||||
var Button = wp.components.Button;
|
|
||||||
var Popover = wp.components.Popover;
|
|
||||||
var TextControl = wp.components.TextControl;
|
|
||||||
var useState = wp.element.useState;
|
|
||||||
|
|
||||||
blocks.registerBlockType('simplified-tracking/track-element', {
|
|
||||||
title: 'Tracking Wrapper',
|
|
||||||
icon: 'chart-bar',
|
|
||||||
category: 'design',
|
|
||||||
attributes: {
|
|
||||||
eventName: {
|
|
||||||
type: 'string',
|
|
||||||
default: 'tracked_element'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
edit: function(props) {
|
|
||||||
var blockProps = useBlockProps();
|
|
||||||
var eventName = props.attributes.eventName;
|
|
||||||
var [isPopoverVisible, setPopoverVisible] = useState(false);
|
|
||||||
|
|
||||||
function onChangeEventName(newEventName) {
|
|
||||||
props.setAttributes({ eventName: newEventName });
|
|
||||||
}
|
|
||||||
|
|
||||||
return el(
|
|
||||||
'div',
|
|
||||||
blockProps,
|
|
||||||
el(
|
|
||||||
'div',
|
|
||||||
{ className: 'tracking-block-wrapper' },
|
|
||||||
el(
|
|
||||||
'div',
|
|
||||||
{ className: 'tracking-block-notice' },
|
|
||||||
'Event: ' + eventName,
|
|
||||||
el(
|
|
||||||
Button,
|
|
||||||
{
|
|
||||||
isSmall: true,
|
|
||||||
onClick: function() {
|
|
||||||
setPopoverVisible(!isPopoverVisible);
|
|
||||||
},
|
|
||||||
style: {
|
|
||||||
marginLeft: '8px',
|
|
||||||
background: 'white',
|
|
||||||
color: '#007cba'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'Edit'
|
|
||||||
),
|
|
||||||
isPopoverVisible && el(
|
|
||||||
Popover,
|
|
||||||
{
|
|
||||||
onClose: function() {
|
|
||||||
setPopoverVisible(false);
|
|
||||||
},
|
|
||||||
position: 'bottom',
|
|
||||||
focusOnMount: 'firstElement'
|
|
||||||
},
|
|
||||||
el(
|
|
||||||
'div',
|
|
||||||
{
|
|
||||||
style: {
|
|
||||||
padding: '16px',
|
|
||||||
width: '300px'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
el(
|
|
||||||
'h3',
|
|
||||||
{
|
|
||||||
style: {
|
|
||||||
margin: '0 0 8px 0'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'Tracking Event Settings'
|
|
||||||
),
|
|
||||||
el(
|
|
||||||
TextControl,
|
|
||||||
{
|
|
||||||
label: 'Event Name',
|
|
||||||
value: eventName,
|
|
||||||
onChange: onChangeEventName,
|
|
||||||
help: 'Enter the event name to track when this element is clicked'
|
|
||||||
}
|
|
||||||
),
|
|
||||||
el(
|
|
||||||
Button,
|
|
||||||
{
|
|
||||||
isPrimary: true,
|
|
||||||
onClick: function() {
|
|
||||||
setPopoverVisible(false);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'Done'
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
),
|
|
||||||
el(
|
|
||||||
'div',
|
|
||||||
{ style: { marginTop: '5px' } },
|
|
||||||
el(InnerBlocks)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
save: function(props) {
|
|
||||||
var blockProps = useBlockProps.save({
|
|
||||||
className: 'tracking-block-wrapper',
|
|
||||||
onClick: "tE('" + props.attributes.eventName + "')"
|
|
||||||
});
|
|
||||||
|
|
||||||
return el(
|
|
||||||
'div',
|
|
||||||
blockProps,
|
|
||||||
el(InnerBlocks.Content)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}(
|
|
||||||
window.wp.blocks,
|
|
||||||
window.wp.element,
|
|
||||||
window.wp.blockEditor
|
|
||||||
));
|
|
||||||
40
wordpress/palantics-tracking-plugin/assets/css/admin.css
Normal file
40
wordpress/palantics-tracking-plugin/assets/css/admin.css
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
/**
|
||||||
|
* Palantics Admin Styles
|
||||||
|
*/
|
||||||
|
|
||||||
|
.palantics-heading {
|
||||||
|
color: #007cba;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.palantics-methods-container {
|
||||||
|
background-color: #fff;
|
||||||
|
padding: 20px;
|
||||||
|
margin-top: 20px;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.palantics-method {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.palantics-method-title {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: bold;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.palantics-code-sample {
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
padding: 10px;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-family: monospace;
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.palantics-description {
|
||||||
|
margin-top: 5px;
|
||||||
|
font-size: 13px;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
2
wordpress/palantics-tracking-plugin/assets/css/index.php
Normal file
2
wordpress/palantics-tracking-plugin/assets/css/index.php
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
<?php
|
||||||
|
// silence is golden
|
||||||
@ -1,13 +1,13 @@
|
|||||||
/**
|
/**
|
||||||
* Tracking Block Styles
|
* Palantics Tracking Block Styles
|
||||||
*/
|
*/
|
||||||
.tracking-block-wrapper {
|
.palantics-tracking-block-wrapper {
|
||||||
border: 1px dashed #007cba;
|
border: 1px dashed #007cba;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tracking-block-notice {
|
.palantics-tracking-block-notice {
|
||||||
background: #007cba;
|
background: #007cba;
|
||||||
color: white;
|
color: white;
|
||||||
padding: 5px 10px;
|
padding: 5px 10px;
|
||||||
@ -18,4 +18,9 @@
|
|||||||
border-bottom-left-radius: 4px;
|
border-bottom-left-radius: 4px;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
/* Frontend styles */
|
||||||
|
/*
|
||||||
|
.palantics-tracking-wrapper {
|
||||||
|
|
||||||
|
} */
|
||||||
2
wordpress/palantics-tracking-plugin/assets/index.php
Normal file
2
wordpress/palantics-tracking-plugin/assets/index.php
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
<?php
|
||||||
|
// silence is golden
|
||||||
87
wordpress/palantics-tracking-plugin/assets/js/block.js
Normal file
87
wordpress/palantics-tracking-plugin/assets/js/block.js
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
/**
|
||||||
|
* Palantics Tracking Block
|
||||||
|
*/
|
||||||
|
|
||||||
|
const { registerBlockType } = wp.blocks;
|
||||||
|
const { InspectorControls } = wp.blockEditor;
|
||||||
|
const { PanelBody, TextControl } = wp.components;
|
||||||
|
const { Fragment } = wp.element;
|
||||||
|
const { __ } = wp.i18n;
|
||||||
|
|
||||||
|
// Register the block
|
||||||
|
registerBlockType('palantics-tracking/track-element', {
|
||||||
|
title: __('Tracking Element', 'palantics-tracking-plugin'),
|
||||||
|
icon: 'chart-line',
|
||||||
|
category: 'widgets',
|
||||||
|
keywords: [
|
||||||
|
__('track', 'palantics-tracking-plugin'),
|
||||||
|
__('analytics', 'palantics-tracking-plugin'),
|
||||||
|
__('palantics', 'palantics-tracking-plugin'),
|
||||||
|
],
|
||||||
|
|
||||||
|
attributes: {
|
||||||
|
eventName: {
|
||||||
|
type: 'string',
|
||||||
|
default: 'tracked_element',
|
||||||
|
},
|
||||||
|
content: {
|
||||||
|
type: 'string',
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
edit: function(props) {
|
||||||
|
const { attributes, setAttributes } = props;
|
||||||
|
const { eventName, content } = attributes;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Fragment>
|
||||||
|
<InspectorControls>
|
||||||
|
<PanelBody title={__('Tracking Settings', 'palantics-tracking-plugin')}>
|
||||||
|
<TextControl
|
||||||
|
label={__('Event Name', 'palantics-tracking-plugin')}
|
||||||
|
value={eventName}
|
||||||
|
onChange={(value) => setAttributes({ eventName: value })}
|
||||||
|
help={__('Enter the event name that will be used for tracking this element', 'palantics-tracking-plugin')}
|
||||||
|
/>
|
||||||
|
</PanelBody>
|
||||||
|
</InspectorControls>
|
||||||
|
|
||||||
|
<div
|
||||||
|
className="palantics-tracking-block"
|
||||||
|
style={{
|
||||||
|
padding: '20px',
|
||||||
|
border: '1px dashed #ccc',
|
||||||
|
backgroundColor: '#f8f8f8'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div style={{ marginBottom: '10px', fontWeight: 'bold' }}>
|
||||||
|
{__('Palantics Tracking Element', 'palantics-tracking-plugin')}
|
||||||
|
</div>
|
||||||
|
<div style={{ fontSize: '0.9em', marginBottom: '10px' }}>
|
||||||
|
{__('Event:', 'palantics-tracking-plugin')} <code>{eventName}</code>
|
||||||
|
</div>
|
||||||
|
<div style={{ fontStyle: 'italic', fontSize: '0.8em' }}>
|
||||||
|
{__('This element will be tracked when clicked', 'palantics-tracking-plugin')}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Fragment>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
save: function(props) {
|
||||||
|
const { attributes } = props;
|
||||||
|
const { eventName } = attributes;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className="palantics-tracking-wrapper"
|
||||||
|
onClick={`tE('${eventName}')`}
|
||||||
|
>
|
||||||
|
<div className="palantics-tracking-content">
|
||||||
|
{props.children}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
@ -0,0 +1,87 @@
|
|||||||
|
/**
|
||||||
|
* Palantics class-based tracking script
|
||||||
|
*/
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
// Helper function to get element details for tracking
|
||||||
|
function getElementDetails(element) {
|
||||||
|
const details = {};
|
||||||
|
|
||||||
|
// Get element text or alternative
|
||||||
|
if (element.textContent && element.textContent.trim()) {
|
||||||
|
details.text = element.textContent.trim();
|
||||||
|
} else if (element.placeholder) {
|
||||||
|
details.text = element.placeholder;
|
||||||
|
} else if (element.value) {
|
||||||
|
details.text = element.value;
|
||||||
|
} else if (element.alt) {
|
||||||
|
details.text = element.alt;
|
||||||
|
} else if (element.getAttribute('aria-label')) {
|
||||||
|
details.text = element.getAttribute('aria-label');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Limit text length
|
||||||
|
if (details.text && details.text.length > 50) {
|
||||||
|
details.text = details.text.substring(0, 47) + '...';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get element ID, class and href if available
|
||||||
|
if (element.id) {
|
||||||
|
details.id = element.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (element.className) {
|
||||||
|
details.class = element.className;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (element.href) {
|
||||||
|
const href = element.href;
|
||||||
|
// Only include if it's not too long
|
||||||
|
if (href.length < 100) {
|
||||||
|
details.href = href;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return details;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to initialize tracking for a specific class
|
||||||
|
function initializeClassTracking(className) {
|
||||||
|
const elements = document.querySelectorAll('.' + className);
|
||||||
|
elements.forEach(function(element) {
|
||||||
|
element.addEventListener('click', function(e) {
|
||||||
|
const details = getElementDetails(element);
|
||||||
|
tE('custom_element_click', {
|
||||||
|
element: 'custom',
|
||||||
|
class: className,
|
||||||
|
...details
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Track elements with data-track attribute
|
||||||
|
function initializeDataAttributeTracking() {
|
||||||
|
const trackedElements = document.querySelectorAll('[data-track]');
|
||||||
|
trackedElements.forEach(function(element) {
|
||||||
|
element.addEventListener('click', function(e) {
|
||||||
|
const eventName = element.getAttribute('data-track') || 'tracked_element';
|
||||||
|
const details = getElementDetails(element);
|
||||||
|
tE(eventName, {
|
||||||
|
element: 'data-track',
|
||||||
|
...details
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize data attribute tracking
|
||||||
|
initializeDataAttributeTracking();
|
||||||
|
|
||||||
|
// If trackClasses is defined (will be injected by WordPress), initialize class tracking
|
||||||
|
if (typeof trackClasses !== 'undefined' && Array.isArray(trackClasses)) {
|
||||||
|
trackClasses.forEach(function(className) {
|
||||||
|
initializeClassTracking(className);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
2
wordpress/palantics-tracking-plugin/assets/js/index.php
Normal file
2
wordpress/palantics-tracking-plugin/assets/js/index.php
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
<?php
|
||||||
|
// silence is golden
|
||||||
@ -0,0 +1,95 @@
|
|||||||
|
/**
|
||||||
|
* Palantics main tracking script
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Initialize tracking function
|
||||||
|
function tE(eventName, additionalParams = {}) {
|
||||||
|
// Create tracking data object
|
||||||
|
const data = {
|
||||||
|
event: eventName,
|
||||||
|
url: window.location.href,
|
||||||
|
ref: document.referrer,
|
||||||
|
ua: navigator.userAgent,
|
||||||
|
sw: window.screen.width,
|
||||||
|
lang: navigator.language || navigator.userLanguage,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add any additional parameters
|
||||||
|
Object.assign(data, additionalParams);
|
||||||
|
|
||||||
|
// Helper function to serialize an object into URL parameters
|
||||||
|
function serializeObject(obj, prefix) {
|
||||||
|
const str = [];
|
||||||
|
for (const p in obj) {
|
||||||
|
if (obj.hasOwnProperty(p)) {
|
||||||
|
const k = prefix ? prefix + "[" + p + "]" : p;
|
||||||
|
const v = obj[p];
|
||||||
|
if (v !== null && typeof v === "object") {
|
||||||
|
str.push(serializeObject(v, k));
|
||||||
|
} else {
|
||||||
|
str.push(encodeURIComponent(k) + "=" + encodeURIComponent(v));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return str.join("&");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function for sending tracking data
|
||||||
|
function sendInfo() {
|
||||||
|
try {
|
||||||
|
// Get site URL and prepare REST API endpoint URL
|
||||||
|
const siteUrl = window.location.origin;
|
||||||
|
const restApiEndpoint = `${siteUrl}/wp-json/palantics/v1/sun`;
|
||||||
|
|
||||||
|
// Use POST request with data in body and query string
|
||||||
|
fetch(restApiEndpoint + '?' + serializeObject(data), {
|
||||||
|
method: "POST",
|
||||||
|
mode: "no-cors",
|
||||||
|
cache: "no-cache",
|
||||||
|
credentials: "omit", // Don't send cookies
|
||||||
|
headers: {
|
||||||
|
"X-Final-Destination": server, // Pass the final destination
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
},
|
||||||
|
keepalive: true, // Ensures request completes even if page unloads
|
||||||
|
})
|
||||||
|
.catch(e => {
|
||||||
|
console.error("Tracking error:", e);
|
||||||
|
|
||||||
|
// If POST fails, try GET as fallback
|
||||||
|
fetch(restApiEndpoint + '?' + serializeObject(data), {
|
||||||
|
method: "GET",
|
||||||
|
mode: "no-cors",
|
||||||
|
cache: "no-cache",
|
||||||
|
credentials: "omit",
|
||||||
|
headers: {
|
||||||
|
"X-Final-Destination": server
|
||||||
|
},
|
||||||
|
keepalive: true,
|
||||||
|
}).catch(e2 => {
|
||||||
|
console.error("Fallback tracking error:", e2);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Tracking error:", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sendInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Page load tracking function
|
||||||
|
function pL() {
|
||||||
|
tE("pageLoad_" + window.location.pathname);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up page load tracking
|
||||||
|
document.addEventListener("DOMContentLoaded", function() {
|
||||||
|
try {
|
||||||
|
pL();
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error in page load tracking:", error);
|
||||||
|
}
|
||||||
|
});
|
||||||
149
wordpress/palantics-tracking-plugin/includes/class-admin.php
Normal file
149
wordpress/palantics-tracking-plugin/includes/class-admin.php
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Admin functionality class
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Exit if accessed directly
|
||||||
|
if (!defined('ABSPATH')) {
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
class Palantics_Admin {
|
||||||
|
|
||||||
|
// Tracking server URL
|
||||||
|
private $tracking_server_url = 'tracking1.karlbreuer.com';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*/
|
||||||
|
public function __construct() {
|
||||||
|
// Add settings page
|
||||||
|
add_action('admin_menu', array($this, 'add_settings_page'));
|
||||||
|
add_action('admin_init', array($this, 'register_settings'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add settings page
|
||||||
|
*/
|
||||||
|
public function add_settings_page() {
|
||||||
|
add_options_page(
|
||||||
|
'Palantics Tracking',
|
||||||
|
'Palantics Tracking',
|
||||||
|
'manage_options',
|
||||||
|
'palantics-tracking-settings',
|
||||||
|
array($this, 'render_settings_page')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register settings
|
||||||
|
*/
|
||||||
|
public function register_settings() {
|
||||||
|
register_setting('palantics_tracking_settings', 'palantics_tracking_server_url');
|
||||||
|
register_setting('palantics_tracking_settings', 'palantics_tracking_track_classes');
|
||||||
|
|
||||||
|
add_settings_section(
|
||||||
|
'palantics_tracking_section',
|
||||||
|
'Tracking Settings',
|
||||||
|
array($this, 'settings_section_callback'),
|
||||||
|
'palantics-tracking-settings'
|
||||||
|
);
|
||||||
|
|
||||||
|
add_settings_field(
|
||||||
|
'palantics_tracking_server_url',
|
||||||
|
'Tracking Server URL',
|
||||||
|
array($this, 'server_url_callback'),
|
||||||
|
'palantics-tracking-settings',
|
||||||
|
'palantics_tracking_section'
|
||||||
|
);
|
||||||
|
|
||||||
|
add_settings_section(
|
||||||
|
'palantics_tracking_auto_section',
|
||||||
|
'Element Tracking Settings',
|
||||||
|
array($this, 'auto_settings_section_callback'),
|
||||||
|
'palantics-tracking-settings'
|
||||||
|
);
|
||||||
|
|
||||||
|
add_settings_field(
|
||||||
|
'palantics_tracking_track_classes',
|
||||||
|
'Track Elements with Classes',
|
||||||
|
array($this, 'track_classes_callback'),
|
||||||
|
'palantics-tracking-settings',
|
||||||
|
'palantics_tracking_auto_section'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Settings section callback
|
||||||
|
*/
|
||||||
|
public function settings_section_callback() {
|
||||||
|
echo '<p>Configure your Palantics tracking server settings.</p>';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Auto tracking settings section callback
|
||||||
|
*/
|
||||||
|
public function auto_settings_section_callback() {
|
||||||
|
echo '<p>Configure which elements to track based on CSS classes.</p>';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Server URL field callback
|
||||||
|
*/
|
||||||
|
public function server_url_callback() {
|
||||||
|
$value = get_option('palantics_tracking_server_url', $this->tracking_server_url);
|
||||||
|
echo '<input type="text" id="palantics_tracking_server_url" name="palantics_tracking_server_url" value="' . esc_attr($value) . '" class="regular-text">';
|
||||||
|
echo '<p class="description">Enter the tracking server URL without https:// (e.g., tracking1.karlbreuer.com)</p>';
|
||||||
|
echo '<p class="description">You will find this in your domain screen in the Palantics app</p>';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Track classes callback
|
||||||
|
*/
|
||||||
|
public function track_classes_callback() {
|
||||||
|
$value = get_option('palantics_tracking_track_classes', '');
|
||||||
|
echo '<input type="text" id="palantics_tracking_track_classes" name="palantics_tracking_track_classes" value="' . esc_attr($value) . '" class="regular-text">';
|
||||||
|
echo '<p class="description">Enter comma-separated class names to automatically track clicks on elements with these classes (e.g., cta-button, featured-product)</p>';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render settings page
|
||||||
|
*/
|
||||||
|
public function render_settings_page() {
|
||||||
|
?>
|
||||||
|
<div class="wrap">
|
||||||
|
<h1><span style="color: #007cba;">Palantics</span> Tracking Settings</h1>
|
||||||
|
<form method="post" action="options.php">
|
||||||
|
<?php
|
||||||
|
settings_fields('palantics_tracking_settings');
|
||||||
|
do_settings_sections('palantics-tracking-settings');
|
||||||
|
submit_button();
|
||||||
|
?>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<div style="background-color: #fff; padding: 20px; margin-top: 20px; border: 1px solid #ccc; border-radius: 4px;">
|
||||||
|
<h2>Manual Tracking Methods</h2>
|
||||||
|
|
||||||
|
<div style="margin-bottom: 20px;">
|
||||||
|
<h3>Method 1: Using Data Attributes</h3>
|
||||||
|
<p>Add the <code>data-track</code> attribute to any HTML element to track clicks:</p>
|
||||||
|
<pre style="background-color: #f5f5f5; padding: 10px; border-radius: 4px;"><button data-track="signup_button_click">Sign Up</button></pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style="margin-bottom: 20px;">
|
||||||
|
<h3>Method 2: Using Shortcode</h3>
|
||||||
|
<p>Wrap any content with the shortcode to track clicks:</p>
|
||||||
|
<pre style="background-color: #f5f5f5; padding: 10px; border-radius: 4px;">[track_element event="download_click" class="your-class" style="your-style"]
|
||||||
|
Your content here (can include other shortcodes)
|
||||||
|
[/track_element]</pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h3>Method 3: Using Direct JavaScript</h3>
|
||||||
|
<p>You can also manually add <code>onclick="tE('your_event_name')"</code> to any HTML element.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,92 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Asset loader class
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Exit if accessed directly
|
||||||
|
if (!defined('ABSPATH')) {
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
class Palantics_Loader {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*/
|
||||||
|
public function __construct() {
|
||||||
|
// Enqueue frontend scripts
|
||||||
|
add_action('wp_enqueue_scripts', array($this, 'enqueue_frontend_scripts'));
|
||||||
|
|
||||||
|
// Enqueue admin scripts
|
||||||
|
add_action('admin_enqueue_scripts', array($this, 'enqueue_admin_scripts'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enqueue frontend scripts
|
||||||
|
*/
|
||||||
|
public function enqueue_frontend_scripts() {
|
||||||
|
// Register main tracking script
|
||||||
|
wp_register_script(
|
||||||
|
'palantics-tracking-script',
|
||||||
|
PALANTICS_PLUGIN_URL . 'assets/js/tracking-script.js',
|
||||||
|
array(),
|
||||||
|
PALANTICS_PLUGIN_VERSION,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
|
// Register class tracking script
|
||||||
|
wp_register_script(
|
||||||
|
'palantics-class-tracking',
|
||||||
|
PALANTICS_PLUGIN_URL . 'assets/js/class-tracking.js',
|
||||||
|
array('palantics-tracking-script'),
|
||||||
|
PALANTICS_PLUGIN_VERSION,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
// Get tracking classes from options
|
||||||
|
$track_classes = get_option('palantics_tracking_track_classes', '');
|
||||||
|
$track_classes_array = array_filter(array_map('trim', explode(',', $track_classes)));
|
||||||
|
|
||||||
|
// Only enqueue class tracking if we have classes to track
|
||||||
|
if (!empty($track_classes_array)) {
|
||||||
|
// Add trackClasses as a JavaScript variable
|
||||||
|
wp_localize_script(
|
||||||
|
'palantics-class-tracking',
|
||||||
|
'trackClasses',
|
||||||
|
$track_classes_array
|
||||||
|
);
|
||||||
|
|
||||||
|
// Enqueue the script
|
||||||
|
wp_enqueue_script('palantics-class-tracking');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Always enqueue the main tracking script
|
||||||
|
wp_enqueue_script('palantics-tracking-script');
|
||||||
|
|
||||||
|
// Add server URL to JavaScript
|
||||||
|
$server_url = esc_url(get_option('palantics_tracking_server_url', 'tracking1.karlbreuer.com'));
|
||||||
|
wp_add_inline_script(
|
||||||
|
'palantics-tracking-script',
|
||||||
|
"const server = 'https://" . $server_url . "';",
|
||||||
|
'before'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enqueue admin scripts
|
||||||
|
*/
|
||||||
|
public function enqueue_admin_scripts($hook) {
|
||||||
|
// Only load on our settings page
|
||||||
|
if ($hook != 'settings_page_palantics-tracking-settings') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enqueue admin styles
|
||||||
|
wp_enqueue_style(
|
||||||
|
'palantics-admin-style',
|
||||||
|
PALANTICS_PLUGIN_URL . 'assets/css/admin.css',
|
||||||
|
array(),
|
||||||
|
PALANTICS_PLUGIN_VERSION
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
261
wordpress/palantics-tracking-plugin/includes/class-tracking.php
Normal file
261
wordpress/palantics-tracking-plugin/includes/class-tracking.php
Normal file
@ -0,0 +1,261 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Tracking functionality class
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Exit if accessed directly
|
||||||
|
if (!defined('ABSPATH')) {
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
class Palantics_Tracking {
|
||||||
|
|
||||||
|
// Tracking server URL
|
||||||
|
private $tracking_server_url = 'tracking1.karlbreuer.com';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*/
|
||||||
|
public function __construct() {
|
||||||
|
// Add the script to the header
|
||||||
|
add_action('wp_head', array($this, 'add_tracking_script'), 10);
|
||||||
|
|
||||||
|
// Register REST API endpoint
|
||||||
|
add_action('rest_api_init', array($this, 'register_rest_endpoint'));
|
||||||
|
|
||||||
|
// Add focused tracking for elements with specific classes
|
||||||
|
add_action('wp_footer', array($this, 'add_class_tracking_script'), 99);
|
||||||
|
|
||||||
|
// Add shortcode for manual tracking
|
||||||
|
add_shortcode('track_element', array($this, 'tracking_shortcode'));
|
||||||
|
|
||||||
|
// Register custom block for Gutenberg
|
||||||
|
add_action('init', array($this, 'register_tracking_block'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add tracking script to header
|
||||||
|
*/
|
||||||
|
public function add_tracking_script() {
|
||||||
|
// This is now handled by the Loader class using wp_enqueue_scripts
|
||||||
|
|
||||||
|
// Fallback for backward compatibility - will call pL() function
|
||||||
|
?>
|
||||||
|
<!-- Page Load Tracking Initialization -->
|
||||||
|
<script>
|
||||||
|
document.addEventListener("DOMContentLoaded", function() {
|
||||||
|
if (typeof pL === 'function') {
|
||||||
|
try {
|
||||||
|
pL();
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error in page load tracking:", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add JavaScript to track elements with specific classes
|
||||||
|
*/
|
||||||
|
public function add_class_tracking_script() {
|
||||||
|
// This is now handled by the Loader class using wp_enqueue_scripts
|
||||||
|
// The function is kept for backward compatibility but doesn't output anything
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register REST API endpoint for tracking
|
||||||
|
*/
|
||||||
|
public function register_rest_endpoint() {
|
||||||
|
register_rest_route('palantics/v1', '/sun', array(
|
||||||
|
'methods' => 'POST',
|
||||||
|
'callback' => array($this, 'handle_rest_request'),
|
||||||
|
'permission_callback' => '__return_true', // Allow unauthenticated access
|
||||||
|
));
|
||||||
|
|
||||||
|
// Also register GET method for easier testing and compatibility
|
||||||
|
register_rest_route('palantics/v1', '/sun', array(
|
||||||
|
'methods' => 'GET',
|
||||||
|
'callback' => array($this, 'handle_rest_request'),
|
||||||
|
'permission_callback' => '__return_true', // Allow unauthenticated access
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle REST API request for tracking
|
||||||
|
*/
|
||||||
|
public function handle_rest_request($request) {
|
||||||
|
// Get all parameters from the request
|
||||||
|
$params = $request->get_params();
|
||||||
|
|
||||||
|
// Add IP address to the parameters
|
||||||
|
$params['ip'] = $this->get_real_ip();
|
||||||
|
|
||||||
|
// Forward tracking data to the tracking server
|
||||||
|
$this->forward_to_tracker($params, $request);
|
||||||
|
|
||||||
|
// Return an empty success response
|
||||||
|
return new WP_REST_Response(array('status' => 'success'), 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shortcode for tracking elements
|
||||||
|
*/
|
||||||
|
public function tracking_shortcode($atts, $content = null) {
|
||||||
|
$atts = shortcode_atts(array(
|
||||||
|
'event' => 'tracked_element',
|
||||||
|
'class' => '',
|
||||||
|
'style' => '',
|
||||||
|
), $atts, 'track_element');
|
||||||
|
|
||||||
|
// Sanitize attributes
|
||||||
|
$event = esc_attr($atts['event']);
|
||||||
|
$class = esc_attr($atts['class']);
|
||||||
|
$style = esc_attr($atts['style']);
|
||||||
|
|
||||||
|
// Return the div with content and onclick attribute
|
||||||
|
return sprintf(
|
||||||
|
'<div class="palantics-tracking-wrapper %s" style="%s" onclick="tE(\'%s\')">%s</div>',
|
||||||
|
$class,
|
||||||
|
$style,
|
||||||
|
$event,
|
||||||
|
do_shortcode($content)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register Gutenberg tracking block
|
||||||
|
*/
|
||||||
|
public function register_tracking_block() {
|
||||||
|
// Only register block if Gutenberg is available
|
||||||
|
if (!function_exists('register_block_type')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register block script
|
||||||
|
wp_register_script(
|
||||||
|
'palantics-tracking-block-editor',
|
||||||
|
PALANTICS_PLUGIN_URL . 'assets/js/block.js',
|
||||||
|
array(
|
||||||
|
'wp-blocks',
|
||||||
|
'wp-element',
|
||||||
|
'wp-block-editor',
|
||||||
|
'wp-components',
|
||||||
|
'wp-i18n'
|
||||||
|
),
|
||||||
|
PALANTICS_PLUGIN_VERSION
|
||||||
|
);
|
||||||
|
|
||||||
|
// Register block styles
|
||||||
|
wp_register_style(
|
||||||
|
'palantics-tracking-block-editor-style',
|
||||||
|
PALANTICS_PLUGIN_URL . 'assets/css/tracking-block.css',
|
||||||
|
array(),
|
||||||
|
PALANTICS_PLUGIN_VERSION
|
||||||
|
);
|
||||||
|
|
||||||
|
// Register the block
|
||||||
|
register_block_type('palantics-tracking/track-element', array(
|
||||||
|
'editor_script' => 'palantics-tracking-block-editor',
|
||||||
|
'editor_style' => 'palantics-tracking-block-editor-style',
|
||||||
|
'attributes' => array(
|
||||||
|
'eventName' => array(
|
||||||
|
'type' => 'string',
|
||||||
|
'default' => 'tracked_element',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
// Add inline script to ensure tE function is available in editor
|
||||||
|
wp_add_inline_script('palantics-tracking-block-editor', "
|
||||||
|
// Mock tE function for the editor if it doesn't exist
|
||||||
|
if (typeof window.tE === 'undefined') {
|
||||||
|
window.tE = function(eventName) {
|
||||||
|
console.log('Tracking event: ' + eventName);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Forward the request to the tracking server
|
||||||
|
*/
|
||||||
|
public function forward_to_tracker($params, $request) {
|
||||||
|
// Get tracking server URL from settings
|
||||||
|
$tracking_server_url = get_option('palantics_tracking_server_url', $this->tracking_server_url);
|
||||||
|
$forward_url = 'https://' . $tracking_server_url . '/spur';
|
||||||
|
|
||||||
|
// Create a new cURL resource
|
||||||
|
$ch = curl_init();
|
||||||
|
|
||||||
|
// Set URL and other appropriate options
|
||||||
|
curl_setopt($ch, CURLOPT_URL, $forward_url);
|
||||||
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||||
|
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
|
||||||
|
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $request->get_method());
|
||||||
|
|
||||||
|
// Build query string from parameters
|
||||||
|
$query_string = http_build_query($params);
|
||||||
|
curl_setopt($ch, CURLOPT_URL, $forward_url . '?' . $query_string);
|
||||||
|
|
||||||
|
// Prepare headers
|
||||||
|
$headers = array();
|
||||||
|
|
||||||
|
// Get all request headers
|
||||||
|
$request_headers = $request->get_headers();
|
||||||
|
|
||||||
|
// Check for final destination header
|
||||||
|
if (isset($request_headers['x_final_destination']) && !empty($request_headers['x_final_destination'][0])) {
|
||||||
|
// If a custom destination is provided in the header, use it
|
||||||
|
$final_destination = $request_headers['x_final_destination'][0];
|
||||||
|
$forward_url = 'https://' . $final_destination . '/spur';
|
||||||
|
curl_setopt($ch, CURLOPT_URL, $forward_url . '?' . $query_string);
|
||||||
|
|
||||||
|
// Add the header to the forwarded request
|
||||||
|
$headers[] = "X-Final-Destination: " . $final_destination;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Forward all other headers
|
||||||
|
foreach ($request_headers as $name => $values) {
|
||||||
|
if ($name !== 'x_final_destination') {
|
||||||
|
foreach ($values as $value) {
|
||||||
|
$headers[] = sprintf("%s: %s", str_replace('_', '-', ucwords($name, '_')), $value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set headers for cURL request
|
||||||
|
if (!empty($headers)) {
|
||||||
|
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute request
|
||||||
|
$response = curl_exec($ch);
|
||||||
|
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||||
|
|
||||||
|
if (curl_errno($ch)) {
|
||||||
|
error_log('Palantics tracking error: ' . curl_error($ch));
|
||||||
|
$http_code = 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close cURL resource
|
||||||
|
curl_close($ch);
|
||||||
|
|
||||||
|
return $http_code;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the real IP address
|
||||||
|
*/
|
||||||
|
private function get_real_ip() {
|
||||||
|
if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
|
||||||
|
$ip = $_SERVER['HTTP_CLIENT_IP'];
|
||||||
|
} elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
|
||||||
|
$ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
|
||||||
|
} else {
|
||||||
|
$ip = $_SERVER['REMOTE_ADDR'];
|
||||||
|
}
|
||||||
|
return $ip;
|
||||||
|
}
|
||||||
|
}
|
||||||
1
wordpress/palantics-tracking-plugin/includes/index.php
Normal file
1
wordpress/palantics-tracking-plugin/includes/index.php
Normal file
@ -0,0 +1 @@
|
|||||||
|
<?php // silence is golden
|
||||||
1
wordpress/palantics-tracking-plugin/index.php
Normal file
1
wordpress/palantics-tracking-plugin/index.php
Normal file
@ -0,0 +1 @@
|
|||||||
|
<?php // silence is golden
|
||||||
@ -0,0 +1,81 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Plugin Name: Palantics Tracking Plugin
|
||||||
|
* Description: Adds tracking script to website header and tracks user interactions using WordPress REST API
|
||||||
|
* Version: 1.3.0
|
||||||
|
* Author: Karl Breuer
|
||||||
|
* Text Domain: palantics-tracking-plugin
|
||||||
|
* Domain Path: /languages
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Exit if accessed directly
|
||||||
|
if (!defined('ABSPATH')) {
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Define plugin constants
|
||||||
|
define('PALANTICS_PLUGIN_PATH', plugin_dir_path(__FILE__));
|
||||||
|
define('PALANTICS_PLUGIN_URL', plugin_dir_url(__FILE__));
|
||||||
|
define('PALANTICS_PLUGIN_VERSION', '1.3.0');
|
||||||
|
|
||||||
|
// Include required files
|
||||||
|
require_once PALANTICS_PLUGIN_PATH . 'includes/class-tracking.php';
|
||||||
|
require_once PALANTICS_PLUGIN_PATH . 'includes/class-admin.php';
|
||||||
|
require_once PALANTICS_PLUGIN_PATH . 'includes/class-loader.php';
|
||||||
|
|
||||||
|
class Palantics_Tracking_Plugin {
|
||||||
|
|
||||||
|
// Plugin instance
|
||||||
|
private static $instance = null;
|
||||||
|
|
||||||
|
// Tracking instance
|
||||||
|
private $tracking;
|
||||||
|
|
||||||
|
// Admin instance
|
||||||
|
private $admin;
|
||||||
|
|
||||||
|
// Loader instance
|
||||||
|
private $loader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*/
|
||||||
|
private function __construct() {
|
||||||
|
// Initialize tracking
|
||||||
|
$this->tracking = new Palantics_Tracking();
|
||||||
|
|
||||||
|
// Initialize admin
|
||||||
|
$this->admin = new Palantics_Admin();
|
||||||
|
|
||||||
|
// Initialize loader
|
||||||
|
$this->loader = new Palantics_Loader();
|
||||||
|
|
||||||
|
// Add settings link on plugin page
|
||||||
|
add_filter('plugin_action_links_' . plugin_basename(__FILE__), array($this, 'add_settings_link'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get plugin instance
|
||||||
|
*/
|
||||||
|
public static function get_instance() {
|
||||||
|
if (null === self::$instance) {
|
||||||
|
self::$instance = new self();
|
||||||
|
}
|
||||||
|
return self::$instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add settings link to plugin page
|
||||||
|
*/
|
||||||
|
public function add_settings_link($links) {
|
||||||
|
$settings_link = '<a href="options-general.php?page=palantics-tracking-settings">Settings</a>';
|
||||||
|
array_unshift($links, $settings_link);
|
||||||
|
return $links;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize the plugin
|
||||||
|
function palantics_tracking_init() {
|
||||||
|
Palantics_Tracking_Plugin::get_instance();
|
||||||
|
}
|
||||||
|
add_action('plugins_loaded', 'palantics_tracking_init');
|
||||||
@ -1,555 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* Plugin Name: Simplified Tracking Plugin
|
|
||||||
* Description: Adds tracking script to website header and tracks user interactions
|
|
||||||
* Version: 1.2.0
|
|
||||||
* Author: Karl Breuer
|
|
||||||
* Text Domain: simple-tracking
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Exit if accessed directly
|
|
||||||
if (!defined('ABSPATH')) {
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
class Simplified_Tracking_Plugin {
|
|
||||||
|
|
||||||
// Plugin instance
|
|
||||||
private static $instance = null;
|
|
||||||
|
|
||||||
// Tracking server URL
|
|
||||||
private $tracking_server_url = 'tracking1.karlbreuer.com';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*/
|
|
||||||
private function __construct() {
|
|
||||||
// Add the script to the header
|
|
||||||
add_action('wp_head', array($this, 'add_tracking_script'), 10);
|
|
||||||
|
|
||||||
// Register the endpoint
|
|
||||||
add_action('init', array($this, 'register_tracking_endpoint'));
|
|
||||||
|
|
||||||
// Add settings page
|
|
||||||
add_action('admin_menu', array($this, 'add_settings_page'));
|
|
||||||
add_action('admin_init', array($this, 'register_settings'));
|
|
||||||
|
|
||||||
// Add focused tracking for elements with specific classes
|
|
||||||
add_action('wp_footer', array($this, 'add_class_tracking_script'), 99);
|
|
||||||
|
|
||||||
// Add shortcode for manual tracking
|
|
||||||
add_shortcode('track_element', array($this, 'tracking_shortcode'));
|
|
||||||
|
|
||||||
// Register custom block for Gutenberg
|
|
||||||
add_action('init', array($this, 'register_tracking_block'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get plugin instance
|
|
||||||
*/
|
|
||||||
public static function get_instance() {
|
|
||||||
if (null === self::$instance) {
|
|
||||||
self::$instance = new self();
|
|
||||||
}
|
|
||||||
return self::$instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add tracking script to header
|
|
||||||
*/
|
|
||||||
public function add_tracking_script() {
|
|
||||||
$server_url = esc_url(get_option('simple_tracking_server_url', $this->tracking_server_url));
|
|
||||||
?>
|
|
||||||
<!-- Global server config -->
|
|
||||||
<script> const server = "https://<?php echo $server_url; ?>";</script>
|
|
||||||
<!-- Tracking function -->
|
|
||||||
<script>
|
|
||||||
// Initialize tracking function
|
|
||||||
function tE(eventName, additionalParams = {}) {
|
|
||||||
// Create tracking data object
|
|
||||||
const data = {
|
|
||||||
event: eventName,
|
|
||||||
url: window.location.href,
|
|
||||||
ref: document.referrer,
|
|
||||||
ua: navigator.userAgent,
|
|
||||||
sw: window.screen.width,
|
|
||||||
lang: navigator.language || navigator.userLanguage,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Add any additional parameters
|
|
||||||
Object.assign(data, additionalParams);
|
|
||||||
|
|
||||||
// Helper function to serialize an object into URL parameters
|
|
||||||
function serializeObject(obj, prefix) {
|
|
||||||
const str = [];
|
|
||||||
for (const p in obj) {
|
|
||||||
if (obj.hasOwnProperty(p)) {
|
|
||||||
const k = prefix ? prefix + "[" + p + "]" : p;
|
|
||||||
const v = obj[p];
|
|
||||||
if (v !== null && typeof v === "object") {
|
|
||||||
str.push(serializeObject(v, k));
|
|
||||||
} else {
|
|
||||||
str.push(encodeURIComponent(k) + "=" + encodeURIComponent(v));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return str.join("&");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Function for sending tracking data
|
|
||||||
function sendInfo() {
|
|
||||||
try {
|
|
||||||
// Send to our WordPress endpoint first, which will forward to the tracking server
|
|
||||||
const siteUrl = window.location.origin;
|
|
||||||
const trackingUrl = `${siteUrl}/track?${serializeObject(data)}`;
|
|
||||||
fetch(trackingUrl, {
|
|
||||||
method: "POST",
|
|
||||||
mode: "no-cors",
|
|
||||||
cache: "no-cache",
|
|
||||||
credentials: "omit", // Don't send cookies
|
|
||||||
headers: {
|
|
||||||
"X-Final-Destination": server // Pass the final destination
|
|
||||||
},
|
|
||||||
keepalive: true, // Ensures request completes even if page unloads
|
|
||||||
});
|
|
||||||
return true;
|
|
||||||
} catch (e) {
|
|
||||||
console.error("Tracking error:", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return sendInfo();
|
|
||||||
}
|
|
||||||
|
|
||||||
function pL() {
|
|
||||||
tE("pageLoad_" + window.location.pathname);
|
|
||||||
}
|
|
||||||
|
|
||||||
</script>
|
|
||||||
<!-- Set up page load tracking -->
|
|
||||||
<script>
|
|
||||||
document.addEventListener("DOMContentLoaded", function() {
|
|
||||||
try {
|
|
||||||
pL();
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error in page load tracking:", error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
<?php
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add JavaScript to track elements with specific classes
|
|
||||||
*/
|
|
||||||
public function add_class_tracking_script() {
|
|
||||||
// Get custom elements to track
|
|
||||||
$track_classes = get_option('simple_tracking_track_classes', '');
|
|
||||||
$track_classes_array = array_filter(array_map('trim', explode(',', $track_classes)));
|
|
||||||
|
|
||||||
if (empty($track_classes_array)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
||||||
<!-- Simplified class-based tracking script -->
|
|
||||||
<script>
|
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
|
||||||
// Helper function to get element details for tracking
|
|
||||||
function getElementDetails(element) {
|
|
||||||
const details = {};
|
|
||||||
|
|
||||||
// Get element text or alternative
|
|
||||||
if (element.textContent && element.textContent.trim()) {
|
|
||||||
details.text = element.textContent.trim();
|
|
||||||
} else if (element.placeholder) {
|
|
||||||
details.text = element.placeholder;
|
|
||||||
} else if (element.value) {
|
|
||||||
details.text = element.value;
|
|
||||||
} else if (element.alt) {
|
|
||||||
details.text = element.alt;
|
|
||||||
} else if (element.getAttribute('aria-label')) {
|
|
||||||
details.text = element.getAttribute('aria-label');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Limit text length
|
|
||||||
if (details.text && details.text.length > 50) {
|
|
||||||
details.text = details.text.substring(0, 47) + '...';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get element ID, class and href if available
|
|
||||||
if (element.id) {
|
|
||||||
details.id = element.id;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (element.className) {
|
|
||||||
details.class = element.className;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (element.href) {
|
|
||||||
const href = element.href;
|
|
||||||
// Only include if it's not too long
|
|
||||||
if (href.length < 100) {
|
|
||||||
details.href = href;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return details;
|
|
||||||
}
|
|
||||||
|
|
||||||
<?php foreach ($track_classes_array as $class) : ?>
|
|
||||||
// Track elements with class: <?php echo esc_js($class); ?>
|
|
||||||
const <?php echo str_replace('-', '_', sanitize_key($class)); ?>Elements = document.querySelectorAll('.<?php echo esc_js($class); ?>');
|
|
||||||
<?php echo str_replace('-', '_', sanitize_key($class)); ?>Elements.forEach(function(element) {
|
|
||||||
element.addEventListener('click', function(e) {
|
|
||||||
const details = getElementDetails(element);
|
|
||||||
tE('custom_element_click', { element: 'custom', class: '<?php echo esc_js($class); ?>', ...details });
|
|
||||||
});
|
|
||||||
});
|
|
||||||
<?php endforeach; ?>
|
|
||||||
|
|
||||||
// Track elements with data-track attribute
|
|
||||||
const trackedElements = document.querySelectorAll('[data-track]');
|
|
||||||
trackedElements.forEach(function(element) {
|
|
||||||
element.addEventListener('click', function(e) {
|
|
||||||
const eventName = element.getAttribute('data-track') || 'tracked_element';
|
|
||||||
const details = getElementDetails(element);
|
|
||||||
tE(eventName, { element: 'data-track', ...details });
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
<?php
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Shortcode for tracking elements
|
|
||||||
*/
|
|
||||||
public function tracking_shortcode($atts, $content = null) {
|
|
||||||
$atts = shortcode_atts(array(
|
|
||||||
'event' => 'tracked_element',
|
|
||||||
'class' => '',
|
|
||||||
'style' => '',
|
|
||||||
), $atts, 'track_element');
|
|
||||||
|
|
||||||
// Sanitize attributes
|
|
||||||
$event = esc_attr($atts['event']);
|
|
||||||
$class = esc_attr($atts['class']);
|
|
||||||
$style = esc_attr($atts['style']);
|
|
||||||
|
|
||||||
// Return the div with content and onclick attribute
|
|
||||||
return sprintf(
|
|
||||||
'<div class="tracking-wrapper %s" style="%s" onclick="tE(\'%s\')">%s</div>',
|
|
||||||
$class,
|
|
||||||
$style,
|
|
||||||
$event,
|
|
||||||
do_shortcode($content)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Register Gutenberg tracking block
|
|
||||||
*/
|
|
||||||
public function register_tracking_block() {
|
|
||||||
// Only register block if Gutenberg is available
|
|
||||||
if (!function_exists('register_block_type')) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Register block script
|
|
||||||
wp_register_script(
|
|
||||||
'tracking-block-editor',
|
|
||||||
plugins_url('block.js', __FILE__),
|
|
||||||
array(
|
|
||||||
'wp-blocks',
|
|
||||||
'wp-element',
|
|
||||||
'wp-block-editor',
|
|
||||||
'wp-components',
|
|
||||||
'wp-i18n'
|
|
||||||
),
|
|
||||||
filemtime(plugin_dir_path(__FILE__) . 'block.js')
|
|
||||||
);
|
|
||||||
|
|
||||||
// Register block styles
|
|
||||||
wp_register_style(
|
|
||||||
'tracking-block-editor-style',
|
|
||||||
plugins_url('block.css', __FILE__),
|
|
||||||
array(),
|
|
||||||
filemtime(plugin_dir_path(__FILE__) . 'tracking-block.css')
|
|
||||||
);
|
|
||||||
|
|
||||||
// Register the block
|
|
||||||
register_block_type('simplified-tracking/track-element', array(
|
|
||||||
'editor_script' => 'tracking-block-editor',
|
|
||||||
'editor_style' => 'tracking-block-editor-style',
|
|
||||||
'attributes' => array(
|
|
||||||
'eventName' => array(
|
|
||||||
'type' => 'string',
|
|
||||||
'default' => 'tracked_element',
|
|
||||||
),
|
|
||||||
),
|
|
||||||
));
|
|
||||||
|
|
||||||
// Add inline script to ensure tE function is available in editor
|
|
||||||
wp_add_inline_script('tracking-block-editor', "
|
|
||||||
// Mock tE function for the editor if it doesn't exist
|
|
||||||
if (typeof window.tE === 'undefined') {
|
|
||||||
window.tE = function(eventName) {
|
|
||||||
console.log('Tracking event: ' + eventName);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Register tracking endpoint
|
|
||||||
*/
|
|
||||||
public function register_tracking_endpoint() {
|
|
||||||
add_rewrite_rule('^track/?$', 'index.php?tracking_endpoint=1', 'top');
|
|
||||||
add_rewrite_tag('%tracking_endpoint%', '1');
|
|
||||||
add_action('parse_request', array($this, 'handle_tracking_request'));
|
|
||||||
|
|
||||||
// Flush rewrite rules only on plugin activation
|
|
||||||
if (get_option('simple_tracking_flush_rules', false)) {
|
|
||||||
flush_rewrite_rules();
|
|
||||||
update_option('simple_tracking_flush_rules', false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle tracking request
|
|
||||||
*/
|
|
||||||
public function handle_tracking_request($wp) {
|
|
||||||
if (isset($wp->query_vars['tracking_endpoint'])) {
|
|
||||||
$this->forward_to_tracker();
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Forward the request to the tracking server
|
|
||||||
*/
|
|
||||||
public function forward_to_tracker() {
|
|
||||||
// Get tracking server URL from settings
|
|
||||||
$tracking_server_url = get_option('simple_tracking_server_url', $this->tracking_server_url);
|
|
||||||
$forward_url = 'https://' . $tracking_server_url . '/spur';
|
|
||||||
|
|
||||||
// Create a new cURL resource
|
|
||||||
$ch = curl_init();
|
|
||||||
|
|
||||||
// Set URL and other appropriate options
|
|
||||||
curl_setopt($ch, CURLOPT_URL, $forward_url);
|
|
||||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
|
||||||
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
|
|
||||||
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $_SERVER['REQUEST_METHOD']);
|
|
||||||
|
|
||||||
// Get query parameters and add IP
|
|
||||||
$query = $_GET;
|
|
||||||
$query['ip'] = $this->get_real_ip();
|
|
||||||
|
|
||||||
// Build query string
|
|
||||||
$query_string = http_build_query($query);
|
|
||||||
curl_setopt($ch, CURLOPT_URL, $forward_url . '?' . $query_string);
|
|
||||||
|
|
||||||
// Prepare headers
|
|
||||||
$headers = array();
|
|
||||||
$all_headers = function_exists('getallheaders') ? getallheaders() : $this->get_all_headers();
|
|
||||||
|
|
||||||
// Forward all headers, checking for the final destination
|
|
||||||
foreach ($all_headers as $name => $value) {
|
|
||||||
if ($name == 'X-Final-Destination' && !empty($value)) {
|
|
||||||
// If a custom destination is provided in the header, use it
|
|
||||||
$forward_url = 'https://' . $value . '/spur';
|
|
||||||
curl_setopt($ch, CURLOPT_URL, $forward_url . '?' . $query_string);
|
|
||||||
}
|
|
||||||
$headers[] = "$name: $value";
|
|
||||||
}
|
|
||||||
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
|
|
||||||
|
|
||||||
// Execute request
|
|
||||||
$response = curl_exec($ch);
|
|
||||||
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
|
||||||
|
|
||||||
if (curl_errno($ch)) {
|
|
||||||
$http_code = 500;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close cURL resource
|
|
||||||
curl_close($ch);
|
|
||||||
|
|
||||||
// Send response
|
|
||||||
http_response_code($http_code);
|
|
||||||
header('Content-Type: application/json');
|
|
||||||
echo '{}';
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fallback implementation of getallheaders() for servers that don't have it
|
|
||||||
*/
|
|
||||||
private function get_all_headers() {
|
|
||||||
$headers = [];
|
|
||||||
foreach ($_SERVER as $name => $value) {
|
|
||||||
if (substr($name, 0, 5) == 'HTTP_') {
|
|
||||||
$headers[str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5)))))] = $value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $headers;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the real IP address
|
|
||||||
*/
|
|
||||||
private function get_real_ip() {
|
|
||||||
if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
|
|
||||||
$ip = $_SERVER['HTTP_CLIENT_IP'];
|
|
||||||
} elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
|
|
||||||
$ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
|
|
||||||
} else {
|
|
||||||
$ip = $_SERVER['REMOTE_ADDR'];
|
|
||||||
}
|
|
||||||
return $ip;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add settings page
|
|
||||||
*/
|
|
||||||
public function add_settings_page() {
|
|
||||||
add_options_page(
|
|
||||||
'Tracking Settings',
|
|
||||||
'Tracking Settings',
|
|
||||||
'manage_options',
|
|
||||||
'simple-tracking-settings',
|
|
||||||
array($this, 'render_settings_page')
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Register settings
|
|
||||||
*/
|
|
||||||
public function register_settings() {
|
|
||||||
register_setting('simple_tracking_settings', 'simple_tracking_server_url');
|
|
||||||
register_setting('simple_tracking_settings', 'simple_tracking_track_classes');
|
|
||||||
|
|
||||||
add_settings_section(
|
|
||||||
'simple_tracking_section',
|
|
||||||
'Tracking Settings',
|
|
||||||
array($this, 'settings_section_callback'),
|
|
||||||
'simple-tracking-settings'
|
|
||||||
);
|
|
||||||
|
|
||||||
add_settings_field(
|
|
||||||
'simple_tracking_server_url',
|
|
||||||
'Tracking Server URL',
|
|
||||||
array($this, 'server_url_callback'),
|
|
||||||
'simple-tracking-settings',
|
|
||||||
'simple_tracking_section'
|
|
||||||
);
|
|
||||||
|
|
||||||
add_settings_section(
|
|
||||||
'simple_tracking_auto_section',
|
|
||||||
'Element Tracking Settings',
|
|
||||||
array($this, 'auto_settings_section_callback'),
|
|
||||||
'simple-tracking-settings'
|
|
||||||
);
|
|
||||||
|
|
||||||
add_settings_field(
|
|
||||||
'simple_tracking_track_classes',
|
|
||||||
'Track Elements with Classes',
|
|
||||||
array($this, 'track_classes_callback'),
|
|
||||||
'simple-tracking-settings',
|
|
||||||
'simple_tracking_auto_section'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Settings section callback
|
|
||||||
*/
|
|
||||||
public function settings_section_callback() {
|
|
||||||
echo '<p>Configure your tracking server settings.</p>';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Auto tracking settings section callback
|
|
||||||
*/
|
|
||||||
public function auto_settings_section_callback() {
|
|
||||||
echo '<p>Configure which elements to track based on CSS classes.</p>';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Server URL field callback
|
|
||||||
*/
|
|
||||||
public function server_url_callback() {
|
|
||||||
$value = get_option('simple_tracking_server_url', $this->tracking_server_url);
|
|
||||||
echo '<input type="text" id="simple_tracking_server_url" name="simple_tracking_server_url" value="' . esc_attr($value) . '" class="regular-text">';
|
|
||||||
echo '<p class="description">Enter the tracking server URL without https:// (e.g., tracking1.karlbreuer.com)</p>';
|
|
||||||
echo '<p class="description">You will find this in your domain screen in the Palantics app</p>';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Track classes callback
|
|
||||||
*/
|
|
||||||
public function track_classes_callback() {
|
|
||||||
$value = get_option('simple_tracking_track_classes', '');
|
|
||||||
echo '<input type="text" id="simple_tracking_track_classes" name="simple_tracking_track_classes" value="' . esc_attr($value) . '" class="regular-text">';
|
|
||||||
echo '<p class="description">Enter comma-separated class names to automatically track clicks on elements with these classes (e.g., cta-button, featured-product)</p>';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Render settings page
|
|
||||||
*/
|
|
||||||
public function render_settings_page() {
|
|
||||||
?>
|
|
||||||
<div class="wrap">
|
|
||||||
<h1><?php echo esc_html(get_admin_page_title()); ?></h1>
|
|
||||||
<form method="post" action="options.php">
|
|
||||||
<?php
|
|
||||||
settings_fields('simple_tracking_settings');
|
|
||||||
do_settings_sections('simple-tracking-settings');
|
|
||||||
submit_button();
|
|
||||||
?>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<div style="background-color: #fff; padding: 20px; margin-top: 20px; border: 1px solid #ccc; border-radius: 4px;">
|
|
||||||
<h2>Manual Tracking Methods</h2>
|
|
||||||
|
|
||||||
<div style="margin-bottom: 20px;">
|
|
||||||
<h3>Method 1: Using Data Attributes</h3>
|
|
||||||
<p>Add the <code>data-track</code> attribute to any HTML element to track clicks:</p>
|
|
||||||
<pre style="background-color: #f5f5f5; padding: 10px; border-radius: 4px;"><button data-track="signup_button_click">Sign Up</button></pre>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div style="margin-bottom: 20px;">
|
|
||||||
<h3>Method 2: Using Shortcode</h3>
|
|
||||||
<p>Wrap any content with the shortcode to track clicks:</p>
|
|
||||||
<pre style="background-color: #f5f5f5; padding: 10px; border-radius: 4px;">[track_element event="download_click" class="your-class" style="your-style"]
|
|
||||||
Your content here (can include other shortcodes)
|
|
||||||
[/track_element]</pre>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<h3>Method 3: Using Direct JavaScript</h3>
|
|
||||||
<p>You can also manually add <code>onclick="tE('your_event_name')"</code> to any HTML element.</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<?php
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Activate plugin
|
|
||||||
*/
|
|
||||||
public static function activate() {
|
|
||||||
// Set flag to flush rewrite rules on next load
|
|
||||||
update_option('simple_tracking_flush_rules', true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize the plugin
|
|
||||||
function simplified_tracking_init() {
|
|
||||||
Simplified_Tracking_Plugin::get_instance();
|
|
||||||
}
|
|
||||||
add_action('plugins_loaded', 'simplified_tracking_init');
|
|
||||||
|
|
||||||
// Register activation hook
|
|
||||||
register_activation_hook(__FILE__, array('Simplified_Tracking_Plugin', 'activate'));
|
|
||||||
Loading…
x
Reference in New Issue
Block a user