claude-plugin-wordpress-manager 2.2.1 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/plugin.json +2 -2
- package/CHANGELOG.md +21 -0
- package/agents/wp-content-strategist.md +25 -0
- package/agents/wp-ecommerce-manager.md +23 -0
- package/agents/wp-site-manager.md +26 -0
- package/package.json +8 -3
- package/skills/wordpress-router/references/decision-tree.md +8 -2
- package/skills/wp-content/SKILL.md +1 -0
- package/skills/wp-content-attribution/SKILL.md +97 -0
- package/skills/wp-content-attribution/references/attribution-models.md +189 -0
- package/skills/wp-content-attribution/references/conversion-funnels.md +137 -0
- package/skills/wp-content-attribution/references/reporting-dashboards.md +199 -0
- package/skills/wp-content-attribution/references/roi-calculation.md +202 -0
- package/skills/wp-content-attribution/references/utm-tracking-setup.md +161 -0
- package/skills/wp-content-attribution/scripts/attribution_inspect.mjs +277 -0
- package/skills/wp-headless/SKILL.md +1 -0
- package/skills/wp-i18n/SKILL.md +1 -0
- package/skills/wp-multilang-network/SKILL.md +107 -0
- package/skills/wp-multilang-network/references/content-sync.md +182 -0
- package/skills/wp-multilang-network/references/hreflang-config.md +198 -0
- package/skills/wp-multilang-network/references/language-routing.md +234 -0
- package/skills/wp-multilang-network/references/network-architecture.md +119 -0
- package/skills/wp-multilang-network/references/seo-international.md +213 -0
- package/skills/wp-multilang-network/scripts/multilang_inspect.mjs +308 -0
- package/skills/wp-multisite/SKILL.md +1 -0
- package/skills/wp-programmatic-seo/SKILL.md +97 -0
- package/skills/wp-programmatic-seo/references/data-sources.md +200 -0
- package/skills/wp-programmatic-seo/references/location-seo.md +134 -0
- package/skills/wp-programmatic-seo/references/product-seo.md +147 -0
- package/skills/wp-programmatic-seo/references/technical-seo.md +197 -0
- package/skills/wp-programmatic-seo/references/template-architecture.md +125 -0
- package/skills/wp-programmatic-seo/scripts/programmatic_seo_inspect.mjs +264 -0
- package/skills/wp-woocommerce/SKILL.md +1 -0
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
# Reporting Dashboards
|
|
2
|
+
|
|
3
|
+
Use this file when setting up content attribution reporting — GA4 integration, analytics plugin configuration, dashboard KPIs, and automated reporting workflows.
|
|
4
|
+
|
|
5
|
+
## WooCommerce + WordPress Analytics Correlation
|
|
6
|
+
|
|
7
|
+
The core reporting methodology links three data sources:
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
WordPress Content Data WooCommerce Order Data Analytics Data
|
|
11
|
+
(list_content, post dates) + (wc_list_orders, order meta) + (GA4, MonsterInsights)
|
|
12
|
+
│ │ │
|
|
13
|
+
└──────────── Correlate via UTM campaign = post slug ─────────┘
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
### Manual Correlation Workflow
|
|
17
|
+
|
|
18
|
+
1. **Export orders** with UTM meta for the reporting period
|
|
19
|
+
2. **Export content** published in the same period
|
|
20
|
+
3. **Match** `_last_utm_campaign` values to post slugs
|
|
21
|
+
4. **Aggregate** revenue per post, per category, per content type
|
|
22
|
+
5. **Rank** by revenue, ROI, or conversion rate
|
|
23
|
+
|
|
24
|
+
## Google Analytics 4 Integration
|
|
25
|
+
|
|
26
|
+
### UTM → GA4 → WooCommerce Reconciliation
|
|
27
|
+
|
|
28
|
+
GA4 automatically captures UTM parameters as session-level dimensions:
|
|
29
|
+
|
|
30
|
+
| GA4 Dimension | UTM Parameter | Use |
|
|
31
|
+
|---------------|--------------|-----|
|
|
32
|
+
| Session source | `utm_source` | Where traffic came from |
|
|
33
|
+
| Session medium | `utm_medium` | Channel type |
|
|
34
|
+
| Session campaign | `utm_campaign` | Specific campaign/post |
|
|
35
|
+
| Session manual ad content | `utm_content` | Link variant |
|
|
36
|
+
| Session manual term | `utm_term` | Search keyword |
|
|
37
|
+
|
|
38
|
+
**GA4 Exploration report for content attribution:**
|
|
39
|
+
1. Go to Explore → Free-form
|
|
40
|
+
2. Dimensions: Session campaign, Landing page
|
|
41
|
+
3. Metrics: Sessions, Conversions, Revenue
|
|
42
|
+
4. Filter: Session source = "blog"
|
|
43
|
+
5. Sort by Revenue descending
|
|
44
|
+
|
|
45
|
+
### Enhanced E-commerce Events
|
|
46
|
+
|
|
47
|
+
GA4 tracks the full purchase funnel when configured:
|
|
48
|
+
- `view_item` — product page view
|
|
49
|
+
- `add_to_cart` — item added to cart
|
|
50
|
+
- `begin_checkout` — checkout started
|
|
51
|
+
- `purchase` — order completed with revenue
|
|
52
|
+
|
|
53
|
+
## MonsterInsights / WooCommerce Google Analytics Plugin
|
|
54
|
+
|
|
55
|
+
### MonsterInsights Setup
|
|
56
|
+
|
|
57
|
+
MonsterInsights bridges WordPress content data with GA4:
|
|
58
|
+
|
|
59
|
+
1. **Install:** MonsterInsights plugin (free tier sufficient for basic attribution)
|
|
60
|
+
2. **Connect:** Link to GA4 property via the setup wizard
|
|
61
|
+
3. **Enable:** Enhanced E-commerce tracking in MonsterInsights settings
|
|
62
|
+
4. **Dashboard:** View top posts by revenue directly in WordPress admin
|
|
63
|
+
|
|
64
|
+
**Key MonsterInsights reports:**
|
|
65
|
+
- Top Landing Pages (awareness stage)
|
|
66
|
+
- Top Outbound Links (consideration stage)
|
|
67
|
+
- E-commerce Revenue by Source (attribution)
|
|
68
|
+
- Top Products (conversion stage)
|
|
69
|
+
|
|
70
|
+
### WooCommerce Google Analytics Plugin (Official)
|
|
71
|
+
|
|
72
|
+
Alternative for sites already using GA4 without MonsterInsights:
|
|
73
|
+
|
|
74
|
+
1. Install: "WooCommerce Google Analytics" (official extension)
|
|
75
|
+
2. Enter GA4 Measurement ID
|
|
76
|
+
3. Enable: Enhanced E-commerce events
|
|
77
|
+
4. Events auto-tracked: `view_item`, `add_to_cart`, `purchase`
|
|
78
|
+
|
|
79
|
+
## Custom Dashboard Options
|
|
80
|
+
|
|
81
|
+
### WP Admin Dashboard Widget
|
|
82
|
+
|
|
83
|
+
Create a simple attribution summary widget:
|
|
84
|
+
|
|
85
|
+
```php
|
|
86
|
+
add_action('wp_dashboard_setup', function () {
|
|
87
|
+
wp_add_dashboard_widget(
|
|
88
|
+
'content_attribution_widget',
|
|
89
|
+
'Content Attribution — Top 5 Posts by Revenue',
|
|
90
|
+
function () {
|
|
91
|
+
// Query recent completed orders with UTM data
|
|
92
|
+
$orders = wc_get_orders([
|
|
93
|
+
'status' => 'completed',
|
|
94
|
+
'limit' => 100,
|
|
95
|
+
'date_created' => '>' . date('Y-m-d', strtotime('-30 days')),
|
|
96
|
+
]);
|
|
97
|
+
$revenue_by_campaign = [];
|
|
98
|
+
foreach ($orders as $order) {
|
|
99
|
+
$campaign = $order->get_meta('_last_utm_campaign');
|
|
100
|
+
if ($campaign) {
|
|
101
|
+
$revenue_by_campaign[$campaign] = ($revenue_by_campaign[$campaign] ?? 0) + $order->get_total();
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
arsort($revenue_by_campaign);
|
|
105
|
+
echo '<table><tr><th>Content</th><th>Revenue</th></tr>';
|
|
106
|
+
$i = 0;
|
|
107
|
+
foreach ($revenue_by_campaign as $campaign => $revenue) {
|
|
108
|
+
if ($i++ >= 5) break;
|
|
109
|
+
echo '<tr><td>' . esc_html($campaign) . '</td><td>' . wc_price($revenue) . '</td></tr>';
|
|
110
|
+
}
|
|
111
|
+
echo '</table>';
|
|
112
|
+
}
|
|
113
|
+
);
|
|
114
|
+
});
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### External BI Tools
|
|
118
|
+
|
|
119
|
+
For larger operations, export data to external dashboards:
|
|
120
|
+
|
|
121
|
+
| Tool | Integration Method | Cost |
|
|
122
|
+
|------|-------------------|------|
|
|
123
|
+
| Google Looker Studio | GA4 connector + WC data export | Free |
|
|
124
|
+
| Tableau | WooCommerce REST API → CSV/database | Paid |
|
|
125
|
+
| Metabase | Direct MySQL/PostgreSQL connection | Free (self-hosted) |
|
|
126
|
+
| Power BI | REST API connector or CSV import | Paid |
|
|
127
|
+
|
|
128
|
+
## Automated Reporting
|
|
129
|
+
|
|
130
|
+
### Monthly Content Attribution Report Template
|
|
131
|
+
|
|
132
|
+
```
|
|
133
|
+
## Content Attribution Report — {Month} {Year}
|
|
134
|
+
|
|
135
|
+
### Summary
|
|
136
|
+
- Total content-attributed revenue: ${total}
|
|
137
|
+
- Orders with UTM attribution: {count} ({percentage}% of total orders)
|
|
138
|
+
- Top attribution model used: {model}
|
|
139
|
+
|
|
140
|
+
### Top 10 Converting Content Pieces
|
|
141
|
+
| Rank | Post | Revenue | Orders | Avg Order Value |
|
|
142
|
+
|------|------|---------|--------|-----------------|
|
|
143
|
+
| 1 | {title} | ${rev} | {n} | ${aov} |
|
|
144
|
+
| ... | ... | ... | ... | ... |
|
|
145
|
+
|
|
146
|
+
### Revenue by Content Category
|
|
147
|
+
| Category | Revenue | Posts | Revenue/Post |
|
|
148
|
+
|----------|---------|-------|-------------|
|
|
149
|
+
| {cat} | ${rev} | {n} | ${rpp} |
|
|
150
|
+
|
|
151
|
+
### Revenue by Source
|
|
152
|
+
| Source | Revenue | Orders | CAC |
|
|
153
|
+
|--------|---------|--------|-----|
|
|
154
|
+
| blog | ${rev} | {n} | ${cac} |
|
|
155
|
+
| newsletter | ${rev} | {n} | ${cac} |
|
|
156
|
+
|
|
157
|
+
### Recommendations
|
|
158
|
+
- Invest more in: {top category}
|
|
159
|
+
- Reduce investment in: {lowest ROI category}
|
|
160
|
+
- Content gap: {opportunity identified}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### Automation via WP-Cron
|
|
164
|
+
|
|
165
|
+
Schedule monthly report generation:
|
|
166
|
+
|
|
167
|
+
```php
|
|
168
|
+
// Register cron event
|
|
169
|
+
if (!wp_next_scheduled('generate_attribution_report')) {
|
|
170
|
+
wp_schedule_event(time(), 'monthly', 'generate_attribution_report');
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
add_action('generate_attribution_report', function () {
|
|
174
|
+
// Generate report data (query orders, correlate with content)
|
|
175
|
+
// Save as a private post or send via email
|
|
176
|
+
// Uses same logic as dashboard widget but for full month
|
|
177
|
+
});
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
## Key KPIs Dashboard
|
|
181
|
+
|
|
182
|
+
The essential metrics for an at-a-glance attribution dashboard:
|
|
183
|
+
|
|
184
|
+
| KPI | Description | Update Frequency |
|
|
185
|
+
|-----|-------------|-----------------|
|
|
186
|
+
| **Content-Attributed Revenue** | Total revenue from orders with UTM data | Weekly |
|
|
187
|
+
| **Top Converting Post** | Post with highest attributed revenue this month | Monthly |
|
|
188
|
+
| **Attribution Rate** | % of orders with UTM attribution data | Weekly |
|
|
189
|
+
| **Content ROI** | (Revenue - Cost) / Cost × 100% | Monthly |
|
|
190
|
+
| **CAC by Source** | Customer acquisition cost per channel | Monthly |
|
|
191
|
+
| **Revenue/Post Trend** | Month-over-month revenue per post | Monthly |
|
|
192
|
+
|
|
193
|
+
## Decision Checklist
|
|
194
|
+
|
|
195
|
+
1. Is GA4 connected and tracking enhanced e-commerce events? → Verify in GA4 Realtime report
|
|
196
|
+
2. Is MonsterInsights or equivalent analytics plugin active? → Check WordPress admin dashboard
|
|
197
|
+
3. Are WooCommerce orders showing UTM meta data? → Spot-check 5 recent orders
|
|
198
|
+
4. Is a monthly report process defined (manual or automated)? → Set up template + schedule
|
|
199
|
+
5. Are KPIs reviewed and actioned on regularly? → Schedule monthly review meeting
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
# ROI Calculation
|
|
2
|
+
|
|
3
|
+
Use this file when calculating content return on investment — revenue per post, content ROI formula, customer acquisition cost, and lifetime value by content source.
|
|
4
|
+
|
|
5
|
+
## Revenue Per Post
|
|
6
|
+
|
|
7
|
+
The most straightforward content attribution metric.
|
|
8
|
+
|
|
9
|
+
**Formula:**
|
|
10
|
+
```
|
|
11
|
+
Revenue Per Post = Total attributed revenue / Number of posts
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
**Per-post attribution (last-touch):**
|
|
15
|
+
```
|
|
16
|
+
Revenue(Post X) = SUM(order_total) WHERE _last_utm_campaign = "post-x-slug"
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
**Per-post attribution (first-touch):**
|
|
20
|
+
```
|
|
21
|
+
Revenue(Post X) = SUM(order_total) WHERE _first_utm_campaign = "post-x-slug"
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### Calculating with WooCommerce MCP Tools
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
# Step 1: Get completed orders for the period
|
|
28
|
+
wc_list_orders(status="completed", after="2025-01-01", before="2025-01-31", per_page=100)
|
|
29
|
+
|
|
30
|
+
# Step 2: For each order, read utm meta
|
|
31
|
+
# Group orders by _last_utm_campaign value
|
|
32
|
+
# Sum order_total per campaign (campaign = post slug)
|
|
33
|
+
|
|
34
|
+
# Step 3: Get content list for the same period
|
|
35
|
+
list_content(type="post", status="publish", after="2025-01-01", before="2025-01-31")
|
|
36
|
+
|
|
37
|
+
# Step 4: Match campaign slugs to post titles
|
|
38
|
+
# Result: { post_title: "Cactus Water Benefits", slug: "cactus-water-benefits", revenue: 2500, orders: 15 }
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Revenue Per Post Benchmarks
|
|
42
|
+
|
|
43
|
+
| Content Type | Typical Revenue/Post | Notes |
|
|
44
|
+
|-------------|---------------------|-------|
|
|
45
|
+
| Product review | $500–$5,000 | High intent, bottom-of-funnel |
|
|
46
|
+
| How-to guide | $100–$1,000 | Indirect conversion, builds trust |
|
|
47
|
+
| Comparison post | $1,000–$10,000 | Very high intent, decision-stage |
|
|
48
|
+
| Category guide | $200–$2,000 | Mid-funnel, product discovery |
|
|
49
|
+
| News/update | $50–$500 | Low intent, brand awareness |
|
|
50
|
+
|
|
51
|
+
## Content ROI Formula
|
|
52
|
+
|
|
53
|
+
**Formula:**
|
|
54
|
+
```
|
|
55
|
+
Content ROI = (Revenue - Content Cost) / Content Cost × 100%
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
**Example:**
|
|
59
|
+
```
|
|
60
|
+
Blog post cost: $200 (writer) + $50 (images) + $30 (editing) = $280
|
|
61
|
+
Revenue attributed: $1,400 (last-touch, 3 months)
|
|
62
|
+
Content ROI: ($1,400 - $280) / $280 × 100% = 400% ROI
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Content Cost Components
|
|
66
|
+
|
|
67
|
+
| Component | Typical Cost | How to Track |
|
|
68
|
+
|-----------|-------------|--------------|
|
|
69
|
+
| Writing | $0.10–$0.50/word | Per-post invoice or hourly rate |
|
|
70
|
+
| Editing | $25–$100/post | Editor time tracking |
|
|
71
|
+
| Images/media | $10–$100/post | Stock photo licenses, design time |
|
|
72
|
+
| SEO optimization | $25–$75/post | SEO tool costs + specialist time |
|
|
73
|
+
| Publishing/formatting | $15–$30/post | CMS time |
|
|
74
|
+
| **Total typical cost** | **$100–$500/post** | Sum all components |
|
|
75
|
+
|
|
76
|
+
### ROI by Content Category
|
|
77
|
+
|
|
78
|
+
Track ROI by category to identify the most profitable content pillars:
|
|
79
|
+
|
|
80
|
+
```
|
|
81
|
+
Category Posts Total Cost Total Revenue ROI
|
|
82
|
+
──────────────────────────────────────────────────────
|
|
83
|
+
Product reviews 10 $3,000 $25,000 733%
|
|
84
|
+
How-to guides 20 $4,000 $8,000 100%
|
|
85
|
+
Company news 15 $1,500 $750 -50%
|
|
86
|
+
Case studies 5 $2,500 $12,000 380%
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
**Action:** Double down on product reviews and case studies; reduce company news investment.
|
|
90
|
+
|
|
91
|
+
## Customer Acquisition Cost (CAC) by Content Type
|
|
92
|
+
|
|
93
|
+
**Formula:**
|
|
94
|
+
```
|
|
95
|
+
CAC = Total content investment / New customers acquired from content
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
**By content type:**
|
|
99
|
+
```
|
|
100
|
+
CAC(blog) = Blog content costs / New customers with _first_utm_source = "blog"
|
|
101
|
+
CAC(email) = Email costs / New customers with _first_utm_source = "newsletter"
|
|
102
|
+
CAC(social) = Social costs / New customers with _first_utm_source = "facebook|instagram"
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### CAC Benchmarks (E-commerce)
|
|
106
|
+
|
|
107
|
+
| Channel | Typical CAC | Notes |
|
|
108
|
+
|---------|------------|-------|
|
|
109
|
+
| Organic blog content | $20–$80 | Lower CAC, longer to build |
|
|
110
|
+
| Email newsletter | $10–$40 | Lowest CAC, requires list |
|
|
111
|
+
| Paid search (Google) | $30–$100 | Immediate but expensive |
|
|
112
|
+
| Social media (organic) | $25–$75 | Variable, platform-dependent |
|
|
113
|
+
| Social media (paid) | $15–$60 | Scalable with budget |
|
|
114
|
+
|
|
115
|
+
## Lifetime Value (LTV) by Acquisition Source
|
|
116
|
+
|
|
117
|
+
**Formula:**
|
|
118
|
+
```
|
|
119
|
+
LTV = Average Order Value × Purchase Frequency × Customer Lifespan
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
**By source:**
|
|
123
|
+
```
|
|
124
|
+
LTV(blog) = AOV(blog customers) × Frequency(blog customers) × Lifespan(blog customers)
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Calculating with WooCommerce Data
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
# Get top sellers to understand AOV patterns
|
|
131
|
+
wc_get_top_sellers(period="year")
|
|
132
|
+
|
|
133
|
+
# Get sales report for overall metrics
|
|
134
|
+
wc_get_sales_report(period="year")
|
|
135
|
+
# Returns: total_sales, total_orders → AOV = total_sales / total_orders
|
|
136
|
+
|
|
137
|
+
# For source-specific LTV:
|
|
138
|
+
# 1. Filter orders by _first_utm_source
|
|
139
|
+
# 2. Group by customer_id
|
|
140
|
+
# 3. Calculate per-customer: total_spent, order_count, first_order_date, last_order_date
|
|
141
|
+
# 4. Average across customers from that source
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### LTV:CAC Ratio
|
|
145
|
+
|
|
146
|
+
```
|
|
147
|
+
Healthy ratio: LTV:CAC > 3:1
|
|
148
|
+
|
|
149
|
+
Example:
|
|
150
|
+
Blog customers: LTV = $240, CAC = $50 → Ratio = 4.8:1 ✓ Excellent
|
|
151
|
+
Paid ad customers: LTV = $180, CAC = $80 → Ratio = 2.25:1 ⚠ Below target
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
**Action:** If LTV:CAC < 3:1, either reduce acquisition cost or increase customer retention/upsell.
|
|
155
|
+
|
|
156
|
+
## Content Efficiency Metrics
|
|
157
|
+
|
|
158
|
+
### Revenue Per Word
|
|
159
|
+
|
|
160
|
+
```
|
|
161
|
+
Revenue Per Word = Total attributed revenue / Total words published
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Useful for comparing content formats: long-form guides vs short product reviews.
|
|
165
|
+
|
|
166
|
+
### Revenue Per Topic
|
|
167
|
+
|
|
168
|
+
```
|
|
169
|
+
Revenue Per Topic = SUM(revenue of posts in topic cluster) / Number of posts in cluster
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Identifies which topic clusters are most commercially valuable.
|
|
173
|
+
|
|
174
|
+
### Time to ROI
|
|
175
|
+
|
|
176
|
+
```
|
|
177
|
+
Time to ROI = Days from publish date to break-even (revenue ≥ content cost)
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
Short time to ROI = content with immediate commercial intent (product reviews).
|
|
181
|
+
Long time to ROI = evergreen SEO content (compounds over months).
|
|
182
|
+
|
|
183
|
+
## Using WC Reports for Date Correlation
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
# Monthly sales report
|
|
187
|
+
wc_get_sales_report(date_min="2025-03-01", date_max="2025-03-31")
|
|
188
|
+
|
|
189
|
+
# Top-selling products in the period
|
|
190
|
+
wc_get_top_sellers(date_min="2025-03-01", date_max="2025-03-31")
|
|
191
|
+
|
|
192
|
+
# Cross-reference with content published before the period:
|
|
193
|
+
list_content(type="post", status="publish", before="2025-03-31", orderby="date", order="desc", per_page=20)
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
## Decision Checklist
|
|
197
|
+
|
|
198
|
+
1. Is content cost tracked per post? → Set up cost tracking (spreadsheet or custom field)
|
|
199
|
+
2. Is revenue attributed to individual posts via UTM? → Verify mu-plugin capturing data
|
|
200
|
+
3. Is CAC calculated by acquisition source? → Group orders by first-touch source
|
|
201
|
+
4. Is LTV:CAC ratio above 3:1? → If not, optimize acquisition or retention
|
|
202
|
+
5. Are content investments being shifted to highest-ROI categories? → Review quarterly
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
# UTM Tracking Setup
|
|
2
|
+
|
|
3
|
+
Use this file when setting up UTM parameter capture for WooCommerce orders — parameter architecture, mu-plugin installation, naming conventions, and verification.
|
|
4
|
+
|
|
5
|
+
## UTM Parameter Architecture
|
|
6
|
+
|
|
7
|
+
| Parameter | Purpose | Example |
|
|
8
|
+
|-----------|---------|---------|
|
|
9
|
+
| `utm_source` | Where traffic originates | `blog`, `newsletter`, `google`, `facebook` |
|
|
10
|
+
| `utm_medium` | Marketing channel type | `organic`, `email`, `cpc`, `social`, `referral` |
|
|
11
|
+
| `utm_campaign` | Specific campaign name | `spring-sale-2025`, `product-launch-x` |
|
|
12
|
+
| `utm_content` | Differentiates ad/link variants | `cta-button`, `sidebar-banner`, `post-footer` |
|
|
13
|
+
| `utm_term` | Paid search keywords | `cactus-water-buy`, `zero-calorie-drink` |
|
|
14
|
+
|
|
15
|
+
## mu-plugin Pattern: Capture UTM on Checkout
|
|
16
|
+
|
|
17
|
+
Create a mu-plugin to automatically capture UTM parameters from the visitor session and store them as WooCommerce order meta:
|
|
18
|
+
|
|
19
|
+
```php
|
|
20
|
+
<?php
|
|
21
|
+
/**
|
|
22
|
+
* Plugin Name: UTM Order Attribution
|
|
23
|
+
* Description: Captures UTM parameters from visitor session and stores as order meta.
|
|
24
|
+
* Version: 1.0.0
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
// Store UTM params in session cookie on first visit
|
|
28
|
+
add_action('init', function () {
|
|
29
|
+
if (!is_admin() && !wp_doing_cron()) {
|
|
30
|
+
$utm_params = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term'];
|
|
31
|
+
foreach ($utm_params as $param) {
|
|
32
|
+
if (isset($_GET[$param]) && !empty($_GET[$param])) {
|
|
33
|
+
// Store in cookie for 30 days (first-touch attribution)
|
|
34
|
+
$cookie_name = '_wc_' . $param;
|
|
35
|
+
if (!isset($_COOKIE[$cookie_name])) {
|
|
36
|
+
setcookie($cookie_name, sanitize_text_field($_GET[$param]), time() + (30 * DAY_IN_SECONDS), '/');
|
|
37
|
+
}
|
|
38
|
+
// Always update last-touch cookie
|
|
39
|
+
setcookie('_wc_last_' . $param, sanitize_text_field($_GET[$param]), time() + (30 * DAY_IN_SECONDS), '/');
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
// Save UTM data to order meta on checkout
|
|
46
|
+
add_action('woocommerce_checkout_order_processed', function ($order_id) {
|
|
47
|
+
$order = wc_get_order($order_id);
|
|
48
|
+
if (!$order) return;
|
|
49
|
+
|
|
50
|
+
$utm_params = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term'];
|
|
51
|
+
foreach ($utm_params as $param) {
|
|
52
|
+
// Save first-touch
|
|
53
|
+
$first_cookie = '_wc_' . $param;
|
|
54
|
+
if (isset($_COOKIE[$first_cookie]) && !empty($_COOKIE[$first_cookie])) {
|
|
55
|
+
$order->update_meta_data('_first_' . $param, sanitize_text_field($_COOKIE[$first_cookie]));
|
|
56
|
+
}
|
|
57
|
+
// Save last-touch
|
|
58
|
+
$last_cookie = '_wc_last_' . $param;
|
|
59
|
+
if (isset($_COOKIE[$last_cookie]) && !empty($_COOKIE[$last_cookie])) {
|
|
60
|
+
$order->update_meta_data('_last_' . $param, sanitize_text_field($_COOKIE[$last_cookie]));
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Save landing page URL (first page visited)
|
|
65
|
+
if (isset($_COOKIE['_wc_landing_page'])) {
|
|
66
|
+
$order->update_meta_data('_landing_page', sanitize_url($_COOKIE['_wc_landing_page']));
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
$order->save();
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
// Track landing page
|
|
73
|
+
add_action('init', function () {
|
|
74
|
+
if (!is_admin() && !wp_doing_cron() && !isset($_COOKIE['_wc_landing_page'])) {
|
|
75
|
+
$landing = esc_url_raw((isset($_SERVER['HTTPS']) ? 'https' : 'http') . '://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']);
|
|
76
|
+
setcookie('_wc_landing_page', $landing, time() + (30 * DAY_IN_SECONDS), '/');
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
**Installation:**
|
|
82
|
+
1. Save as `wp-content/mu-plugins/utm-order-attribution.php`
|
|
83
|
+
2. mu-plugins load automatically — no activation needed
|
|
84
|
+
3. Verify by placing a test order with UTM params in the URL
|
|
85
|
+
|
|
86
|
+
## UTM Naming Conventions
|
|
87
|
+
|
|
88
|
+
Consistent naming is critical for accurate attribution. Adopt these rules:
|
|
89
|
+
|
|
90
|
+
| Rule | Good | Bad |
|
|
91
|
+
|------|------|-----|
|
|
92
|
+
| Lowercase always | `utm_source=blog` | `utm_source=Blog` |
|
|
93
|
+
| Hyphens for spaces | `spring-sale-2025` | `spring_sale_2025` or `spring sale` |
|
|
94
|
+
| No special chars | `product-launch` | `product_launch!` |
|
|
95
|
+
| Consistent source names | `newsletter` (always) | `email`, `newsletter`, `mail` (mixed) |
|
|
96
|
+
| Date in campaigns | `black-friday-2025` | `black-friday` (ambiguous year) |
|
|
97
|
+
|
|
98
|
+
**Recommended source taxonomy:**
|
|
99
|
+
|
|
100
|
+
| Source | Medium | When to Use |
|
|
101
|
+
|--------|--------|-------------|
|
|
102
|
+
| `blog` | `organic` | Internal blog post links to products |
|
|
103
|
+
| `blog` | `cta` | Blog post CTA buttons to products |
|
|
104
|
+
| `newsletter` | `email` | Email newsletter links |
|
|
105
|
+
| `google` | `cpc` | Google Ads campaigns |
|
|
106
|
+
| `facebook` | `social` | Facebook organic or paid posts |
|
|
107
|
+
| `instagram` | `social` | Instagram bio/stories links |
|
|
108
|
+
| `partner-name` | `referral` | Partner/affiliate links |
|
|
109
|
+
|
|
110
|
+
## Internal Link UTM Tagging
|
|
111
|
+
|
|
112
|
+
Tag all blog-to-product links with UTMs:
|
|
113
|
+
|
|
114
|
+
```html
|
|
115
|
+
<!-- Blog post CTA linking to product -->
|
|
116
|
+
<a href="/product/cactus-water/?utm_source=blog&utm_medium=cta&utm_campaign=cactus-water-benefits&utm_content=post-footer-button">
|
|
117
|
+
Buy Cactus Water
|
|
118
|
+
</a>
|
|
119
|
+
|
|
120
|
+
<!-- Sidebar widget linking to product -->
|
|
121
|
+
<a href="/product/cactus-water/?utm_source=blog&utm_medium=sidebar&utm_campaign=always-on&utm_content=product-widget">
|
|
122
|
+
Try Cactus Water
|
|
123
|
+
</a>
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
**Automated tagging approach:** Use a WordPress filter to append UTMs to all internal product links in post content:
|
|
127
|
+
|
|
128
|
+
```php
|
|
129
|
+
add_filter('the_content', function ($content) {
|
|
130
|
+
if (!is_singular('post')) return $content;
|
|
131
|
+
$post_slug = get_post_field('post_name', get_the_ID());
|
|
132
|
+
// Append UTM to internal /product/ links that don't already have UTM
|
|
133
|
+
$content = preg_replace_callback(
|
|
134
|
+
'#href="(/product/[^"]*?)(?<!\?[^"]*utm_source[^"]*)"#',
|
|
135
|
+
function ($matches) use ($post_slug) {
|
|
136
|
+
$sep = strpos($matches[1], '?') !== false ? '&' : '?';
|
|
137
|
+
return 'href="' . $matches[1] . $sep . 'utm_source=blog&utm_medium=organic&utm_campaign=' . $post_slug . '"';
|
|
138
|
+
},
|
|
139
|
+
$content
|
|
140
|
+
);
|
|
141
|
+
return $content;
|
|
142
|
+
});
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## Verification
|
|
146
|
+
|
|
147
|
+
After installing the mu-plugin:
|
|
148
|
+
|
|
149
|
+
1. **Test visit:** Navigate to `yoursite.com/product/example/?utm_source=test&utm_medium=test&utm_campaign=test`
|
|
150
|
+
2. **Place test order** through WooCommerce checkout
|
|
151
|
+
3. **Check order meta:** Use `wc_list_orders` MCP tool or WooCommerce admin → Orders → order details
|
|
152
|
+
4. **Verify fields:** `_first_utm_source`, `_last_utm_source`, `_first_utm_campaign`, etc. should be populated
|
|
153
|
+
5. **Check cookies:** Browser dev tools → Application → Cookies → look for `_wc_utm_*` cookies
|
|
154
|
+
|
|
155
|
+
## Decision Checklist
|
|
156
|
+
|
|
157
|
+
1. Is the mu-plugin installed in `wp-content/mu-plugins/`? → Verify file exists
|
|
158
|
+
2. Are UTM naming conventions documented for the team? → Share taxonomy table
|
|
159
|
+
3. Are internal blog→product links tagged with UTMs? → Audit sample posts
|
|
160
|
+
4. Has a test order been placed with UTM params to verify capture? → Must pass before going live
|
|
161
|
+
5. Is cookie duration appropriate (30 days default)? → Adjust for sales cycle length
|