Remove REST API endpoints and related functionality from Oribi Sync

This commit is contained in:
Matt Batchelder
2026-02-21 13:07:41 -05:00
parent b01e7e0e88
commit 6c5e503eb2
4 changed files with 80 additions and 163 deletions

Binary file not shown.

View File

@@ -8,27 +8,47 @@
if ( ! defined( 'ABSPATH' ) ) exit; if ( ! defined( 'ABSPATH' ) ) exit;
// ─── Admin bar pull button (front-end) ───────────────────────────────────── // ─── Admin bar pull buttons (front-end) ─────────────────────────────────────
add_action( 'admin_bar_menu', function ( WP_Admin_Bar $wp_admin_bar ) { add_action( 'admin_bar_menu', function ( WP_Admin_Bar $wp_admin_bar ) {
// Front-end only, logged-in admins, singular pages/posts
if ( is_admin() ) return; if ( is_admin() ) return;
if ( ! is_user_logged_in() ) return; if ( ! is_user_logged_in() ) return;
if ( ! current_user_can( 'manage_options' ) ) return; if ( ! current_user_can( 'manage_options' ) ) return;
if ( ! is_singular() ) return;
$post = get_queried_object();
if ( ! $post instanceof WP_Post ) return;
// "Pull All" — visible everywhere on the front-end
$wp_admin_bar->add_node( [ $wp_admin_bar->add_node( [
'id' => 'oribi-sync-pull', 'id' => 'oribi-sync-pull-all',
'title' => '<span class="ab-icon dashicons dashicons-download" aria-hidden="true"></span><span class="ab-label">Pull Page</span>', 'title' => '<span class="ab-icon dashicons dashicons-update" aria-hidden="true"></span><span class="ab-label">Pull All</span>',
'href' => '#', 'href' => '#',
'meta' => [ 'meta' => [
'title' => 'Pull this page and theme from Git', 'title' => 'Pull all pages and theme from Git',
], ],
] ); ] );
// "Pull Page" — only on singular pages/posts
if ( is_singular() ) {
$post = get_queried_object();
if ( $post instanceof WP_Post ) {
$wp_admin_bar->add_node( [
'id' => 'oribi-sync-pull',
'title' => '<span class="ab-icon dashicons dashicons-download" aria-hidden="true"></span><span class="ab-label">Pull Page</span>',
'href' => '#',
'meta' => [
'title' => 'Pull this page and theme from Git',
],
] );
}
}
}, 100 ); }, 100 );
// AJAX handler for the admin bar "Pull All" button
add_action( 'wp_ajax_oribi_sync_pull_all_pages', function () {
check_ajax_referer( 'oribi_sync_pull_all_pages' );
if ( ! current_user_can( 'manage_options' ) ) wp_send_json_error( 'Permission denied.', 403 );
$result = oribi_sync_run();
$result['ok'] ? wp_send_json_success( $result ) : wp_send_json_error( $result, 500 );
} );
// AJAX handler for the admin bar pull button (no REST API exposure) // AJAX handler for the admin bar pull button (no REST API exposure)
add_action( 'wp_ajax_oribi_sync_pull_page', function () { add_action( 'wp_ajax_oribi_sync_pull_page', function () {
check_ajax_referer( 'oribi_sync_pull_page' ); check_ajax_referer( 'oribi_sync_pull_page' );
@@ -41,6 +61,57 @@ add_action( 'wp_ajax_oribi_sync_pull_page', function () {
$result['ok'] ? wp_send_json_success( $result ) : wp_send_json_error( $result, 500 ); $result['ok'] ? wp_send_json_success( $result ) : wp_send_json_error( $result, 500 );
} ); } );
// Front-end script for the "Pull All" admin bar button
add_action( 'wp_footer', function () {
if ( ! is_user_logged_in() ) return;
if ( ! current_user_can( 'manage_options' ) ) return;
if ( ! is_admin_bar_showing() ) return;
$ajax_url = admin_url( 'admin-ajax.php' );
$nonce_all = wp_create_nonce( 'oribi_sync_pull_all_pages' );
?>
<script>
(function () {
'use strict';
var btn = document.getElementById('wp-admin-bar-oribi-sync-pull-all');
if (!btn) return;
btn.addEventListener('click', function (e) {
e.preventDefault();
var link = btn.querySelector('a');
var label = btn.querySelector('.ab-label');
if (link) { link.style.opacity = '0.5'; link.style.pointerEvents = 'none'; }
if (label) { label.textContent = 'Pulling…'; }
var data = new URLSearchParams({
action: 'oribi_sync_pull_all_pages',
_ajax_nonce: <?php echo wp_json_encode( $nonce_all ); ?>
});
fetch(<?php echo wp_json_encode( $ajax_url ); ?>, {
method: 'POST',
credentials: 'same-origin',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: data.toString()
})
.then(function (r) { return r.json(); })
.then(function () {
var url = new URL(window.location.href);
url.searchParams.set('_nocache', Date.now());
window.location.replace(url.toString());
})
.catch(function (err) {
if (label) { label.textContent = 'Pull All'; }
if (link) { link.style.opacity = ''; link.style.pointerEvents = ''; }
alert('Oribi Sync pull failed: ' + err);
});
});
})();
</script>
<?php
} );
// Front-end script that wires up the admin bar pull button // Front-end script that wires up the admin bar pull button
add_action( 'wp_footer', function () { add_action( 'wp_footer', function () {
if ( ! is_user_logged_in() ) return; if ( ! is_user_logged_in() ) return;

View File

@@ -1,153 +0,0 @@
<?php
/**
* Oribi Sync — REST API endpoints.
*
* POST /wp-json/oribi-sync/v1/sync — Trigger a sync
* POST /wp-json/oribi-sync/v1/sync — With ?dry_run=1 for preview
* GET /wp-json/oribi-sync/v1/status — Get last sync status
* POST /wp-json/oribi-sync/v1/webhook — Webhook trigger (secret-based auth)
*/
if ( ! defined( 'ABSPATH' ) ) exit;
add_action( 'rest_api_init', function () {
// ── Trigger sync ──────────────────────────────────────────────────────
register_rest_route( 'oribi-sync/v1', '/sync', [
'methods' => 'POST',
'callback' => 'oribi_sync_rest_sync',
'permission_callback' => function () {
return current_user_can( 'manage_options' );
},
] );
// ── Sync status ───────────────────────────────────────────────────────
register_rest_route( 'oribi-sync/v1', '/status', [
'methods' => 'GET',
'callback' => 'oribi_sync_rest_status',
'permission_callback' => function () {
return current_user_can( 'manage_options' );
},
] );
// ── Push page to repo ──────────────────────────────────────────────────
register_rest_route( 'oribi-sync/v1', '/push', [
'methods' => 'POST',
'callback' => 'oribi_sync_rest_push',
'permission_callback' => function () {
return current_user_can( 'manage_options' );
},
] );
// ── Push all synced pages to repo ──────────────────────────────────────
register_rest_route( 'oribi-sync/v1', '/push-all', [
'methods' => 'POST',
'callback' => 'oribi_sync_rest_push_all',
'permission_callback' => function () {
return current_user_can( 'manage_options' );
},
] );
// ── Webhook (secret-based auth, no WP login required) ─────────────────
register_rest_route( 'oribi-sync/v1', '/webhook', [
'methods' => 'POST',
'callback' => 'oribi_sync_rest_webhook',
'permission_callback' => '__return_true', // Auth handled in callback
] );
} );
/**
* REST: Trigger sync.
*/
function oribi_sync_rest_sync( WP_REST_Request $request ): WP_REST_Response {
$dry_run = (bool) $request->get_param( 'dry_run' );
$result = oribi_sync_run( $dry_run );
// After pulling, push local changes back (skip during dry-run)
if ( ! $dry_run ) {
$push = oribi_sync_push_all();
$result['push'] = $push['results'];
}
return new WP_REST_Response( $result, $result['ok'] ? 200 : 500 );
}
/**
* REST: Get last sync status.
*/
function oribi_sync_rest_status(): WP_REST_Response {
return new WP_REST_Response( [
'last_run' => get_option( 'oribi_sync_last_run', null ),
'log' => array_slice( get_option( 'oribi_sync_log', [] ), 0, 5 ),
'repo' => get_option( 'oribi_sync_repo', '' ),
'branch' => get_option( 'oribi_sync_branch', 'main' ),
'provider' => oribi_sync_get_provider(),
'has_pat' => ! empty( get_option( 'oribi_sync_pat', '' ) ),
] );
}
/**
* REST: Webhook trigger.
*
* Validates using a shared secret stored in the WP option oribi_sync_webhook_secret
* or the constant ORIBI_SYNC_WEBHOOK_SECRET.
*
* Accepts GitHub-style X-Hub-Signature-256 header, or a simple
* Authorization: Bearer <secret> header.
*/
function oribi_sync_rest_webhook( WP_REST_Request $request ): WP_REST_Response {
$secret = defined( 'ORIBI_SYNC_WEBHOOK_SECRET' )
? ORIBI_SYNC_WEBHOOK_SECRET
: get_option( 'oribi_sync_webhook_secret', '' );
if ( empty( $secret ) ) {
return new WP_REST_Response( [ 'error' => 'Webhook secret not configured.' ], 403 );
}
// Check Authorization: Bearer <secret>
$auth = $request->get_header( 'Authorization' );
if ( $auth && preg_match( '/^Bearer\s+(.+)$/i', $auth, $m ) ) {
if ( ! hash_equals( $secret, $m[1] ) ) {
return new WP_REST_Response( [ 'error' => 'Invalid secret.' ], 403 );
}
}
// Check GitHub X-Hub-Signature-256
elseif ( $sig = $request->get_header( 'X-Hub-Signature-256' ) ) {
$body = $request->get_body();
$expected = 'sha256=' . hash_hmac( 'sha256', $body, $secret );
if ( ! hash_equals( $expected, $sig ) ) {
return new WP_REST_Response( [ 'error' => 'Invalid signature.' ], 403 );
}
} else {
return new WP_REST_Response( [ 'error' => 'Missing authentication.' ], 403 );
}
// Run sync
$result = oribi_sync_run();
return new WP_REST_Response( $result, $result['ok'] ? 200 : 500 );
}
/**
* REST: Push a single page to the repo.
*/
function oribi_sync_rest_push( WP_REST_Request $request ): WP_REST_Response {
$post_id = (int) $request->get_param( 'post_id' );
if ( $post_id < 1 ) {
return new WP_REST_Response( [ 'ok' => false, 'message' => 'Missing or invalid post_id.' ], 400 );
}
$opts = [];
$message = $request->get_param( 'message' );
if ( ! empty( $message ) ) {
$opts['message'] = sanitize_text_field( $message );
}
$result = oribi_sync_push_page( $post_id, $opts );
return new WP_REST_Response( $result, $result['ok'] ? 200 : 500 );
}
/**
* REST: Push all synced pages to the repo.
*/

View File

@@ -22,7 +22,6 @@ require_once ORIBI_SYNC_DIR . 'includes/sync-engine.php';
require_once ORIBI_SYNC_DIR . 'includes/push-client.php'; require_once ORIBI_SYNC_DIR . 'includes/push-client.php';
require_once ORIBI_SYNC_DIR . 'includes/post-sync.php'; require_once ORIBI_SYNC_DIR . 'includes/post-sync.php';
require_once ORIBI_SYNC_DIR . 'includes/admin.php'; require_once ORIBI_SYNC_DIR . 'includes/admin.php';
require_once ORIBI_SYNC_DIR . 'includes/rest.php';
require_once ORIBI_SYNC_DIR . 'includes/theme-preview.php'; require_once ORIBI_SYNC_DIR . 'includes/theme-preview.php';
// ─── Activation / Deactivation ──────────────────────────────────────────────── // ─── Activation / Deactivation ────────────────────────────────────────────────