Add website fields to project meta box
Adds a 'This project is a website' toggle to the Repository meta box. When checked, site fields (URL, platform, optional screenshot) replace the git-repo fields; when unchecked, repo fields are shown and site fields are cleared. Existing posts default to repo mode. - admin/metabox.php: checkbox, site URL/platform/screenshot inputs with media-library picker, JS toggle, save handler that switches modes - includes/helper-functions.php: projects_portfolio_is_website / get _site_url / get_site_platform / get_site_screenshot_url helpers - templates/single-projects.php: website-mode rendering (Visit Site button, platform row, screenshot) - tests/test-metabox.php: website-mode persistence + mode-switch tests - tests/wp-stubs.php: sanitize_text_field, absint stubs
This commit is contained in:
+151
-4
@@ -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,7 +43,19 @@ 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 );
|
||||
?>
|
||||
<p>
|
||||
<label>
|
||||
<input type="checkbox" id="projects_portfolio_is_website" name="projects_portfolio_is_website" value="1" <?php checked( $is_website, true ); ?> />
|
||||
<?php esc_html_e( 'This project is a website', 'projects-wp' ); ?>
|
||||
</label>
|
||||
</p>
|
||||
|
||||
<div class="projects-portfolio-repo-fields" <?php echo $is_website ? 'style="display:none;"' : ''; ?>>
|
||||
<p>
|
||||
<label for="projects_portfolio_provider"><?php esc_html_e( 'Provider', 'projects-wp' ); ?></label>
|
||||
<select id="projects_portfolio_provider" name="projects_portfolio_provider" style="width: 100%;">
|
||||
@@ -59,22 +72,110 @@ function projects_portfolio_render_meta_box( $post ) {
|
||||
<input type="url" id="projects_portfolio_gitea_base_url" name="projects_portfolio_gitea_base_url" value="<?php echo esc_attr( $gitea_base_url ); ?>" style="width: 100%;" placeholder="https://codeberg.org" />
|
||||
<span class="description"><?php esc_html_e( 'Leave blank to use the default from Settings.', 'projects-wp' ); ?></span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="projects-portfolio-website-fields"<?php echo $is_website ? '' : ' style="display:none;"'; ?>>
|
||||
<p>
|
||||
<label for="projects_portfolio_site_url"><?php esc_html_e( 'Site URL', 'projects-wp' ); ?></label>
|
||||
<input type="url" id="projects_portfolio_site_url" name="projects_portfolio_site_url" value="<?php echo esc_attr( $site_url ); ?>" style="width: 100%;" placeholder="https://example.com" />
|
||||
</p>
|
||||
<p>
|
||||
<label for="projects_portfolio_site_platform"><?php esc_html_e( 'Platform', 'projects-wp' ); ?></label>
|
||||
<textarea id="projects_portfolio_site_platform" name="projects_portfolio_site_platform" rows="3" style="width: 100%;" placeholder="<?php esc_attr_e( 'e.g. WordPress, custom Next.js, etc.', 'projects-wp' ); ?>"><?php echo esc_textarea( $site_platform ); ?></textarea>
|
||||
</p>
|
||||
<p>
|
||||
<label for="projects_portfolio_site_screenshot_id"><?php esc_html_e( 'Screenshot (optional)', 'projects-wp' ); ?></label>
|
||||
<span class="projects-portfolio-screenshot-preview" style="<?php echo $site_screenshot ? '' : 'display:none;'; ?> margin-right: 8px;">
|
||||
<?php if ( $site_screenshot ) : ?>
|
||||
<?php echo wp_get_attachment_image( $site_screenshot, 'thumbnail' ); // phpcs:ignore ?>
|
||||
<?php endif; ?>
|
||||
</span>
|
||||
<input type="hidden" id="projects_portfolio_site_screenshot_id" name="projects_portfolio_site_screenshot_id" value="<?php echo esc_attr( $site_screenshot ); ?>" />
|
||||
<button type="button" class="button projects-portfolio-screenshot-select"><?php esc_html_e( 'Select / Upload', 'projects-wp' ); ?></button>
|
||||
<button type="button" class="button projects-portfolio-screenshot-clear" <?php echo $site_screenshot ? '' : 'style="display:none;"'; ?>><?php esc_html_e( 'Remove', 'projects-wp' ); ?></button>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
(function(){
|
||||
var sel = document.getElementById('projects_portfolio_provider');
|
||||
if (!sel) return;
|
||||
if (sel) {
|
||||
var gitea = document.querySelector('.projects-portfolio-gitea-only');
|
||||
function toggle(){
|
||||
function toggleGitea(){
|
||||
if (!gitea) return;
|
||||
gitea.style.display = sel.value === 'gitea' ? '' : 'none';
|
||||
}
|
||||
sel.addEventListener('change', toggle);
|
||||
toggle();
|
||||
sel.addEventListener('change', toggleGitea);
|
||||
toggleGitea();
|
||||
}
|
||||
|
||||
var toggle = document.getElementById('projects_portfolio_is_website');
|
||||
if (toggle) {
|
||||
var repoBox = document.querySelector('.projects-portfolio-repo-fields');
|
||||
var siteBox = document.querySelector('.projects-portfolio-website-fields');
|
||||
function toggleMode(){
|
||||
var on = !!toggle.checked;
|
||||
if (repoBox) repoBox.style.display = on ? 'none' : '';
|
||||
if (siteBox) siteBox.style.display = on ? '' : 'none';
|
||||
}
|
||||
toggle.addEventListener('change', toggleMode);
|
||||
toggleMode();
|
||||
}
|
||||
|
||||
var frame;
|
||||
var selectBtn = document.querySelector('.projects-portfolio-screenshot-select');
|
||||
var clearBtn = document.querySelector('.projects-portfolio-screenshot-clear');
|
||||
var inputEl = document.getElementById('projects_portfolio_site_screenshot_id');
|
||||
var previewEl = document.querySelector('.projects-portfolio-screenshot-preview');
|
||||
function openFrame(){
|
||||
if (typeof wp === 'undefined' || !wp.media) { return; }
|
||||
frame = wp.media({
|
||||
title: '<?php echo esc_js( __( 'Select Screenshot', 'projects-wp' ) ); ?>',
|
||||
button: { text: '<?php echo esc_js( __( 'Use this image', 'projects-wp' ) ); ?>' },
|
||||
library: { type: 'image' },
|
||||
multiple: false
|
||||
});
|
||||
frame.on('select', function(){
|
||||
var attachment = frame.state().get('selection').first().toJSON();
|
||||
inputEl.value = attachment.id;
|
||||
previewEl.innerHTML = '<img src="' + attachment.sizes && attachment.sizes.thumbnail ? attachment.sizes.thumbnail.url : attachment.url + '" alt="" />';
|
||||
previewEl.style.display = '';
|
||||
clearBtn.style.display = '';
|
||||
});
|
||||
frame.open();
|
||||
}
|
||||
if (selectBtn) { selectBtn.addEventListener('click', openFrame); }
|
||||
if (clearBtn) {
|
||||
clearBtn.addEventListener('click', function(){
|
||||
inputEl.value = '';
|
||||
previewEl.innerHTML = '';
|
||||
previewEl.style.display = 'none';
|
||||
clearBtn.style.display = 'none';
|
||||
});
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue media picker assets for the project meta box.
|
||||
*
|
||||
* @since 1.4.0
|
||||
* @return void
|
||||
*/
|
||||
function projects_portfolio_enqueue_media_for_meta_box( $hook ) {
|
||||
if ( ! in_array( $hook, [ 'post.php', 'post-new.php' ], true ) ) {
|
||||
return;
|
||||
}
|
||||
$screen = function_exists( 'get_current_screen' ) ? get_current_screen() : null;
|
||||
if ( ! $screen || 'projects' !== $screen->post_type ) {
|
||||
return;
|
||||
}
|
||||
wp_enqueue_media();
|
||||
}
|
||||
add_action( 'admin_enqueue_scripts', 'projects_portfolio_enqueue_media_for_meta_box' );
|
||||
|
||||
/**
|
||||
* Save the Repository meta box.
|
||||
*
|
||||
@@ -103,6 +204,14 @@ function projects_portfolio_save_meta_box( $post_id ) {
|
||||
update_post_meta( $post_id, '_projects_portfolio_repo_url', $legacy_github );
|
||||
}
|
||||
|
||||
// "This project is a website" toggle — drives which set of fields is kept.
|
||||
$is_website = isset( $_POST['projects_portfolio_is_website'] ) && '1' === $_POST['projects_portfolio_is_website'];
|
||||
if ( $is_website ) {
|
||||
update_post_meta( $post_id, '_projects_portfolio_is_website', '1' );
|
||||
} else {
|
||||
delete_post_meta( $post_id, '_projects_portfolio_is_website' );
|
||||
}
|
||||
|
||||
if ( isset( $_POST['projects_portfolio_provider'] ) ) {
|
||||
$provider = ( 'gitea' === $_POST['projects_portfolio_provider'] ) ? 'gitea' : 'github';
|
||||
update_post_meta( $post_id, '_projects_portfolio_provider', $provider );
|
||||
@@ -130,5 +239,43 @@ function projects_portfolio_save_meta_box( $post_id ) {
|
||||
if ( isset( $_POST['projects_portfolio_gitea_base_url'] ) ) {
|
||||
update_post_meta( $post_id, '_projects_portfolio_gitea_base_url', esc_url_raw( wp_unslash( $_POST['projects_portfolio_gitea_base_url'] ) ) );
|
||||
}
|
||||
|
||||
// Website fields.
|
||||
if ( isset( $_POST['projects_portfolio_site_url'] ) ) {
|
||||
$site_url = esc_url_raw( wp_unslash( $_POST['projects_portfolio_site_url'] ) );
|
||||
if ( '' === $site_url ) {
|
||||
delete_post_meta( $post_id, '_projects_portfolio_site_url' );
|
||||
} else {
|
||||
update_post_meta( $post_id, '_projects_portfolio_site_url', $site_url );
|
||||
}
|
||||
}
|
||||
if ( isset( $_POST['projects_portfolio_site_platform'] ) ) {
|
||||
$platform = sanitize_text_field( wp_unslash( $_POST['projects_portfolio_site_platform'] ) );
|
||||
if ( '' === $platform ) {
|
||||
delete_post_meta( $post_id, '_projects_portfolio_site_platform' );
|
||||
} else {
|
||||
update_post_meta( $post_id, '_projects_portfolio_site_platform', $platform );
|
||||
}
|
||||
}
|
||||
if ( isset( $_POST['projects_portfolio_site_screenshot_id'] ) ) {
|
||||
$screenshot_id = absint( wp_unslash( $_POST['projects_portfolio_site_screenshot_id'] ) );
|
||||
if ( $screenshot_id <= 0 ) {
|
||||
delete_post_meta( $post_id, '_projects_portfolio_site_screenshot_id' );
|
||||
} else {
|
||||
update_post_meta( $post_id, '_projects_portfolio_site_screenshot_id', $screenshot_id );
|
||||
}
|
||||
}
|
||||
|
||||
// When modes switch, clear the opposite mode's fields so the project is cleanly one or the other.
|
||||
if ( $is_website ) {
|
||||
delete_post_meta( $post_id, '_projects_portfolio_provider' );
|
||||
delete_post_meta( $post_id, '_projects_portfolio_repo_url' );
|
||||
delete_post_meta( $post_id, '_projects_portfolio_gitea_base_url' );
|
||||
delete_post_meta( $post_id, '_projects_portfolio_github_url' );
|
||||
} else {
|
||||
delete_post_meta( $post_id, '_projects_portfolio_site_url' );
|
||||
delete_post_meta( $post_id, '_projects_portfolio_site_platform' );
|
||||
delete_post_meta( $post_id, '_projects_portfolio_site_screenshot_id' );
|
||||
}
|
||||
}
|
||||
add_action( 'save_post', 'projects_portfolio_save_meta_box' );
|
||||
|
||||
@@ -104,6 +104,56 @@ function projects_portfolio_get_repo_browse_url( int $post_id ): string {
|
||||
return projects_portfolio_get_provider( $post_id )->get_repo_browse_url();
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this project is configured as a website rather than a git repo.
|
||||
*
|
||||
* @since 1.4.0
|
||||
* @param int $post_id
|
||||
* @return bool
|
||||
*/
|
||||
function projects_portfolio_is_website( int $post_id ): bool {
|
||||
return (bool) get_post_meta( $post_id, '_projects_portfolio_is_website', true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Public URL for the project's website (when configured as a website).
|
||||
*
|
||||
* @since 1.4.0
|
||||
* @param int $post_id
|
||||
* @return string
|
||||
*/
|
||||
function projects_portfolio_get_site_url( int $post_id ): string {
|
||||
return (string) get_post_meta( $post_id, '_projects_portfolio_site_url', true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Platform label for the project's website (when configured as a website).
|
||||
*
|
||||
* @since 1.4.0
|
||||
* @param int $post_id
|
||||
* @return string
|
||||
*/
|
||||
function projects_portfolio_get_site_platform( int $post_id ): string {
|
||||
return (string) get_post_meta( $post_id, '_projects_portfolio_site_platform', true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Screenshot attachment URL for the project's website.
|
||||
*
|
||||
* @since 1.4.0
|
||||
* @param int $post_id
|
||||
* @param string $size
|
||||
* @return string
|
||||
*/
|
||||
function projects_portfolio_get_site_screenshot_url( int $post_id, string $size = 'large' ): string {
|
||||
$attachment_id = (int) get_post_meta( $post_id, '_projects_portfolio_site_screenshot_id', true );
|
||||
if ( $attachment_id <= 0 ) {
|
||||
return '';
|
||||
}
|
||||
$src = wp_get_attachment_image_src( $attachment_id, $size );
|
||||
return $src[0] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* GitHub API call for owner data
|
||||
*
|
||||
|
||||
@@ -13,23 +13,31 @@ $settings = projects_portfolio_settings();
|
||||
$project_id = get_the_ID();
|
||||
$download_count = (int) get_post_meta( $project_id, '_projects_portfolio_download_count', true );
|
||||
|
||||
$repo_url = get_post_meta( $project_id, '_projects_portfolio_repo_url', true );
|
||||
if ( '' === $repo_url ) {
|
||||
$is_website = projects_portfolio_is_website( $project_id );
|
||||
|
||||
if ( $is_website ) {
|
||||
$site_url = projects_portfolio_get_site_url( $project_id );
|
||||
$site_platform = projects_portfolio_get_site_platform( $project_id );
|
||||
$site_shot_url = projects_portfolio_get_site_screenshot_url( $project_id, 'large' );
|
||||
} else {
|
||||
$repo_url = get_post_meta( $project_id, '_projects_portfolio_repo_url', true );
|
||||
if ( '' === $repo_url ) {
|
||||
$repo_url = get_post_meta( $project_id, '_projects_portfolio_github_url', true );
|
||||
}
|
||||
|
||||
$repo_data = projects_portfolio_get_repo_data( $project_id );
|
||||
$version = projects_portfolio_get_version( $project_id );
|
||||
$owner = projects_portfolio_get_owner( $project_id );
|
||||
|
||||
$owner_avatar = $repo_data['owner']['avatar_url'] ?? '';
|
||||
$owner_name = $repo_data['owner']['login'] ?? '';
|
||||
$owner_url = $repo_data['owner']['html_url'] ?? '';
|
||||
$last_updated = $repo_data['updated_at'] ?? '';
|
||||
$language = $repo_data['language'] ?? '';
|
||||
$license = $repo_data['license']['name'] ?? 'None';
|
||||
$browse_url = $repo_url ? projects_portfolio_get_repo_browse_url( $project_id ) : '';
|
||||
}
|
||||
|
||||
$repo_data = projects_portfolio_get_repo_data( $project_id );
|
||||
$version = projects_portfolio_get_version( $project_id );
|
||||
$owner = projects_portfolio_get_owner( $project_id );
|
||||
|
||||
$owner_avatar = $repo_data['owner']['avatar_url'] ?? '';
|
||||
$owner_name = $repo_data['owner']['login'] ?? '';
|
||||
$owner_url = $repo_data['owner']['html_url'] ?? '';
|
||||
$last_updated = $repo_data['updated_at'] ?? '';
|
||||
$language = $repo_data['language'] ?? '';
|
||||
$license = $repo_data['license']['name'] ?? 'None';
|
||||
$browse_url = $repo_url ? projects_portfolio_get_repo_browse_url( $project_id ) : '';
|
||||
|
||||
if ( $last_updated ) {
|
||||
$last_updated = date_i18n( get_option( 'date_format' ), strtotime( $last_updated ) );
|
||||
}
|
||||
@@ -49,6 +57,13 @@ if ( $last_updated ) {
|
||||
</div>
|
||||
|
||||
<div class="project-main-content">
|
||||
<?php if ( ! empty( $site_shot_url ) ) : ?>
|
||||
<div class="project-screenshot">
|
||||
<a href="<?php echo esc_url( $site_url ); ?>" target="_blank" rel="noopener noreferrer">
|
||||
<img src="<?php echo esc_url( $site_shot_url ); ?>" alt="<?php echo esc_attr( get_the_title() ); ?>" />
|
||||
</a>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<div class="project-description">
|
||||
<h1 class="project-title">
|
||||
<?php
|
||||
@@ -68,7 +83,15 @@ if ( $last_updated ) {
|
||||
<a href="<?php echo esc_url( site_url( '/download/' . $project_id ) ); ?>" class="button project-download-button">
|
||||
<?php esc_html_e( 'Download Now', 'projects-wp' ); ?>
|
||||
</a>
|
||||
<?php if ( $repo_url ) : ?>
|
||||
<?php if ( $is_website ) : ?>
|
||||
<?php if ( ! empty( $site_url ) ) : ?>
|
||||
<a href="<?php echo esc_url( $site_url ); ?>" class="button project-repo-button" target="_blank" rel="noopener noreferrer">
|
||||
<?php esc_html_e( 'Visit Site', 'projects-wp' ); ?>
|
||||
</a>
|
||||
<?php else : ?>
|
||||
<p><?php esc_html_e( 'Website:', 'projects-wp' ); ?> <?php esc_html_e( 'No URL linked.', 'projects-wp' ); ?></p>
|
||||
<?php endif; ?>
|
||||
<?php elseif ( ! empty( $repo_url ) ) : ?>
|
||||
<a href="<?php echo esc_url( $browse_url ); ?>" class="button project-repo-button" target="_blank" rel="noopener noreferrer">
|
||||
<?php esc_html_e( 'View Repo', 'projects-wp' ); ?>
|
||||
</a>
|
||||
@@ -84,6 +107,14 @@ if ( $last_updated ) {
|
||||
?>
|
||||
<table class="project-meta-table">
|
||||
<tbody>
|
||||
<?php if ( $is_website ) : ?>
|
||||
<?php if ( $site_platform ) : ?>
|
||||
<tr>
|
||||
<th><?php esc_html_e( 'Platform:', 'projects-wp' ); ?></th>
|
||||
<td><?php echo nl2br( esc_html( $site_platform ) ); // phpcs:ignore ?></td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
<?php else : ?>
|
||||
<?php if ( $settings['templates']['version'] ) : ?>
|
||||
<tr>
|
||||
<th><?php esc_html_e( 'Version:', 'projects-wp' ); ?></th>
|
||||
@@ -141,12 +172,13 @@ if ( $last_updated ) {
|
||||
<?php
|
||||
endif;
|
||||
endif;
|
||||
endif; // end repo-mode meta rows (else branch of $is_website).
|
||||
?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<?php if ( $settings['templates']['github_owner'] && $owner_avatar && $owner_name ) : ?>
|
||||
<?php if ( ! $is_website && $settings['templates']['github_owner'] && $owner_avatar && $owner_name ) : ?>
|
||||
<div class="project-owner">
|
||||
<span class="project-owner-avatar" style="display:block !important;width:50px !important;height:50px !important;min-width:50px !important;min-height:50px !important;max-width:50px !important;max-height:50px !important;border-radius:50% !important;background-image:url('<?php echo esc_url( $owner_avatar ); ?>') !important;background-size:40px 40px !important;background-position:center center !important;background-repeat:no-repeat !important;flex-shrink:0 !important;flex-grow:0 !important;" aria-label="<?php echo esc_attr( $owner_name ); ?>" role="img"></span>
|
||||
<span class="project-owner-name">
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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' ) ) {
|
||||
|
||||
Reference in New Issue
Block a user