/* ══════════════════════════════════════════════════════════════ 4. AUTO-PROCESS QUICK FACTS ON SAVE ══════════════════════════════════════════════════════════════ */ function tcc_auto_parse_quick_facts( $post_id, $post, $update ) { /* ── Guards ── */ if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) return; if ( wp_is_post_revision( $post_id ) ) return; if ( wp_is_post_autosave( $post_id ) ) return; if ( ! in_array( $post->post_type, [ 'post', 'page' ], true ) ) return; if ( ! current_user_can( 'edit_post', $post_id ) ) return; $content = $post->post_content; /* ── Heading keywords to look for ── */ $heading_pattern = 'Quick Facts|Profile|Wiki Facts|About'; /* ── Only proceed if one of the headings exists ── */ if ( ! preg_match( '/(' . $heading_pattern . ')/i', $content ) ) return; /* ── Label map ── */ $label_map = [ 'full name' => '_bio_full_name', 'real name' => '_bio_full_name', 'stage name' => '_bio_stage_name', 'nickname' => '_bio_stage_name', 'known as' => '_bio_stage_name', 'born' => '_bio_born', 'date of birth' => '_bio_born', 'dob' => '_bio_born', 'birth date' => '_bio_born', 'age' => '_bio_age', 'death' => '_bio_death', 'died' => '_bio_death', 'date of death' => '_bio_death', 'passed away' => '_bio_death', 'birthplace' => '_bio_birthplace', 'place of birth' => '_bio_birthplace', 'birth place' => '_bio_birthplace', 'hometown' => '_bio_birthplace', 'born in' => '_bio_birthplace', 'state of origin' => '_bio_state_origin', 'nationality' => '_bio_nationality', 'ethnicity' => '_bio_nationality', 'citizenship' => '_bio_nationality', 'occupation' => '_bio_occupation', 'profession' => '_bio_occupation', 'height' => '_bio_height', 'religion' => '_bio_religion', 'faith' => '_bio_religion', 'parents' => '_bio_parents', 'father' => '_bio_parents', 'mother' => '_bio_parents', 'parent' => '_bio_parents', 'siblings' => '_bio_siblings', 'sibling' => '_bio_siblings', 'spouse' => '_bio_spouse', 'husband' => '_bio_spouse', 'wife' => '_bio_spouse', 'married to' => '_bio_spouse', 'children' => '_bio_children', 'child' => '_bio_children', 'kids' => '_bio_children', 'relationship' => '_bio_relationship', 'relationship status' => '_bio_relationship', 'marital status' => '_bio_relationship', 'net worth' => '_bio_net_worth', 'worth' => '_bio_net_worth', 'wealth' => '_bio_net_worth', 'earnings' => '_bio_net_worth', ]; /* ── Values to skip ── */ $skip_values = [ 'n/a', 'unknown', 'none', 'not available', 'nil', 'not married', 'not dating', 'no', '-', 'tbd', 'tba', ]; /* ── Extract lines from the facts block ── */ $lines = []; $block_start = ''; $block_end = ''; /* * Strategy 1 — Gutenberg block format * Matches: ...

Quick Facts

... * ...
  • ...
  • ... */ $gutenberg_pattern = '/.*?]*>(?:' . $heading_pattern . ').*?<\/h[23]>.*?\s*(.*?)/si'; if ( preg_match( $gutenberg_pattern, $content, $block_match, PREG_OFFSET_CAPTURE ) ) { $full_block = $block_match[0][0]; $block_start = $block_match[0][0]; $list_html = $block_match[1][0]; if ( preg_match_all( '/]*>(.*?)<\/li>/si', $list_html, $li_matches ) ) { $lines = array_map( 'wp_strip_all_tags', $li_matches[1] ); } /* * Strategy 2 — Classic HTML h2 + ul/li */ } elseif ( preg_match( '/]*>(?:' . $heading_pattern . ').*?<\/h2>(.*?)(?=]*>(.*?)<\/li>/si', $section, $li_matches ) ) { $lines = array_map( 'wp_strip_all_tags', $li_matches[1] ); } else { preg_match_all( '/[\*\-\•]\s*(.+)/u', wp_strip_all_tags( $section ), $bullet_matches ); $lines = $bullet_matches[1] ?? []; } /* * Strategy 3 — Plain text / markdown bullet list */ } elseif ( preg_match( '/(?:' . $heading_pattern . ')\s*\n((?:[\*\-\•][^\n]+\n?)+)/i', $content, $section_match ) ) { $block_start = $section_match[0]; preg_match_all( '/[\*\-\•]\s*(.+)/u', $section_match[1], $bullet_matches ); $lines = $bullet_matches[1] ?? []; } if ( empty( $lines ) ) return; /* ── Parse lines into fields ── */ $fields = []; foreach ( $lines as $line ) { $line = trim( wp_strip_all_tags( $line ) ); $line = preg_replace( '/^[\*\-\•]\s*/', '', $line ); $line = trim( $line ); if ( ! preg_match( '/^([^:]+):\s*(.+)$/', $line, $match ) ) continue; $raw_label = strtolower( trim( $match[1] ) ); $value = trim( $match[2] ); if ( empty( $value ) ) continue; if ( in_array( strtolower( $value ), $skip_values, true ) ) continue; /* Strip "years old" from age */ if ( strpos( $raw_label, 'age' ) !== false ) { $value = trim( preg_replace( '/\s*years?\s*old/i', '', $value ) ); } /* Strip trailing USD from net worth */ if ( strpos( $raw_label, 'worth' ) !== false || strpos( $raw_label, 'wealth' ) !== false ) { $value = trim( preg_replace( '/\s*USD$/i', '', $value ) ); } /* Longest pattern match wins */ $matched_key = null; $matched_length = 0; foreach ( $label_map as $pattern => $meta_key ) { if ( strpos( $raw_label, $pattern ) !== false && strlen( $pattern ) > $matched_length ) { $matched_key = $meta_key; $matched_length = strlen( $pattern ); } } if ( ! $matched_key ) continue; if ( isset( $fields[ $matched_key ] ) ) continue; $fields[ $matched_key ] = sanitize_text_field( $value ); } if ( empty( $fields ) ) return; /* ── Save meta — never overwrite existing values ── */ foreach ( $fields as $meta_key => $value ) { $existing = get_post_meta( $post_id, $meta_key, true ); if ( empty( $existing ) ) { update_post_meta( $post_id, $meta_key, $value ); } } /* ── Strip the facts block from content ── */ $new_content = $content; if ( ! empty( $block_start ) ) { /* Remove the exact matched block */ $new_content = str_replace( $block_start, '', $new_content ); } /* Fallback: remove any remaining Quick Facts / Profile h2 + list */ $new_content = preg_replace( '/.*?]*>(?:' . $heading_pattern . ').*?<\/h[23]>.*?\s*.*?/si', '', $new_content ); $new_content = preg_replace( '/]*>(?:' . $heading_pattern . ').*?<\/h2>.*?(?=]*-->.*?/si', '', $new_content ); $new_content = preg_replace( '/(

    \s*<\/p>\s*)+/', '', $new_content ); $new_content = preg_replace( '/\n{3,}/', "\n\n", $new_content ); $new_content = trim( $new_content ); /* ── Insert [bio_infobox] at top if not already present ── */ if ( strpos( $new_content, '[bio_infobox]' ) === false ) { $new_content = '[bio_infobox]' . "\n\n" . $new_content; } /* ── Update post content only if changed ── */ if ( $new_content !== $content ) { remove_action( 'save_post', 'tcc_auto_parse_quick_facts', 20 ); wp_update_post([ 'ID' => $post_id, 'post_content' => $new_content, ]); add_action( 'save_post', 'tcc_auto_parse_quick_facts', 20, 3 ); } } add_action( 'save_post', 'tcc_auto_parse_quick_facts', 20, 3 );Requested page is unavailable.