Skip to content

Commit d25b92d

Browse files
author
TechStack Global
committed
fix: comprehensive pillar UI and affiliate integrity repairs
1 parent 3c9d2fe commit d25b92d

23 files changed

+9867
-608
lines changed
11.6 KB
Binary file not shown.

amazon-stack.html

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@
2323
<link href="style.css?v=9" rel="stylesheet" />
2424
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet" />
2525
<link href="assets/icons/favicon-32.png?v=1" rel="icon" sizes="32x32" type="image/png" />
26+
<link href="assets/icons/favicon-16.png?v=1" rel="icon" sizes="16x16" type="image/png" />
27+
<link href="assets/icons/techstack-logo-192.png?v=1" rel="apple-touch-icon" sizes="192x192" />
28+
<link href="assets/icons/favicon.ico?v=1" rel="shortcut icon" />
2629
<script type="application/ld+json">
2730
[
2831
{
@@ -48,13 +51,13 @@
4851
</script>
4952
<link href="https://techstackglobal.github.io/amazon-stack.html" rel="canonical" />
5053
<meta content="https://techstackglobal.github.io/amazon-stack.html" property="og:url" />
51-
<meta content="https://techstackglobal.github.io/og-image.jpg" property="og:image" />
54+
<meta content="https://techstackglobal.github.io/assets/og-image.jpg" property="og:image" />
5255
<meta content="summary_large_image" name="twitter:card" />
5356
<meta content="Amazon Product Stack | Modern Tech Hardware | TechStack Global" name="twitter:title" />
5457
<meta
5558
content="The definitive guide to Amazon-sourced hardware for students, freelancers, and remote workers. Vetted benchmarks for modern productivity."
5659
name="twitter:description" />
57-
<meta content="https://techstackglobal.github.io/og-image.jpg" name="twitter:image" />
60+
<meta content="https://techstackglobal.github.io/assets/og-image.jpg" name="twitter:image" />
5861
</head>
5962

6063
<body class="dark-theme">
@@ -124,6 +127,23 @@ <h3><a aria-label="Open review: Sony WH-1000XM5" href="posts/sony-wh-1000xm5-rev
124127
class="fa-solid fa-arrow-right"></i></a>
125128
</div>
126129
</div>
130+
<!-- Sennheiser Momentum 4 -->
131+
<div class="product-item glass-card">
132+
<div class="product-thumbnail-wrapper">
133+
<img alt="Sennheiser Momentum 4 wireless headphones thumbnail" class="product-thumbnail"
134+
loading="lazy" src="posts/images/sony-wh-1000xm5-front.jpg"
135+
style="filter: brightness(0.8);" />
136+
</div>
137+
<div class="product-info">
138+
<div class="product-meta">Audiophile Wireless</div>
139+
<h3>Sennheiser Momentum 4</h3>
140+
<p style="font-size: 0.85rem; color: #aaa; margin: 0.5rem 0;">60-hour battery life & premium
141+
sound.</p>
142+
<a class="view-review-cta" href="https://www.amazon.com/dp/B09HN5XCMQ?tag=techstackglob-20"
143+
target="_blank" rel="nofollow noopener">View on Amazon <i
144+
class="fa-solid fa-external-link"></i></a>
145+
</div>
146+
</div>
127147
<!-- Samsung Odyssey G8 -->
128148
<div class="product-item glass-card">
129149
<div class="product-thumbnail-wrapper">
@@ -167,6 +187,22 @@ <h3><a aria-label="Open review: Shure SM7dB Dynamic Microphone"
167187
Review <i class="fa-solid fa-arrow-right"></i></a>
168188
</div>
169189
</div>
190+
<!-- Rode PodMic USB -->
191+
<div class="product-item glass-card">
192+
<div class="product-thumbnail-wrapper">
193+
<img alt="Rode PodMic USB product thumbnail" class="product-thumbnail" loading="lazy"
194+
src="posts/images/shure-sm7b-primary.jpg" style="opacity: 0.8;" />
195+
</div>
196+
<div class="product-info">
197+
<div class="product-meta">Hybrid Microphone</div>
198+
<h3>Rode PodMic USB</h3>
199+
<p style="font-size: 0.85rem; color: #aaa; margin: 0.5rem 0;">Versatile XLR/USB broadcasting
200+
mic.</p>
201+
<a class="view-review-cta" href="https://www.amazon.com/dp/B0C39K9S9C?tag=techstackglob-20"
202+
target="_blank" rel="nofollow noopener">View on Amazon <i
203+
class="fa-solid fa-external-link"></i></a>
204+
</div>
205+
</div>
170206
<!-- MacBook Pro-->
171207
<div class="product-item glass-card">
172208
<div class="product-thumbnail-wrapper">

assets/icons/favicon-16.png

604 KB
Loading

assets/icons/favicon-32.png

604 KB
Loading
604 KB
Loading

audit_report_utf8.txt

Lines changed: 99 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,18 @@ Viewport: OK
8484
Indexing: OK
8585
Broken Links: None
8686
--------------------------------
87+
PAGE: /smart-tools.html
88+
Title: OK (Length: 53)
89+
Meta Description: OK (Length: 122)
90+
Canonical: OK
91+
OpenGraph: OK
92+
Twitter Card: OK
93+
Schema: OK
94+
H1 Count: 1
95+
Viewport: OK
96+
Indexing: OK
97+
Broken Links: None
98+
--------------------------------
8799
PAGE: /terms-of-service.html
88100
Title: OK (Length: 35)
89101
Meta Description: OK (Length: 138)
@@ -120,6 +132,18 @@ Viewport: OK
120132
Indexing: OK
121133
Broken Links: None
122134
--------------------------------
135+
PAGE: /posts/alienware-aw3423dwf-vs-odyssey-g8.html
136+
Title: WARNING (Length: 86 > 70)
137+
Meta Description: OK (Length: 160)
138+
Canonical: OK
139+
OpenGraph: OK
140+
Twitter Card: OK
141+
Schema: OK
142+
H1 Count: 1
143+
Viewport: OK
144+
Indexing: OK
145+
Broken Links: None
146+
--------------------------------
123147
PAGE: /posts/apple-macbook-pro-m4-pro-review.html
124148
Title: OK (Length: 57)
125149
Meta Description: OK (Length: 142)
@@ -144,6 +168,30 @@ Viewport: OK
144168
Indexing: OK
145169
Broken Links: None
146170
--------------------------------
171+
PAGE: /posts/best-noise-cancelling-headphones-2026.html
172+
Title: OK (Length: 39)
173+
Meta Description: OK (Length: 151)
174+
Canonical: OK
175+
OpenGraph: OK
176+
Twitter Card: OK
177+
Schema: OK
178+
H1 Count: 1
179+
Viewport: OK
180+
Indexing: OK
181+
Broken Links: None
182+
--------------------------------
183+
PAGE: /posts/best-podcast-microphones-2026.html
184+
Title: OK (Length: 31)
185+
Meta Description: OK (Length: 134)
186+
Canonical: OK
187+
OpenGraph: OK
188+
Twitter Card: OK
189+
Schema: OK
190+
H1 Count: 1
191+
Viewport: OK
192+
Indexing: OK
193+
Broken Links: None
194+
--------------------------------
147195
PAGE: /posts/best-premium-laptop-for-work-2026.html
148196
Title: OK (Length: 55)
149197
Meta Description: OK (Length: 173)
@@ -168,6 +216,30 @@ Viewport: OK
168216
Indexing: OK
169217
Broken Links: None
170218
--------------------------------
219+
PAGE: /posts/best-ultrawide-monitors-2026.html
220+
Title: OK (Length: 30)
221+
Meta Description: OK (Length: 156)
222+
Canonical: OK
223+
OpenGraph: OK
224+
Twitter Card: OK
225+
Schema: OK
226+
H1 Count: 1
227+
Viewport: OK
228+
Indexing: OK
229+
Broken Links: None
230+
--------------------------------
231+
PAGE: /posts/bose-qc-ultra-review.html
232+
Title: OK (Length: 66)
233+
Meta Description: OK (Length: 185)
234+
Canonical: OK
235+
OpenGraph: OK
236+
Twitter Card: OK
237+
Schema: OK
238+
H1 Count: 1
239+
Viewport: OK
240+
Indexing: OK
241+
Broken Links: None
242+
--------------------------------
171243
PAGE: /posts/budget-laptops-under-1000.html
172244
Title: OK (Length: 57)
173245
Meta Description: OK (Length: 164)
@@ -298,7 +370,7 @@ Schema: OK
298370
H1 Count: 1
299371
Viewport: OK
300372
Indexing: OK
301-
Broken Links: best-headphones-for-classes.html
373+
Broken Links: None
302374
--------------------------------
303375
PAGE: /posts/shure-sm7b-vs-sm7db.html
304376
Title: OK (Length: 50)
@@ -324,6 +396,30 @@ Viewport: OK
324396
Indexing: OK
325397
Broken Links: None
326398
--------------------------------
399+
PAGE: /posts/sony-wh-1000xm5-review.html
400+
Title: OK (Length: 62)
401+
Meta Description: OK (Length: 165)
402+
Canonical: OK
403+
OpenGraph: OK
404+
Twitter Card: OK
405+
Schema: OK
406+
H1 Count: 1
407+
Viewport: OK
408+
Indexing: OK
409+
Broken Links: None
410+
--------------------------------
411+
PAGE: /posts/sony-xm5-vs-bose-qc-ultra.html
412+
Title: OK (Length: 49)
413+
Meta Description: OK (Length: 148)
414+
Canonical: OK
415+
OpenGraph: OK
416+
Twitter Card: OK
417+
Schema: OK
418+
H1 Count: 1
419+
Viewport: OK
420+
Indexing: OK
421+
Broken Links: None
422+
--------------------------------
327423
PAGE: /posts/surface-laptop-studio-2-review.html
328424
Title: OK (Length: 47)
329425
Meta Description: OK (Length: 150)
@@ -349,10 +445,10 @@ Image Alt Text: OK
349445

350446

351447
=== SITE RISK SUMMARY ===
352-
Total Pages Scanned: 28
448+
Total Pages Scanned: 36
353449
Pages With Critical Errors: 0
354450
Pages With Duplicate Meta: 0
355451
Pages With Duplicate Titles: 0
356452
Pages With Missing Schema: 0
357453
Pages With Missing Alt Text: 0
358-
Clean Pages: 28
454+
Clean Pages: 36

bump_favicon_cache.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import os
2+
import re
3+
4+
root = r'C:\Users\PMLS\Desktop\Youtube Shorts\b2b_blog\posts'
5+
6+
files = [
7+
'best-noise-cancelling-headphones-2026.html',
8+
'best-podcast-microphones-2026.html',
9+
'best-ultrawide-monitors-2026.html',
10+
]
11+
12+
for filename in files:
13+
fpath = os.path.join(root, filename)
14+
with open(fpath, 'r', encoding='utf-8') as f:
15+
content = f.read()
16+
17+
# Bump favicon version query strings: ?v=1 -> ?v=5
18+
updated = content.replace('favicon-32.png?v=1', 'favicon-32.png?v=5')
19+
updated = updated.replace('favicon-16.png?v=1', 'favicon-16.png?v=5')
20+
updated = updated.replace('favicon.ico?v=1', 'favicon.ico?v=5')
21+
updated = updated.replace('techstack-logo-192.png?v=1', 'techstack-logo-192.png?v=5')
22+
23+
if updated != content:
24+
with open(fpath, 'w', encoding='utf-8') as f:
25+
f.write(updated)
26+
print(f'Updated: {filename}')
27+
else:
28+
print(f'No change needed: {filename}')

emergency_repair.py

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
from bs4 import BeautifulSoup
2+
import re
3+
import os
4+
5+
target_files = [
6+
'posts/best-noise-cancelling-headphones-2026.html',
7+
'posts/best-podcast-microphones-2026.html',
8+
'posts/best-ultrawide-monitors-2026.html'
9+
]
10+
ref_file = 'posts/shure-sm7b-review.html'
11+
base_dir = r"C:\Users\PMLS\Desktop\Youtube Shorts\b2b_blog"
12+
13+
# Read reference file for header and favicon
14+
with open(os.path.join(base_dir, ref_file), 'r', encoding='utf-8') as f:
15+
ref_soup = BeautifulSoup(f, 'html.parser')
16+
17+
ref_header = ref_soup.find('header', class_='glass-header')
18+
ref_favicons = ref_soup.find_all('link', rel=lambda r: r and ('icon' in r or 'apple-touch-icon' in r))
19+
20+
affiliate_links_fixed = 0
21+
non_affiliate_buttons_removed = 0
22+
favicon_standardized_count = 0
23+
24+
for file_path in target_files:
25+
full_path = os.path.join(base_dir, file_path)
26+
with open(full_path, 'r', encoding='utf-8') as f:
27+
html = f.read()
28+
29+
soup = BeautifulSoup(html, 'html.parser')
30+
31+
# 1. Navigation Restoration
32+
# Replace existing header
33+
existing_header = soup.find('header', class_='glass-header')
34+
if existing_header and ref_header:
35+
existing_header.replace_with(ref_soup.new_tag("div")) # placeholder
36+
soup.find("div").replace_with(ref_header.copy())
37+
38+
# 2. Affiliate Link Integrity
39+
# Find all amazon links. Ensure tag, target, rel
40+
amazon_links = soup.find_all('a', href=re.compile(r'amazon\.com'))
41+
for link in amazon_links:
42+
href = link.get('href', '')
43+
changed = False
44+
45+
# tag
46+
if '?tag=techstackglob-20' not in href and '&tag=techstackglob-20' not in href:
47+
if '?' in href:
48+
link['href'] = href.replace('?', '?tag=techstackglob-20&', 1)
49+
else:
50+
link['href'] = href + '?tag=techstackglob-20'
51+
changed = True
52+
53+
# target
54+
if link.get('target') != '_blank':
55+
link['target'] = '_blank'
56+
changed = True
57+
58+
# rel
59+
current_rel = link.get('rel', [])
60+
if isinstance(current_rel, str):
61+
current_rel = current_rel.split()
62+
required_rels = ['nofollow', 'noopener', 'sponsored']
63+
if not all(r in current_rel for r in required_rels):
64+
# Combine current logic plus required
65+
final_rels = set(current_rel + required_rels)
66+
link['rel'] = " ".join(sorted(final_rels)) # output space separated string
67+
changed = True
68+
69+
if changed:
70+
affiliate_links_fixed += 1
71+
72+
# 3. Remove non-affiliate CTR buttons
73+
btn_links = soup.find_all('a', class_=re.compile(r'btn-(primary|secondary|tertiary)'))
74+
for btn in btn_links:
75+
href = btn.get('href', '')
76+
if 'amazon.com' not in href:
77+
btn.decompose()
78+
non_affiliate_buttons_removed += 1
79+
80+
# 4. Favicon Restore
81+
# Remove existing favicon links
82+
for old_fav in soup.find_all('link', rel=lambda r: r and ('icon' in r or 'apple-touch-icon' in r)):
83+
old_fav.decompose()
84+
85+
# Insert standard favicons in head
86+
head = soup.find('head')
87+
if head and list(ref_favicons):
88+
for fav in reversed(ref_favicons): # reversed since inserting at beginning usually pushes down, but insert after meta
89+
if head.find_all('meta'):
90+
head.find_all('meta')[-1].insert_after(fav.copy())
91+
else:
92+
head.insert(0, fav.copy())
93+
favicon_standardized_count += 1
94+
95+
# Bump v1 to v5
96+
for link in soup.find_all('link', rel=lambda r: r and ('icon' in r or 'apple-touch-icon' in r)):
97+
if '?v=1' in link['href']:
98+
link['href'] = link['href'].replace('?v=1', '?v=5')
99+
100+
# 5. Mobile toggle fix
101+
# Ensure script is loaded exactly before </body>
102+
if not soup.find('script', src='../script.js'):
103+
script_tag = soup.new_tag('script', src='../script.js')
104+
if soup.body:
105+
soup.body.append(script_tag)
106+
107+
# Write out
108+
with open(full_path, 'w', encoding='utf-8') as f:
109+
# Use str(soup) to keep formatting reasonably close (though it might reformat slightly)
110+
# Using a safer approach with regex on original text if we just wanted exact text replace, but bs4 is robust for DOM manipulation.
111+
f.write(soup.prettify(formatter="html"))
112+
113+
print(f"Affiliate Links Fixed: {affiliate_links_fixed}")
114+
print(f"Non-Affiliate Buttons Removed: {non_affiliate_buttons_removed}")
115+
print(f"Favicon Standardized Pages: {favicon_standardized_count}")
116+

0 commit comments

Comments
 (0)