const path = require('path');
nv_create_dirs('./nv-content/data/');
//用户创建的所有分类、tag、或者别的什么内容
const db_terms = new NV_Database(path.join(process.cwd(),"./nv-content/data/terms.json"),{
columns: ['name','slug','taxonomy','parent','count'],
index: 'id'
});
nvdb.terms = db_terms;
//哪些term和哪些文章对应
const db_term_relationships = new NV_Database(path.join(process.cwd(),"./nv-content/data/term_relationships.json"),{
columns: ['term_id','object_id'],
index: 'id'
});
nvdb.term_relationships = db_term_relationships;
global.taxonomy_exists = (taxonomy)=>{
//判断是否register了这个taxonomy
var taxonomies = apply_filters('_nv_taxonomies',[]);
return !!taxonomies.filter(r=>r.taxonomy == taxonomy)[0];
}
global.term_exists = (arg, taxonomy)=>{
// arg是id
if ( typeof(arg)=='number' ) {
var term = db_terms.find(r=>r.id == arg && r.taxonomy == taxonomy)[0];
return term ? arg : false;
} else {
//arg是name或slug
var term_slug = encodeURIComponent(decodeURIComponent(arg));
var term = db_terms.find(r=>(r.name == arg || r.slug == arg || r.slug == term_slug) && r.taxonomy == taxonomy)[0];
return term ? term.id : false;
}
}
global.nv_unique_term_slug = (slug, taxonomy)=>{
var mySlug = slug.toLowerCase().replace(/\ /g,'-');
mySlug = encodeURIComponent(mySlug);
if ( db_terms.find(r=>r.slug == mySlug)[0] ) {
return `${mySlug}-${ Date.now() }`;
} else {
return mySlug;
}
}
global.get_taxonomies = (post_type)=>{
var all_taxonomies = apply_filters('_nv_taxonomies',[]);
if (post_type) {
return all_taxonomies.filter(r=>r.post_type == post_type);
} else {
//返回已注册的所有taxonomy
return all_taxonomies
}
}
global.___query_terms___DEPRECATED = (args)=>{
/*args = {
taxonomy: String/[String],
hide_empty: Boolean
include: [term_id],
exclude: [term_id],
keyword: String, // name、slug相似的
parent: Number, // 0 仅搜索首层
hierarchical: Boolean // 层次显示
orderby: name,slug,taxonomy,parent,count,rand, //默认:slug
order: ASC/DESC, 默认:ASC
terms_per_page: Number,
current_page: Number
}*/
if ( args.taxonomy ) {
if ( typeof(args.taxonomy) == 'string' ) {
if ( !taxonomy_exists(args.taxonomy) ) {
return [];
}
args.taxonomy = [ args.taxonomy ];
} else {
args.taxonomy = args.taxonomy.filter(tax=>taxonomy_exists(tax))
}
}
var terms = db_terms.find(r=>{
var result = [];
if (args.taxonomy && !args.taxonomy.includes(r.taxonomy)) { return false; }
if (args.hide_empty && r.count == 0) {return false}
var slug_encoded = encodeURIComponent(decodeURIComponent(r.slug));
if (args.include) {
var include_slugs = args.include.map(slug=>encodeURIComponent(decodeURIComponent(slug)))
if ( !(args.include.includes(r.id) || args.include.includes(r.name) || args.include.includes(r.slug) || include_slugs.includes(slug_encoded) ) ) {
return false;
}
}
if (args.exclude) {
var exclude_slugs = args.exclude.map(slug=>encodeURIComponent(decodeURIComponent(slug)))
if ( args.exclude.includes(r.id) || args.exclude.includes(r.name) || args.exclude.includes(r.slug) || exclude_slugs.includes(slug_encoded) ) {
return false;
}
}
if (args.keyword) {
if ( !(r.name.includes(args.keyword) || r.slug.includes(args.keyword) ) ) {
return false;
}
}
/*if (args.hierarchical) {
if (r.parent !== 0) {
return false;
}
}*/
return true;
})
// 至此,terms就是所有满足条件的内容。准备输出:
// 排序
if (args.orderby == 'rand') {
terms.sort(() => Math.random() - 0.5);
} else {
terms.sort((term1,term2)=>{
if ( typeof( term1[args.orderby || 'slug'] ) == 'string' ) {
var diff = term1[args.orderby || 'slug'].localeCompare( term2[args.orderby || 'slug'] )
} else {
var diff = term1[args.orderby || 'slug'] - term2[args.orderby || 'slug'];
}
return args.order == "DESC" ? -diff : diff;
})
}
//分页(和文章、评论不同的是:如果没有分页参数,那么返回全部terms。而不是默认分页个数)
if (args.current_page !== undefined || args.terms_per_page !== undefined) {
var current_page = parseInt(args.current_page) || 0;
if (current_page <= 0) {current_page = 1}
var terms_per_page = parseInt(args.terms_per_page) || 0;
if (terms_per_page <= 0) {terms_per_page = 10}
var comments_start_index = ( current_page - 1 ) * terms_per_page;
var termsPaged = terms.slice(comments_start_index, comments_start_index + terms_per_page);
} else {
var termsPaged = terms;
}
var all_parent_level_ids = termsPaged.map(r=>r.id);
//如果是按层次显示,那么还应该循环查找该页中所有的子级
if (args.hierarchical) {
var all_child_level_ids = [];
var getChildren = (parentIDs)=>{
var childrenIDs = db_terms.find(r=>parentIDs.includes(r.parent)).map(r=>r.id);
if (childrenIDs.length > 0) {
all_child_level_ids = all_child_level_ids.concat(childrenIDs)
getChildren(childrenIDs)
}
}
getChildren( termsPaged.map(r=>r.id) );
// 所有的子集id不应该包含父id
all_child_level_ids = all_child_level_ids.filter(id=>!all_parent_level_ids.includes(id))
var all_child_level_terms = db_terms.find(r=>all_child_level_ids.includes(r.id));
// 对层次进行排序
if (args.orderby == 'rand') {
all_child_level_terms.sort(() => Math.random() - 0.5);
} else {
all_child_level_terms.sort((term1,term2)=>{
if ( typeof( term1[args.orderby || 'slug'] ) == 'string' ) {
var diff = term1[args.orderby || 'slug'].localeCompare( term2[args.orderby || 'slug'] )
} else {
var diff = term1[args.orderby || 'slug'] - term2[args.orderby || 'slug'];
}
return args.order == "DESC" ? -diff : diff;
})
}
termsPaged = termsPaged.concat( all_child_level_terms )
}
//有分页,返回时带上分页信息。否则仅返回数据
if (args.current_page !== undefined || args.terms_per_page !== undefined) {
return {
data: termsPaged,
pagination: {
current_page,
terms_per_page,
total: terms.length
}
}
} else {
return termsPaged;
}
}
global.query_terms = args=>{
/*args = {
taxonomy: String/[String],
hide_empty: Boolean
include: [term_id],
exclude: [term_id],
keyword: String, // name、slug相似的
parent: Number, // 0 仅搜索首层
hierarchical: Boolean // 层次显示
orderby: name,slug,taxonomy,parent,count,rand, //默认:slug
order: ASC/DESC, 默认:ASC
terms_per_page: Number,
current_page: Number
}*/
if ( args.taxonomy ) {
if ( typeof(args.taxonomy) == 'string' ) {
if ( !taxonomy_exists(args.taxonomy) ) {
return [];
}
args.taxonomy = [ args.taxonomy ];
} else {
args.taxonomy = args.taxonomy.filter(tax=>taxonomy_exists(tax))
}
}
var terms = db_terms.find(r=>{
var result = [];
if (args.taxonomy && !args.taxonomy.includes(r.taxonomy)) { return false; }
if (args.hide_empty && r.count == 0) {return false}
var slug_encoded = encodeURIComponent(decodeURIComponent(r.slug));
if (args.include) {
var include_slugs = args.include.map(slug=>encodeURIComponent(decodeURIComponent(slug)))
if ( !(args.include.includes(r.id) || args.include.includes(r.name) || args.include.includes(r.slug) || include_slugs.includes(slug_encoded) ) ) {
return false;
}
}
if (args.exclude) {
var exclude_slugs = args.exclude.map(slug=>encodeURIComponent(decodeURIComponent(slug)))
if ( args.exclude.includes(r.id) || args.exclude.includes(r.name) || args.exclude.includes(r.slug) || exclude_slugs.includes(slug_encoded) ) {
return false;
}
}
if (args.keyword) {
if ( !(r.name.includes(args.keyword) || r.slug.includes(args.keyword) ) ) {
return false;
}
}
return true;
})
if (args.meta_query) {
var meta_queried_term_ids = [];
//先根据opts分别获取term_id
var meta_query_result = [ /*[term_ids],[term_ids]*/ ]
args.meta_query.opts.forEach(({key,value,compare})=>{
var term_ids = nvdb.termmeta.find(r=>{
if (r.key !== key) {return false;}
var term = terms.find(term=>term.id == r.term_id);
if (!term) {return;}
if (!term.metas) { term.metas = {} }
term.metas[key] = r.value;
try {
switch (compare) {
case '=': return r.value == value;
case '!=': return r.value !== value;
case '>': return r.value > value;
case '>=': return r.value >= value;
case '<=': return r.value <= value;
case 'LIKE': return r.value.toString().includes(value);
case 'NOT LIKE': return !r.value.toString().includes(value);
case 'IN': return value.includes(r.value);
case 'NOT IN': return !value.includes(r.value);
case 'BETWEEN': return r.value >= value[0] && r.value <=value[1];
case 'NOT BETWEEN': return r.value >= value[1] || r.value <=value[0];
default: return true;
}
} catch(e) {
console.log(e,`比较类型:${compare}`,`原始数据:`,r)
return false;
}
}).map(r=>r.term_ids)
meta_query_result.push(term_ids)
})
//根据relation将每次获取的term_id进行交集或并集
if (args.meta_query.relation == 'OR') {
// 取并集
meta_queried_term_ids = meta_query_result.reduce( (arr1,arr2)=> arr1.concat(arr2.filter(v => !arr1.includes(v))) )
} else {
// 取交集
meta_queried_term_ids = meta_query_result.reduce( (arr1,arr2)=> arr1.filter(v => arr2.includes(v)) )
}
//最后根据最终交或并结果的[term_ids]来过滤terms
var meta_term_intersections = [];
terms.forEach(term=>{
if ( meta_queried_term_ids.includes(term.id) ) {
meta_term_intersections.push(term)
}
})
terms = meta_term_intersections;
}
//如果是按层次显示,那么还应该循环查找该页中所有的子级
if (args.hierarchical) {
var all_child_level_ids = [];
var getChildren = (parentIDs)=>{
var childrenIDs = db_terms.find(r=>parentIDs.includes(r.parent)).map(r=>r.id);
if (childrenIDs.length > 0) {
all_child_level_ids = all_child_level_ids.concat(childrenIDs)
getChildren(childrenIDs)
}
}
getChildren( terms.map(r=>r.id) );
var all_child_level_terms = db_terms.find(r=>all_child_level_ids.includes(r.id));
terms = terms.concat( all_child_level_terms );
// 清除相同的term信息(本身query的时候,找到的结果就一个是另一个的子级,然后再找子集之后,会出现重复元素)
var putted_ids = [];
var unique_terms = [];
terms.forEach(term=>{
if (!putted_ids.includes(term.id)) {
unique_terms.push(term);
putted_ids.push(term.id)
}
})
terms = unique_terms;
}
// 排序
if (args.orderby == 'rand') {
terms.sort(() => Math.random() - 0.5);
} else {
terms.sort((term1,term2)=>{
if ( typeof( term1[args.orderby || 'slug'] ) == 'string' ) {
var diff = term1[args.orderby || 'slug'].localeCompare( term2[args.orderby || 'slug'] )
} else {
var diff = term1[args.orderby || 'slug'] - term2[args.orderby || 'slug'];
}
return args.order == "DESC" ? -diff : diff;
})
}
// 如果是层级显示,先装入层级,然后再分页!
if (args.hierarchical) {
var child_ids = [];
var collapser = arr => {
arr.forEach(item=>{
var {id} = item;
var children = arr.filter(item=>item.parent == id);
if (children.length) {
item.children = children;
child_ids = [...child_ids, ...children.map(item=>item.id)]
}
})
}
collapser(terms)
for (var i = terms.length - 1; i >= 0; i--) {
if ( child_ids.includes(terms[i].id) ) {
terms.splice(i,1)
}
}
}
//分页(和文章、评论不同的是:如果没有分页参数,那么返回全部terms。而不是默认分页个数)
if (args.current_page !== undefined || args.terms_per_page !== undefined) {
var current_page = parseInt(args.current_page) || 0;
if (current_page <= 0) {current_page = 1}
var terms_per_page = parseInt(args.terms_per_page) || 0;
if (terms_per_page <= 0) {terms_per_page = 10}
var comments_start_index = ( current_page - 1 ) * terms_per_page;
var termsPaged = terms.slice(comments_start_index, comments_start_index + terms_per_page);
} else {
var termsPaged = terms;
}
// 将tree展开,理由:方便写api接口的时候对每个user数据处理。否则循环起来不方便
var expanded = [];
var expander = arr => {
arr.forEach(item=>{
var {children} = item;
if (children) {
delete item.children;
if (children.length) {
expanded.push(item);
return expander(children)
}
}
expanded.push(item)
})
}
expander(termsPaged)
termsPaged = expanded;
//有分页,返回时带上分页信息。否则仅返回数据
if (args.current_page !== undefined || args.terms_per_page !== undefined) {
return {
data: termsPaged,
pagination: {
current_page,
terms_per_page,
total: terms.length
}
}
} else {
return termsPaged;
}
}
global.get_terms = (args)=>{
delete args.current_page;
delete args.terms_per_page;
return query_terms(args);
};
global.get_term = arg => {
if (!arg) { return new NV_Error('参数错误') }
if ( typeof(arg)=='number' ) {
var term = db_terms.find(r=>r.id == arg)[0];
return term || new NV_Error('Term ID不存在');
} else {
//arg是slug
var term_slug = encodeURIComponent(decodeURIComponent(arg));
var term = db_terms.find(r=>r.slug == term_slug)[0];
return term || new NV_Error('Term别名不存在');
}
}
global.nv_insert_term = (termName, taxonomy, {parentID,slug})=>{
if ( !taxonomy_exists(taxonomy) ) {
return new NV_Error(`新增失败,taxonomy不存在:${taxonomy}`);
}
if (!termName) {
return new NV_Error(`新增失败,名称不能为空`);
}
var term_id = db_terms.insert({
name: termName,
slug: nv_unique_term_slug(slug || termName, taxonomy),
taxonomy,
parent: parentID || 0,
count: 0
});
return term_id;
}
global.nv_delete_term = (term, taxonomy)=>{
var term_id = term_exists( term, taxonomy );
if (!term_id) {
return new NV_Error(`删除失败,不存在term:${term}`);
}
// 对于允许有层级的(hierarchical)。如果是别的父级,其子级将更新到父级
var registered_taxonomies = get_taxonomies();
var hierarchical = ( registered_taxonomies.filter(r=>r.taxonomy == taxonomy)[0] || {} ).opts.hierarchical || false;
if (hierarchical) {
var current_term = db_terms.find(r=>r.id == term_id)[0];
db_terms.setColumn(r=>r.parent == term_id,{
parent: current_term.parent || 0
})
}
db_terms.drop(r=>r.id == term_id);
delete_term_meta(term_id);
db_term_relationships.drop(r=>r.term_id == term_id);
}
global.nv_update_term = (term, taxonomy, {parentID,slug,name})=>{
var term_id = term_exists( term, taxonomy );
if (!term_id) {
return new NV_Error(`更新失败,不存在term:${term}`);
}
//判定要不要重写parentID
if ( parentID !== undefined || parentID !== null ) {
var parent = (db_terms.find(r=>r.id == term_id)[0] || {}).parent || 0;
if (parent !== parentID) {
//既然修改了parentID,那么,要判断parentID是不是自身或者自身的子节点。否则会导致自身和自身组成树状出现故障。
var terms = get_terms({taxonomy});
var getParent = currentID => (terms.filter(r=>r.id == currentID)[0] || {}).parent;
var err = false;
var checkParent = (current) => {
var parent = getParent(current);
if (parent == undefined) {
return;
}
if ( current == term_id || parent == parentID ) {
err = true;
return;
}
checkParent(parent)
}
checkParent(parentID);
if (err) {
return new NV_Error(`父节点不能是自身或自身的子节点`);
}
db_terms.setColumn(r=>r.id == term_id,{
parent: parentID
})
}
}
var term_data = {};
//判定要不要重写slug
var term = db_terms.find(r=>r.id == term_id)[0] || {};
if (slug !== undefined || slug !== null || slug !== '') {
if (term.slug !== slug && slug) {
term_data.slug = nv_unique_term_slug(slug, taxonomy);
}
}
//判定要不要重写name
if (name !== undefined || name !== null || name !== '') {
if (term.name !== name && name) {
term_data.name = name;
}
}
if ( Object.keys(term_data).length > 0 ) {
db_terms.setColumn(r=>r.id == term_id,term_data);
}
return term_id;
}
global.nv_get_object_terms = (object_id, taxonomy)=>{
if ( !taxonomy_exists(taxonomy) ) {
return new NV_Error('Object所在的taxonomy不存在');
}
var term_ids = db_term_relationships.find(r=>r.object_id == object_id).map(r=>r.term_id);
return get_terms({
taxonomy,
include: term_ids
});
}
global.nv_set_object_terms = (object_id, term_ids, taxonomy, append)=>{
var current_terms = nv_get_object_terms(object_id,taxonomy);
if ( is_nv_error(current_terms) ) {
return current_terms;
}
var current_term_ids = current_terms.map(r=>r.id);
var new_term_ids = [];
term_ids.forEach(id=>{
if ( !current_term_ids.includes(id) && term_exists(id, taxonomy) ) {
new_term_ids.push(id);
}
})
new_term_ids.forEach(new_tid=>{
//先读取term(文章计数也要用),没有term就不处理
var term = db_terms.find(r=>r.id == new_tid && r.taxonomy == taxonomy)[0];
if (!term) {return;}
db_term_relationships.insert({
term_id: new_tid,
object_id
})
// 增加term文章计数
db_terms.setColumn(r=>r.id == new_tid,{
count: (parseInt(term.count) || 0) + 1,
})
})
if (append) {return;}
//移除
var remove_term_ids = [];
current_term_ids.forEach(id=>{
if ( !term_ids.includes(id) ) {
remove_term_ids.push(id);
}
})
nv_remove_object_terms(object_id, remove_term_ids, taxonomy);
}
global.nv_remove_object_terms = (object_id, term_ids, taxonomy )=>{
if ( !taxonomy_exists(taxonomy) ) {
return new NV_Error('Object所在的taxonomy不存在');
}
term_ids.forEach(tid=>{
//先读取term(文章计数也要用),没有term就不处理
var term = db_terms.find(r=>r.id == tid && r.taxonomy == taxonomy)[0];
if (!term) {return;}
db_term_relationships.drop(r=>r.term_id == tid && r.object_id == object_id);
// 移除term文章计数
db_terms.setColumn(r=>r.id == tid,{
count: (parseInt(term.count) || 0) - 1,
})
})
}
global.get_term_permalink = (arg) =>{
// arg 可以是 term_id 或 term 对象
if ( typeof(arg) == 'number' ) {
var term_id = arg;
var term = query_terms({include:[term_id]})[0];
} else {
var term_id = ( arg || {} ).id;
var term = arg;
}
var url = "";
if ( term && term_id ) {
// 默认:安装地址/taxonomy/slug
url = `${get_option('nv_home_url','')}/${term.taxonomy}/${term.slug}`;
}
return apply_filters('term_permalink', url, term, arg );
}
global.update_term_meta = (term_id,key,value) => {
if ( db_terms.find(r=>r.id == term_id)[0] ) {
return update_metadata('term',term_id,key,value);
}
}
global.get_term_meta = (term_id,key)=>{
return get_metadata('term',term_id,key);
}
global.delete_term_meta = (term_id,key) => {
return delete_metadata('term',term_id,key);
}
global.add_taxonomy_meta_box = ({ post_types, taxonomies, meta_box_slug, component, component_url, position, content })=>{
add_filter('_nv_taxonomy_custom_metaboxes',(meta_boxes)=>{
meta_boxes = meta_boxes || [];
//查找有没有相同的slug,不相同才放进去
if ( !meta_boxes.filter(r=>r.meta_box_slug == meta_box_slug)[0] ) {
meta_boxes.push({
post_types, taxonomies, meta_box_slug, component, component_url, position, content
})
}
return meta_boxes;
});
}