chore: initial snapshot of 2meet-data-optimizer v0.1.0
Baseline before backporting wp-data-optimizer v3.0.1-v3.4.6. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TbG1keQQ7XBa7qMQY16KCY
This commit is contained in:
@@ -0,0 +1,247 @@
|
||||
/**
|
||||
* WP Data Optimizer — REST API JavaScript SDK
|
||||
*
|
||||
* Lightweight client for /wp-json/wpdo/v1/ endpoints.
|
||||
* No dependencies required.
|
||||
*
|
||||
* Usage:
|
||||
* const wpdo = new WpdoClient();
|
||||
*
|
||||
* // Fetch listings (Zone A)
|
||||
* const { items, total } = await wpdo.getListings({ hp_price_min: 100, per_page: 20 });
|
||||
*
|
||||
* // Single listing (Zone A + Zone C)
|
||||
* const listing = await wpdo.getListing(123);
|
||||
*
|
||||
* // View count (Zone B)
|
||||
* const { view_count } = await wpdo.getStats(123);
|
||||
*
|
||||
* // Increment view count (Zone B, requires WP REST nonce)
|
||||
* const { view_count: updated } = await wpdo.incrementView(123);
|
||||
*
|
||||
* // Iterate all pages
|
||||
* for await (const page of wpdo.paginateListings({ hp_featured: 1 })) {
|
||||
* console.log(page.items);
|
||||
* }
|
||||
*
|
||||
* @package WP_Data_Optimizer
|
||||
*/
|
||||
|
||||
/* global wpdo_sdk_config */
|
||||
|
||||
( function ( global ) {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* WpdoClient — REST API wrapper for WP Data Optimizer.
|
||||
*
|
||||
* @param {object} [options]
|
||||
* @param {string} [options.baseUrl] REST base URL (default: auto-detected from wpdo_sdk_config or /wp-json)
|
||||
* @param {string} [options.nonce] WP REST nonce for authenticated requests
|
||||
* @param {string} [options.postType] Default post type (default: 'hp_listing')
|
||||
*/
|
||||
function WpdoClient( options ) {
|
||||
options = options || {};
|
||||
|
||||
var config = ( typeof wpdo_sdk_config !== 'undefined' ) ? wpdo_sdk_config : {};
|
||||
|
||||
this._base = options.baseUrl || config.rest_url || '/wp-json/wpdo/v1';
|
||||
this._nonce = options.nonce || config.nonce || '';
|
||||
this._postType = options.postType || config.post_type || 'hp_listing';
|
||||
}
|
||||
|
||||
// ── Core fetch ────────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* Internal GET fetch helper.
|
||||
*
|
||||
* @param {string} path Relative path (e.g. '/listings')
|
||||
* @param {object} params Query parameters
|
||||
* @return {Promise<{data: *, headers: Headers, status: number}>}
|
||||
*/
|
||||
WpdoClient.prototype._fetch = function ( path, params ) {
|
||||
var url = this._base + path;
|
||||
|
||||
if ( params && Object.keys( params ).length ) {
|
||||
var qs = Object.keys( params )
|
||||
.filter(
|
||||
function ( k ) {
|
||||
return params[ k ] !== null && params[ k ] !== undefined && params[ k ] !== ''; }
|
||||
)
|
||||
.map(
|
||||
function ( k ) {
|
||||
return encodeURIComponent( k ) + '=' + encodeURIComponent( params[ k ] ); }
|
||||
)
|
||||
.join( '&' );
|
||||
if ( qs ) {
|
||||
url += '?' + qs;
|
||||
}
|
||||
}
|
||||
|
||||
var headers = { 'Content-Type': 'application/json' };
|
||||
if ( this._nonce ) {
|
||||
headers[ 'X-WP-Nonce' ] = this._nonce;
|
||||
}
|
||||
|
||||
return fetch( url, { headers: headers } ).then(
|
||||
function ( res ) {
|
||||
return res.json().then(
|
||||
function ( data ) {
|
||||
return { data: data, headers: res.headers, status: res.status };
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Internal POST fetch helper.
|
||||
*
|
||||
* @param {string} path Relative path
|
||||
* @param {object} body JSON body (optional)
|
||||
* @return {Promise<{data: *, status: number}>}
|
||||
*/
|
||||
WpdoClient.prototype._post = function ( path, body ) {
|
||||
var headers = { 'Content-Type': 'application/json' };
|
||||
if ( this._nonce ) {
|
||||
headers[ 'X-WP-Nonce' ] = this._nonce;
|
||||
}
|
||||
|
||||
return fetch(
|
||||
this._base + path,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: headers,
|
||||
body: body ? JSON.stringify( body ) : null,
|
||||
}
|
||||
).then(
|
||||
function ( res ) {
|
||||
return res.json().then(
|
||||
function ( data ) {
|
||||
return { data: data, status: res.status };
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
// ── Public API ────────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* Fetch a page of listings from Zone A.
|
||||
*
|
||||
* @param {object} [params]
|
||||
* @param {string} [params.post_type] Default: configured post type
|
||||
* @param {number} [params.per_page] 1–100, default 20
|
||||
* @param {number} [params.page] Default 1
|
||||
* @param {string} [params.orderby] Column name, default 'post_id'
|
||||
* @param {string} [params.order] 'ASC' | 'DESC', default 'DESC'
|
||||
* @param {number} [params.*_min] Numeric range filter (e.g. hp_price_min)
|
||||
* @param {number} [params.*_max] Numeric range filter (e.g. hp_price_max)
|
||||
* @param {*} [params.*] Exact match filter (e.g. hp_featured: 1)
|
||||
* @return {Promise<{items: Array, total: number, totalPages: number}>}
|
||||
*/
|
||||
WpdoClient.prototype.getListings = function ( params ) {
|
||||
var merged = Object.assign( { post_type: this._postType }, params || {} );
|
||||
return this._fetch( '/listings', merged ).then(
|
||||
function ( res ) {
|
||||
return {
|
||||
items: res.data,
|
||||
total: parseInt( res.headers.get( 'X-WP-Total' ) || '0', 10 ),
|
||||
totalPages: parseInt( res.headers.get( 'X-WP-TotalPages' ) || '0', 10 ),
|
||||
status: res.status,
|
||||
};
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Fetch a single listing (Zone A + Zone C merged).
|
||||
*
|
||||
* @param {number} id Post ID
|
||||
* @return {Promise<object>}
|
||||
*/
|
||||
WpdoClient.prototype.getListing = function ( id ) {
|
||||
return this._fetch( '/listings/' + id, null ).then(
|
||||
function ( res ) {
|
||||
return res.data;
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Fetch Zone B view count for a post.
|
||||
*
|
||||
* @param {number} id Post ID
|
||||
* @return {Promise<{post_id: number, view_count: number}>}
|
||||
*/
|
||||
WpdoClient.prototype.getStats = function ( id ) {
|
||||
return this._fetch( '/stats/' + id, null ).then(
|
||||
function ( res ) {
|
||||
return res.data;
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Increment Zone B view count for a post (requires WP REST nonce).
|
||||
*
|
||||
* The nonce must be passed via the `nonce` constructor option or
|
||||
* via `wpdo_sdk_config.nonce` (wp_create_nonce('wp_rest')).
|
||||
*
|
||||
* @param {number} id Post ID
|
||||
* @return {Promise<{post_id: number, view_count: number}>}
|
||||
*
|
||||
* Example:
|
||||
* // Auto-tracks a view when a listing page loads:
|
||||
* document.addEventListener('DOMContentLoaded', () => {
|
||||
* const postId = parseInt(document.body.dataset.postId);
|
||||
* if (postId) wpdo.incrementView(postId);
|
||||
* });
|
||||
*/
|
||||
WpdoClient.prototype.incrementView = function ( id ) {
|
||||
return this._post( '/listings/' + id + '/view', null ).then(
|
||||
function ( res ) {
|
||||
return res.data;
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Async generator — iterates every page of listings.
|
||||
*
|
||||
* @param {object} [params] Same params as getListings (page is managed internally)
|
||||
* @yields {{items: Array, total: number, page: number, totalPages: number}}
|
||||
*
|
||||
* Example:
|
||||
* for await (const page of wpdo.paginateListings({ hp_featured: 1 })) {
|
||||
* page.items.forEach(item => console.log(item));
|
||||
* }
|
||||
*/
|
||||
WpdoClient.prototype.paginateListings = async function * ( params ) {
|
||||
var page = 1;
|
||||
var total = Infinity;
|
||||
var perPage = ( params && params.per_page ) ? params.per_page : 20;
|
||||
|
||||
while ( ( page - 1 ) * perPage < total ) {
|
||||
var merged = Object.assign( {}, params || {}, { page: page } );
|
||||
var result = await this.getListings( merged );
|
||||
total = result.total;
|
||||
yield { items: result.items, total: total, page: page, totalPages: result.totalPages };
|
||||
if ( page >= result.totalPages ) {
|
||||
break;
|
||||
}
|
||||
page++;
|
||||
}
|
||||
};
|
||||
|
||||
// ── Export ────────────────────────────────────────────────────────────────
|
||||
|
||||
global.WpdoClient = WpdoClient;
|
||||
|
||||
// Auto-instantiate as window.wpdo if config is present.
|
||||
if ( typeof wpdo_sdk_config !== 'undefined' ) {
|
||||
global.wpdo = new WpdoClient();
|
||||
}
|
||||
|
||||
}( window ) );
|
||||
Reference in New Issue
Block a user