nextpress-core 1.0.3 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (211) hide show
  1. package/cli/install.js +27 -0
  2. package/{dist/acf-functions/core/acf-builder.js → lib/acf-functions/core/acf-builder.ts} +45 -17
  3. package/{dist/acf-functions/core/acf-component-autoloader.js → lib/acf-functions/core/acf-component-autoloader.ts} +13 -7
  4. package/{dist/acf-functions/core/acf-field-group-autoloader.js → lib/acf-functions/core/acf-field-group-autoloader.ts} +11 -5
  5. package/{dist/acf-functions/services/define-field-group.d.ts → lib/acf-functions/services/define-field-group.ts} +4 -1
  6. package/{dist/acf-functions/services/define-layout.d.ts → lib/acf-functions/services/define-layout.ts} +4 -1
  7. package/lib/acf-functions/services/map-fields/helpers/map-choice-object.ts +20 -0
  8. package/{dist/acf-functions/services/map-fields/map-fields.js → lib/acf-functions/services/map-fields/map-fields.ts} +128 -89
  9. package/{dist/acf-functions/types/acf-field-group.d.ts → lib/acf-functions/types/acf-field-group.ts} +49 -28
  10. package/lib/acf-functions/types/acf-field.ts +2853 -0
  11. package/lib/acf-functions/types/acf-layout.ts +22 -0
  12. package/lib/acf-functions/types/components/field-props.ts +189 -0
  13. package/{dist/acf-functions/types/components/nextpress-component.d.ts → lib/acf-functions/types/components/nextpress-component.ts} +4 -3
  14. package/lib/ambient.d.ts +16 -0
  15. package/{dist/entities/common.d.ts → lib/entities/common.ts} +6 -4
  16. package/{dist/entities/option/option.interface.d.ts → lib/entities/option/option.interface.ts} +3 -3
  17. package/{dist/entities/option/option.js → lib/entities/option/option.ts} +21 -14
  18. package/{dist/entities/post/post.interface.d.ts → lib/entities/post/post.interface.ts} +26 -21
  19. package/lib/entities/post/post.ts +209 -0
  20. package/{dist/entities/term/term.interface.d.ts → lib/entities/term/term.interface.ts} +3 -3
  21. package/lib/entities/term/term.ts +82 -0
  22. package/{dist/entities/user/user.interface.d.ts → lib/entities/user/user.interface.ts} +2 -1
  23. package/lib/entities/user/user.ts +86 -0
  24. package/{dist/globals/entity-loader/entity-loader-base.js → lib/globals/entity-loader/entity-loader-base.ts} +64 -10
  25. package/{dist/globals/entity-loader/entity-loader.interface.d.ts → lib/globals/entity-loader/entity-loader.ts} +2 -4
  26. package/lib/globals/entity-loader/option-loader.ts +56 -0
  27. package/lib/globals/entity-loader/post-loader.ts +60 -0
  28. package/lib/globals/entity-loader/term-loader.ts +60 -0
  29. package/lib/globals/entity-loader/user-loader.ts +61 -0
  30. package/lib/globals/get-field/get-field.ts +76 -0
  31. package/{dist/globals/globals.js → lib/globals/globals.ts} +8 -3
  32. package/{dist/globals/nextpress-config/nextpress-config.interface.d.ts → lib/globals/nextpress-config/nextpress-config.interface.ts} +10 -6
  33. package/lib/globals/nextpress-config/nextpress-config.ts +8 -0
  34. package/lib/globals/queried-object/queried-object.ts +124 -0
  35. package/{dist/repository/optionquery/option-query-args.d.ts → lib/repository/optionquery/option-query-args.ts} +5 -2
  36. package/lib/repository/optionquery/option-query.ts +29 -0
  37. package/{dist/repository/postquery/post-query-args.d.ts → lib/repository/postquery/post-query-args.ts} +10 -6
  38. package/lib/repository/postquery/post-query.ts +282 -0
  39. package/{dist/repository/termquery/term-query-args.d.ts → lib/repository/termquery/term-query-args.ts} +16 -6
  40. package/lib/repository/termquery/term-query.ts +244 -0
  41. package/{dist/repository/userquery/user-query-args.d.ts → lib/repository/userquery/user-query-args.ts} +19 -7
  42. package/{dist/repository/userquery/user-query.js → lib/repository/userquery/user-query.ts} +93 -76
  43. package/{dist/router/helpers.js → lib/router/helpers.ts} +4 -4
  44. package/{dist/router/nextpress-layout.js → lib/router/nextpress-layout.tsx} +28 -9
  45. package/{dist/router/routes/not-found-page.js → lib/router/nextpress-not-found-route.tsx} +7 -5
  46. package/{dist/router/nextpress-proxy.js → lib/router/nextpress-proxy.ts} +15 -3
  47. package/{dist/router/nextpress-static-params.js → lib/router/nextpress-static-params.ts} +17 -5
  48. package/{dist/router/router.js → lib/router/router.tsx} +29 -22
  49. package/{dist/router/routes/api/api-get-admin-bar.js → lib/router/routes/api/api-get-admin-bar.ts} +8 -6
  50. package/{dist/router/routes/api/api-get-draft-mode.js → lib/router/routes/api/api-get-draft-mode.ts} +15 -6
  51. package/{dist/router/routes/api/api-get-field-groups.js → lib/router/routes/api/api-get-field-groups.ts} +13 -8
  52. package/{dist/router/routes/api/api-post-revalidate.js → lib/router/routes/api/api-post-revalidate.ts} +6 -4
  53. package/{dist/router/routes/api/helpers.js → lib/router/routes/api/helpers.ts} +4 -3
  54. package/lib/router/routes/author-archive.tsx +75 -0
  55. package/lib/router/routes/post-index-page.tsx +58 -0
  56. package/lib/router/routes/singular-page.tsx +78 -0
  57. package/lib/router/routes/site-front-page.tsx +51 -0
  58. package/lib/router/routes/term-archive.tsx +93 -0
  59. package/{dist/router/types.d.ts → lib/router/types.ts} +4 -2
  60. package/{dist/services/get-menu.js → lib/services/get-menu.ts} +56 -32
  61. package/{dist/services/get-theme-mods.js → lib/services/get-theme-mods.ts} +6 -4
  62. package/{dist/services/metadata/get-blogname.js → lib/services/metadata/get-blogname.ts} +2 -2
  63. package/{dist/services/metadata/get-favicon-url.js → lib/services/metadata/get-favicon-url.ts} +5 -4
  64. package/{dist/services/metadata/get-language-attribute.js → lib/services/metadata/get-language-attribute.ts} +1 -1
  65. package/{dist/services/utilities/capitalise-first-letter.js → lib/services/utilities/capitalise-first-letter.ts} +2 -3
  66. package/{dist/services/utilities/esc-html.js → lib/services/utilities/esc-html.ts} +3 -1
  67. package/{dist/services/utilities/get-date-time-formatter.js → lib/services/utilities/get-date-time-formatter.ts} +16 -6
  68. package/{dist/services/utilities/kses-post.js → lib/services/utilities/kses-post.ts} +2 -1
  69. package/{dist/services/utilities/process-url.js → lib/services/utilities/process-url.ts} +4 -3
  70. package/{dist/template-heirarchy/_autoloader/template-autoloader.js → lib/template-heirarchy/_autoloader/template-autoloader.ts} +18 -9
  71. package/{dist/template-heirarchy/archive/archive.js → lib/template-heirarchy/archive/archive.tsx} +10 -7
  72. package/{dist/template-heirarchy/archive/author.js → lib/template-heirarchy/archive/author.tsx} +10 -7
  73. package/{dist/template-heirarchy/archive/category.js → lib/template-heirarchy/archive/category.tsx} +11 -7
  74. package/{dist/template-heirarchy/archive/posttypearchive.js → lib/template-heirarchy/archive/posttypearchive.tsx} +11 -8
  75. package/{dist/template-heirarchy/archive/tag.js → lib/template-heirarchy/archive/tag.tsx} +12 -7
  76. package/{dist/template-heirarchy/archive/taxonomy.js → lib/template-heirarchy/archive/taxonomy.tsx} +10 -7
  77. package/{dist/template-heirarchy/home/home.js → lib/template-heirarchy/home/home.tsx} +10 -7
  78. package/{dist/template-heirarchy/index.js → lib/template-heirarchy/index.tsx} +9 -5
  79. package/{dist/template-heirarchy/not-found.tsx/not-found.js → lib/template-heirarchy/not-found.tsx/not-found.tsx} +10 -7
  80. package/{dist/template-heirarchy/page/page.js → lib/template-heirarchy/page/page.tsx} +10 -7
  81. package/{dist/template-heirarchy/page/posttype.js → lib/template-heirarchy/page/posttype.tsx} +12 -8
  82. package/{dist/template-heirarchy/page/single.js → lib/template-heirarchy/page/single.tsx} +10 -7
  83. package/{dist/template-heirarchy/page/singular.js → lib/template-heirarchy/page/singular.tsx} +10 -7
  84. package/lib/ui/render-attachment-image.tsx +28 -0
  85. package/lib/ui/render-components.tsx +12 -0
  86. package/lib/ui/render-the-admin-bar.tsx +79 -0
  87. package/lib/ui/render-the-logo.tsx +24 -0
  88. package/{dist/wpdb/wpdb.interface.d.ts → lib/wpdb/wpdb.interface.ts} +20 -1
  89. package/{dist/wpdb/wpdb.js → lib/wpdb/wpdb.ts} +9 -5
  90. package/package.json +8 -15
  91. package/dist/acf-functions/core/acf-builder.d.ts +0 -51
  92. package/dist/acf-functions/core/acf-component-autoloader.d.ts +0 -11
  93. package/dist/acf-functions/core/acf-field-group-autoloader.d.ts +0 -10
  94. package/dist/acf-functions/field-props.d.ts +0 -196
  95. package/dist/acf-functions/field-props.js +0 -1
  96. package/dist/acf-functions/services/define-field-group.js +0 -10
  97. package/dist/acf-functions/services/define-layout.js +0 -10
  98. package/dist/acf-functions/services/map-fields/helpers/map-choice-object.d.ts +0 -2
  99. package/dist/acf-functions/services/map-fields/helpers/map-choice-object.js +0 -18
  100. package/dist/acf-functions/services/map-fields/map-fields.d.ts +0 -21
  101. package/dist/acf-functions/types/acf-field-group.js +0 -1
  102. package/dist/acf-functions/types/acf-field.d.ts +0 -2813
  103. package/dist/acf-functions/types/acf-field.js +0 -1
  104. package/dist/acf-functions/types/acf-layout.d.ts +0 -19
  105. package/dist/acf-functions/types/acf-layout.js +0 -1
  106. package/dist/acf-functions/types/acf-values.js +0 -1
  107. package/dist/acf-functions/types/components/field-props.d.ts +0 -196
  108. package/dist/acf-functions/types/components/field-props.js +0 -1
  109. package/dist/acf-functions/types/components/nextpress-component.js +0 -1
  110. package/dist/entities/common.js +0 -1
  111. package/dist/entities/option/option.d.ts +0 -19
  112. package/dist/entities/option/option.interface.js +0 -2
  113. package/dist/entities/post/post.d.ts +0 -50
  114. package/dist/entities/post/post.interface.js +0 -2
  115. package/dist/entities/post/post.js +0 -184
  116. package/dist/entities/term/term.d.ts +0 -28
  117. package/dist/entities/term/term.interface.js +0 -1
  118. package/dist/entities/term/term.js +0 -67
  119. package/dist/entities/user/user.d.ts +0 -27
  120. package/dist/entities/user/user.interface.js +0 -1
  121. package/dist/entities/user/user.js +0 -74
  122. package/dist/globals/entity-loader/entity-loader-base.d.ts +0 -65
  123. package/dist/globals/entity-loader/entity-loader.interface.js +0 -1
  124. package/dist/globals/entity-loader/option-loader.d.ts +0 -15
  125. package/dist/globals/entity-loader/option-loader.js +0 -31
  126. package/dist/globals/entity-loader/post-loader.d.ts +0 -21
  127. package/dist/globals/entity-loader/post-loader.js +0 -28
  128. package/dist/globals/entity-loader/term-loader.d.ts +0 -21
  129. package/dist/globals/entity-loader/term-loader.js +0 -28
  130. package/dist/globals/entity-loader/user-loader.d.ts +0 -21
  131. package/dist/globals/entity-loader/user-loader.js +0 -28
  132. package/dist/globals/get-field/get-field.d.ts +0 -18
  133. package/dist/globals/get-field/get-field.js +0 -44
  134. package/dist/globals/globals.d.ts +0 -18
  135. package/dist/globals/nextpress-config/nextpress-config.d.ts +0 -4
  136. package/dist/globals/nextpress-config/nextpress-config.interface.js +0 -1
  137. package/dist/globals/nextpress-config/nextpress-config.js +0 -2
  138. package/dist/globals/queried-object/queried-object.d.ts +0 -62
  139. package/dist/globals/queried-object/queried-object.js +0 -56
  140. package/dist/repository/optionquery/option-query-args.js +0 -1
  141. package/dist/repository/optionquery/option-query.d.ts +0 -12
  142. package/dist/repository/optionquery/option-query.js +0 -20
  143. package/dist/repository/postquery/post-query-args.js +0 -1
  144. package/dist/repository/postquery/post-query.d.ts +0 -12
  145. package/dist/repository/postquery/post-query.js +0 -272
  146. package/dist/repository/termquery/term-query-args.js +0 -1
  147. package/dist/repository/termquery/term-query.d.ts +0 -11
  148. package/dist/repository/termquery/term-query.js +0 -213
  149. package/dist/repository/userquery/user-query-args.js +0 -1
  150. package/dist/repository/userquery/user-query.d.ts +0 -12
  151. package/dist/router/helpers.d.ts +0 -14
  152. package/dist/router/nextpress-layout.d.ts +0 -11
  153. package/dist/router/nextpress-proxy.d.ts +0 -8
  154. package/dist/router/nextpress-static-params.d.ts +0 -9
  155. package/dist/router/router.d.ts +0 -23
  156. package/dist/router/routes/api/api-get-admin-bar.d.ts +0 -8
  157. package/dist/router/routes/api/api-get-draft-mode.d.ts +0 -8
  158. package/dist/router/routes/api/api-get-field-groups.d.ts +0 -7
  159. package/dist/router/routes/api/api-post-revalidate.d.ts +0 -7
  160. package/dist/router/routes/api/helpers.d.ts +0 -8
  161. package/dist/router/routes/author-archive.d.ts +0 -25
  162. package/dist/router/routes/author-archive.js +0 -49
  163. package/dist/router/routes/not-found-page.d.ts +0 -15
  164. package/dist/router/routes/post-index-page.d.ts +0 -25
  165. package/dist/router/routes/post-index-page.js +0 -33
  166. package/dist/router/routes/singular-page.d.ts +0 -29
  167. package/dist/router/routes/singular-page.js +0 -51
  168. package/dist/router/routes/site-front-page.d.ts +0 -27
  169. package/dist/router/routes/site-front-page.js +0 -26
  170. package/dist/router/routes/term-archive.d.ts +0 -29
  171. package/dist/router/routes/term-archive.js +0 -65
  172. package/dist/router/types.js +0 -1
  173. package/dist/services/get-menu.d.ts +0 -13
  174. package/dist/services/get-theme-mods.d.ts +0 -7
  175. package/dist/services/metadata/get-blogname.d.ts +0 -6
  176. package/dist/services/metadata/get-favicon-url.d.ts +0 -6
  177. package/dist/services/metadata/get-language-attribute.d.ts +0 -6
  178. package/dist/services/services.d.ts +0 -3
  179. package/dist/services/services.js +0 -3
  180. package/dist/services/utilities/capitalise-first-letter.d.ts +0 -7
  181. package/dist/services/utilities/esc-html.d.ts +0 -7
  182. package/dist/services/utilities/get-date-time-formatter.d.ts +0 -6
  183. package/dist/services/utilities/index.d.ts +0 -0
  184. package/dist/services/utilities/index.js +0 -1
  185. package/dist/services/utilities/kses-post.d.ts +0 -7
  186. package/dist/services/utilities/process-url.d.ts +0 -7
  187. package/dist/template-heirarchy/_autoloader/template-autoloader.d.ts +0 -9
  188. package/dist/template-heirarchy/archive/archive.d.ts +0 -16
  189. package/dist/template-heirarchy/archive/author.d.ts +0 -16
  190. package/dist/template-heirarchy/archive/category.d.ts +0 -16
  191. package/dist/template-heirarchy/archive/posttypearchive.d.ts +0 -24
  192. package/dist/template-heirarchy/archive/tag.d.ts +0 -16
  193. package/dist/template-heirarchy/archive/taxonomy.d.ts +0 -16
  194. package/dist/template-heirarchy/home/home.d.ts +0 -16
  195. package/dist/template-heirarchy/index.d.ts +0 -17
  196. package/dist/template-heirarchy/not-found.tsx/not-found.d.ts +0 -16
  197. package/dist/template-heirarchy/page/page.d.ts +0 -16
  198. package/dist/template-heirarchy/page/posttype.d.ts +0 -24
  199. package/dist/template-heirarchy/page/single.d.ts +0 -16
  200. package/dist/template-heirarchy/page/singular.d.ts +0 -16
  201. package/dist/ui/render-attachment-image.d.ts +0 -12
  202. package/dist/ui/render-attachment-image.js +0 -24
  203. package/dist/ui/render-components.d.ts +0 -9
  204. package/dist/ui/render-components.js +0 -7
  205. package/dist/ui/render-the-admin-bar.d.ts +0 -8
  206. package/dist/ui/render-the-admin-bar.js +0 -36
  207. package/dist/ui/render-the-logo.d.ts +0 -10
  208. package/dist/ui/render-the-logo.js +0 -16
  209. package/dist/wpdb/wpdb.d.ts +0 -3
  210. package/dist/wpdb/wpdb.interface.js +0 -5
  211. /package/{dist/acf-functions/types/acf-values.d.ts → lib/acf-functions/types/acf-values.ts} +0 -0
@@ -1,14 +1,18 @@
1
- type NextpressConfig = {
1
+ export type NextpressConfig = {
2
2
  /** Custom taxonomies used to categorize and group content (like categories or tags). Expects the taxonomy's URL prefix, so tag instead of post_tag */
3
- readonly publicTaxonomies?: string[];
3
+ readonly publicTaxonomies?: string[],
4
+
4
5
  /** Custom post types registered for public consumption (like posts, pages, or portfolio). */
5
- readonly publicPostTypes?: string[];
6
+ readonly publicPostTypes?: string[],
7
+
6
8
  /** Post types that should display archive pages on the frontend. */
7
- readonly archivedPostTypes?: string[];
9
+ readonly archivedPostTypes?: string[],
10
+
8
11
  /** The word/character count limit for automatically generated post teasers. */
9
- readonly excerptLength?: number;
12
+ readonly excerptLength?: number,
13
+
10
14
  /** Database option keys (from wp_options) to fetch early for performance optimization. */
11
- readonly preLoadOptions?: string[];
15
+ readonly preLoadOptions?: string[],
12
16
  } & {
13
17
  [key: string]: any;
14
18
  };
@@ -0,0 +1,8 @@
1
+ import { nextpressConfig } from "@/nextpress.config";
2
+ import { NextpressConfig } from "./nextpress-config.interface";
3
+
4
+ declare global {
5
+ var nextpressConfig: NextpressConfig
6
+ }
7
+
8
+ globalThis.nextpressConfig = nextpressConfig;
@@ -0,0 +1,124 @@
1
+ import { IPost } from "../../entities/post/post.interface";
2
+ import { ITerm } from "../../entities/term/term.interface";
3
+ import { IUser } from "../../entities/user/user.interface";
4
+ import { queriedObjectState } from "../globals";
5
+
6
+ /**
7
+ * Represents the state of the queried object.
8
+ */
9
+ interface IQueriedObject {
10
+ /** Type of the queried object. */
11
+ objectType: 'post' | 'term' | 'user' | null,
12
+ /** Array of post IDs associated with the query. */
13
+ posts: number[],
14
+ /** Current page number. */
15
+ page: number,
16
+ /** Total page count. */
17
+ pageCount: number,
18
+ /** ID of the main queried term. */
19
+ mainTerm?: number,
20
+ /** Array of term IDs associated with the query. */
21
+ terms: number[],
22
+ /** ID of the queried user. */
23
+ user?: number,
24
+ }
25
+
26
+ /**
27
+ * Creates a blank queried object state.
28
+ *
29
+ * @returns {IQueriedObject} Blank state object.
30
+ */
31
+ const createBlankState = (): IQueriedObject => ({
32
+ objectType: null,
33
+ posts: [],
34
+ page: 1,
35
+ pageCount: 1,
36
+ terms: [],
37
+ });
38
+
39
+ declare global {
40
+ /** The current queried object. */
41
+ var queriedObject: IQueriedObject
42
+ /**
43
+ * Retrieves the first post from the queried object.
44
+ * @returns {Promise<IPost | undefined>} The post.
45
+ */
46
+ var getThePost: () => Promise<IPost | undefined>
47
+ /**
48
+ * Retrieves all posts from the queried object.
49
+ * @returns {Promise<IPost[]>} Array of posts.
50
+ */
51
+ var getThePosts: () => Promise<IPost[]>
52
+ /**
53
+ * Retrieves the current page number.
54
+ * @returns {number} Page number.
55
+ */
56
+ var getThePage: () => number
57
+ /**
58
+ * Retrieves the total page count.
59
+ * @returns {number} Page count.
60
+ */
61
+ var getThePageCount: () => number
62
+ /**
63
+ * Retrieves the main term from the queried object.
64
+ * @returns {Promise<ITerm | undefined>} The term.
65
+ */
66
+ var getTheTerm: () => Promise<ITerm | undefined>
67
+ /**
68
+ * Retrieves all terms from the queried object.
69
+ * @returns {Promise<ITerm[]>} Array of terms.
70
+ */
71
+ var getTheTerms: () => Promise<ITerm[]>
72
+ /**
73
+ * Retrieves the user from the queried object.
74
+ * @returns {Promise<IUser | undefined>} The user.
75
+ */
76
+ var getTheUser: () => Promise<IUser | undefined>
77
+ }
78
+
79
+ Object.defineProperty(globalThis, 'queriedObject', {
80
+ configurable: true,
81
+ enumerable: true,
82
+ get() {
83
+ const state = queriedObjectState();
84
+ return state.currentState || createBlankState();
85
+ },
86
+ set(newData: IQueriedObject) {
87
+ const store = queriedObjectState();
88
+
89
+ if (newData.posts) postLoader.prime(newData.posts);
90
+ if (newData.mainTerm) termLoader.prime([newData.mainTerm]);
91
+ if (newData.terms) termLoader.prime(newData.terms);
92
+ if (newData.user) userLoader.prime([newData.user]);
93
+
94
+ if (!store.currentState) store.currentState = {};
95
+ Object.assign(store.currentState, newData);
96
+ }
97
+ });
98
+
99
+ globalThis.getThePost = async () => {
100
+ return (await postLoader.get(globalThis.queriedObject.posts))[0];
101
+ };
102
+ globalThis.getThePosts = () => {
103
+ return postLoader.get(globalThis.queriedObject.posts);
104
+ };
105
+
106
+ globalThis.getThePage = () => globalThis.queriedObject.page;
107
+
108
+ globalThis.getThePageCount = () => globalThis.queriedObject.pageCount;
109
+
110
+ globalThis.getTheTerm = async () => {
111
+ if (!globalThis.queriedObject.mainTerm) return;
112
+ return (await termLoader.get([globalThis.queriedObject.mainTerm]))[0];
113
+ };
114
+
115
+ globalThis.getTheTerms = () => {
116
+ return termLoader.get(globalThis.queriedObject.terms);
117
+ };
118
+
119
+ globalThis.getTheUser = async () => {
120
+ if (!globalThis.queriedObject.user) return;
121
+ return (await userLoader.get([globalThis.queriedObject.user]))[0];
122
+ };
123
+
124
+ export {};
@@ -1,5 +1,6 @@
1
- import { DB } from "@/wpdb/wpdb.interface";
2
1
  import { ComparisonOperatorExpression, ReferenceExpression } from "kysely";
2
+ import { DB } from "nextpress/wpdb/wpdb.interface";
3
+
3
4
  /**
4
5
  * Defines the arguments for querying options.
5
6
  */
@@ -7,11 +8,13 @@ export interface OptionQueryArgs {
7
8
  /**
8
9
  * Database column reference to query against.
9
10
  */
10
- column: ReferenceExpression<DB, "wpOptions">;
11
+ column: ReferenceExpression<DB, 'wpOptions'>;
12
+
11
13
  /**
12
14
  * Comparison operator for the query.
13
15
  */
14
16
  operand?: ComparisonOperatorExpression;
17
+
15
18
  /**
16
19
  * Value or array of values to compare.
17
20
  */
@@ -0,0 +1,29 @@
1
+ import { ComparisonOperatorExpression } from "kysely";
2
+ import { EntityQuery } from "../../globals/entity-loader/entity-loader";
3
+ import { OptionQueryArgs } from "./option-query-args";
4
+ import { IOption } from "../../entities/option/option.interface";
5
+ import { wpdb } from "nextpress/wpdb/wpdb";
6
+
7
+ /**
8
+ * Executes database queries to retrieve option IDs (or keys) based on provided arguments.
9
+ */
10
+ export class OptionQuery implements EntityQuery<IOption>
11
+ {
12
+ constructor(
13
+ private args: OptionQueryArgs
14
+ ) {}
15
+
16
+ public getCount(): number | undefined {
17
+ return undefined;
18
+ }
19
+
20
+ public async getIds(): Promise<number[]> {
21
+ const operand: ComparisonOperatorExpression = this.args.operand || '=';
22
+
23
+ return (await wpdb
24
+ .selectFrom('wpOptions')
25
+ .select('optionId')
26
+ .where(this.args.column, operand, this.args.value)
27
+ .execute()).map(option => option.optionId);
28
+ }
29
+ }
@@ -1,9 +1,13 @@
1
- type WPQueryOrderByParam = 'none' | 'id' | 'author' | 'title' | 'name' | 'date' | 'modified' | 'parent' | 'menuOrder' | 'commentCount' | 'rand' | `RAND(${number})` | (string & {});
1
+ type WPQueryOrderByParam =
2
+ | 'none' | 'id' | 'author' | 'title' | 'name' | 'date' | 'modified'
3
+ | 'parent' | 'menuOrder'| 'commentCount' | 'rand' | `RAND(${number})`
4
+ | (string & {});
5
+
2
6
  /**
3
7
  * Defines the arguments for querying posts.
4
8
  * Maps standard WordPress WP_Query parameters.
5
9
  */
6
- interface PostQueryArgs {
10
+ export interface PostQueryArgs {
7
11
  /** Post ID. */
8
12
  postId?: number;
9
13
  /** An array of post IDs to retrieve, sticky posts will be included. */
@@ -95,10 +99,10 @@ interface PostQueryArgs {
95
99
  /** Meta query */
96
100
  metaQuery?: {
97
101
  /** Meta key */
98
- metaKey: string;
102
+ metaKey: string,
99
103
  /** Variable name to save result to */
100
- as: string;
101
- }[];
104
+ as: string
105
+ }[]
102
106
  /** Whether to get multiple, default true */
103
- multiple?: boolean;
107
+ multiple?: boolean
104
108
  }
@@ -0,0 +1,282 @@
1
+ import { QueryCreator, sql } from "kysely";
2
+ import * as phpSerialize from "php-serialize";
3
+ import { EntityQuery } from "../../globals/entity-loader/entity-loader";
4
+ import { IPost } from "../../entities/post/post.interface";
5
+ import { PostQueryArgs } from "./post-query-args";
6
+ import { DB } from "nextpress/wpdb/wpdb.interface";
7
+ import { wpdb } from "nextpress/wpdb/wpdb";
8
+
9
+ /**
10
+ * Executes database queries to retrieve post IDs and counts based on provided arguments.
11
+ */
12
+ export class PostQuery implements EntityQuery<IPost>
13
+ {
14
+ private postCount?: number;
15
+
16
+ constructor(
17
+ private args: PostQueryArgs
18
+ ) {}
19
+
20
+ public getCount(): number | undefined {
21
+ return this.postCount;
22
+ }
23
+
24
+ public async getIds(): Promise<number[]> {
25
+ let builder = wpdb as QueryCreator<any>;
26
+
27
+ if (this.args.postAncestryOf) {
28
+ builder = builder.withRecursive('decendent_tree', (qb) =>
29
+ qb.selectFrom('wpPosts')
30
+ .select(['wpPosts.ID', 'wpPosts.postName', 'wpPosts.postParent'])
31
+ .where('wpPosts.postName', '=', this.args.postAncestryOf)
32
+ .unionAll(
33
+ qb.selectFrom('wpPosts as p')
34
+ .select(['p.ID', 'p.postName', 'p.postParent'])
35
+ .innerJoin('decendent_tree as d', 'p.postParent', 'd.ID')
36
+ )
37
+ )
38
+ }
39
+
40
+ let query = (builder as QueryCreator<DB>).selectFrom('wpPosts');
41
+
42
+ if (this.args.postAncestryOf) {
43
+ query = query.where('wpPosts.postName', 'in', (qb: any) =>
44
+ qb.selectFrom('decendent_tree').select('postName')
45
+ );
46
+ }
47
+
48
+ // --- ID Filters ---
49
+ if (this.args.postId) query = query.where('wpPosts.ID', '=', this.args.postId);
50
+ if (this.args.postIn) query = query.where('wpPosts.ID', 'in', this.args.postIn);
51
+ if (this.args.postNotIn) query = query.where('wpPosts.ID', 'not in', this.args.postNotIn);
52
+
53
+ if (this.args.path) {
54
+ query = query.where((eb) => eb.exists(
55
+ eb.selectFrom('wpPostmeta')
56
+ .select('postId')
57
+ .whereRef('postId', '=', 'wpPosts.ID')
58
+ .where('wpPostmeta.metaKey', '=', '_nextpress_path')
59
+ .where('wpPostmeta.metaValue', '=', this.args.path as string)
60
+ ));
61
+ }
62
+ // --- Type Filters ---
63
+ if (this.args.postType) {
64
+ const types = Array.isArray(this.args.postType) ? this.args.postType : [this.args.postType];
65
+ query = query.where('wpPosts.postType', 'in', types);
66
+ }
67
+ if (this.args.postTypeNot) {
68
+ const types = Array.isArray(this.args.postTypeNot) ? this.args.postTypeNot : [this.args.postTypeNot];
69
+ query = query.where('wpPosts.postType', 'not in', types);
70
+ }
71
+
72
+ // --- Status Filters ---
73
+ if (this.args.postStatus) {
74
+ const statuses = Array.isArray(this.args.postStatus) ? this.args.postStatus : [this.args.postStatus];
75
+ query = query.where('wpPosts.postStatus', 'in', statuses);
76
+ }
77
+
78
+ // --- Content Filters ---
79
+ if (this.args.postSlug) {
80
+ const postSlugs = Array.isArray(this.args.postSlug) ? this.args.postSlug : [this.args.postSlug];
81
+ query = query.where('wpPosts.postName', 'in', postSlugs);
82
+ }
83
+ if (this.args.title) query = query.where('wpPosts.postTitle', '=', this.args.title);
84
+ if (this.args.postMimeType) query = query.where('wpPosts.postMimeType', 'like', `%${this.args.postMimeType}%`);
85
+
86
+ // --- Parent Filters ---
87
+ if (this.args.postParent !== undefined) query = query.where('wpPosts.postParent', '=', this.args.postParent);
88
+ if (this.args.postParentIn) query = query.where('wpPosts.postParent', 'in', this.args.postParentIn);
89
+ if (this.args.postParentNotIn) query = query.where('wpPosts.postParent', 'not in', this.args.postParentNotIn);
90
+
91
+ // --- Term Filters ---
92
+ if (this.args.termId) {
93
+ query = query.innerJoin('wpTermRelationships', 'wpPosts.ID', 'wpTermRelationships.objectId')
94
+ .where('wpTermRelationships.termTaxonomyId', '=', this.args.termId);
95
+ }
96
+ if (this.args.termAnd) {
97
+ query = query.innerJoin('wpTermRelationships', 'wpPosts.ID', 'wpTermRelationships.objectId')
98
+ .where('wpTermRelationships.termTaxonomyId', 'in', this.args.termAnd)
99
+ .groupBy('wpPosts.ID')
100
+ .having((eb) => eb.fn.count('wpTermRelationships.termTaxonomyId'), '=', this.args.termAnd!.length);
101
+ }
102
+ if (this.args.termIn) {
103
+ query = query.innerJoin('wpTermRelationships', 'wpPosts.ID', 'wpTermRelationships.objectId')
104
+ .where('wpTermRelationships.termTaxonomyId', 'in', this.args.termIn);
105
+ }
106
+ if (this.args.termNotIn) {
107
+ query = query.where('wpPosts.ID', 'not in',
108
+ (qb) =>
109
+ qb.selectFrom('wpTermRelationships')
110
+ .select('wpTermRelationships.objectId')
111
+ .where('wpTermRelationships.termTaxonomyId', 'in', this.args.termNotIn!)
112
+ );
113
+ }
114
+ if (this.args.termSlug) {
115
+ query = query.innerJoin('wpTermRelationships', 'wpPosts.ID', 'wpTermRelationships.objectId')
116
+ .innerJoin('wpTerms', 'wpTermRelationships.termTaxonomyId', 'wpTerms.termId')
117
+ .where('wpTerms.slug', '=', this.args.termSlug)
118
+ .groupBy('wpPosts.ID');
119
+ }
120
+ if (this.args.termSlugAnd) {
121
+ query = query.innerJoin('wpTermRelationships', 'wpPosts.ID', 'wpTermRelationships.objectId')
122
+ .innerJoin('wpTerms', 'wpTermRelationships.termTaxonomyId', 'wpTerms.termId')
123
+ .where('wpTerms.slug', 'in', this.args.termSlugAnd)
124
+ .groupBy('wpPosts.ID')
125
+ .having((eb) => eb.fn.count('wpTermRelationships.termTaxonomyId'), '=', this.args.termSlugAnd!.length);
126
+ }
127
+ if (this.args.termSlugIn) {
128
+ query = query.innerJoin('wpTermRelationships', 'wpPosts.ID', 'wpTermRelationships.objectId')
129
+ .innerJoin('wpTerms', 'wpTermRelationships.termTaxonomyId', 'wpTerms.termId')
130
+ .where('wpTerms.slug', 'in', this.args.termSlugIn)
131
+ .groupBy('wpPosts.ID');
132
+ }
133
+
134
+ // --- Author Filters ---
135
+ if (this.args.authorId) query = query.where('wpPosts.postAuthor', '=', this.args.authorId);
136
+ if (this.args.authorIn) query = query.where('wpPosts.postAuthor', 'in', this.args.authorIn);
137
+ if (this.args.authorNotIn) query = query.where('wpPosts.postAuthor', 'not in', this.args.authorNotIn);
138
+ if (this.args.authorName) {
139
+ query = query.innerJoin('wpUsers', 'wpPosts.postAuthor', 'wpUsers.ID')
140
+ .where('wpUsers.displayName', '=', this.args.authorName);
141
+ }
142
+
143
+ // --- Search Filters ---
144
+ if (this.args.search) {
145
+ const searchTerm = this.args.exact ? this.args.search : `%${this.args.search}%`;
146
+ const searchCols = this.args.searchColumns || ['postTitle', 'postContent', 'postExcerpt'];
147
+ const isExact = this.args.exact;
148
+
149
+ query = query.where((eb) => {
150
+ const orClauses = searchCols.map(col => eb(col, isExact ? '=' : 'like', searchTerm));
151
+ return eb.or(orClauses);
152
+ });
153
+ }
154
+
155
+ // --- Date Filters ---
156
+ if (this.args.yyyymm) {
157
+ const mStr = String(this.args.yyyymm);
158
+ const y = Number(mStr.substring(0, 4));
159
+ const mon = Number(mStr.substring(4, 6));
160
+ query = query.where((eb) => eb.fn('YEAR', [eb.ref('wpPosts.postDate')]), '=', y)
161
+ .where((eb) => eb.fn('MONTH', [eb.ref('wpPosts.postDate')]), '=', mon);
162
+ }
163
+ if (this.args.year) query = query.where((eb) => eb.fn('YEAR', [eb.ref('wpPosts.postDate')]), '=', this.args.year);
164
+ if (this.args.monthnum) query = query.where((eb) => eb.fn('MONTH', [eb.ref('wpPosts.postDate')]), '=', this.args.monthnum);
165
+ if (this.args.w) query = query.where((eb) => eb.fn('WEEK', [eb.ref('wpPosts.postDate')]), '=', this.args.w);
166
+ if (this.args.day) query = query.where((eb) => eb.fn('DAY', [eb.ref('wpPosts.postDate')]), '=', this.args.day);
167
+ if (this.args.hour !== undefined) query = query.where((eb) => eb.fn('HOUR', [eb.ref('wpPosts.postDate')]), '=', this.args.hour);
168
+ if (this.args.minute !== undefined) query = query.where((eb) => eb.fn('MINUTE', [eb.ref('wpPosts.postDate')]), '=', this.args.minute);
169
+ if (this.args.second !== undefined) query = query.where((eb) => eb.fn('SECOND', [eb.ref('wpPosts.postDate')]), '=', this.args.second);
170
+
171
+ // -- Calculate Total Count (Before Limits/Offsets) --
172
+ if (!this.args.noFoundRows) {
173
+ try {
174
+ const countQueryBase = query.clearSelect().select('wpPosts.ID').distinct();
175
+ const countResult = await wpdb.selectFrom(countQueryBase.as('sub'))
176
+ .select(sql<number>`count(*)`.as('count'))
177
+ .executeTakeFirst();
178
+
179
+ this.postCount = countResult ? Number(countResult.count) : undefined;
180
+ } catch (error: any) {
181
+ console.error('WPPostQuery: Cannot get row count: ', error.message);
182
+ this.postCount = undefined;
183
+ }
184
+ } else {
185
+ this.postCount = undefined;
186
+ }
187
+
188
+ // -- Apply ORDER BY --
189
+ if (!this.args.ignoreStickyPosts) {
190
+ const rawStickyPostIds = await getOption('sticky_posts');
191
+
192
+ let stickyPosts: number[] = [];
193
+ try {
194
+ const parsed = phpSerialize.unserialize(rawStickyPostIds ?? 'a:0:{}');
195
+ stickyPosts = Object.values(parsed as Record<string, number> | number[]);
196
+ } catch (error) {
197
+ console.warn('WPPostQuery: Failed to parse sticky_posts option. Defaulting to empty.', error);
198
+ }
199
+
200
+ if (stickyPosts.length > 0) {
201
+ query = query.orderBy(
202
+ sql`CASE WHEN wp_posts.ID IN (${sql.join(stickyPosts)}) THEN 0 ELSE 1 END`,
203
+ 'asc'
204
+ );
205
+ }
206
+ }
207
+
208
+ const orderDirection = this.args.order === 'ASC' ? 'asc' : 'desc';
209
+ const orderBy = this.args.orderBy || 'none';
210
+
211
+ switch(orderBy) {
212
+ case 'none': break;
213
+ case 'id': query = query.orderBy('wpPosts.ID', orderDirection); break;
214
+ case 'author': query = query.orderBy('wpPosts.postAuthor', orderDirection).orderBy('wpPosts.ID', orderDirection); break;
215
+ case 'title': query = query.orderBy('wpPosts.postTitle', orderDirection).orderBy('wpPosts.ID', orderDirection); break;
216
+ case 'name': query = query.orderBy('wpPosts.postName', orderDirection).orderBy('wpPosts.ID', orderDirection); break;
217
+ case 'date': query = query.orderBy('wpPosts.postDate', orderDirection).orderBy('wpPosts.ID', orderDirection); break;
218
+ case 'modified': query = query.orderBy('wpPosts.postModified', orderDirection).orderBy('wpPosts.ID', orderDirection); break;
219
+ case 'parent': query = query.orderBy('wpPosts.postParent', orderDirection).orderBy('wpPosts.ID', orderDirection); break;
220
+ case 'menuOrder': query = query.orderBy('wpPosts.menuOrder', orderDirection).orderBy('wpPosts.ID', orderDirection); break;
221
+ case 'commentCount': query = query.orderBy('wpPosts.commentCount', orderDirection).orderBy('wpPosts.ID', orderDirection); break;
222
+ case 'rand': query = query.orderBy((eb) => eb.fn('RAND', [])).orderBy('wpPosts.ID', orderDirection); break;
223
+ default:
224
+ if (orderBy.startsWith('RAND(')) {
225
+ const seed = parseInt(orderBy.replace(/\D/g, ''), 10);
226
+ query = query.orderBy((eb) => eb.fn('RAND', [eb.val(seed)])).orderBy('wpPosts.ID', orderDirection);
227
+ } else {
228
+ query = query.orderBy('wpPosts.postDate', orderDirection).orderBy('wpPosts.ID', orderDirection);
229
+ }
230
+ break;
231
+ }
232
+
233
+ // -- Apply LIMIT & OFFSET --
234
+ if (!this.args.noPaging) {
235
+ const perPage = this.args.postsPerPage ?? 10;
236
+
237
+ if (perPage > -1) {
238
+ query = query.limit(perPage);
239
+
240
+ const page = this.args.page ?? 1;
241
+ const baseOffset = this.args.offset ?? 0;
242
+ const offsetAmount = ((page - 1) * perPage) + baseOffset;
243
+
244
+ if (offsetAmount > 0) {
245
+ query = query.offset(offsetAmount);
246
+ }
247
+ }
248
+ }
249
+
250
+ if (this.args.metaQuery) {
251
+ let dynamicQuery: any = query;
252
+
253
+ for (let metaQuery of this.args.metaQuery) {
254
+ const uniqueAlias = `meta_${metaQuery.as}`;
255
+
256
+ dynamicQuery = dynamicQuery.leftJoin(`wpPostmeta as ${uniqueAlias}`, (join: any) =>
257
+ join
258
+ .onRef(`${uniqueAlias}.postId`, '=', 'wpPosts.ID')
259
+ .on(`${uniqueAlias}.metaKey`, '=', metaQuery.metaKey)
260
+ )
261
+ .select(`${uniqueAlias}.metaValue as ${metaQuery.as}`);
262
+ }
263
+
264
+ query = dynamicQuery;
265
+ }
266
+
267
+ try {
268
+ if(this.args.multiple !== false) {
269
+ return (await query
270
+ .select('wpPosts.ID as id')
271
+ .groupBy('wpPosts.ID')
272
+ .execute()).map(res => res.id);
273
+ } else {
274
+ return (await query
275
+ .select('wpPosts.ID as id')
276
+ .execute()).map(res => res.id);
277
+ }
278
+ } catch (error: any) {
279
+ throw new Error(`WPPostQuery: Cannot get posts: ${error.message}`, { cause: error });
280
+ }
281
+ }
282
+ }
@@ -2,7 +2,7 @@
2
2
  * Defines the arguments for querying terms.
3
3
  * Maps standard WordPress WP_Term_Query parameters.
4
4
  */
5
- interface TermQueryArgs {
5
+ export interface TermQueryArgs {
6
6
  /** Taxonomy name, or array of taxonomy names, to which results should be limited. */
7
7
  taxonomy?: string | string[];
8
8
  /** Taxonomy ID, or array of term taxonomy IDs, to match when querying terms. */
@@ -22,7 +22,17 @@ interface TermQueryArgs {
22
22
  /** Whether to hide terms not assigned to any posts. Default true. */
23
23
  hideEmpty?: boolean;
24
24
  /** Field(s) to order terms by. Default 'none'. */
25
- orderBy?: 'term_id' | 'name' | 'slug' | 'term_group' | 'description' | 'parent' | 'term_order' | 'count' | 'none' | string;
25
+ orderBy?:
26
+ | 'term_id'
27
+ | 'name'
28
+ | 'slug'
29
+ | 'term_group'
30
+ | 'description'
31
+ | 'parent'
32
+ | 'term_order'
33
+ | 'count'
34
+ | 'none'
35
+ | string;
26
36
  /** Whether to order terms in ascending or descending order. Default 'ASC'. */
27
37
  order?: 'ASC' | 'DESC';
28
38
  /** Maximum number of terms to return. Accepts 0 (all) or any positive number. Default 0 (all). */
@@ -42,10 +52,10 @@ interface TermQueryArgs {
42
52
  /** Meta query */
43
53
  metaQuery?: {
44
54
  /** Meta key */
45
- metaKey: string;
55
+ metaKey: string,
46
56
  /** Variable name to save result to */
47
- as: string;
48
- }[];
57
+ as: string
58
+ }[]
49
59
  /** Whether to get multiple, default true */
50
- multiple?: boolean;
60
+ multiple?: boolean
51
61
  }