433
This commit is contained in:
38
backend/cleanup_structure_categories.py
Normal file
38
backend/cleanup_structure_categories.py
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
"""
|
||||||
|
Clean up structure-based categories that were incorrectly created
|
||||||
|
This will remove categories like "Guide", "Article", etc. that match content_structure values
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import django
|
||||||
|
|
||||||
|
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
||||||
|
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'igny8_core.settings')
|
||||||
|
django.setup()
|
||||||
|
|
||||||
|
from django.db import transaction
|
||||||
|
from igny8_core.business.content.models import ContentTaxonomy
|
||||||
|
|
||||||
|
# List of structure values that were incorrectly added as categories
|
||||||
|
STRUCTURE_VALUES = ['Guide', 'Article', 'Listicle', 'How To', 'Tutorial', 'Review', 'Comparison']
|
||||||
|
|
||||||
|
print("=" * 80)
|
||||||
|
print("CLEANING UP STRUCTURE-BASED CATEGORIES")
|
||||||
|
print("=" * 80)
|
||||||
|
|
||||||
|
for structure_name in STRUCTURE_VALUES:
|
||||||
|
categories = ContentTaxonomy.objects.filter(
|
||||||
|
taxonomy_type='category',
|
||||||
|
name=structure_name
|
||||||
|
)
|
||||||
|
|
||||||
|
if categories.exists():
|
||||||
|
count = categories.count()
|
||||||
|
print(f"\nRemoving {count} '{structure_name}' categor{'y' if count == 1 else 'ies'}...")
|
||||||
|
categories.delete()
|
||||||
|
print(f" ✓ Deleted {count} '{structure_name}' categor{'y' if count == 1 else 'ies'}")
|
||||||
|
|
||||||
|
print("\n" + "=" * 80)
|
||||||
|
print("CLEANUP COMPLETE")
|
||||||
|
print("=" * 80)
|
||||||
@@ -42,15 +42,10 @@ for content in content_without_tags:
|
|||||||
if content.secondary_keywords and isinstance(content.secondary_keywords, list):
|
if content.secondary_keywords and isinstance(content.secondary_keywords, list):
|
||||||
tags_to_add.extend(content.secondary_keywords[:3]) # Limit to 3
|
tags_to_add.extend(content.secondary_keywords[:3]) # Limit to 3
|
||||||
|
|
||||||
# Create category based on content_type and cluster
|
# Create category based on cluster only
|
||||||
if content.cluster:
|
if content.cluster:
|
||||||
categories_to_add.append(content.cluster.name)
|
categories_to_add.append(content.cluster.name)
|
||||||
|
|
||||||
# Add content_structure as category
|
|
||||||
if content.content_structure:
|
|
||||||
structure_name = content.content_structure.replace('_', ' ').title()
|
|
||||||
categories_to_add.append(structure_name)
|
|
||||||
|
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
# Process tags
|
# Process tags
|
||||||
for tag_name in tags_to_add:
|
for tag_name in tags_to_add:
|
||||||
|
|||||||
@@ -111,27 +111,7 @@ export function createPublishedPageConfig(params: {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
key: 'wordpress_status',
|
|
||||||
label: 'WordPress',
|
|
||||||
sortable: false,
|
|
||||||
width: '140px',
|
|
||||||
render: (_value: any, row: Content) => {
|
|
||||||
if (row.external_id && row.external_url) {
|
|
||||||
return (
|
|
||||||
<Badge color="success" size="xs" variant="soft">
|
|
||||||
<CheckCircleIcon className="w-3 h-3 mr-1" />
|
|
||||||
<span className="text-[11px] font-normal">Published</span>
|
|
||||||
</Badge>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<Badge color="amber" size="xs" variant="soft">
|
|
||||||
<span className="text-[11px] font-normal">Not Published</span>
|
|
||||||
</Badge>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
key: 'content_type',
|
key: 'content_type',
|
||||||
label: 'Type',
|
label: 'Type',
|
||||||
@@ -166,6 +146,71 @@ export function createPublishedPageConfig(params: {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: 'cluster_name',
|
||||||
|
label: 'Cluster',
|
||||||
|
sortable: false,
|
||||||
|
width: '130px',
|
||||||
|
render: (_value: any, row: Content) => {
|
||||||
|
const clusterName = row.cluster_name;
|
||||||
|
if (!clusterName) {
|
||||||
|
return <span className="text-gray-400 dark:text-gray-500 text-[11px]">-</span>;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<Badge color="indigo" size="xs" variant="soft">
|
||||||
|
<span className="text-[11px] font-normal">{clusterName}</span>
|
||||||
|
</Badge>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'tags',
|
||||||
|
label: 'Tags',
|
||||||
|
sortable: false,
|
||||||
|
width: '150px',
|
||||||
|
render: (_value: any, row: Content) => {
|
||||||
|
const tags = row.tags || [];
|
||||||
|
if (!tags || tags.length === 0) {
|
||||||
|
return <span className="text-gray-400 dark:text-gray-500 text-[11px]">-</span>;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<div className="flex flex-wrap gap-1">
|
||||||
|
{tags.slice(0, 2).map((tag, index) => (
|
||||||
|
<Badge key={`${tag}-${index}`} color="pink" size="xs" variant="soft">
|
||||||
|
<span className="text-[11px] font-normal">{tag}</span>
|
||||||
|
</Badge>
|
||||||
|
))}
|
||||||
|
{tags.length > 2 && (
|
||||||
|
<span className="text-[11px] text-gray-500">+{tags.length - 2}</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'categories',
|
||||||
|
label: 'Categories',
|
||||||
|
sortable: false,
|
||||||
|
width: '150px',
|
||||||
|
render: (_value: any, row: Content) => {
|
||||||
|
const categories = row.categories || [];
|
||||||
|
if (!categories || categories.length === 0) {
|
||||||
|
return <span className="text-gray-400 dark:text-gray-500 text-[11px]">-</span>;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<div className="flex flex-wrap gap-1">
|
||||||
|
{categories.slice(0, 2).map((category, index) => (
|
||||||
|
<Badge key={`${category}-${index}`} color="blue" size="xs" variant="soft">
|
||||||
|
<span className="text-[11px] font-normal">{category}</span>
|
||||||
|
</Badge>
|
||||||
|
))}
|
||||||
|
{categories.length > 2 && (
|
||||||
|
<span className="text-[11px] text-gray-500">+{categories.length - 2}</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
key: 'word_count',
|
key: 'word_count',
|
||||||
label: 'Words',
|
label: 'Words',
|
||||||
|
|||||||
@@ -85,18 +85,23 @@ export function createReviewPageConfig(params: {
|
|||||||
sortable: false,
|
sortable: false,
|
||||||
width: '180px',
|
width: '180px',
|
||||||
render: (_value: any, row: Content) => {
|
render: (_value: any, row: Content) => {
|
||||||
const categories = row.taxonomy_terms_data?.filter((t: any) => t.taxonomy_type === 'category') || [];
|
const categories = row.categories || [];
|
||||||
if (!categories.length) return <span className="text-gray-400 dark:text-gray-500">-</span>;
|
if (!categories || categories.length === 0) {
|
||||||
|
return <span className="text-gray-400 dark:text-gray-500 text-[11px]">-</span>;
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-wrap gap-1">
|
<div className="flex flex-wrap gap-1">
|
||||||
{categories.map((cat: any) => (
|
{categories.slice(0, 2).map((category, index) => (
|
||||||
<span key={cat.id} className="px-2 py-0.5 bg-purple-50 dark:bg-purple-900/20 text-purple-700 dark:text-purple-300 rounded-full text-xs font-medium">{cat.name}</span>
|
<Badge key={`${category}-${index}`} color="blue" size="xs" variant="soft">
|
||||||
|
<span className="text-[11px] font-normal">{category}</span>
|
||||||
|
</Badge>
|
||||||
))}
|
))}
|
||||||
|
{categories.length > 2 && (
|
||||||
|
<span className="text-[11px] text-gray-500">+{categories.length - 2}</span>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
toggleable: true,
|
|
||||||
defaultVisible: true,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'tags',
|
key: 'tags',
|
||||||
@@ -104,18 +109,23 @@ export function createReviewPageConfig(params: {
|
|||||||
sortable: false,
|
sortable: false,
|
||||||
width: '180px',
|
width: '180px',
|
||||||
render: (_value: any, row: Content) => {
|
render: (_value: any, row: Content) => {
|
||||||
const tags = row.taxonomy_terms_data?.filter((t: any) => t.taxonomy_type === 'tag') || [];
|
const tags = row.tags || [];
|
||||||
if (!tags.length) return <span className="text-gray-400 dark:text-gray-500">-</span>;
|
if (!tags || tags.length === 0) {
|
||||||
|
return <span className="text-gray-400 dark:text-gray-500 text-[11px]">-</span>;
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-wrap gap-1">
|
<div className="flex flex-wrap gap-1">
|
||||||
{tags.map((tag: any) => (
|
{tags.slice(0, 2).map((tag, index) => (
|
||||||
<span key={tag.id} className="px-2 py-0.5 bg-brand-50 dark:bg-brand-900/20 text-brand-700 dark:text-brand-300 rounded-full text-xs font-medium">{tag.name}</span>
|
<Badge key={`${tag}-${index}`} color="pink" size="xs" variant="soft">
|
||||||
|
<span className="text-[11px] font-normal">{tag}</span>
|
||||||
|
</Badge>
|
||||||
))}
|
))}
|
||||||
|
{tags.length > 2 && (
|
||||||
|
<span className="text-[11px] text-gray-500">+{tags.length - 2}</span>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
toggleable: true,
|
|
||||||
defaultVisible: true,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'content_type',
|
key: 'content_type',
|
||||||
|
|||||||
Reference in New Issue
Block a user