// // // Wordpress Model // import * as WP from "wpapi"; import { Log } from "fme-logger"; var L = new Log("WordPress"); L.setLevel("info"); // // ==> FmePost standard than converts to a WPpost or ? // export type TermNames = { category: string[]; post_tag:string ; } export type Article = { title:string; description:string; summary:string; link:string; origlink:string; permalink:string; date:Date; pubdate:Date; author:string; guid:string; comments:string; image: any; categories:string[] source:any; enclosures: any[]; meta:any[]; timestamp:Date; feedCategories:string[]; } export type Feed = { name: string; img_url: string; cats: string; tags: string; url: string; guid: any[]; authorID: number; wpAuthorId:number; wpThumbnail:number; type: string; feedStatus:string; priority:number; update_date: string; frequency: string; blocks: string; id: number; status:string; isAutopost:string; doTweets:boolean; hasFilter:boolean; filter: any; maxPerDay:number; lastUpdate: Date; lifePostCount:number; todayPostCount:number; lastPosted: Date; delay:number; linkText:string; comments:string; includeCategories:string[]; excludeCategories:string[]; featuredImageUrl:string; canRewriteHttps:string; } export type FmePost = { date: Date; title: string; termNames : TermNames; categories: number[]; tags:number[]; content: string; excerpt: string; status: string; wpAuthor: string; wpAuthorId:number; author_display_name: string; author_img_url : string; html: string; version: string; customFields: any[]; likes: string; dislikes: string; up_voters: any[]; down_voters : any[]; clicks : Number; article: Article; source: {}; last_read: string; isPosted: Boolean; isAutoPost: Boolean; timestamp: Date; guid: string; priority:number; maxPerDay:number; pubdate:Date; pubAvailable:Date; linkText:string; feed:Feed; } export interface WpConfig { name:string, username:string, password:string, endpoint:string categories: number[], tags : number[], featured_media : number } export enum WpStatus { publish = "publish", future = "future", draft = "draft", pending = "pending", private = "private" } export enum WpCommentStatus { open = "open", close = "closed", } export enum WpPingStatus { open = "open", close = "closed", } export enum WpFormat { standard = "standard", aside="aside", chat ="chat", gallery="gallery", link="link", image="image", quote="quote", status="status", video="video", audio="audio" } export interface WpImageOptions { title:string,caption:string,description:string,path:string,type:string } export interface WpPost { date:Date, date_gmt: Date, slug:string, status:WpStatus, pasword:string, title:string, content:string, featured_media:number, comment_status:WpCommentStatus, ping_status:WpPingStatus, format:WpFormat, meta:any, sticky:boolean, template:string, categories:any[], tags:any[] } export class WordPress { wp:any; categories: any[]; tags: any[]; catCache: any[] = []; tagCache: any[] = []; constructor(config:WpConfig) { L.info("Calling WP with config",config); this.wp = new WP({endpoint:config.endpoint,username:config.username,password:config.password}); this.wp.acf = this.wp.registerRoute('acf/v3','/posts/(?P\\d+)'); this.categories = []; this.tags = []; } init = () => { return new Promise ( async ( resolve,reject ) => { L.debug("*** Init Wordpress *****") try{ } catch (err) { L.error(err) reject(err) return } L.debug("WordpressInit finished categories",this.categories.length,"tags",this.tags.length) resolve(true) }) } createCategory = (name:string) => { return new Promise ( async ( resolve,reject ) => { var t = { "description":"auto-generated from silver aggregator", "name" : name, "slug": name.replace(" ","-").toLowerCase(), } try{ var cat = await this.wp.categories().create(t); } catch (err) { L.error("CreateCategory: Term:",name,"error",err) reject(err) return } resolve(cat) }) } searchCategoryWp = (name:string) => { return new Promise ( async ( resolve,reject ) => { L.debug("Seraching website for category",name); try{ var cats:any[] = await this.wp.categories().slug(name.toLowerCase().replace(/\s+/g, '-').toLowerCase()) as any[]; L.debug("SearchCategoryWp:search returned the following categories",cats) if (cats) { this.catCache.push(...cats); var cat = this.catCache.find((a)=> {return ( a.name.toLowerCase() == name.toLowerCase()) }) L.debug("SearchCategoryWP: Returning cat",cat); } else { L.debug("searchCategory: No category on website for cat",name); cat = null; } } catch (err) { L.error(err) reject(err) return } resolve(cat) }) } getCategoryId = (name:string) => { return new Promise ( async ( resolve,reject ) => { try{ // => 1 lookin in cache var cat = this.catCache.find((a)=> {return ( a.name.toLowerCase() == name.toLowerCase()) }) if (!cat) { L.debug("getCategory: CacheMiss for",name,"looking for it on website"); // => 2 Not there, look on websites cat = await this.searchCategoryWp(name) as any; if (!cat) { L.debug("getCategoryId, no cat",name,"found on server either, need to create on"); try { // =====> 3. Still not there? Create a new one cat = await this.createCategory(name); } catch (err) { L.error(err) reject(err) return } } } } catch (err) { L.error(err) reject(err) return } resolve(cat.id) }) } createTag = (name:string) => { return new Promise ( async ( resolve,reject ) => { var t = { "description":"auto-generated from silver aggregator", "name" : name, "slug": name.replace(" ","-").toLowerCase(), } try{ var tag = await this.wp.tags().create(t); this.tagCache.push(tag); } catch (err) { L.error("CreateTag: Term:",name,"error",err) reject(err) return } resolve(tag) }) } searchTagWp = (name:string) => { return new Promise ( async ( resolve,reject ) => { try{ var tags:any[] = await this.wp.tags().slug(name.replace(/\s+/g, '-').toLowerCase()) as any[]; L.debug("search tags returned",JSON.stringify(tags),"for tag",name); if (tags) { this.tagCache.push(...tags); var tag = this.tagCache.find((a)=> {return ( a.name.toLowerCase() == name.toLowerCase()) }) } else { L.debug("searchTag: No tag on website for tag",name); tag = null } } catch (err) { L.error(err) reject(err) return } resolve(tag) }) } getTagId = (name:string) => { return new Promise ( async ( resolve,reject ) => { try{ // ==> 1 . check cache var tag = this.tagCache.find((a)=> {return ( a.name.toLowerCase() == name.toLowerCase()) }) if (!tag) { L.debug("getTagId: CacheMiss for",name,"looking for it on website"); // ==> 2. search terms and throw results onto the cache tag = await this.searchTagWp(name) as any[]; if (!tag) { L.debug("getTagId, no tag",name,"found on server either, need to create on"); try { // ======> 3. Still no tag? Create a new one then tag = await this.createTag(name); } catch (err) { L.error("getTagId:Error for name",name,"Resolving to 64 [missing]") resolve(64) return } } } } catch (err) { L.error(err) reject(err) return } resolve(tag.id) }) } addFeaturedImage = (post:FmePost,imageUrl:string) => { post.content = 'mrtopstep
'+post.content; return post; } // // // ==> Priority for selecting featured image; // // if fmePost.feed.wpThumbnail > 0 then use that and don't posts a featued image url // if fmePost.feed.wpThumnail == -1 then look for the first image and use that, if not appropriate use // fmePost.feed.featuredImageUrl; // if fmePost.feed.spThumbnail == -2 always use fmePost.feed.featuredImageurl // findImageUrl = (fmePost:FmePost) => { var url = ""; if (typeof fmePost.article.image.url == "string" ) { L.info("found an image url tag",fmePost.article.image.url) if (fmePost.article.image.url.substring(0,5) == "https") { return fmePost.article.image.url; } else if (fmePost.article.image.url.substring(0,5) == "http:" && fmePost.feed.canRewriteHttps) { if (fmePost.feed.canRewriteHttps.toLowerCase() == "true" ) { var tempUrl = fmePost.article.image.url.replace(/http:/g,"https:"); L.info("rewriting the protocol from http to https",tempUrl); return tempUrl; } } } if ( typeof fmePost.article.enclosures !== "object") return url; for (var i in fmePost.article.enclosures) { if (fmePost.article.enclosures[i].type == 'image/jpeg' ||fmePost.article.enclosures[i].type == 'image/png' || fmePost.article.enclosures[i].type == 'image/gif' ) { L.info("Found image",fmePost.article.enclosures[i].url); return fmePost.article.enclosures[i].url } } return url; } // // => Using the wp-api uploads an image in to the media and returns an imageID for use in posts // uploadImage = async (options:WpImageOptions) => { var resp:any = {}; try { resp = await this.wp.media().file(options.path).create(options) as any; } catch (err) { L.error("uploadImage: ",err,resp) return false; } if (resp.id) return resp; return false } createPost = async (post:WpPost) => { var res = undefined; try { var res = await this.wp.posts().create(post); L.info("created a new post",res.id); } catch (err) { L.error(err) return(err) } L.debug("WP: CreatePost returned",JSON.stringify(res)); return( res ) } }