diff --git a/dist/oribi-tech-sync.zip b/dist/oribi-tech-sync.zip
index 7bde34e..e1ed639 100644
Binary files a/dist/oribi-tech-sync.zip and b/dist/oribi-tech-sync.zip differ
diff --git a/includes/admin.php b/includes/admin.php
index 1f070ff..3b303d0 100644
--- a/includes/admin.php
+++ b/includes/admin.php
@@ -35,12 +35,9 @@ add_action( 'admin_post_oribi_sync_save_settings', function () {
$provider = sanitize_text_field( wp_unslash( $_POST['oribi_sync_provider'] ?? '' ) );
$pat = wp_unslash( $_POST['oribi_sync_pat'] ?? '' );
- $pages_folder = sanitize_text_field( wp_unslash( $_POST['oribi_sync_pages_folder'] ?? '' ) );
-
update_option( 'oribi_sync_repo', $repo, 'no' );
update_option( 'oribi_sync_branch', $branch, 'no' );
update_option( 'oribi_sync_provider', $provider, 'no' );
- update_option( 'oribi_sync_pages_folder', $pages_folder, 'no' );
// Only update PAT if a new one was provided (non-empty)
if ( ! empty( $pat ) ) {
@@ -135,7 +132,6 @@ function oribi_sync_settings_page() {
$repo = get_option( 'oribi_sync_repo', '' );
$branch = get_option( 'oribi_sync_branch', 'main' );
$provider = get_option( 'oribi_sync_provider', '' );
- $pages_folder = get_option( 'oribi_sync_pages_folder', '' );
$has_pat = ! empty( get_option( 'oribi_sync_pat', '' ) );
$last_run = get_option( 'oribi_sync_last_run', '' );
$log = get_option( 'oribi_sync_log', [] );
@@ -251,22 +247,6 @@ function oribi_sync_settings_page() {
-
- |
-
-
-
-
- Sub-folder inside Pages/ to sync from.
- |
-
@@ -386,42 +366,6 @@ function oribi_sync_settings_page() {
-
-
'page',
+ 'meta_key' => '_oribi_sync_source',
+ 'numberposts' => 1,
+ 'fields' => 'ids',
+ ] );
+
+ if ( ! empty( $existing ) ) {
+ $source = get_post_meta( $existing[0], '_oribi_sync_source', true );
+ // Extract the repo-path portion after the last colon (skip 'https:').
+ $colon = strrpos( $source, ':' );
+ if ( $colon !== false ) {
+ $path_part = substr( $source, $colon + 1 ); // e.g. 'pages/about.php'
+ // Validate it looks like a pages/ path before trusting it.
+ if ( strncasecmp( $path_part, 'pages/', 6 ) === 0 ) {
+ return substr( $path_part, 0, 6 ); // preserve original casing
+ }
+ }
+ }
+
+ return 'pages/';
+}
+
// ─── Auto-push on page save ──────────────────────────────────────────────────
add_action( 'save_post_page', 'oribi_sync_maybe_push_on_save', 20, 3 );
@@ -242,18 +275,15 @@ function oribi_sync_generate_php_wrapper( string $content, string $slug, string
$title = oribi_sync_slug_to_title( $slug );
}
- $date = current_time( 'Y-m-d H:i:s' );
-
// Use a nowdoc so the content is treated as a literal string (no interpolation).
- // Escape the content if it accidentally contains the heredoc delimiter on its own line.
$delimiter = 'ORIBI_SYNC_CONTENT';
$safe_content = str_replace( "\n" . $delimiter, "\n " . $delimiter, $content );
$php = " false, 'action' => 'error', 'message' => 'Cannot determine repo path — no pages folder configured and no source meta on this page.' ];
- }
- $repo_path = 'Pages/' . $pages_folder . '/' . $post->post_name . '.php';
+ // Derive from slug — files live under pages/
+ $repo_path = 'pages/' . $post->post_name . '.php';
}
// ── Generate content ──────────────────────────────────────────────────
$slug = $post->post_name;
$title = $post->post_title;
$wp_content = $post->post_content;
- $php_source = oribi_sync_generate_php_wrapper( $wp_content, $slug, $title );
- $new_checksum = hash( 'sha256', $php_source );
$commit_msg = $opts['message'] ?? "Sync: update {$slug} from WordPress";
@@ -350,6 +411,14 @@ function oribi_sync_push_page( int $post_id, array $opts = [] ): array {
return [ 'ok' => false, 'action' => 'error', 'message' => 'Failed to check remote file: ' . $remote->get_error_message() ];
}
+ // Build PHP source: preserve original header for existing files, fresh wrapper for new ones.
+ if ( $remote !== null && ! empty( $remote['content'] ) ) {
+ $php_source = oribi_sync_replace_php_body( $remote['content'], $wp_content, $slug, $title );
+ } else {
+ $php_source = oribi_sync_generate_php_wrapper( $wp_content, $slug, $title );
+ }
+ $new_checksum = hash( 'sha256', $php_source );
+
$stored_sha = get_post_meta( $post_id, '_oribi_sync_git_sha', true );
// ── Decide strategy ───────────────────────────────────────────────────
diff --git a/includes/rest.php b/includes/rest.php
index 9103d79..23c768b 100644
--- a/includes/rest.php
+++ b/includes/rest.php
@@ -30,15 +30,6 @@ add_action( 'rest_api_init', function () {
},
] );
- // ── List Pages sub-folders from the repo ───────────────────────────
- register_rest_route( 'oribi-sync/v1', '/repo-folders', [
- 'methods' => 'GET',
- 'callback' => 'oribi_sync_rest_repo_folders',
- 'permission_callback' => function () {
- return current_user_can( 'manage_options' );
- },
- ] );
-
// ── Push page to repo ──────────────────────────────────────────────────
register_rest_route( 'oribi-sync/v1', '/push', [
'methods' => 'POST',
@@ -160,53 +151,3 @@ function oribi_sync_rest_push( WP_REST_Request $request ): WP_REST_Response {
/**
* REST: Push all synced pages to the repo.
*/
-function oribi_sync_rest_push_all( WP_REST_Request $request ): WP_REST_Response {
- $result = oribi_sync_push_all();
-
- return new WP_REST_Response( $result, $result['ok'] ? 200 : 500 );
-}
-
-/**
- * REST: List available sub-folders under Pages/ in the configured repository.
- *
- * Returns a JSON object: { folders: ["folder-a", "folder-b", …] }
- */
-function oribi_sync_rest_repo_folders(): WP_REST_Response {
- $repo_url = get_option( 'oribi_sync_repo', '' );
- $branch = get_option( 'oribi_sync_branch', 'main' ) ?: 'main';
- $pat = oribi_sync_get_pat();
-
- if ( empty( $repo_url ) || empty( $pat ) ) {
- return new WP_REST_Response( [ 'error' => 'Repository URL or PAT is not configured.' ], 400 );
- }
-
- $parsed = oribi_sync_parse_repo_url( $repo_url );
- if ( is_wp_error( $parsed ) ) {
- return new WP_REST_Response( [ 'error' => $parsed->get_error_message() ], 400 );
- }
-
- $provider = oribi_sync_get_provider();
- $api_base = oribi_sync_api_base( $provider, $parsed );
-
- $tree = oribi_sync_fetch_tree( $api_base, $branch, $provider, $pat );
- if ( is_wp_error( $tree ) ) {
- return new WP_REST_Response( [ 'error' => 'Tree fetch failed: ' . $tree->get_error_message() ], 500 );
- }
-
- // Find direct sub-directories of Pages/
- $folders = [];
- $prefix = 'Pages/';
- foreach ( $tree as $entry ) {
- if ( $entry['type'] !== 'tree' ) continue;
- if ( strpos( $entry['path'], $prefix ) !== 0 ) continue;
- $relative = substr( $entry['path'], strlen( $prefix ) );
- // Only direct children (no nested slash)
- if ( strpos( $relative, '/' ) !== false ) continue;
- if ( $relative === '' ) continue;
- $folders[] = $relative;
- }
-
- sort( $folders );
-
- return new WP_REST_Response( [ 'folders' => $folders ], 200 );
-}
diff --git a/includes/sync-engine.php b/includes/sync-engine.php
index 2859093..2f9ce88 100644
--- a/includes/sync-engine.php
+++ b/includes/sync-engine.php
@@ -9,6 +9,21 @@
if ( ! defined( 'ABSPATH' ) ) exit;
+// ─── Helpers ──────────────────────────────────────────────────────────────────
+
+/**
+ * Strip a case-insensitive directory prefix from a file path.
+ *
+ * Example: oribi_sync_strip_prefix( 'Theme/header.php', 'theme' ) → 'header.php'
+ */
+function oribi_sync_strip_prefix( string $path, string $prefix ): string {
+ $prefix = rtrim( $prefix, '/' ) . '/';
+ if ( strncasecmp( $path, $prefix, strlen( $prefix ) ) === 0 ) {
+ return substr( $path, strlen( $prefix ) );
+ }
+ return $path;
+}
+
// ─── Gutenberg block helpers ──────────────────────────────────────────────────
/** Generate a self-closing block comment (standalone or child blocks). */
@@ -129,18 +144,12 @@ function oribi_sync_run( bool $dry_run = false ): array {
return $result;
}
- // ── Filter to selected Pages sub-folder ────────────────────────────────
- $pages_folder = get_option( 'oribi_sync_pages_folder', '' );
+ // ── Filter to Pages/ directory ─────────────────────────────────────────
$synced_slugs = [];
+ $page_files = oribi_sync_filter_tree( $tree, 'Pages' );
- if ( empty( $pages_folder ) ) {
- $result['skipped'][] = 'Pages sync skipped — no folder selected in settings.';
- $page_files = [];
- } else {
- $page_files = oribi_sync_filter_tree( $tree, 'Pages/' . $pages_folder );
- if ( empty( $page_files ) ) {
- $result['errors'][] = 'No files found under Pages/' . $pages_folder . '/ in the repository.';
- }
+ if ( empty( $page_files ) ) {
+ $result['skipped'][] = 'No files found under Pages/ in the repository.';
}
// ── Process each page file ─────────────────────────────────────────────
@@ -274,7 +283,7 @@ function oribi_sync_run( bool $dry_run = false ): array {
}
// ── Trash pages removed from repo ──────────────────────────────────────
- if ( ! $dry_run && ! empty( $pages_folder ) ) {
+ if ( ! $dry_run ) {
$trashed = oribi_sync_trash_removed_pages( $synced_slugs );
$result['trashed'] = $trashed;
}
@@ -456,7 +465,7 @@ function oribi_sync_apply_theme_files( string $api_base, string $branch, string
$theme_entries = oribi_sync_filter_tree( $tree, 'theme', true );
foreach ( $theme_entries as $entry ) {
- $relative = substr( $entry['path'], strlen( 'theme/' ) );
+ $relative = oribi_sync_strip_prefix( $entry['path'], 'theme' );
$ext = strtolower( pathinfo( $relative, PATHINFO_EXTENSION ) );
if ( ! in_array( $ext, $allowed, true ) ) {
@@ -540,7 +549,7 @@ function oribi_sync_fetch_theme_files(): array {
foreach ( $theme_entries as $entry ) {
// Derive relative path by stripping the 'theme/' prefix
- $relative = substr( $entry['path'], strlen( 'theme/' ) );
+ $relative = oribi_sync_strip_prefix( $entry['path'], 'theme' );
$content = oribi_sync_fetch_file( $api_base, $branch, $entry['path'], $provider, $pat );
if ( is_wp_error( $content ) ) {