Files
Keith Solomon 58a0b0c808 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
2026-08-22 15:16:51 -05:00

105 lines
3.5 KiB
PHP

<?php
namespace Brain\Monkey\Actions {
if ( ! function_exists( __NAMESPACE__ . '\\anyArgs' ) && function_exists( 'anyArgs' ) ) {
function anyArgs( ...$args ) { return \anyArgs( ...$args ); }
}
}
namespace {
// Shim: ensure Mockery's anyArgs() helper is loaded.
if ( ! function_exists( 'anyArgs' ) ) {
require_once dirname( __DIR__ ) . '/vendor/mockery/mockery/library/helpers.php';
}
// Define WP constants the helpers rely on.
if ( ! defined( 'HOUR_IN_SECONDS' ) ) {
define( 'HOUR_IN_SECONDS', 3600 );
}
if ( ! defined( 'WPINC' ) ) {
define( 'WPINC', 'wp-includes' );
}
if ( ! defined( 'ABSPATH' ) ) {
define( 'ABSPATH', __DIR__ . '/' );
}
// Provide minimal WordPress function stubs used by the providers under test.
if ( ! function_exists( 'get_option' ) ) {
function get_option( $key, $default = false ) { return $default; }
}
if ( ! function_exists( 'get_transient' ) ) {
function get_transient( $key ) { return false; }
}
if ( ! function_exists( 'set_transient' ) ) {
function set_transient( $key, $value, $expiration ) { return true; }
}
if ( ! function_exists( 'delete_transient' ) ) {
function delete_transient( $key ) { return true; }
}
if ( ! function_exists( 'wp_remote_get' ) ) {
function wp_remote_get( $url, $args = [] ) { return new \WP_Error( 'no_http', 'no http' ); }
}
if ( ! function_exists( 'is_wp_error' ) ) {
function is_wp_error( $thing ) { return $thing instanceof \WP_Error; }
}
if ( ! function_exists( 'wp_remote_retrieve_response_code' ) ) {
function wp_remote_retrieve_response_code( $response ) {
if ( $response instanceof \WP_Error ) { return 0; }
return $response['response']['code'] ?? 0;
}
}
if ( ! function_exists( 'wp_remote_retrieve_body' ) ) {
function wp_remote_retrieve_body( $response ) {
if ( $response instanceof \WP_Error ) { return ''; }
return $response['body'] ?? '';
}
}
if ( ! function_exists( 'wp_remote_retrieve_header' ) ) {
function wp_remote_retrieve_header( $response, $header ) {
if ( $response instanceof \WP_Error ) { return ''; }
$headers = $response['headers'] ?? [];
$key = strtolower( $header );
return $headers[ $key ] ?? '';
}
}
if ( ! function_exists( 'error_log' ) ) {
function error_log( $message ) { /* swallow during tests */ }
}
if ( ! function_exists( 'get_post_meta' ) ) {
function get_post_meta( $post_id, $key = '', $single = false ) { return ''; }
}
if ( ! function_exists( 'update_post_meta' ) ) {
function update_post_meta( $post_id, $key, $value ) { return true; }
}
if ( ! function_exists( 'delete_post_meta' ) ) {
function delete_post_meta( $post_id, $key ) { return true; }
}
if ( ! function_exists( 'wp_unslash' ) ) {
function wp_unslash( $value ) { return $value; }
}
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' ) ) {
class WP_Error {
private $code;
private $message;
public function __construct( $code = '', $message = '' ) {
$this->code = $code;
$this->message = $message;
}
public function get_error_code() { return $this->code; }
public function get_error_message() { return $this->message; }
}
}
}