@ai-growth/n8n-nodes-wordpress
Version:
n8n node for WordPress integration with AI GROWTH - SEO WP plugin
541 lines • 26 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.PostCreateService = void 0;
const ErrorUtils_1 = require("../utils/ErrorUtils");
const SeoService_1 = require("./SeoService");
const FaqService_1 = require("./FaqService");
const CtaService_1 = require("./CtaService");
const MetadataService_1 = require("./MetadataService");
const FeaturedImageService_1 = require("./FeaturedImageService");
const TaxonomyService_1 = require("./TaxonomyService");
/**
* Serviço para criação e atualização de posts e páginas no WordPress
*/
class PostCreateService {
/**
* Construtor do serviço
* @param client Cliente WordPress
*/
constructor(client) {
this.client = client;
this.seoService = new SeoService_1.SeoService(client);
this.faqService = new FaqService_1.FaqService(client, this.seoService);
this.ctaService = new CtaService_1.CtaService(client, this.seoService);
this.metadataService = new MetadataService_1.MetadataService(client);
this.featuredImageService = new FeaturedImageService_1.FeaturedImageService(client);
this.taxonomyService = new TaxonomyService_1.TaxonomyService(client);
}
/**
* Cria um novo post no WordPress
* @param post Dados do post a ser criado
* @param options Opções da operação
* @returns Post criado
*/
async createPost(post, options = {}) {
try {
// Separar metadados do post principal
const { meta_title, meta_description, meta_keywords, og_title, og_description, twitter_title, twitter_description, faq, cta, ...postData } = post;
// Converter para o formato esperado pela API WordPress
const postPayload = this.formatPostForApi(postData, 'post');
// Criar post no WordPress
const response = await this.client.post('posts', postPayload);
if (!response || !response.id) {
throw new ErrorUtils_1.WordPressError('Failed to create WordPress post: Invalid response', ErrorUtils_1.WordPressErrorType.SERVER);
}
// ID do post criado
const postId = response.id;
// Processar taxonomias (categorias e tags) se necessário
if (post.categories || post.tags) {
await this.taxonomyService.associateTaxonomiesWithPost(postId, post.categories || [], post.tags || []);
}
// Verificar se deve processar imagem destacada automaticamente
const shouldProcessFeaturedImage = options.updateFeaturedImage ||
!!post.featured_image_url ||
!!post.featured_image_id ||
post.featured_media !== undefined;
// Configurar opções para processamento de metadados
const metadataOptions = {
...options,
updateFeaturedImage: shouldProcessFeaturedImage
};
// Processar metadados SEO se necessário
await this.processMetadata(postId, post, metadataOptions);
// Obter post completo com metadados
return this.getCompletePost(postId, 'post', options);
}
catch (error) {
if (error instanceof ErrorUtils_1.WordPressError) {
throw error;
}
throw new ErrorUtils_1.WordPressError(`Failed to create WordPress post: ${error.message}`, ErrorUtils_1.WordPressErrorType.SERVER, undefined, error);
}
}
/**
* Cria uma nova página no WordPress
* @param page Dados da página a ser criada
* @param options Opções da operação
* @returns Página criada
*/
async createPage(page, options = {}) {
try {
// Separar metadados da página principal
const { meta_title, meta_description, meta_keywords, og_title, og_description, twitter_title, twitter_description, faq, cta, ...pageData } = page;
// Converter para o formato esperado pela API WordPress
const pagePayload = this.formatPostForApi(pageData, 'page');
// Criar página no WordPress
const response = await this.client.post('pages', pagePayload);
if (!response || !response.id) {
throw new ErrorUtils_1.WordPressError('Failed to create WordPress page: Invalid response', ErrorUtils_1.WordPressErrorType.SERVER);
}
// ID da página criada
const pageId = response.id;
// Verificar se deve processar imagem destacada automaticamente
const shouldProcessFeaturedImage = options.updateFeaturedImage ||
!!page.featured_image_url ||
!!page.featured_image_id ||
page.featured_media !== undefined;
// Configurar opções para processamento de metadados
const metadataOptions = {
...options,
updateFeaturedImage: shouldProcessFeaturedImage
};
// Processar metadados SEO se necessário
await this.processMetadata(pageId, page, metadataOptions);
// Obter página completa com metadados
return this.getCompletePost(pageId, 'page', options);
}
catch (error) {
if (error instanceof ErrorUtils_1.WordPressError) {
throw error;
}
throw new ErrorUtils_1.WordPressError(`Failed to create WordPress page: ${error.message}`, ErrorUtils_1.WordPressErrorType.SERVER, undefined, error);
}
}
/**
* Atualiza um post existente no WordPress
* @param postId ID do post a ser atualizado
* @param post Dados do post
* @param options Opções da operação
* @returns Post atualizado
*/
async updatePost(postId, post, options = {}) {
try {
// Verificar se o post existe
await this.validateResourceExists(postId, 'post');
// Separar metadados do post principal
const { meta_title, meta_description, meta_keywords, og_title, og_description, twitter_title, twitter_description, faq, cta, ...postData } = post;
// Construir payload de atualização apenas com campos especificados
const postPayload = {};
// Adicionar campos apenas se definidos
if (postData.title !== undefined) {
postPayload.title = postData.title;
}
if (postData.content !== undefined) {
postPayload.content = postData.content;
}
if (postData.status !== undefined) {
postPayload.status = postData.status;
}
if (postData.excerpt !== undefined) {
postPayload.excerpt = postData.excerpt;
}
if (postData.slug !== undefined) {
postPayload.slug = postData.slug;
}
if (postData.featured_media !== undefined) {
postPayload.featured_media = postData.featured_media;
}
if (postData.categories !== undefined) {
postPayload.categories = postData.categories;
}
if (postData.tags !== undefined) {
postPayload.tags = postData.tags;
}
// Se não há campos para atualizar, verificar se há metadados para atualizar
if (Object.keys(postPayload).length === 0 &&
!meta_title && !meta_description && !meta_keywords && !og_title && !og_description && !twitter_title && !twitter_description && !faq && !cta) {
throw new ErrorUtils_1.WordPressError('No fields specified for update', ErrorUtils_1.WordPressErrorType.VALIDATION);
}
// Atualizar post no WordPress (apenas se houver campos para atualizar)
let response = null;
if (Object.keys(postPayload).length > 0) {
response = await this.client.put(`posts/${postId}`, postPayload);
if (!response || !response.id) {
throw new ErrorUtils_1.WordPressError(`Failed to update WordPress post with ID ${postId}: Invalid response`, ErrorUtils_1.WordPressErrorType.SERVER);
}
}
// Processar metadados SEO se necessário
await this.processMetadata(postId, {
...post,
type: 'post'
}, options);
// Obter post completo com metadados
return this.getCompletePost(postId, 'post', options);
}
catch (error) {
if (error instanceof ErrorUtils_1.WordPressError) {
throw error;
}
throw new ErrorUtils_1.WordPressError(`Failed to update WordPress post with ID ${postId}: ${error.message}`, ErrorUtils_1.WordPressErrorType.SERVER, undefined, error);
}
}
/**
* Atualiza uma página existente no WordPress
* @param pageId ID da página a ser atualizada
* @param page Dados da página
* @param options Opções da operação
* @returns Página atualizada
*/
async updatePage(pageId, page, options = {}) {
try {
// Verificar se a página existe
await this.validateResourceExists(pageId, 'page');
// Separar metadados da página principal
const { meta_title, meta_description, meta_keywords, og_title, og_description, twitter_title, twitter_description, faq, cta, ...pageData } = page;
// Construir payload de atualização apenas com campos especificados
const pagePayload = {};
// Adicionar campos apenas se definidos
if (pageData.title !== undefined) {
pagePayload.title = pageData.title;
}
if (pageData.content !== undefined) {
pagePayload.content = pageData.content;
}
if (pageData.status !== undefined) {
pagePayload.status = pageData.status;
}
if (pageData.excerpt !== undefined) {
pagePayload.excerpt = pageData.excerpt;
}
if (pageData.slug !== undefined) {
pagePayload.slug = pageData.slug;
}
if (pageData.featured_media !== undefined) {
pagePayload.featured_media = pageData.featured_media;
}
// Se não há campos para atualizar, verificar se há metadados para atualizar
if (Object.keys(pagePayload).length === 0 &&
!meta_title && !meta_description && !meta_keywords && !og_title && !og_description && !twitter_title && !twitter_description && !faq && !cta) {
throw new ErrorUtils_1.WordPressError('No fields specified for update', ErrorUtils_1.WordPressErrorType.VALIDATION);
}
// Atualizar página no WordPress (apenas se houver campos para atualizar)
let response = null;
if (Object.keys(pagePayload).length > 0) {
response = await this.client.put(`pages/${pageId}`, pagePayload);
if (!response || !response.id) {
throw new ErrorUtils_1.WordPressError(`Failed to update WordPress page with ID ${pageId}: Invalid response`, ErrorUtils_1.WordPressErrorType.SERVER);
}
}
// Processar metadados SEO se necessário
await this.processMetadata(pageId, {
...page,
type: 'page'
}, options);
// Obter página completa com metadados
return this.getCompletePost(pageId, 'page', options);
}
catch (error) {
if (error instanceof ErrorUtils_1.WordPressError) {
throw error;
}
throw new ErrorUtils_1.WordPressError(`Failed to update WordPress page with ID ${pageId}: ${error.message}`, ErrorUtils_1.WordPressErrorType.SERVER, undefined, error);
}
}
/**
* Exclui um post do WordPress
* @param postId ID do post a ser excluído
* @param force Forçar exclusão permanente (true) ou mover para lixeira (false)
* @returns true se excluído com sucesso
*/
async deletePost(postId, force = false) {
try {
// Parâmetros da requisição
const params = {};
// Adicionar parâmetro force se solicitado
if (force) {
params.force = 'true';
}
// Excluir post
await this.client.get(`posts/${postId}`, params);
await this.client.delete(`posts/${postId}`);
return true;
}
catch (error) {
if (error instanceof ErrorUtils_1.WordPressError) {
throw error;
}
throw new ErrorUtils_1.WordPressError(`Failed to delete WordPress post with ID ${postId}: ${error.message}`, ErrorUtils_1.WordPressErrorType.SERVER, undefined, error);
}
}
/**
* Exclui uma página do WordPress
* @param pageId ID da página a ser excluída
* @param force Forçar exclusão permanente (true) ou mover para lixeira (false)
* @returns true se excluída com sucesso
*/
async deletePage(pageId, force = false) {
try {
// Parâmetros da requisição
const params = {};
// Adicionar parâmetro force se solicitado
if (force) {
params.force = 'true';
}
// Excluir página
await this.client.get(`pages/${pageId}`, params);
await this.client.delete(`pages/${pageId}`);
return true;
}
catch (error) {
if (error instanceof ErrorUtils_1.WordPressError) {
throw error;
}
throw new ErrorUtils_1.WordPressError(`Failed to delete WordPress page with ID ${pageId}: ${error.message}`, ErrorUtils_1.WordPressErrorType.SERVER, undefined, error);
}
}
/**
* Processa os metadados SEO, FAQ e CTA
* @param postId ID do post/página
* @param post Dados do post/página
* @param options Opções da operação
* @returns void
*/
async processMetadata(postId, post, options) {
try {
const { updateSeoMetadata = false, updateFaqs = false, updateCta = false, updateFeaturedImage = false } = options;
// Atualizar metadados SEO se solicitado
if (updateSeoMetadata) {
console.log('[PostCreateService] Processing SEO metadata:', {
postId,
updateSeoMetadata,
meta_title: post.meta_title,
meta_description: post.meta_description,
meta_keywords: post.meta_keywords,
og_title: post.og_title,
og_description: post.og_description,
twitter_title: post.twitter_title,
twitter_description: post.twitter_description,
hasMetaTitle: post.meta_title !== undefined,
hasMetaDescription: post.meta_description !== undefined,
hasMetaKeywords: post.meta_keywords !== undefined
});
// Verificar se há pelo menos um campo de metadados definido (incluindo strings vazias)
if (post.meta_title !== undefined || post.meta_description !== undefined || post.meta_keywords !== undefined ||
post.og_title !== undefined || post.og_description !== undefined ||
post.twitter_title !== undefined || post.twitter_description !== undefined) {
const seoMetadata = {};
if (post.meta_title !== undefined) {
seoMetadata.meta_title = post.meta_title;
console.log('[PostCreateService] Including meta_title:', post.meta_title);
}
if (post.meta_description !== undefined) {
seoMetadata.meta_description = post.meta_description;
console.log('[PostCreateService] Including meta_description:', post.meta_description);
}
if (post.meta_keywords !== undefined) {
seoMetadata.meta_keywords = post.meta_keywords;
console.log('[PostCreateService] Including meta_keywords:', post.meta_keywords);
}
if (post.og_title !== undefined) {
seoMetadata.og_title = post.og_title;
console.log('[PostCreateService] Including og_title:', post.og_title);
}
if (post.og_description !== undefined) {
seoMetadata.og_description = post.og_description;
console.log('[PostCreateService] Including og_description:', post.og_description);
}
if (post.twitter_title !== undefined) {
seoMetadata.twitter_title = post.twitter_title;
console.log('[PostCreateService] Including twitter_title:', post.twitter_title);
}
if (post.twitter_description !== undefined) {
seoMetadata.twitter_description = post.twitter_description;
console.log('[PostCreateService] Including twitter_description:', post.twitter_description);
}
console.log('[PostCreateService] Calling MetadataService.updateMetadata with:', seoMetadata);
await this.metadataService.updateMetadata(postId, seoMetadata);
}
else {
console.log('[PostCreateService] No SEO metadata fields provided to update');
}
}
else {
console.log('[PostCreateService] SEO metadata update not requested');
}
// Verificar disponibilidade do plugin apenas para FAQs e CTA
const pluginInfo = await this.seoService.checkPluginAvailability();
// Atualizar FAQs se solicitado e plugin disponível
if (updateFaqs && post.faq !== undefined && pluginInfo.status === 'active') {
await this.faqService.updatePostFaqs(postId, post.faq);
}
// Atualizar CTA se solicitado e plugin disponível
if (updateCta && post.cta !== undefined && pluginInfo.status === 'active') {
await this.ctaService.updatePostCta(postId, post.cta);
}
// Processar imagem destacada se solicitado
if (updateFeaturedImage) {
await this.processFeaturedImage(postId, post);
}
}
catch (error) {
throw new ErrorUtils_1.WordPressError(`Failed to process metadata for post/page with ID ${postId}: ${error.message}`, ErrorUtils_1.WordPressErrorType.SERVER, undefined, error);
}
}
/**
* Processa a imagem destacada de um post/página
* @param postId ID do post/página
* @param post Dados do post/página
* @returns void
*/
async processFeaturedImage(postId, post) {
try {
const contentType = post.type === 'page' ? 'page' : 'post';
if (post.featured_image_url) {
// Definir metadados da imagem
const metadata = {
alt_text: post.featured_image_alt,
title: post.featured_image_title,
caption: post.featured_image_caption,
description: post.featured_image_description
};
// Fazer upload e definir a imagem destacada a partir da URL
await this.featuredImageService.setFeaturedImageFromUrl(postId, contentType, post.featured_image_url, { metadata });
}
else if (post.featured_image_id) {
// Definir imagem destacada a partir do ID existente
await this.featuredImageService.setFeaturedImage(postId, contentType, post.featured_image_id);
}
else if (post.featured_media) {
// Definir imagem destacada a partir do ID de mídia
await this.featuredImageService.setFeaturedImage(postId, contentType, post.featured_media);
}
else if (post.featured_media === 0) {
// Remover imagem destacada
await this.featuredImageService.removeFeaturedImage(postId, contentType);
}
}
catch (error) {
// Logar erro mas não interromper a operação principal
console.error('Erro ao processar imagem destacada:', error);
}
}
/**
* Formata um post/página para o formato esperado pela API WordPress
* @param post Dados do post
* @param type Tipo de conteúdo (post ou page)
* @returns Payload formatado para a API
*/
formatPostForApi(post, type) {
// Converter para o formato esperado pela API WordPress
const payload = {
title: post.title,
content: post.content,
status: post.status || 'draft',
};
// Note: Categories and tags are handled separately via TaxonomyService
// to ensure proper format validation and ID conversion
return payload;
}
/**
* Obtém um post/página completo com metadados
* @param id ID do post/página
* @param type Tipo de conteúdo (post ou page)
* @param options Opções da operação
* @returns Post/página completo
*/
async getCompletePost(id, type, options) {
var _a, _b, _c;
const { updateSeoMetadata = false, updateFaqs = false, updateCta = false } = options;
// Obter post/página da API WordPress
const endpoint = type === 'post' ? `posts/${id}` : `pages/${id}`;
const response = await this.client.get(endpoint);
// Formatar a resposta
const formattedPost = {
id: response.id,
title: ((_a = response.title) === null || _a === void 0 ? void 0 : _a.rendered) || '',
content: ((_b = response.content) === null || _b === void 0 ? void 0 : _b.rendered) || '',
status: response.status || 'draft',
categories: type === 'post' ? response.categories || [] : [],
tags: type === 'post' ? response.tags || [] : [],
image_url: response.featured_media && typeof response.featured_media === 'number'
? '' // Não temos acesso direto à URL da imagem pelo ID
: ((_c = response.featured_media) === null || _c === void 0 ? void 0 : _c.source_url) || '',
};
// Verificar disponibilidade do plugin
const pluginInfo = await this.seoService.checkPluginAvailability();
// Se o plugin não está disponível, retorna o post sem metadados
if (pluginInfo.status !== 'active') {
return formattedPost;
}
// Adicionar metadados SEO se solicitado
if (updateSeoMetadata) {
try {
const seoMetadata = await this.seoService.getPostSeoMetadata(id);
if (seoMetadata) {
formattedPost.meta_title = seoMetadata.meta_title;
formattedPost.meta_description = seoMetadata.meta_description;
formattedPost.meta_keywords = seoMetadata.meta_keywords;
}
}
catch (error) {
// Ignorar erros ao buscar metadados SEO
}
}
// Adicionar FAQs se solicitado
if (updateFaqs) {
try {
const faqs = await this.faqService.getPostFaqs(id);
if (faqs && faqs.length > 0) {
formattedPost.faq = faqs;
}
}
catch (error) {
// Ignorar erros ao buscar FAQs
}
}
// Adicionar CTA se solicitado
if (updateCta) {
try {
const cta = await this.ctaService.getPostCta(id);
if (cta) {
formattedPost.cta = cta;
}
}
catch (error) {
// Ignorar erros ao buscar CTA
}
}
return formattedPost;
}
/**
* Verifica se um post/página existe no WordPress
* @param id ID do post/página
* @param type Tipo de conteúdo (post ou page)
* @returns O post/página se existir
* @throws WordPressError se não existir
*/
async validateResourceExists(id, type) {
try {
const endpoint = type === 'post' ? `posts/${id}` : `pages/${id}`;
const response = await this.client.get(endpoint);
if (!response || !response.id) {
throw new ErrorUtils_1.WordPressError(`${type === 'post' ? 'Post' : 'Page'} with ID ${id} not found`, ErrorUtils_1.WordPressErrorType.NOT_FOUND);
}
return response;
}
catch (error) {
// Se já é um WordPressError do tipo NOT_FOUND, apenas relançar
if (error instanceof ErrorUtils_1.WordPressError && error.type === ErrorUtils_1.WordPressErrorType.NOT_FOUND) {
throw error;
}
// Se é um erro de outra natureza
if (error instanceof ErrorUtils_1.WordPressError) {
throw error;
}
// Erro genérico
throw new ErrorUtils_1.WordPressError(`Error validating ${type} with ID ${id}: ${error.message}`, ErrorUtils_1.WordPressErrorType.UNKNOWN, undefined, error);
}
}
}
exports.PostCreateService = PostCreateService;
//# sourceMappingURL=PostCreateService.js.map