Adds a 'Season taxonomy' setting (default empty) that points at an existing taxonomy registered against the destination post type. On every successful import the plugin reads itunes:season, looks up (or creates) a term with that numeric name in the configured taxonomy, and assigns it to the imported post via wp_set_object_terms. Behavior: - Empty option: no-op. Existing posts and installs without a season taxonomy are unaffected. - Tax that doesn't exist or isn't attached to the post type: no-op. - Feed item with no itunes:season: no-op. Manual taxonomy assignments are preserved on subsequent refreshes. - Otherwise: the feed value wins, on both create and update paths. The new assign_season_term() helper is public so it is unit-testable, and four smoke tests cover the lookup, create-on-miss, unconfigured, and no-season paths.
213 lines
6.0 KiB
PHP
213 lines
6.0 KiB
PHP
<?php
|
|
/**
|
|
* PHPUnit bootstrap.
|
|
*
|
|
* @package RSS2CPT
|
|
*/
|
|
|
|
define( 'ABSPATH', dirname( __DIR__ ) . '/' );
|
|
define( 'MINUTE_IN_SECONDS', 60 );
|
|
|
|
/**
|
|
* Minimal option stub for isolated settings tests.
|
|
*
|
|
* @param string $option Option name.
|
|
* @param mixed $default_value Default value.
|
|
* @return mixed
|
|
*/
|
|
function get_option( $option, $default_value = false ) {
|
|
unset( $option );
|
|
return $default_value;
|
|
}
|
|
|
|
/**
|
|
* Minimal wp_parse_args stub for isolated settings tests.
|
|
*
|
|
* @param array $args Supplied values.
|
|
* @param array $defaults Default values.
|
|
* @return array
|
|
*/
|
|
function wp_parse_args( $args, $defaults = array() ) {
|
|
return array_merge( $defaults, $args );
|
|
}
|
|
|
|
/**
|
|
* Minimal get_date_from_gmt stub matching WordPress's MySQL-string behavior.
|
|
*
|
|
* @param string $date_string GMT timestamp in MySQL date format.
|
|
* @return string Timestamp converted to the site's local timezone.
|
|
*/
|
|
function get_date_from_gmt( $date_string ) {
|
|
return get_gmt_from_date( $date_string );
|
|
}
|
|
|
|
/**
|
|
* Minimal get_gmt_from_date stub: the inverse of get_date_from_gmt.
|
|
*
|
|
* @param string $date_string Local timestamp in MySQL date format.
|
|
* @return string Timestamp converted to GMT (UTC).
|
|
*/
|
|
function get_gmt_from_date( $date_string ) {
|
|
$timestamp = strtotime( $date_string . ' UTC' );
|
|
if ( false === $timestamp ) {
|
|
return $date_string;
|
|
}
|
|
return gmdate( 'Y-m-d H:i:s', $timestamp );
|
|
}
|
|
|
|
/**
|
|
* In-memory option store for isolated tests.
|
|
*
|
|
* @param string $name Option name.
|
|
* @return bool Always true; the test asserts via $GLOBALS['rss2cpt_test_deleted_options'].
|
|
*/
|
|
function delete_option( $name ) {
|
|
$GLOBALS['rss2cpt_test_deleted_options'][] = $name;
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* In-memory site-transient store for isolated tests.
|
|
*
|
|
* @param string $name Transient name.
|
|
* @return bool Always true; the test asserts via $GLOBALS['rss2cpt_test_deleted_site_transients'].
|
|
*/
|
|
function delete_site_transient( $name ) {
|
|
$GLOBALS['rss2cpt_test_deleted_site_transients'][] = $name;
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Reset recorded delete_* call logs between tests.
|
|
*
|
|
* @return void
|
|
*/
|
|
function rss2cpt_test_reset_delete_logs() {
|
|
$GLOBALS['rss2cpt_test_deleted_options'] = array();
|
|
$GLOBALS['rss2cpt_test_deleted_site_transients'] = array();
|
|
}
|
|
|
|
/**
|
|
* Reset in-memory term/taxonomy stores between tests.
|
|
*
|
|
* @return void
|
|
*/
|
|
function rss2cpt_test_reset_term_stores() {
|
|
$GLOBALS['rss2cpt_test_taxonomies'] = array();
|
|
$GLOBALS['rss2cpt_test_object_in_taxonomy'] = array();
|
|
$GLOBALS['rss2cpt_test_terms'] = array();
|
|
$GLOBALS['rss2cpt_test_object_terms'] = array();
|
|
$GLOBALS['rss2cpt_test_next_term_id'] = 1;
|
|
}
|
|
rss2cpt_test_reset_delete_logs();
|
|
rss2cpt_test_reset_term_stores();
|
|
|
|
/**
|
|
* Minimal do_action stub for isolated tests.
|
|
*
|
|
* @param string $hook Hook name.
|
|
* @param mixed ...$args Hook arguments.
|
|
*/
|
|
function do_action( $hook, ...$args ) {
|
|
unset( $hook, $args );
|
|
}
|
|
|
|
/**
|
|
* In-memory taxonomy registry for isolated tests.
|
|
*
|
|
* Populate via $GLOBALS['rss2cpt_test_taxonomies'][$tax] = true.
|
|
*
|
|
* @param string $taxonomy Taxonomy slug.
|
|
* @return bool
|
|
*/
|
|
function taxonomy_exists( $taxonomy ) {
|
|
return ! empty( $GLOBALS['rss2cpt_test_taxonomies'][ (string) $taxonomy ] );
|
|
}
|
|
|
|
/**
|
|
* In-memory post-type/taxonomy attachment map for isolated tests.
|
|
*
|
|
* Populate via $GLOBALS['rss2cpt_test_object_in_taxonomy'][$post_type][$tax] = bool.
|
|
*
|
|
* @param string $post_type Post type slug.
|
|
* @param string $taxonomy Taxonomy slug.
|
|
* @return bool
|
|
*/
|
|
function is_object_in_taxonomy( $post_type, $taxonomy ) {
|
|
return ! empty( $GLOBALS['rss2cpt_test_object_in_taxonomy'][ (string) $post_type ][ (string) $taxonomy ] );
|
|
}
|
|
|
|
/**
|
|
* In-memory term store for isolated tests.
|
|
*
|
|
* Populate via $GLOBALS['rss2cpt_test_terms'][$tax][$name] = $term_id.
|
|
*
|
|
* @param string $field Field to look up (only 'name' is meaningful here).
|
|
* @param string|int $value Value to look up.
|
|
* @param string $taxonomy Taxonomy slug.
|
|
* @return object|null
|
|
*/
|
|
function get_term_by( $field, $value, $taxonomy ) {
|
|
$taxonomy = (string) $taxonomy;
|
|
if ( 'name' !== $field ) {
|
|
return null;
|
|
}
|
|
if ( empty( $GLOBALS['rss2cpt_test_terms'][ $taxonomy ][ (string) $value ] ) ) {
|
|
return null;
|
|
}
|
|
return (object) array( 'term_id' => (int) $GLOBALS['rss2cpt_test_terms'][ $taxonomy ][ (string) $value ] );
|
|
}
|
|
|
|
/**
|
|
* In-memory term creator for isolated tests.
|
|
*
|
|
* @param string $term Term name.
|
|
* @param string $taxonomy Taxonomy slug.
|
|
* @return array<string,int>|\WP_Error
|
|
*/
|
|
function wp_insert_term( $term, $taxonomy ) {
|
|
$taxonomy = (string) $taxonomy;
|
|
$term = (string) $term;
|
|
if ( ! isset( $GLOBALS['rss2cpt_test_terms'][ $taxonomy ] ) ) {
|
|
$GLOBALS['rss2cpt_test_terms'][ $taxonomy ] = array();
|
|
}
|
|
if ( isset( $GLOBALS['rss2cpt_test_terms'][ $taxonomy ][ $term ] ) ) {
|
|
return array( 'term_id' => (int) $GLOBALS['rss2cpt_test_terms'][ $taxonomy ][ $term ] );
|
|
}
|
|
$next = ( isset( $GLOBALS['rss2cpt_test_next_term_id'] ) ? (int) $GLOBALS['rss2cpt_test_next_term_id'] : 1 );
|
|
$GLOBALS['rss2cpt_test_next_term_id'] = $next + 1;
|
|
$GLOBALS['rss2cpt_test_terms'][ $taxonomy ][ $term ] = $next;
|
|
return array( 'term_id' => $next );
|
|
}
|
|
|
|
/**
|
|
* In-memory object-term linker for isolated tests.
|
|
*
|
|
* Records (post_id, term_ids[], taxonomy) on $GLOBALS['rss2cpt_test_object_terms'].
|
|
*
|
|
* @param int $object_id Object ID.
|
|
* @param array|string $terms Term IDs or slugs.
|
|
* @param string $taxonomy Taxonomy slug.
|
|
*/
|
|
function wp_set_object_terms( $object_id, $terms, $taxonomy ) {
|
|
$terms = array_map( 'intval', (array) $terms );
|
|
$GLOBALS['rss2cpt_test_object_terms'][] = array(
|
|
'object_id' => (int) $object_id,
|
|
'term_ids' => $terms,
|
|
'taxonomy' => (string) $taxonomy,
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Minimal is_wp_error stub: tests construct WP_Error objects by hand.
|
|
*
|
|
* @param mixed $thing Thing to check.
|
|
* @return bool
|
|
*/
|
|
function is_wp_error( $thing ) {
|
|
return $thing instanceof \WP_Error;
|
|
}
|
|
|
|
require_once dirname( __DIR__ ) . '/src/Options.php';
|
|
require_once dirname( __DIR__ ) . '/src/Import/Importer.php';
|