@plasmicpkgs/wordpress 0.0.10 → 0.0.12

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.
package/dist/index.d.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import type { RulesLogic } from 'json-logic-js';
2
+
1
3
  export declare function _ensure<T>(x: T | null | undefined, message?: string): T;
2
4
 
3
5
  export declare type _QueryOperator = (typeof _queryOperators)[number]["value"];
@@ -13,14 +15,85 @@ export declare const _queryOperators: readonly [{
13
15
  readonly label: "Filter by author";
14
16
  }];
15
17
 
16
- export declare function queryWordpress({ wordpressUrl, queryType, queryOperator, filterValue, limit, }: QueryWordpressOpts): Promise<any>;
18
+ /**
19
+ * Query WordPress posts or pages with optional filtering, pagination, and ordering.
20
+ *
21
+ * @param opts - Query options including URL, content type, filter logic, pagination, and ordering
22
+ * @returns Promise resolving to the WordPress query response or raw items array for backward compatibility
23
+ *
24
+ * @example
25
+ * ```ts
26
+ * // Fetch all published posts
27
+ * const result = await queryWordpress({
28
+ * wordpressUrl: 'https://example.com',
29
+ * queryType: 'posts'
30
+ * });
31
+ *
32
+ * // Fetch with filters
33
+ * const filtered = await queryWordpress({
34
+ * wordpressUrl: 'https://example.com',
35
+ * queryType: 'posts',
36
+ * filterLogic: { "==": [{ var: "status" }, "publish"] },
37
+ * });
38
+ * ```
39
+ */
40
+ export declare function queryWordpress(opts: QueryWordpressOpts): Promise<QueryWordpressResponse | any>;
41
+
42
+ /**
43
+ * Query Wordpress with simplified filter props.
44
+ *
45
+ * @deprecated Use {@link queryWordpress} with `filterLogic` parameter instead.
46
+ *
47
+ * @example
48
+ * ```ts
49
+ * // Old way (deprecated)
50
+ * _queryWordpress({
51
+ * wordpressUrl: 'https://example.com',
52
+ * queryType: 'posts',
53
+ * queryOperator: 'status',
54
+ * filterValue: 'publish'
55
+ * });
56
+ *
57
+ * // New way
58
+ * queryWordpress({
59
+ * wordpressUrl: 'https://example.com',
60
+ * queryType: 'posts',
61
+ * filterLogic: { "==": [{ var: "status" }, "publish"] },
62
+ * });
63
+ * ```
64
+ */
65
+ export declare function _queryWordpress(opts: QueryWordpressOpts & QueryWordpressOldFilterProps): Promise<QueryWordpressResponse>;
66
+
67
+ /**
68
+ * @deprecated These filter props are deprecated. Use `filterLogic` with the query builder instead.
69
+ * Only used by the deprecated plasmic-wordpress package
70
+ */
71
+ declare interface QueryWordpressOldFilterProps {
72
+ queryOperator?: _QueryOperator;
73
+ filterValue?: string;
74
+ }
17
75
 
18
76
  declare interface QueryWordpressOpts {
19
77
  wordpressUrl?: string;
20
78
  queryType?: "pages" | "posts";
21
- queryOperator?: _QueryOperator;
22
- filterValue?: string;
79
+ /**
80
+ * Filter logic using JSON Logic format to filter WordPress entries.
81
+ * See {@link https://www.npmjs.com/package/@types/json-logic-js?activeTab=readme}
82
+ */
83
+ filterLogic?: RulesLogic;
23
84
  limit?: number;
85
+ page?: number;
86
+ offset?: number;
87
+ reverseOrder?: boolean;
88
+ orderby?: string;
89
+ }
90
+
91
+ declare interface QueryWordpressResponse {
92
+ items: any[];
93
+ total: number;
94
+ totalPages: number;
95
+ page: number;
96
+ perPage: number;
24
97
  }
25
98
 
26
99
  export declare function registerWordpress(loader?: {
package/dist/index.esm.js CHANGED
@@ -1,3 +1,22 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __defProps = Object.defineProperties;
3
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
4
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
7
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
8
+ var __spreadValues = (a, b) => {
9
+ for (var prop in b || (b = {}))
10
+ if (__hasOwnProp.call(b, prop))
11
+ __defNormalProp(a, prop, b[prop]);
12
+ if (__getOwnPropSymbols)
13
+ for (var prop of __getOwnPropSymbols(b)) {
14
+ if (__propIsEnum.call(b, prop))
15
+ __defNormalProp(a, prop, b[prop]);
16
+ }
17
+ return a;
18
+ };
19
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
1
20
  var __async = (__this, __arguments, generator) => {
2
21
  return new Promise((resolve, reject) => {
3
22
  var fulfilled = (value) => {
@@ -45,33 +64,344 @@ function ensure(x, message) {
45
64
  return x;
46
65
  }
47
66
  }
67
+ function cleanUrl(url) {
68
+ return url.replace(/\/$/, "");
69
+ }
70
+
71
+ // src/where.ts
72
+ var WORDPRESS_POST_FIELDS = {
73
+ id: {
74
+ type: "number",
75
+ label: "ID",
76
+ operators: ["equal", "not_equal"]
77
+ },
78
+ date: {
79
+ type: "datetime",
80
+ label: "Published Date",
81
+ operators: ["less", "greater"],
82
+ defaultOperator: "greater"
83
+ // this prevents "equals" operator from being shown by default
84
+ },
85
+ modified: {
86
+ type: "datetime",
87
+ label: "Modified Date",
88
+ operators: ["less", "greater"],
89
+ defaultOperator: "greater"
90
+ },
91
+ slug: {
92
+ type: "text",
93
+ label: "Slug",
94
+ operators: ["equal"]
95
+ },
96
+ author: {
97
+ type: "number",
98
+ label: "Author ID",
99
+ operators: ["equal", "not_equal"]
100
+ },
101
+ categories: {
102
+ type: "multiselect",
103
+ label: "Category",
104
+ operators: ["multiselect_contains", "multiselect_not_contains"],
105
+ defaultOperator: "multiselect_contains",
106
+ fieldSettings: {
107
+ listValues: []
108
+ // Will be populated dynamically
109
+ }
110
+ },
111
+ tags: {
112
+ type: "multiselect",
113
+ label: "Tag",
114
+ operators: ["multiselect_contains", "multiselect_not_contains"],
115
+ defaultOperator: "multiselect_contains",
116
+ fieldSettings: {
117
+ listValues: []
118
+ // Will be populated dynamically
119
+ }
120
+ },
121
+ sticky: {
122
+ type: "boolean",
123
+ label: "Sticky",
124
+ operators: ["equal"]
125
+ },
126
+ search: {
127
+ type: "text",
128
+ label: "Search",
129
+ operators: ["equal"]
130
+ },
131
+ search_columns: {
132
+ type: "multiselect",
133
+ label: "Search Columns",
134
+ operators: ["multiselect_contains"],
135
+ defaultOperator: "multiselect_contains",
136
+ fieldSettings: {
137
+ listValues: ["post_title", "post_content", "post_excerpt"]
138
+ }
139
+ }
140
+ };
141
+ var WORDPRESS_PAGE_FIELDS = {
142
+ id: WORDPRESS_POST_FIELDS.id,
143
+ date: WORDPRESS_POST_FIELDS.date,
144
+ modified: WORDPRESS_POST_FIELDS.modified,
145
+ slug: WORDPRESS_POST_FIELDS.slug,
146
+ author: WORDPRESS_POST_FIELDS.author,
147
+ search: WORDPRESS_POST_FIELDS.search,
148
+ search_columns: WORDPRESS_POST_FIELDS.search_columns,
149
+ // Page-specific fields
150
+ parent: {
151
+ type: "number",
152
+ label: "Parent Page",
153
+ operators: ["equal", "not_equal"]
154
+ },
155
+ menu_order: {
156
+ type: "number",
157
+ label: "Menu Order",
158
+ operators: ["equal"]
159
+ }
160
+ };
161
+ function fetchCategories(wordpressUrl) {
162
+ return __async(this, null, function* () {
163
+ try {
164
+ const url = `${cleanUrl(
165
+ wordpressUrl
166
+ )}/wp-json/wp/v2/categories?per_page=100`;
167
+ const resp = yield fetch(url);
168
+ if (!resp.ok) {
169
+ return [];
170
+ }
171
+ const categories = yield resp.json();
172
+ const formatted = categories.map((cat) => ({
173
+ value: cat.id,
174
+ title: cat.name
175
+ }));
176
+ return formatted;
177
+ } catch (error) {
178
+ console.error("Failed to fetch WordPress categories:", error);
179
+ return [];
180
+ }
181
+ });
182
+ }
183
+ function fetchTags(wordpressUrl) {
184
+ return __async(this, null, function* () {
185
+ try {
186
+ const url = `${cleanUrl(wordpressUrl)}/wp-json/wp/v2/tags?per_page=100`;
187
+ const resp = yield fetch(url);
188
+ if (!resp.ok) {
189
+ return [];
190
+ }
191
+ const tags = yield resp.json();
192
+ const formatted = tags.map((tag) => ({
193
+ value: tag.id,
194
+ title: tag.name
195
+ }));
196
+ return formatted;
197
+ } catch (error) {
198
+ console.error("Failed to fetch WordPress tags:", error);
199
+ return [];
200
+ }
201
+ });
202
+ }
203
+ function buildWordPressConfig(queryType, categories, tags) {
204
+ const fields = queryType === "posts" ? __spreadValues({}, WORDPRESS_POST_FIELDS) : __spreadValues({}, WORDPRESS_PAGE_FIELDS);
205
+ if (queryType === "posts" && categories && tags) {
206
+ fields.categories = __spreadProps(__spreadValues({}, fields.categories), {
207
+ fieldSettings: { listValues: categories }
208
+ });
209
+ fields.tags = __spreadProps(__spreadValues({}, fields.tags), {
210
+ fieldSettings: { listValues: tags }
211
+ });
212
+ }
213
+ return {
214
+ fields,
215
+ // WordPress REST API doesn't support OR logic natively
216
+ // Limit to AND-only combinations
217
+ conjunctions: {
218
+ AND: { label: "AND" }
219
+ },
220
+ settings: {
221
+ showNot: false,
222
+ // hides group controls (we don't want to support nested groups, because the only supported conjunction is AND)
223
+ maxNesting: 1
224
+ }
225
+ };
226
+ }
227
+ function rulesLogicToWordPressFilters(logic) {
228
+ if (logic === null || logic === void 0) {
229
+ return {};
230
+ } else if (typeof logic !== "object") {
231
+ throw new Error(`unexpected logic: ${JSON.stringify(logic)}`);
232
+ } else if ("and" in logic) {
233
+ return handleAndGroup(logic.and);
234
+ }
235
+ return handleCondition(logic);
236
+ }
237
+ function handleAndGroup(conditions) {
238
+ const filters = {};
239
+ for (const condition of conditions) {
240
+ const result = handleCondition(condition);
241
+ Object.assign(filters, result);
242
+ }
243
+ return filters;
244
+ }
245
+ function handleCondition(condition, negated = false) {
246
+ if ("some" in condition) {
247
+ const [fieldExpr, inExpr] = condition.some;
248
+ if ("var" in fieldExpr && "in" in inExpr && Array.isArray(inExpr.in) && inExpr.in.length === 2) {
249
+ const field = fieldExpr.var;
250
+ const values = inExpr.in[1];
251
+ return negated ? convertNotEqualOperator(field, values) : convertEqualOperator(field, values);
252
+ }
253
+ }
254
+ if ("!" in condition) {
255
+ return handleCondition(condition["!"], true);
256
+ }
257
+ if ("==" in condition) {
258
+ const [fieldExpr, value] = condition["=="];
259
+ if ("var" in fieldExpr) {
260
+ return convertEqualOperator(fieldExpr.var, value);
261
+ }
262
+ }
263
+ if ("!=" in condition) {
264
+ const [fieldExpr, value] = condition["!="];
265
+ if ("var" in fieldExpr) {
266
+ return convertNotEqualOperator(fieldExpr.var, value);
267
+ }
268
+ }
269
+ if ("<" in condition) {
270
+ const [fieldExpr, value] = condition["<"];
271
+ if ("var" in fieldExpr) {
272
+ return convertLessThanOperator(fieldExpr.var, value);
273
+ }
274
+ }
275
+ if (">" in condition) {
276
+ const [fieldExpr, right] = condition[">"];
277
+ if ("var" in fieldExpr) {
278
+ return convertGreaterThanOperator(fieldExpr.var, right);
279
+ }
280
+ }
281
+ throw new Error(
282
+ `Unsupported WordPress filter condition: ${JSON.stringify(condition)}`
283
+ );
284
+ }
285
+ function convertEqualOperator(field, value) {
286
+ if (field === "id") {
287
+ return { include: value };
288
+ }
289
+ return { [field]: value };
290
+ }
291
+ function convertNotEqualOperator(field, value) {
292
+ if (field === "id") {
293
+ return { exclude: value };
294
+ }
295
+ return { [`${field}_exclude`]: value };
296
+ }
297
+ function convertLessThanOperator(field, value) {
298
+ if (field === "date") {
299
+ return { before: value };
300
+ }
301
+ if (field === "modified") {
302
+ return { modified_before: value };
303
+ }
304
+ console.warn(
305
+ `WordPress: Less than operator not supported for field: ${field}`
306
+ );
307
+ return {};
308
+ }
309
+ function convertGreaterThanOperator(field, value) {
310
+ if (field === "date") {
311
+ return { after: value };
312
+ }
313
+ if (field === "modified") {
314
+ return { modified_after: value };
315
+ }
316
+ console.warn(
317
+ `WordPress: Greater than operator not supported for field: ${field}`
318
+ );
319
+ return {};
320
+ }
48
321
 
49
322
  // src/query-wordpress.ts
50
- function queryWordpress(_0) {
51
- return __async(this, arguments, function* ({
52
- wordpressUrl,
53
- queryType,
54
- queryOperator,
55
- filterValue,
56
- limit
57
- }) {
323
+ function _queryWordpress(opts) {
324
+ return __async(this, null, function* () {
325
+ const {
326
+ wordpressUrl,
327
+ queryType,
328
+ queryOperator,
329
+ filterValue,
330
+ filterLogic,
331
+ limit,
332
+ page,
333
+ offset,
334
+ reverseOrder,
335
+ orderby
336
+ } = opts;
58
337
  if (!wordpressUrl || !queryType) {
59
338
  throw new Error("Wordpress URL and query type are required");
60
339
  }
61
340
  const urlParams = new URLSearchParams();
62
- if (queryOperator && filterValue) {
341
+ if (filterLogic) {
342
+ const filters = rulesLogicToWordPressFilters(filterLogic);
343
+ appendFiltersToParams(urlParams, filters);
344
+ } else if (queryOperator && filterValue) {
63
345
  urlParams.append(queryOperator, filterValue);
64
346
  }
65
347
  if (limit) {
66
- urlParams.append("per_page", limit.toString());
348
+ urlParams.append("per_page", String(Math.min(limit, 100)));
67
349
  }
68
- const urlWithSlash = wordpressUrl.endsWith("/") ? wordpressUrl : `${wordpressUrl}/`;
69
- const url = new URL(`wp-json/wp/v2/${queryType}`, urlWithSlash);
350
+ if (page) {
351
+ urlParams.append("page", String(page));
352
+ }
353
+ if (offset) {
354
+ urlParams.append("offset", String(offset));
355
+ }
356
+ if (reverseOrder) {
357
+ urlParams.append("order", "asc");
358
+ }
359
+ if (orderby) {
360
+ urlParams.append("orderby", orderby);
361
+ }
362
+ const url = new URL(`wp-json/wp/v2/${queryType}`, cleanUrl(wordpressUrl));
70
363
  url.search = urlParams.toString();
71
364
  const resp = yield fetch(url);
72
- return yield resp.json();
365
+ if (!resp.ok) {
366
+ const errorText = yield resp.text();
367
+ let errorMessage = `WordPress API error (${resp.status})`;
368
+ try {
369
+ const errorJson = JSON.parse(errorText);
370
+ errorMessage = errorJson.message || errorMessage;
371
+ } catch (e) {
372
+ errorMessage += `: ${errorText}`;
373
+ }
374
+ throw new Error(errorMessage);
375
+ }
376
+ const items = yield resp.json();
377
+ const total = parseInt(resp.headers.get("X-WP-Total") || "0", 10);
378
+ const totalPages = parseInt(resp.headers.get("X-WP-TotalPages") || "0", 10);
379
+ return {
380
+ items,
381
+ total,
382
+ totalPages,
383
+ page: page || 1,
384
+ perPage: limit || 10
385
+ };
386
+ });
387
+ }
388
+ function queryWordpress(opts) {
389
+ return __async(this, null, function* () {
390
+ return _queryWordpress(opts);
73
391
  });
74
392
  }
393
+ function appendFiltersToParams(params, filters) {
394
+ for (const [key, value] of Object.entries(filters)) {
395
+ if (value === void 0 || value === null) {
396
+ continue;
397
+ }
398
+ if (Array.isArray(value)) {
399
+ params.append(key, value.join(","));
400
+ } else {
401
+ params.append(key, String(value));
402
+ }
403
+ }
404
+ }
75
405
  var queryWordpressMeta = {
76
406
  name: "queryWordpress",
77
407
  displayName: "Query WordPress",
@@ -83,28 +413,139 @@ var queryWordpressMeta = {
83
413
  display: "flatten",
84
414
  fields: {
85
415
  wordpressUrl: {
86
- type: "string"
416
+ type: "string",
417
+ displayName: "WordPress URL",
418
+ description: "Base URL of your WordPress site (e.g., https://example.com)",
419
+ helpText: "The root URL of your WordPress installation"
87
420
  },
88
421
  queryType: {
89
422
  type: "choice",
90
- options: ["pages", "posts"]
423
+ options: [
424
+ { label: "Posts", value: "posts" },
425
+ { label: "Pages", value: "pages" }
426
+ ],
427
+ displayName: "Content Type",
428
+ description: "Type of content to query",
429
+ defaultValue: "posts"
91
430
  },
92
- queryOperator: {
93
- type: "choice",
94
- options: Object.values(queryOperators).map((item) => ({
95
- label: item.label,
96
- value: item.value
97
- }))
431
+ filterLogic: {
432
+ type: "queryBuilder",
433
+ displayName: "Filters",
434
+ description: "Filter fetched entries. Defaults to fetch all entries.",
435
+ config: (_, ctx) => {
436
+ const { queryType, categories, tags } = ctx;
437
+ if (!queryType) {
438
+ return { fields: {} };
439
+ }
440
+ return buildWordPressConfig(queryType, categories, tags);
441
+ }
98
442
  },
99
- filterValue: {
100
- type: "string"
443
+ // Pagination
444
+ page: {
445
+ type: "number",
446
+ displayName: "Page",
447
+ description: "Page number for pagination (starts at 1)",
448
+ min: 1,
449
+ defaultValueHint: 1
101
450
  },
102
451
  limit: {
103
- type: "number"
452
+ type: "number",
453
+ displayName: "Items per page",
454
+ description: "Maximum number of items to return (max: 100)",
455
+ min: 1,
456
+ max: 100,
457
+ defaultValueHint: 10
458
+ },
459
+ offset: {
460
+ type: "number",
461
+ displayName: "Offset",
462
+ description: "Number of items to skip",
463
+ min: 0,
464
+ hidden: (opts) => !!opts.page,
465
+ // Hide if page is being used
466
+ defaultValueHint: 0
467
+ },
468
+ // Ordering
469
+ // One of: author, date, id, include, modified, parent, relevance, slug, include_slugs, title
470
+ orderby: {
471
+ type: "choice",
472
+ options: ([opts]) => [
473
+ {
474
+ label: "Relevance (search results)",
475
+ value: "relevance"
476
+ },
477
+ {
478
+ label: "Publish date",
479
+ value: "date"
480
+ },
481
+ {
482
+ label: "Last modified date",
483
+ value: "modified"
484
+ },
485
+ {
486
+ label: "Title (A\u2013Z)",
487
+ value: "title"
488
+ },
489
+ {
490
+ label: "Slug (URL)",
491
+ value: "slug"
492
+ },
493
+ {
494
+ label: "Author",
495
+ value: "author"
496
+ },
497
+ {
498
+ label: "ID",
499
+ value: "id"
500
+ },
501
+ ...(opts == null ? void 0 : opts.queryType) === "pages" ? [
502
+ {
503
+ label: "Menu order",
504
+ value: "menu_order"
505
+ },
506
+ {
507
+ label: "Parent page",
508
+ value: "parent"
509
+ }
510
+ ] : []
511
+ ],
512
+ displayName: "Sort by",
513
+ description: "Field to sort results by",
514
+ defaultValueHint: "date"
515
+ },
516
+ reverseOrder: {
517
+ type: "boolean",
518
+ displayName: "Reverse order",
519
+ description: "Reverse the order of the results",
520
+ defaultValueHint: false
104
521
  }
105
522
  }
106
523
  }
107
- ]
524
+ ],
525
+ fnContext: (wordpressOpts) => {
526
+ const { wordpressUrl, queryType } = wordpressOpts != null ? wordpressOpts : {};
527
+ if (!wordpressUrl || !queryType) {
528
+ return {
529
+ dataKey: "",
530
+ fetcher: () => __async(void 0, null, function* () {
531
+ return { categories: [], tags: [] };
532
+ })
533
+ };
534
+ }
535
+ return {
536
+ dataKey: `${wordpressUrl}:${queryType}`,
537
+ fetcher: () => __async(void 0, null, function* () {
538
+ if (queryType === "posts") {
539
+ const [categories, tags] = yield Promise.all([
540
+ fetchCategories(wordpressUrl),
541
+ fetchTags(wordpressUrl)
542
+ ]);
543
+ return { categories, tags, queryType };
544
+ }
545
+ return { categories: [], tags: [], queryType };
546
+ })
547
+ };
548
+ }
108
549
  };
109
550
 
110
551
  // src/index.ts
@@ -121,6 +562,7 @@ function registerWordpress(loader) {
121
562
  export {
122
563
  ensure as _ensure,
123
564
  queryOperators as _queryOperators,
565
+ _queryWordpress,
124
566
  queryWordpress,
125
567
  registerWordpress
126
568
  };