Skip to content

Instantly share code, notes, and snippets.

@rmpel
Last active August 9, 2024 10:16
Show Gist options
  • Save rmpel/78a710f2d0c3cabffab7cace0b438944 to your computer and use it in GitHub Desktop.
Save rmpel/78a710f2d0c3cabffab7cace0b438944 to your computer and use it in GitHub Desktop.
ACF FieldGroups Deduplication
<?php
/**
* Sometimes, shit happens and you end up with duplication of ACF FieldGroups.
* This mu-plugin will fix that.
* It is also compatible with ACF-to-PHP.
*/
add_action( 'admin_init', 'deduplicate_acf_data' );
function deduplicate_acf_data() {
if ( empty( $_SERVER ) && 'cli' !== php_sapi_name() ) {
// not CLI and not a web request, bail.
return;
}
if ( ! current_user_can( 'manage_options' ) ) {
return;
}
if ( $_SERVER['REQUEST_METHOD'] !== 'GET' ) {
return;
}
if ( ! is_admin() ) {
return;
}
if ( ( $_GET['acf-deduplicated'] ?? 0 ) > 2 ) {
wp_die( 'ACF deduplication is stuck in a loop.' );
}
global $wpdb;
$acf_groups = $wpdb->get_results( "SELECT ID, post_title, post_name FROM {$wpdb->prefix}posts WHERE post_type = 'acf-field-group' ORDER BY ID" );
$acf_groups_unique = $wpdb->get_col( "SELECT DISTINCT(post_name) FROM {$wpdb->prefix}posts WHERE post_type = 'acf-field-group'" );
// Check for duplication.
if ( count( $acf_groups ) === count( $acf_groups_unique ) ) {
return;
}
// Disable ACF to PHP sync temporarily.
add_filter( 'pre_option_acf_to_php_enable_sync', '__return_null' );
// There is duplication.
// Find all IDs of the duplicated ACF groups, except the first one found.
$duplicated_ids = [];
foreach ( $acf_groups as $acf_group ) {
if ( in_array( $acf_group->post_name, $acf_groups_unique, true ) && ! array_key_exists( $acf_group->post_name, $duplicated_ids ) ) {
// This is the first occurrence of this ACF group, we create the empty list, we continue thereby skipping this first record.
$duplicated_ids[ $acf_group->post_name ] = [];
} else {
// This is a duplicate.
$duplicated_ids[ $acf_group->post_name ][] = $acf_group->ID;
}
}
// With duplicated field-groups, come duplicated fields.
// We will just delete the duplicated fields, and trigger an ACF refresh by reducing the "last_modified" field of the ACF field-group.
foreach ( $duplicated_ids as $acf_group_name => $acf_group_ids ) {
// We will keep the first ACF field-group, and delete the rest.
foreach ( $acf_group_ids as $acf_group_id_to_delete ) {
$wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}posts WHERE post_type = 'acf-field-group' AND ID = %d", $acf_group_id_to_delete ) );
}
// Trigger an ACF refresh by reducing the "last_modified" field of the ACF field-group.
$wpdb->query( $wpdb->prepare( "UPDATE {$wpdb->prefix}posts SET post_modified = post_modified - 1, post_modified_gmt = post_modified_gmt - 1 WHERE post_name = %s", $acf_group_name ) );
}
// Cleanup acf-fields.
$orphan_post_ids = $wpdb->get_col( "SELECT ID FROM wp_posts WHERE post_parent NOT IN (SELECT ID FROM wp_posts WHERE post_type = 'acf-field-group') AND post_type = 'acf-field'" );
foreach ( $orphan_post_ids as $orphan_post_id ) {
$wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}posts WHERE ID = %d", $orphan_post_id ) );
}
// reload the page.
$deduplicated_count = $_GET['acf-deduplicated'] ?? 0;
$deduplicated_count++;
wp_redirect( add_query_arg( 'acf-deduplicated', $deduplicated_count, $_SERVER['REQUEST_URI'] ) );
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment