When you click 'Merge Contacts', all associated records will be moved onto the contact selected as the primary contact, and all other contacts will be deleted.
';
$contact = new PH_Contact( (int)$contact_id );
// Initialise array to hold information about each contact
$contact_parts = array( '
' . ( trim($contact->post_title) != '' ? $contact->post_title : '(' . __('Unnamed Contact', 'propertyhive' ) . ')' ) . ' ' ) ;
$date_posted = get_the_date( '', $contact->id );
$contact_parts[] = 'Added on ' . $date_posted;
// Add contact address to contact parts
if ( $contact->get_formatted_full_address() != '' )
{
$contact_parts[] = $contact->get_formatted_full_address();
}
// Add email address and number to contact parts, if set
$email_address = $contact->_email_address;
$telephone_number = $contact->_telephone_number;
if ( !empty( $email_address ) || !empty( $telephone_number ) )
{
$contact_details_array = array_filter(array(
$contact->_email_address,
$contact->_telephone_number
));
$contact_parts[] = implode( ', ', $contact_details_array );
}
// Display all selected contact types. This may be redundant when all profiles are displayed
$contact_types = $contact->_contact_types;
if ( !empty( $contact_types ) )
{
$contact_types_lookup = array(
'owner' => __( 'Owner', 'propertyhive' ),
'potentialowner' => __( 'Potential Owner', 'propertyhive' ),
'applicant' => __( 'Applicant', 'propertyhive' ),
'hotapplicant' => __( 'Hot Applicant', 'propertyhive' ),
'thirdparty' => __( 'Third Party Contact', 'propertyhive' ),
);
$contact_types_array = array();
foreach( $contact_types as $contact_type )
{
if ( isset( $contact_types_lookup[$contact_type] ) )
{
$contact_types_array[] = $contact_types_lookup[$contact_type];
}
else
{
$contact_types_array[] = ucfirst($contact_type);
}
}
$contact_parts[] = implode( ', ', $contact_types_array );
}
$contact_parts = $this->get_property_owner_records( $contact, $contact_parts );
$contact_parts = $this->get_potential_owner_records( $contact, $contact_parts );
$contact_parts = $this->get_third_party_records( $contact, $contact_parts );
$contact_parts = $this->get_applicant_records( $contact, $contact_parts );
$contact_parts = $this->get_enquiry_records( $contact, $contact_parts );
$contact_parts = $this->get_viewing_records( $contact, $contact_parts );
$contact_parts = $this->get_offer_records( $contact, $contact_parts );
$contact_parts = $this->get_sale_records( $contact, $contact_parts );
$contact_parts = $this->get_tenancy_records( $contact, $contact_parts );
$contact_parts = $this->get_note_records( $contact, $contact_parts );
// Stored contact details may contain markup; sanitize before the trusted extension HTML filter.
$contact_parts = array_map( 'wp_kses_post', $contact_parts );
$contact_parts = apply_filters( 'propertyhive_merge_contact_parts', $contact_parts );
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Built-in contact summary HTML is sanitized immediately before the trusted propertyhive_merge_contact_parts extension filter.
echo implode( '
', $contact_parts );
?>
>
";
}
?>
Could not find multiple contacts to merge. Please return to the contact list and try again.
'property',
'nopaging' => true,
// phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Contact merge must find every record linked through contact metadata so summaries and reassignment do not omit relationships.
'meta_query' => array(
'relation' => 'OR',
array(
'key' => '_owner_contact_id',
'value' => $contact->id,
'compare' => '='
),
array(
'key' => '_owner_contact_id',
'value' => ':"' . $contact->id . '"',
'compare' => 'LIKE'
),
array(
'key' => '_owner_contact_id',
'value' => ':' . $contact->id . ';',
'compare' => 'LIKE'
)
)
);
$property_query = new WP_Query($args);
if ($property_query->have_posts())
{
while ($property_query->have_posts())
{
$property_query->the_post();
$property = new PH_Property( get_the_ID() );
$property_department = ucwords( str_replace( '-', ' ', $property->_department) );
$contact_parts[] = $property_department . ' Owner: ' . $property->get_formatted_full_address();
}
}
wp_reset_postdata();
return $contact_parts;
}
/**
* Adds details of any potential owner records to the list of contact parts
*
* @access private
* @return array
*/
private function get_potential_owner_records( $contact, $contact_parts )
{
// get appraisals where this is the owner and where not instructed
$args = array(
'post_type' => 'appraisal',
'nopaging' => true,
// phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Contact merge must find every record linked through contact metadata so summaries and reassignment do not omit relationships.
'meta_query' => array(
array(
'key' => '_property_owner_contact_id',
'value' => $contact->id,
'compare' => '='
),
)
);
$appraisal_query = new WP_Query($args);
if ($appraisal_query->have_posts())
{
while ($appraisal_query->have_posts())
{
$appraisal_query->the_post();
$appraisal = new PH_Appraisal( get_the_ID() );
$property_department = ucwords( str_replace( '-', ' ', $appraisal->_department) );
$contact_parts[] = $property_department . ' Appraisal Owner: ' . $appraisal->get_formatted_full_address();
}
}
wp_reset_postdata();
return $contact_parts;
}
/**
* Adds details of any third party contact records to the list of contact parts
*
* @access private
* @return array
*/
private function get_third_party_records( $contact, $contact_parts )
{
$third_party_categories = get_post_meta( $contact->id, '_third_party_categories', TRUE );
if ( is_array($third_party_categories) && !empty($third_party_categories) )
{
$third_party_category_names = array();
$ph_third_party_contacts = new PH_Third_Party_Contacts();
foreach ( $third_party_categories as $third_party_category )
{
if ( $third_party_category != '' && $third_party_category != 0 )
{
$category_name = $ph_third_party_contacts->get_category( $third_party_category );
if ( $category_name !== false )
{
$third_party_category_names[] = $category_name;
}
}
else
{
$third_party_category_names[] = 'General';
}
}
$contact_parts[] = 'Third Party Contact: ' . implode( ', ', $third_party_category_names);
}
return $contact_parts;
}
/**
* Adds details of any applicant records to the list of contact parts
*
* @access private
* @return array
*/
private function get_applicant_records( $contact, $contact_parts )
{
$num_applicant_profiles = get_post_meta( $contact->id, '_applicant_profiles', TRUE );
if ( !empty( $num_applicant_profiles ) )
{
for ( $i = 0; $i < $num_applicant_profiles; ++$i )
{
$applicant_profile = get_post_meta( $contact->id, '_applicant_profile_' . $i, TRUE );
$applicant_department = isset( $applicant_profile['department'] ) ? $applicant_profile['department'] : 'Empty';
$applicant_profile_parts = array();
if ( $applicant_department == 'residential-sales' || ph_get_custom_department_based_on($applicant_department) == 'residential-sales' )
{
if ( isset( $applicant_profile['max_price'] ) && !empty( $applicant_profile['max_price'] ) )
{
$applicant_profile_parts[] = '£' . ph_display_price_field( $applicant_profile['max_price'] );
}
if ( isset( $applicant_profile['min_beds'] ) && !empty( $applicant_profile['min_beds'] ) )
{
$applicant_profile_parts[] = $applicant_profile['min_beds'] . ' bedrooms';
}
}
if ( $applicant_department == 'residential-lettings' || ph_get_custom_department_based_on($applicant_department) == 'residential-lettings' )
{
if ( isset( $applicant_profile['max_rent'] ) && !empty( $applicant_profile['max_rent'] ) )
{
$maximum_rent = '£' . ph_display_price_field( $applicant_profile['max_rent'] );
if ( isset( $applicant_profile['rent_frequency'] ) && !empty( $applicant_profile['rent_frequency'] ) )
{
$maximum_rent .= ' ' . $applicant_profile['rent_frequency'];
}
else
{
$maximum_rent .= 'pcm';
}
$applicant_profile_parts[] = $maximum_rent;
}
if ( isset( $applicant_profile['min_beds'] ) && !empty( $applicant_profile['min_beds'] ) )
{
$applicant_profile_parts[] = $applicant_profile['min_beds'] . ' bedrooms';
}
}
if ( $applicant_department == 'commercial' || ph_get_custom_department_based_on($applicant_department) == 'commercial' )
{
if ( isset( $applicant_profile['available_as'] ) && !empty( $applicant_profile['available_as'] ) )
{
$available_as = implode( '/', $applicant_profile['available_as'] );
$applicant_profile_parts[] = 'Available as ' . $available_as;
}
}
$applicant_profile_parts = array_filter( $applicant_profile_parts );
$applicant_profile_text = ucwords( str_replace( '-', ' ', $applicant_department ) ) . ' Applicant';
if ( count($applicant_profile_parts) > 0 )
{
$applicant_profile_text .= ': ' . implode( ', ', $applicant_profile_parts );
}
$contact_parts[] = $applicant_profile_text;
}
}
return $contact_parts;
}
/**
* Adds count of any enquiry records to the list of contact parts
*
* @access private
* @return array
*/
private function get_enquiry_records( $contact, $contact_parts )
{
$meta_query = array(
'relation' => 'OR',
array(
'key' => '_contact_id',
'value' => $contact->id,
),
);
// Not including email address lookup in enquiry count as they won't be moved or removed by the merge
$contact_email_address = $contact->_email_address;
if ( !empty($contact_email_address) )
{
$meta_query[] = array(
'key' => 'email',
'value' => $contact_email_address,
);
$meta_query[] = array(
'key' => 'email_address',
'value' => $contact_email_address,
);
}
$args = array(
'post_type' => 'enquiry',
'posts_per_page' => 1,
'no_found_rows' => false,
'fields' => 'ids',
// phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- One-ID query retains found_rows for the complete related-enquiry count.
'meta_query' => $meta_query,
);
$enquiries_query = new WP_Query( $args );
$enquiries_count = $enquiries_query->found_posts;
wp_reset_postdata();
if ( $enquiries_count > 0 )
{
$contact_parts[] = $enquiries_count . ' enquir' . ( $enquiries_count != 1 ? 'ies' : 'y' );
}
return $contact_parts;
}
/**
* Adds count of any viewing records to the list of contact parts
*
* @access private
* @return array
*/
private function get_viewing_records( $contact, $contact_parts )
{
$args = array(
'post_type' => 'viewing',
'posts_per_page' => 1,
'fields' => 'ids',
// phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Viewing/offer/sale/tenancy merge summaries use posts_per_page=1, fields=ids and found_posts to display counts for one contact. Each query has a single _applicant_contact_id equality and posts_per_page=1; found_rows remains enabled for the count.
'meta_query' => array(
array(
'key' => '_applicant_contact_id',
'value' => $contact->id,
)
)
);
$viewings_query = new WP_Query( $args );
$viewings_count = $viewings_query->found_posts;
wp_reset_postdata();
if ( $viewings_count > 0 )
{
$contact_parts[] = $viewings_count . ' viewing' . ( $viewings_count != 1 ? 's' : '' );
}
return $contact_parts;
}
/**
* Adds count of any offer records to the list of contact parts
*
* @access private
* @return array
*/
private function get_offer_records( $contact, $contact_parts )
{
$args = array(
'post_type' => 'offer',
'posts_per_page' => 1,
'fields' => 'ids',
// phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Viewing/offer/sale/tenancy merge summaries use posts_per_page=1, fields=ids and found_posts to display counts for one contact. Each query has a single _applicant_contact_id equality and posts_per_page=1; found_rows remains enabled for the count.
'meta_query' => array(
array(
'key' => '_applicant_contact_id',
'value' => $contact->id,
)
)
);
$offers_query = new WP_Query( $args );
$offers_count = $offers_query->found_posts;
wp_reset_postdata();
if ( $offers_count > 0 )
{
$contact_parts[] = $offers_count . ' offer' . ( $offers_count != 1 ? 's' : '' );
}
return $contact_parts;
}
/**
* Adds count of any sale records to the list of contact parts
*
* @access private
* @return array
*/
private function get_sale_records( $contact, $contact_parts )
{
$args = array(
'post_type' => 'sale',
'posts_per_page' => 1,
'fields' => 'ids',
// phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Viewing/offer/sale/tenancy merge summaries use posts_per_page=1, fields=ids and found_posts to display counts for one contact. Each query has a single _applicant_contact_id equality and posts_per_page=1; found_rows remains enabled for the count.
'meta_query' => array(
array(
'key' => '_applicant_contact_id',
'value' => $contact->id,
)
)
);
$sales_query = new WP_Query( $args );
$sales_count = $sales_query->found_posts;
wp_reset_postdata();
if ( $sales_count > 0 )
{
$contact_parts[] = $sales_count . ' sale' . ( $sales_count != 1 ? 's' : '' );
}
return $contact_parts;
}
/**
* Adds count of any tenancy records to the list of contact parts
*
* @access private
* @return array
*/
private function get_tenancy_records( $contact, $contact_parts )
{
$args = array(
'post_type' => 'tenancy',
'posts_per_page' => 1,
'fields' => 'ids',
// phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Viewing/offer/sale/tenancy merge summaries use posts_per_page=1, fields=ids and found_posts to display counts for one contact. Each query has a single _applicant_contact_id equality and posts_per_page=1; found_rows remains enabled for the count.
'meta_query' => array(
array(
'key' => '_applicant_contact_id',
'value' => $contact->id
)
)
);
$tenancies_query = new WP_Query( $args );
$tenancies_count = $tenancies_query->found_posts;
wp_reset_postdata();
if ( $tenancies_count > 0 )
{
$contact_parts[] = $tenancies_count . ' tenanc' . ( $tenancies_count != 1 ? 'ies' : 'y' );
}
return $contact_parts;
}
/**
* Adds count of any note records to the list of contact parts
*
* @access private
* @return array
*/
private function get_note_records( $contact, $contact_parts )
{
global $post;
$post = get_post((int)$contact->id);
$args = array(
'post_id' => (int)$contact->id,
'type' => 'propertyhive_note',
// phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Contact merge must find every record linked through contact metadata so summaries and reassignment do not omit relationships.
'meta_query' => array(
array(
'key' => 'related_to',
'value' => '"' . (int)$contact->id . '"',
'compare' => 'LIKE',
),
)
);
$notes = get_comments( $args );
$notes_count = count($notes);
if ( $notes_count > 0 )
{
$contact_parts[] = $notes_count . ' note' . ( $notes_count != 1 ? 's' : '' );
}
return $contact_parts;
}
public function do_merge( $primary_contact_id, $contacts_to_merge )
{
global $wpdb, $post;
// Merge contact_types into primary
$primary_contact_types = get_post_meta( $primary_contact_id, '_contact_types', true );
if ( $primary_contact_types == '' || !is_array($primary_contact_types) )
{
$primary_contact_types = array();
}
foreach ( $contacts_to_merge as $child_contact_id )
{
$child_contact_types = get_post_meta( $child_contact_id, '_contact_types', true );
if ( is_array($child_contact_types) )
{
$primary_contact_types = array_merge( $primary_contact_types, $child_contact_types );
}
}
update_post_meta( $primary_contact_id, '_contact_types', array_unique( $primary_contact_types ) );
// Merge third party categories into primary
$primary_third_party_categories = get_post_meta( $primary_contact_id, '_third_party_categories', true );
if ( $primary_third_party_categories == '' || !is_array($primary_third_party_categories) )
{
$primary_third_party_categories = array();
}
foreach ( $contacts_to_merge as $child_contact_id )
{
$child_third_party_categories = get_post_meta( $child_contact_id, '_third_party_categories', true );
if ( is_array($child_third_party_categories) )
{
$primary_third_party_categories = array_merge( $primary_third_party_categories, $child_third_party_categories );
}
}
if ( count($primary_third_party_categories) > 0 )
{
update_post_meta( $primary_contact_id, '_third_party_categories', array_unique( $primary_third_party_categories ) );
}
// Move applicant profiles to primary
$primary_applicant_profiles = get_post_meta( $primary_contact_id, '_applicant_profiles', true );
if ( empty($primary_applicant_profiles) )
{
$primary_applicant_profiles = 0;
}
$hot_applicant = '';
foreach ( $contacts_to_merge as $child_contact_id )
{
$child_applicant_profiles = get_post_meta( $child_contact_id, '_applicant_profiles', true );
if ( !empty($child_applicant_profiles) )
{
for ( $i = 0; $i < $child_applicant_profiles; ++$i )
{
$child_applicant_profile = get_post_meta( $child_contact_id, '_applicant_profile_' . $i, true );
if ( !empty($child_applicant_profile) )
{
update_post_meta( $primary_contact_id, '_applicant_profile_' . $primary_applicant_profiles, $child_applicant_profile );
$child_applicant_profile_match_history = get_post_meta( $child_contact_id, '_applicant_profile_' . $i . '_match_history', true );
if ( !empty($child_applicant_profile_match_history) )
{
update_post_meta( $primary_contact_id, '_applicant_profile_' . $primary_applicant_profiles . '_match_history', $child_applicant_profile_match_history );
}
if ( isset($child_applicant_profile['grading']) && ph_clean($child_applicant_profile['grading']) == 'hot' )
{
$hot_applicant = 'yes';
}
++$primary_applicant_profiles;
}
}
}
}
if ( $hot_applicant == 'yes' )
{
update_post_meta( $primary_contact_id, '_hot_applicant', $hot_applicant );
}
if ( $primary_applicant_profiles > 0 )
{
update_post_meta( $primary_contact_id, '_applicant_profiles', $primary_applicant_profiles );
}
// Merge dismissed properties
$primary_dismissed_properties = get_post_meta( $primary_contact_id, '_dismissed_properties', true );
if ( empty($primary_dismissed_properties) )
{
$primary_dismissed_properties = array();
}
foreach ( $contacts_to_merge as $child_contact_id )
{
$child_dismissed_properties = get_post_meta( $child_contact_id, '_dismissed_properties', true );
if ( is_array($child_dismissed_properties) && !empty($child_dismissed_properties) )
{
$primary_dismissed_properties = array_merge($primary_dismissed_properties, $child_dismissed_properties);
}
}
if ( !empty($primary_dismissed_properties) )
{
$primary_dismissed_properties = array_unique($primary_dismissed_properties);
update_post_meta( $primary_contact_id, '_dismissed_properties', $primary_dismissed_properties );
}
// Move appraisal records to primary
$args = array(
'post_type' => 'appraisal',
'nopaging' => true,
// phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Contact merge must find every record linked through contact metadata so summaries and reassignment do not omit relationships.
'meta_query' => array(
array(
'key' => '_property_owner_contact_id',
'value' => $contacts_to_merge,
'compare' => 'IN'
),
)
);
$appraisal_query = new WP_Query($args);
if ($appraisal_query->have_posts())
{
while ($appraisal_query->have_posts())
{
$appraisal_query->the_post();
foreach ( $contacts_to_merge as $child_contact_id )
{
update_post_meta( get_the_id(), '_property_owner_contact_id', $primary_contact_id, $child_contact_id );
}
}
}
wp_reset_postdata();
foreach ( $contacts_to_merge as $child_contact_id )
{
// Move property owner records to primary
$args = array(
'post_type' => 'property',
'nopaging' => true,
// phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Contact merge must find every record linked through contact metadata so summaries and reassignment do not omit relationships.
'meta_query' => array(
'relation' => 'OR',
array(
'key' => '_owner_contact_id',
'value' => $child_contact_id,
'compare' => '='
),
array(
'key' => '_owner_contact_id',
'value' => ':"' . $child_contact_id . '"',
'compare' => 'LIKE'
),
array(
'key' => '_owner_contact_id',
'value' => ':' . $child_contact_id . ';',
'compare' => 'LIKE'
)
)
);
$property_query = new WP_Query($args);
if ($property_query->have_posts())
{
while ($property_query->have_posts())
{
$property_query->the_post();
$property_owner_ids = get_post_meta( get_the_id(), '_owner_contact_id', true );
if ( !is_array( $property_owner_ids ) )
{
update_post_meta( get_the_id(), '_owner_contact_id', $primary_contact_id, $child_contact_id );
}
else
{
unset($property_owner_ids[array_search($child_contact_id, $property_owner_ids)]);
$property_owner_ids[] = $primary_contact_id;
update_post_meta( get_the_id(), '_owner_contact_id', $property_owner_ids );
}
}
}
wp_reset_postdata();
}
// Move enquiries to primary
$args = array(
'post_type' => 'enquiry',
'nopaging' => true,
'fields' => 'ids',
// phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Contact merge must find every record linked through contact metadata so summaries and reassignment do not omit relationships.
'meta_query' => array(
array(
'key' => '_contact_id',
'value' => $contacts_to_merge,
'compare' => 'IN'
),
),
);
$enquiries_query = new WP_Query( $args );
if ($enquiries_query->have_posts())
{
while ($enquiries_query->have_posts())
{
$enquiries_query->the_post();
foreach ( $contacts_to_merge as $child_contact_id )
{
update_post_meta( get_the_id(), '_contact_id', $primary_contact_id, $child_contact_id );
}
}
}
wp_reset_postdata();
// Move viewings to primary
$args = array(
'post_type' => 'viewing',
'nopaging' => true,
'fields' => 'ids',
// phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Contact merge must find every record linked through contact metadata so summaries and reassignment do not omit relationships.
'meta_query' => array(
array(
'key' => '_applicant_contact_id',
'value' => $contacts_to_merge,
'compare' => 'IN'
),
),
);
$viewings_query = new WP_Query( $args );
if ($viewings_query->have_posts())
{
while ($viewings_query->have_posts())
{
$viewings_query->the_post();
foreach ( $contacts_to_merge as $child_contact_id )
{
update_post_meta( get_the_id(), '_applicant_contact_id', $primary_contact_id, $child_contact_id );
}
}
}
wp_reset_postdata();
// Move offers to primary
$args = array(
'post_type' => 'offer',
'nopaging' => true,
'fields' => 'ids',
// phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Contact merge must find every record linked through contact metadata so summaries and reassignment do not omit relationships.
'meta_query' => array(
array(
'key' => '_applicant_contact_id',
'value' => $contacts_to_merge,
'compare' => 'IN'
),
),
);
$offers_query = new WP_Query( $args );
if ($offers_query->have_posts())
{
while ($offers_query->have_posts())
{
$offers_query->the_post();
foreach ( $contacts_to_merge as $child_contact_id )
{
update_post_meta( get_the_id(), '_applicant_contact_id', $primary_contact_id, $child_contact_id );
}
}
}
wp_reset_postdata();
// Move sales to primary
$args = array(
'post_type' => 'sale',
'nopaging' => true,
'fields' => 'ids',
// phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Contact merge must find every record linked through contact metadata so summaries and reassignment do not omit relationships.
'meta_query' => array(
array(
'key' => '_applicant_contact_id',
'value' => $contacts_to_merge,
'compare' => 'IN'
),
),
);
$sales_query = new WP_Query( $args );
if ($sales_query->have_posts())
{
while ($sales_query->have_posts())
{
$sales_query->the_post();
foreach ( $contacts_to_merge as $child_contact_id )
{
update_post_meta( get_the_id(), '_applicant_contact_id', $primary_contact_id, $child_contact_id );
}
}
}
wp_reset_postdata();
// Move tenancies to primary
$args = array(
'post_type' => 'tenancy',
'nopaging' => true,
'fields' => 'ids',
// phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Contact merge must find every record linked through contact metadata so summaries and reassignment do not omit relationships.
'meta_query' => array(
array(
'key' => '_applicant_contact_id',
'value' => $contacts_to_merge,
'compare' => 'IN'
),
),
);
$tenancies_query = new WP_Query( $args );
if ($tenancies_query->have_posts())
{
while ($tenancies_query->have_posts())
{
$tenancies_query->the_post();
foreach ( $contacts_to_merge as $child_contact_id )
{
update_post_meta( get_the_id(), '_applicant_contact_id', $primary_contact_id, $child_contact_id );
}
}
}
wp_reset_postdata();
// Copy notes to primary
foreach ( $contacts_to_merge as $child_contact_id )
{
$post = get_post((int)$child_contact_id);
$args = array(
'post_id' => (int)$child_contact_id,
'type' => 'propertyhive_note',
// phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Contact merge must find every record linked through contact metadata so summaries and reassignment do not omit relationships.
'meta_query' => array(
array(
'key' => 'related_to',
'value' => '"' . (int)$child_contact_id . '"',
'compare' => 'LIKE',
),
)
);
$notes = get_comments( $args );
foreach ( $notes as $note )
{
// Want to ignore note if it's an existing 'contact_merged' note. This would be confusing
$comment_content = @unserialize($note->comment_content, ['allowed_classes' => false]);
if (
$comment_content !== false &&
isset($comment_content['note_type']) && $comment_content['note_type'] == 'action' &&
isset($comment_content['action']) && $comment_content['action'] == 'contact_merged'
)
{
continue;
}
// This note could've been assigned to this contact, or this contact could just be related to it
// Need to check both
if ( $note->comment_post_ID == $child_contact_id )
{
$data = array(
'comment_ID' => $note->comment_ID,
'comment_post_ID' => $primary_contact_id
);
$updated = wp_update_comment( $data );
}
$related_tos = get_comment_meta( $note->comment_ID, 'related_to', true );
if ( !empty($related_tos) )
{
$new_related_to = array();
foreach ( $related_tos as $related_to )
{
if ( $related_to == $child_contact_id )
{
$new_related_to[] = (string)$primary_contact_id; // convert to string to LIKE lookups work
}
else
{
$new_related_to[] = (string)$related_to; // convert to string to LIKE lookups work
}
}
$new_related_to = array_unique($new_related_to);
update_comment_meta( $note->comment_ID, 'related_to', $new_related_to );
}
}
}
// Write a note to all contacts highlighting what has happened
$current_user = wp_get_current_user();
foreach ( $contacts_to_merge as $child_contact_id )
{
$comment = array(
'note_type' => 'action',
'action' => 'contact_merged',
'merged_into' => (int)$primary_contact_id,
);
$data = array(
'comment_post_ID' => (int)$child_contact_id,
'comment_author' => $current_user->display_name,
'comment_author_email' => 'propertyhive@noreply.com',
'comment_author_url' => '',
'comment_date' => gmdate("Y-m-d H:i:s"),
'comment_content' => serialize($comment),
'comment_approved' => 1,
'comment_type' => 'propertyhive_note',
);
$comment_id = wp_insert_comment( $data );
// Move contact being merged to the bin
wp_trash_post( (int)$child_contact_id );
}
// Update email log
foreach ( $contacts_to_merge as $child_contact_id )
{
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- This writes the plugin-owned email log relationship during a verified merge; no cached read result is used.
$wpdb->update(
$wpdb->prefix . 'ph_email_log',
array( 'contact_id' => (int) $primary_contact_id ),
array( 'contact_id' => (int) $child_contact_id ),
array( '%d' ),
array( '%d' )
);
}
do_action( 'propertyhive_contacts_merged', $primary_contact_id, $contacts_to_merge );
}
}
endif;