diff --git a/admin/metabox.php b/admin/metabox.php
index e3a7b6c..0217a9a 100644
--- a/admin/metabox.php
+++ b/admin/metabox.php
@@ -33,6 +33,7 @@ add_action( 'add_meta_boxes', 'projects_portfolio_add_meta_boxes' );
function projects_portfolio_render_meta_box( $post ) {
wp_nonce_field( 'projects_portfolio_save_meta_box', 'projects_portfolio_meta_box_nonce' );
+ $is_website = (bool) get_post_meta( $post->ID, '_projects_portfolio_is_website', true );
$provider = get_post_meta( $post->ID, '_projects_portfolio_provider', true );
if ( '' === $provider ) {
$provider = 'github';
@@ -42,39 +43,139 @@ function projects_portfolio_render_meta_box( $post ) {
$repo_url = get_post_meta( $post->ID, '_projects_portfolio_github_url', true );
}
$gitea_base_url = get_post_meta( $post->ID, '_projects_portfolio_gitea_base_url', true );
+
+ $site_url = get_post_meta( $post->ID, '_projects_portfolio_site_url', true );
+ $site_platform = get_post_meta( $post->ID, '_projects_portfolio_site_platform', true );
+ $site_screenshot = (int) get_post_meta( $post->ID, '_projects_portfolio_site_screenshot_id', true );
?>
+
+
+
" class="button project-download-button">
-
+
+
+
+
+
+
+
+
+
@@ -84,7 +107,15 @@ if ( $last_updated ) {
?>
-
+
diff --git a/tests/test-metabox.php b/tests/test-metabox.php
index eb88532..5485d2a 100644
--- a/tests/test-metabox.php
+++ b/tests/test-metabox.php
@@ -142,4 +142,115 @@ class Metabox_Test extends \PHPUnit\Framework\TestCase {
$this->assertArrayNotHasKey( '_projects_portfolio_github_url', $existing );
$this->assertContains( '_projects_portfolio_github_url', $deleted );
}
+
+ public function test_website_mode_persists_website_fields_and_clears_repo_fields(): void {
+ $existing = [
+ '_projects_portfolio_provider' => 'github',
+ '_projects_portfolio_repo_url' => 'https://github.com/owner/repo',
+ '_projects_portfolio_github_url' => 'https://github.com/owner/repo',
+ ];
+ $deleted = [];
+ \Brain\Monkey\Functions\stubs( [
+ 'get_post_meta' => function ( $post_id, $key, $single = false ) use ( &$existing ) {
+ return $existing[ $key ] ?? '';
+ },
+ 'update_post_meta' => function ( $post_id, $key, $value ) use ( &$existing ) {
+ $existing[ $key ] = $value;
+ return true;
+ },
+ 'delete_post_meta' => function ( $post_id, $key ) use ( &$existing, &$deleted ) {
+ unset( $existing[ $key ] );
+ $deleted[] = $key;
+ return true;
+ },
+ 'wp_verify_nonce' => function () { return true; },
+ 'wp_nonce_field' => function () { /* noop */ },
+ ] );
+
+ $_POST['projects_portfolio_meta_box_nonce'] = 'nonce';
+ $_POST['projects_portfolio_is_website'] = '1';
+ $_POST['projects_portfolio_site_url'] = 'https://example.com';
+ $_POST['projects_portfolio_site_platform'] = 'WordPress';
+ $_POST['projects_portfolio_site_screenshot_id'] = '42';
+
+ projects_portfolio_save_meta_box( 11 );
+
+ $this->assertSame( '1', $existing['_projects_portfolio_is_website'] );
+ $this->assertSame( 'https://example.com', $existing['_projects_portfolio_site_url'] );
+ $this->assertSame( 'WordPress', $existing['_projects_portfolio_site_platform'] );
+ $this->assertSame( 42, $existing['_projects_portfolio_site_screenshot_id'] );
+
+ // Repo-mode fields should be cleared when switching to website mode.
+ $this->assertArrayNotHasKey( '_projects_portfolio_provider', $existing );
+ $this->assertArrayNotHasKey( '_projects_portfolio_repo_url', $existing );
+ $this->assertArrayNotHasKey( '_projects_portfolio_github_url', $existing );
+ $this->assertContains( '_projects_portfolio_provider', $deleted );
+ $this->assertContains( '_projects_portfolio_repo_url', $deleted );
+ $this->assertContains( '_projects_portfolio_github_url', $deleted );
+ }
+
+ public function test_unchecked_website_checkbox_clears_website_fields(): void {
+ $existing = [
+ '_projects_portfolio_is_website' => '1',
+ '_projects_portfolio_site_url' => 'https://example.com',
+ '_projects_portfolio_site_platform' => 'WordPress',
+ '_projects_portfolio_site_screenshot_id' => 42,
+ ];
+ $deleted = [];
+ \Brain\Monkey\Functions\stubs( [
+ 'get_post_meta' => function ( $post_id, $key, $single = false ) use ( &$existing ) {
+ return $existing[ $key ] ?? '';
+ },
+ 'update_post_meta' => function ( $post_id, $key, $value ) use ( &$existing ) {
+ $existing[ $key ] = $value;
+ return true;
+ },
+ 'delete_post_meta' => function ( $post_id, $key ) use ( &$existing, &$deleted ) {
+ unset( $existing[ $key ] );
+ $deleted[] = $key;
+ return true;
+ },
+ 'wp_verify_nonce' => function () { return true; },
+ 'wp_nonce_field' => function () { /* noop */ },
+ ] );
+
+ $_POST['projects_portfolio_meta_box_nonce'] = 'nonce';
+ // is_website is absent — repo mode is implied.
+
+ projects_portfolio_save_meta_box( 13 );
+
+ $this->assertArrayNotHasKey( '_projects_portfolio_is_website', $existing );
+ $this->assertArrayNotHasKey( '_projects_portfolio_site_url', $existing );
+ $this->assertArrayNotHasKey( '_projects_portfolio_site_platform', $existing );
+ $this->assertArrayNotHasKey( '_projects_portfolio_site_screenshot_id', $existing );
+ $this->assertContains( '_projects_portfolio_is_website', $deleted );
+ }
+
+ public function test_existing_repo_post_without_checkbox_keeps_repo_fields(): void {
+ $existing = [
+ '_projects_portfolio_provider' => 'github',
+ '_projects_portfolio_repo_url' => 'https://github.com/owner/repo',
+ ];
+ \Brain\Monkey\Functions\stubs( [
+ 'get_post_meta' => function ( $post_id, $key, $single = false ) use ( &$existing ) {
+ return $existing[ $key ] ?? '';
+ },
+ 'update_post_meta' => function ( $post_id, $key, $value ) use ( &$existing ) {
+ $existing[ $key ] = $value;
+ return true;
+ },
+ 'delete_post_meta' => function () { return true; },
+ 'wp_verify_nonce' => function () { return true; },
+ 'wp_nonce_field' => function () { /* noop */ },
+ ] );
+
+ $_POST['projects_portfolio_meta_box_nonce'] = 'nonce';
+ // is_website not present in $_POST — should be treated as unchecked.
+
+ projects_portfolio_save_meta_box( 17 );
+
+ $this->assertSame( 'github', $existing['_projects_portfolio_provider'] );
+ $this->assertSame( 'https://github.com/owner/repo', $existing['_projects_portfolio_repo_url'] );
+ $this->assertArrayNotHasKey( '_projects_portfolio_is_website', $existing );
+ }
}
diff --git a/tests/wp-stubs.php b/tests/wp-stubs.php
index 6bc1544..33b738f 100644
--- a/tests/wp-stubs.php
+++ b/tests/wp-stubs.php
@@ -80,6 +80,12 @@ if ( ! function_exists( 'wp_unslash' ) ) {
if ( ! function_exists( 'esc_url_raw' ) ) {
function esc_url_raw( $url ) { return $url; }
}
+if ( ! function_exists( 'sanitize_text_field' ) ) {
+ function sanitize_text_field( $str ) { return is_string( $str ) ? trim( $str ) : ''; }
+}
+if ( ! function_exists( 'absint' ) ) {
+ function absint( $maybeint ) { return abs( (int) $maybeint ); }
+}
// Minimal WP_Error stub if Brain\Monkey doesn't supply one.
if ( ! class_exists( 'WP_Error' ) ) {