Overview
The Blog Marketing Platform provides a dual-layer content organization system using Categories for broad classification and Keywords (tags) for granular tagging. This structure improves content discoverability, SEO, and user navigation.
Categories vs Keywords
Categories Broad classification
Technology, Marketing, Design, etc.
Hierarchical structure (parent-child)
Limited per post (typically 1-3)
Featured in navigation
Keywords (Tags) Specific topics
SEO, React, Content Strategy, etc.
Flat structure (no hierarchy)
Multiple per post (unlimited)
Used for search and filtering
Categories
Category Structure
Categories include rich metadata and hierarchy support:
interface Category {
id : number ;
name : string ;
slug : string ; // URL-friendly identifier
description : string ;
color : string ; // Hex color for UI display
icon : string ; // Icon identifier
postsCount : number ; // Number of posts in category
isActive : boolean ; // Visibility status
createdAt : string ;
updatedAt : string ;
createdBy : number | null ;
parentId ?: number | null ; // Parent category for hierarchy
displayOrder ?: number ; // Sort order
}
Creating Categories
Only users with crear_categoria permission can create categories:
import { createCategory } from '@/services/categoriesService' ;
const newCategory = await createCategory ({
name: 'Content Marketing' ,
description: 'Strategies and tips for effective content marketing' ,
color: '#3B82F6' ,
icon: 'FileText' ,
isActive: true
});
console . log ( `Category created with slug: ${ newCategory . slug } ` );
The system automatically generates URL-friendly slugs from category names. For example, “Content Marketing” becomes “content-marketing”.
Managing Categories
Get All Categories
import { getAllCategories } from '@/services/categoriesService' ;
const categories = await getAllCategories ();
categories . forEach ( cat => {
console . log ( ` ${ cat . name } : ${ cat . postsCount } posts` );
});
Get Active Categories Only
import { getActiveCategories } from '@/services/categoriesService' ;
const activeCategories = getActiveCategories ();
Update Category
import { updateCategory } from '@/services/categoriesService' ;
const updated = await updateCategory ( categoryId , {
name: 'Digital Marketing' ,
description: 'Updated description' ,
color: '#10B981'
});
Toggle Category Status
Enable or disable a category:
import { toggleCategoryStatus } from '@/services/categoriesService' ;
const toggled = await toggleCategoryStatus ( categoryId );
if ( toggled ) {
console . log ( 'Category status changed' );
}
Delete Category
import { deleteCategory } from '@/services/categoriesService' ;
const deleted = await deleteCategory ( categoryId );
if ( ! deleted ) {
console . error ( 'Cannot delete category with existing posts' );
}
Categories containing posts cannot be deleted. Reassign or delete posts first, or disable the category instead using toggleCategoryStatus().
Hierarchical Categories
Create parent-child category relationships:
// Create parent category
const parent = await createCategory ({
name: 'Technology' ,
description: 'Tech-related content' ,
color: '#3B82F6'
});
// Create child categories
const webDev = await createCategory ({
name: 'Web Development' ,
description: 'Web development tutorials' ,
color: '#3B82F6' ,
parentId: parent . id
});
const mobileDev = await createCategory ({
name: 'Mobile Development' ,
description: 'Mobile app development' ,
color: '#3B82F6' ,
parentId: parent . id
});
Hierarchical Structure Query
Retrieve categories in hierarchical format:
import { getCategoriesJerarquicas } from '@/services/categoriesService' ;
const hierarchical = await getCategoriesJerarquicas ();
// Returns:
// [
// {
// id: 1,
// name: 'Technology',
// children: [
// { id: 2, name: 'Web Development', parentId: 1 },
// { id: 3, name: 'Mobile Development', parentId: 1 }
// ]
// },
// ...
// ]
Assigning Categories to Posts
Posts can have multiple categories:
import { addCategoriasToPost } from '@/services/postsService' ;
import { createPost } from '@/services/postsService' ;
// Method 1: During post creation
const post = await createPost ({
title: 'Getting Started with React' ,
content: '...' ,
categoryId: 2 , // Primary category (legacy)
// or use new multi-category field:
// categories: [2, 5, 8]
});
// Method 2: Add categories to existing post
await addCategoriasToPost ( post . id , [ 2 , 5 , 8 ]);
Keyword Structure
Keywords are simple, flexible tags:
interface Keyword {
id : number ;
keyword : string ; // The tag text
slug : string ; // URL-friendly version
}
// Posts include keywords:
interface Post {
keywords ?: Array <{
id : number ;
keyword : string ;
slug : string ;
}>;
tags ?: string []; // Alternative format (just strings)
}
Adding Keywords to Posts
Add Existing Keywords
import { addKeywordsToPost } from '@/services/postsService' ;
// Add keywords by ID
await addKeywordsToPost ( postId , [ 10 , 15 , 20 , 25 ]);
Create and Add New Keywords
import { createAndAddKeywords } from '@/services/postsService' ;
// Create new keywords and add to post
await createAndAddKeywords ( postId , [
'react' ,
'javascript' ,
'web development' ,
'frontend' ,
'tutorial'
]);
During Post Creation
import { createPost } from '@/services/postsService' ;
const post = await createPost ({
title: 'Modern JavaScript Features' ,
content: '...' ,
tags: [ 'javascript' , 'es6' , 'programming' , 'tutorial' ]
});
// Tags are automatically converted to keywords
Managing Keywords
Get Post Keywords
import { getPostKeywords } from '@/services/postsService' ;
const keywords = await getPostKeywords ( postId );
keywords . forEach ( kw => {
console . log ( ` ${ kw . keyword } (ID: ${ kw . id } )` );
});
Find or Create Keyword
Search for existing keyword or create new:
import { findOrCreateKeyword } from '@/services/postsService' ;
const keyword = await findOrCreateKeyword ( 'content-strategy' );
if ( keyword ) {
await addKeywordsToPost ( postId , [ keyword . id ]);
}
Remove Keywords
import { removeKeywordsFromPost } from '@/services/postsService' ;
// Remove specific keywords
await removeKeywordsFromPost ( postId , [ 10 , 15 ]);
// Remove all keywords
await removeKeywordsFromPost ( postId );
Most Used Keywords
Find popular keywords across all posts:
import { getKeywordsMasUsadas } from '@/services/postsService' ;
const topKeywords = await getKeywordsMasUsadas ( 50 );
topKeywords . forEach ( kw => {
console . log ( ` ${ kw . keyword } : ${ kw . count } posts` );
});
Category Analytics
General Statistics
import { getCategoriesStats } from '@/services/categoriesService' ;
const stats = await getCategoriesStats ();
// Returns:
// {
// total: 20,
// active: 18,
// inactive: 2,
// totalPosts: 500
// }
console . log ( `Average posts per category: ${ stats . totalPosts / stats . total } ` );
Category Engagement
Track how categories perform:
import { getCategoriesEngagement } from '@/services/categoriesService' ;
const engagement = await getCategoriesEngagement ();
// Returns:
// [
// {
// category: 'Technology',
// views: 15000,
// engagement: 8.5,
// avgTimeOnPage: 245
// },
// ...
// ]
// Find best performing category
const best = engagement . reduce (( max , cat ) =>
cat . engagement > max . engagement ? cat : max
);
import { getCategoriesMejorRendimiento } from '@/services/categoriesService' ;
const topCategories = await getCategoriesMejorRendimiento ();
topCategories . forEach (( cat , index ) => {
console . log ( `# ${ index + 1 } : ${ cat . name } - ${ cat . postsCount } posts` );
});
SEO Benefits
Category SEO
Category Pages : Each category has a dedicated page (/category/slug)
Meta Tags : Category descriptions used in meta tags
Breadcrumbs : Categories appear in breadcrumb navigation
Sitemaps : Categories included in XML sitemaps
Keyword SEO
Tag Pages : Each keyword has a page listing related posts
Internal Linking : Keywords create natural internal links
Related Content : Keywords help suggest related posts
Search : Keywords improve on-site search results
// SEO-friendly category URLs
const categoryUrl = `/category/ ${ category . slug } ` ;
// Example: /category/content-marketing
// SEO-friendly keyword URLs
const keywordUrl = `/tag/ ${ keyword . slug } ` ;
// Example: /tag/react
Content Organization Strategy
Category Strategy Best Practices:
Keep categories broad (5-15 total)
Use 2-level hierarchy maximum
Ensure even distribution
Review quarterly
Keyword Strategy Best Practices:
Use 5-10 keywords per post
Mix broad and specific terms
Be consistent with naming
Update as content evolves
Filtering Content
Filter by Category
// Get all posts in a category
const categoryPosts = allPosts . filter ( post =>
post . categoryId === categoryId
);
// Or with multiple categories
const multiCategoryPosts = allPosts . filter ( post =>
post . categories ?. some ( cat => [ 1 , 2 , 3 ]. includes ( cat . id ))
);
Filter by Keywords
// Get posts with specific keyword
const keywordPosts = allPosts . filter ( post =>
post . keywords ?. some ( kw => kw . keyword === 'react' )
);
// Multiple keywords (OR logic)
const multiKeywordPosts = allPosts . filter ( post =>
post . keywords ?. some ( kw =>
[ 'react' , 'javascript' , 'frontend' ]. includes ( kw . keyword )
)
);
Category Colors and Icons
Categories support visual customization:
const categoryThemes = {
'Technology' : { color: '#3B82F6' , icon: 'Laptop' },
'Marketing' : { color: '#10B981' , icon: 'TrendingUp' },
'Design' : { color: '#8B5CF6' , icon: 'Palette' },
'Business' : { color: '#F59E0B' , icon: 'Briefcase' },
'Tutorial' : { color: '#06B6D4' , icon: 'BookOpen' }
};
await createCategory ({
name: 'Technology' ,
color: '#3B82F6' ,
icon: 'Laptop' ,
// ...
});
Best Practices
Plan Your Taxonomy
Design category structure before creating content. Consider user needs and content types.
Use Consistent Naming
Establish naming conventions for both categories and keywords. “Web Development” not “web dev” or “WebDev”.
Monitor Usage
Track which categories and keywords perform best. Remove unused tags.
Balance Distribution
Avoid having all posts in one category. Aim for even distribution across categories.
Update Regularly
Review and refine your taxonomy quarterly. Add new categories as content evolves.
Common Patterns
Related Posts by Category
function getRelatedPosts ( currentPost : Post , limit : number = 5 ) {
return allPosts
. filter ( post =>
post . id !== currentPost . id &&
post . categoryId === currentPost . categoryId
)
. sort (( a , b ) => b . views - a . views )
. slice ( 0 , limit );
}
Related Posts by Keywords
function getRelatedPostsByKeywords ( currentPost : Post , limit : number = 5 ) {
const currentKeywords = currentPost . keywords ?. map ( kw => kw . keyword ) || [];
return allPosts
. filter ( post => post . id !== currentPost . id )
. map ( post => {
const matchingKeywords = post . keywords ?. filter ( kw =>
currentKeywords . includes ( kw . keyword )
). length || 0 ;
return { post , score: matchingKeywords };
})
. filter ( item => item . score > 0 )
. sort (( a , b ) => b . score - a . score )
. slice ( 0 , limit )
. map ( item => item . post );
}
import { getAllCategories } from '@/services/categoriesService' ;
async function buildCategoryMenu () {
const categories = await getAllCategories ();
return categories
. filter ( cat => cat . isActive && cat . postsCount > 0 )
. sort (( a , b ) => ( a . displayOrder || 0 ) - ( b . displayOrder || 0 ))
. map ( cat => ({
label: cat . name ,
href: `/category/ ${ cat . slug } ` ,
count: cat . postsCount ,
color: cat . color ,
icon: cat . icon
}));
}