Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/tests-php.yml
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ jobs:
docker network prune -f
${SLIC_BIN} use ${GITHUB_REPOSITORY#*/}
${SLIC_BIN} composer set-version 2
${SLIC_BIN} composer install --ignore-platform-reqs
${SLIC_BIN} composer install
# ------------------------------------------------------------------------------
# Init WordPress container
# ------------------------------------------------------------------------------
Expand Down
6 changes: 5 additions & 1 deletion classes/PodsAPI.php
Original file line number Diff line number Diff line change
Expand Up @@ -4059,7 +4059,11 @@ public function save_field( $params, $table_operation = true, $sanitized = false
}
}
} elseif ( 0 < $sister_id ) {
update_post_meta( $sister_id, 'sister_id', $params->id );
// sister_id can be stale (e.g. from an imported package); only write
// the reciprocal reference onto an actual Pods field post.
if ( '_pods_field' === get_post_type( $sister_id ) ) {
update_post_meta( $sister_id, 'sister_id', $params->id );
}

if ( true === $db && pods_podsrel_enabled( $field, 'save' ) ) {
$sister_field = $this->load_field( [ 'id' => $sister_id ] );
Expand Down
202 changes: 202 additions & 0 deletions components/Migrate-Packages/Migrate-Packages.php
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,9 @@ public static function import( $data, $replace = false ) {
}//end if

if ( isset( $data['pods'] ) && is_array( $data['pods'] ) ) {
// Map source-site field IDs to pod/field names before import strips them.
$package_field_ids = self::get_package_field_ids( $data['pods'] );

foreach ( $data['pods'] as $pod_data ) {
$pod = self::import_pod( $pod_data, $replace );

Expand All @@ -221,6 +224,12 @@ public static function import( $data, $replace = false ) {

$found['pods'][ $pod['name'] ] = $pod['label'];
}//end foreach

// Second pass once all pods exist: remap bi-directional references,
// which the package stores as source-site sister_id post IDs.
if ( ! empty( $found['pods'] ) ) {
self::import_remap_sister_fields( self::get_package_sister_refs( $data['pods'] ), $package_field_ids );
}
}//end if

if ( isset( $data['templates'] ) && is_array( $data['templates'] ) ) {
Expand Down Expand Up @@ -315,6 +324,185 @@ public static function get_meta_from_package( array $data ) {
return $meta;
}

/**
* Map field IDs in the package data to their pod and field names.
*
* @since 3.3.2
*
* @param array $pods The list of pod data from the package.
*
* @return array Map of source-site field ID => [ 'pod' => pod name, 'field' => field name ].
*/
public static function get_package_field_ids( array $pods ) {
$field_ids = [];

foreach ( $pods as $pod_data ) {
$pod_name = pods_v( 'name', $pod_data );

if ( empty( $pod_name ) ) {
continue;
}

$field_lists = [];

if ( ! empty( $pod_data['groups'] ) && is_array( $pod_data['groups'] ) ) {
foreach ( $pod_data['groups'] as $group ) {
if ( ! empty( $group['fields'] ) && is_array( $group['fields'] ) ) {
$field_lists[] = $group['fields'];
}
}
}

if ( ! empty( $pod_data['fields'] ) && is_array( $pod_data['fields'] ) ) {
$field_lists[] = $pod_data['fields'];
}

foreach ( $field_lists as $fields ) {
foreach ( $fields as $field ) {
$field_id = (int) pods_v( 'id', $field, 0 );
$field_name = pods_v( 'name', $field );

if ( 0 < $field_id && ! empty( $field_name ) ) {
$field_ids[ $field_id ] = [
'pod' => $pod_name,
'field' => $field_name,
];
}
}
}
}

return $field_ids;
}

/**
* Collect the bi-directional references the package data carries.
*
* @since 3.3.2
*
* @param array $pods The list of pod data from the package.
*
* @return array Map of pod name => [ field name => [ 'sister_id' => int, 'sister_field' => string|null ] ].
*/
public static function get_package_sister_refs( array $pods ) {
$refs = [];

foreach ( $pods as $pod_data ) {
$pod_name = pods_v( 'name', $pod_data );

if ( empty( $pod_name ) ) {
continue;
}

$field_lists = [];

if ( ! empty( $pod_data['groups'] ) && is_array( $pod_data['groups'] ) ) {
foreach ( $pod_data['groups'] as $group ) {
if ( ! empty( $group['fields'] ) && is_array( $group['fields'] ) ) {
$field_lists[] = $group['fields'];
}
}
}

if ( ! empty( $pod_data['fields'] ) && is_array( $pod_data['fields'] ) ) {
$field_lists[] = $pod_data['fields'];
}

foreach ( $field_lists as $fields ) {
foreach ( $fields as $field ) {
$field_name = pods_v( 'name', $field );
$sister_id = (int) pods_v( 'sister_id', $field, 0 );
$sister_field = pods_v( 'sister_field', $field );

if ( empty( $field_name ) || ( $sister_id < 1 && empty( $sister_field ) ) ) {
continue;
}

$refs[ $pod_name ][ $field_name ] = [
'sister_id' => $sister_id,
'sister_field' => $sister_field,
];
}
}
}

return $refs;
}

/**
* Remap bi-directional (sister_id) references the package carried.
*
* The package stores sister_id as a source-site post ID. After all pods are
* saved, resolve each reference to the destination site's field ID — by the
* portable sister_field name when present, else by the package's old field
* ID — and save it. Unresolvable references are cleared to 0: a stale
* pointer is worse than none. Fields whose package data carried no sister
* reference are left untouched.
*
* @since 3.3.2
*
* @param array $package_sister_refs Map of pod name => [ field name => [ 'sister_id', 'sister_field' ] ].
* @param array $package_field_ids Map of source-site field ID => [ 'pod', 'field' ] names.
*/
public static function import_remap_sister_fields( array $package_sister_refs, array $package_field_ids ) {
// The pods were just saved; cached pod objects still carry pre-import args.
self::$api->cache_flush_pods();

foreach ( $package_sister_refs as $pod_name => $field_refs ) {
$pod = self::$api->load_pod( [ 'name' => $pod_name ], false );

if ( ! $pod instanceof \Pods\Whatsit\Pod ) {
continue;
}

foreach ( $field_refs as $field_name => $ref ) {
$field = $pod->get_field( $field_name );

if ( ! $field instanceof \Pods\Whatsit\Field || 'pick' !== $field->get_type() ) {
continue;
}

$related_pod = $field->get_related_object_name();

$resolved = null;

if ( $related_pod ) {
try {
// Prefer the portable name reference.
if ( ! empty( $ref['sister_field'] ) ) {
$resolved = self::$api->load_field( [
'name' => $ref['sister_field'],
'pod' => $related_pod,
] );
}

// Fall back to the package's source-site field ID.
if ( ! $resolved instanceof \Pods\Whatsit\Field && isset( $package_field_ids[ $ref['sister_id'] ] ) ) {
$resolved = self::$api->load_field( [
'name' => $package_field_ids[ $ref['sister_id'] ]['field'],
'pod' => $related_pod,
] );
}
} catch ( Exception $exception ) {
$resolved = null;
}
}

$new_sister_id = $resolved instanceof \Pods\Whatsit\Field ? (int) $resolved->get_id() : 0;

if ( $new_sister_id === (int) $field->get_arg( 'sister_id', 0 ) ) {
continue;
}

self::$api->save_field( [
'pod' => $pod,
'id' => $field->get_id(),
'sister_id' => $new_sister_id,
] );
}
}
}

/**
* Handle importing of the settings.
*
Expand Down Expand Up @@ -1038,6 +1226,20 @@ public static function export( $params ) {
}
}//end foreach

// sister_id is a source-site post ID; also emit the sister field name
// so import can resolve the bi-directional reference on the new site.
if ( 'pick' === pods_v( 'type', $field ) && 0 < (int) pods_v( 'sister_id', $field ) ) {
try {
$sister_field_obj = self::$api->load_field( [ 'id' => (int) pods_v( 'sister_id', $field ) ] );

if ( $sister_field_obj instanceof \Pods\Whatsit\Field ) {
$field['sister_field'] = $sister_field_obj->get_name();
}
} catch ( Exception $exception ) {
// Leave the field args unchanged if the sister field cannot be loaded.
}
}

$group['fields'][ $field_key ] = $field;
}//end foreach

Expand Down
26 changes: 24 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
"codeception/util-universalframework": "^1.0",
"dealerdirect/phpcodesniffer-composer-installer": "^1.2",
"dms/phpunit-arraysubset-asserts": "^0.5",
"fzaninotto/faker": "^1.9",
"fakerphp/faker": "^1.9.1",
"johnbillion/query-monitor": "dev-develop",
"lucatume/codeception-snapshot-assertions": "^1.4",
"lucatume/function-mocker": "^2.0",
Expand All @@ -73,10 +73,19 @@
"wp-cli/wp-cli": "^v2.12",
"wp-coding-standards/wpcs": "^3.3",
"wp-graphql/wp-graphql": "^v2.6",
"wpsyntex/polylang": "dev-master"
"wpsyntex/polylang": "^3.8.6"
},
"minimum-stability": "stable",
"prefer-stable": true,
"conflict": {
"symfony/console": ">=8",
"symfony/event-dispatcher": ">=8",
"symfony/finder": ">=8",
"symfony/property-info": ">=8",
"symfony/string": ">=8",
"symfony/type-info": ">=8",
"symfony/var-dumper": ">=8"
},
"suggest": {
"wp-cli/wp-cli": "Enables access to Pods CLI commands."
},
Expand Down Expand Up @@ -117,11 +126,24 @@
}
},
"config": {
"platform": {
"php": "8.2.99"
},
"allow-plugins": {
"composer/installers": true,
"dealerdirect/phpcodesniffer-composer-installer": true,
"kylekatarnls/update-helper": true,
"phpstan/extension-installer": true
},
"policy": {
"advisories": {
"ignore": {
"webonyx/graphql-php": {
"constraint": "15.29.3",
"reason": "wp-graphql v2.6.0 (latest release) pins this exact version; dev/test dependency only"
}
}
}
}
}
}
2 changes: 1 addition & 1 deletion init.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
* Text Domain: pods
* License: GPL v2 or later
* License URI: https://www.gnu.org/licenses/gpl-2.0.html
* Requires at least: 6.3
* Requires at least: 6.5
* Requires PHP: 7.2
* GitHub Plugin URI: https://github.com/pods-framework/pods
* Primary Branch: main
Expand Down
2 changes: 1 addition & 1 deletion readme.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
Contributors: sc0ttkclark, zrothauser, keraweb, jimtrue, quasel, nicdford, jamesgol, ramoonus, pglewis, dan.stefan, Desertsnowman, mgibbs189, Shelob9, clubduece, curtismchale, mikedamage, jchristopher, pcfreak30
Donate link: https://friends.pods.io/
Tags: pods, custom post types, custom taxonomies, content types, custom fields
Requires at least: 6.3
Requires at least: 6.5
Tested up to: 7.0
Requires PHP: 7.2
Stable tag: 3.3.9
Expand Down
Loading
Loading