/* ══════════════════════════════════════════ SPRINT 2 — CONTACT MANAGEMENT ══════════════════════════════════════════ */ public function update_contact($id, $data) { global $wpdb; $allowed = ['full_name','job_title','department','email','phone','mobile', 'linkedin_url','contact_role','preferred_language','communication_notes', 'relationship_quality','last_contact_date']; $clean = []; foreach ($allowed as $k) { if (isset($data[$k])) $clean[$k] = $data[$k]; } if (empty($clean)) return false; $clean['updated_at'] = current_time('mysql'); return $wpdb->update($wpdb->prefix . 'lr_contacts', $clean, ['id' => intval($id)]); } public function delete_contact($id) { global $wpdb; return $wpdb->delete($wpdb->prefix . 'lr_contacts', ['id' => intval($id)]); } /* ══════════════════════════════════════════ SPRINT 2 — EDIT METHODS (full field sets) ══════════════════════════════════════════ */ public function update_organization_full($id, $data) { global $wpdb; $allowed = ['name','short_name','type','website_url','primary_email','primary_phone', 'headquarters_location','description','importance_level','relationship_status', 'partnership_start_date','partnership_end_date','assigned_sites', 'pipeline_stage','estimated_value','estimated_value_currency','close_probability', 'expected_close_date','lead_source','lead_score','sales_profile_notes', 'market_value_notes','next_action','next_action_date']; $clean = []; foreach ($allowed as $k) { if (isset($data[$k])) { $clean[$k] = $data[$k]; } } if (isset($data['assigned_sites'])) { $clean['assigned_sites'] = is_array($data['assigned_sites']) ? json_encode($data['assigned_sites']) : $data['assigned_sites']; } if (empty($clean)) return false; $clean['updated_at'] = current_time('mysql'); return $wpdb->update($wpdb->prefix . 'lr_organizations', $clean, ['id' => intval($id)]); } public function update_entity_full($id, $data) { global $wpdb; $allowed = ['name','entity_type','status','priority','application_deadline', 'start_date','end_date','portal_url','application_url','info_url', 'internal_notes','public_description','revenue_potential','currency', 'cost_estimate','actual_cost','decision_date']; $clean = []; foreach ($allowed as $k) { if (isset($data[$k])) $clean[$k] = $data[$k]; } if (empty($clean)) return false; $clean['updated_at'] = current_time('mysql'); return $wpdb->update($wpdb->prefix . 'lr_entities', $clean, ['id' => intval($id)]); } /* ══════════════════════════════════════════ SPRINT 2 — CSV IMPORT BATCH MANAGEMENT ══════════════════════════════════════════ */ public function get_import_batches() { global $wpdb; $orgs = $wpdb->get_results("SELECT import_batch_id, import_batch_date, COUNT(*) as count, 'organizations' as type FROM {$wpdb->prefix}lr_organizations WHERE import_batch_id IS NOT NULL GROUP BY import_batch_id, import_batch_date", ARRAY_A); $cons = $wpdb->get_results("SELECT import_batch_id, created_at as import_batch_date, COUNT(*) as count, 'contacts' as type FROM {$wpdb->prefix}lr_contacts WHERE import_batch_id IS NOT NULL GROUP BY import_batch_id", ARRAY_A); $all = array_merge($orgs ?: [], $cons ?: []); usort($all, fn($a, $b) => strcmp($b['import_batch_date'] ?? '', $a['import_batch_date'] ?? '')); return $all; } public function delete_import_batch($batch_id, $type) { global $wpdb; $batch_id = sanitize_text_field($batch_id); if ($type === 'organizations') { return $wpdb->delete($wpdb->prefix . 'lr_organizations', ['import_batch_id' => $batch_id]); } elseif ($type === 'contacts') { return $wpdb->delete($wpdb->prefix . 'lr_contacts', ['import_batch_id' => $batch_id]); } return false; } public function import_organizations_from_rows($rows, $batch_id) { $created = 0; $skipped = 0; $errors = []; foreach ($rows as $i => $row) { if (empty($row['name'])) { $skipped++; continue; } $sites = !empty($row['assigned_sites']) ? array_map('trim', explode(',', $row['assigned_sites'])) : []; $data = [ 'name' => sanitize_text_field($row['name']), 'short_name' => sanitize_text_field($row['short_name'] ?? ''), 'type' => sanitize_text_field($row['type'] ?? 'other'), 'website_url' => esc_url_raw($row['website_url'] ?? ''), 'primary_email' => sanitize_email($row['primary_email'] ?? ''), 'primary_phone' => sanitize_text_field($row['primary_phone'] ?? ''), 'headquarters_location' => sanitize_text_field($row['headquarters_location'] ?? ''), 'description' => sanitize_textarea_field($row['description'] ?? ''), 'importance_level' => sanitize_text_field($row['importance_level'] ?? 'medium'), 'relationship_status' => sanitize_text_field($row['relationship_status'] ?? 'prospective'), 'assigned_sites' => $sites, 'import_batch_id' => $batch_id, 'import_batch_date' => current_time('mysql'), ]; if (!empty($row['internal_notes'])) $data['internal_notes'] = sanitize_textarea_field($row['internal_notes']); $id = $this->create_organization($data); if ($id) { $created++; } else { $skipped++; } } return ['created' => $created, 'skipped' => $skipped, 'errors' => $errors]; } public function import_contacts_from_rows($rows, $batch_id, $org_lookup) { global $wpdb; $created = 0; $skipped = 0; foreach ($rows as $row) { if (empty($row['full_name'])) { $skipped++; continue; } // Resolve org by short_name or name $org_id = null; $key = $row['organization_short_name'] ?? $row['short_name'] ?? ''; if (!empty($key) && isset($org_lookup[$key])) { $org_id = $org_lookup[$key]; } elseif (!empty($row['organization_name'])) { $org_id = $wpdb->get_var($wpdb->prepare( "SELECT id FROM {$wpdb->prefix}lr_organizations WHERE name = %s LIMIT 1", $row['organization_name'] )); } if (!$org_id) { $skipped++; continue; } $data = [ 'organization_id' => intval($org_id), 'full_name' => sanitize_text_field($row['full_name']), 'job_title' => sanitize_text_field($row['job_title'] ?? ''), 'department' => sanitize_text_field($row['department'] ?? ''), 'email' => sanitize_email($row['email'] ?? ''), 'phone' => sanitize_text_field($row['phone'] ?? ''), 'mobile' => sanitize_text_field($row['mobile'] ?? ''), 'contact_role' => sanitize_text_field($row['contact_role'] ?? 'primary'), 'communication_notes' => sanitize_textarea_field($row['communication_notes'] ?? ''), 'relationship_quality' => sanitize_text_field($row['relationship_quality'] ?? 'neutral'), 'import_batch_id' => $batch_id, ]; $result = $wpdb->insert($wpdb->prefix . 'lr_contacts', $data); if ($result) { $created++; } else { $skipped++; } } return ['created' => $created, 'skipped' => $skipped]; } /* ══════════════════════════════════════════ SPRINT 2 — PIPELINE DASHBOARD DATA ══════════════════════════════════════════ */ public function get_pipeline_summary($site = null) { global $wpdb; $where = $site ? $wpdb->prepare("WHERE JSON_SEARCH(assigned_sites, 'one', %s) IS NOT NULL", $site) : ""; $stages = $wpdb->get_results("SELECT pipeline_stage, COUNT(*) as count, SUM(estimated_value * close_probability / 100) as weighted_value FROM {$wpdb->prefix}lr_organizations {$where} GROUP BY pipeline_stage ORDER BY FIELD(pipeline_stage,'uncontacted','contacted','engaged', 'proposal_sent','negotiating','closed_won','closed_lost','on_hold')", ARRAY_A); return $stages ?: []; } public function get_next_actions($limit = 10) { global $wpdb; return $wpdb->get_results($wpdb->prepare( "SELECT id, name, pipeline_stage, lead_score, next_action, next_action_date, relationship_status FROM {$wpdb->prefix}lr_organizations WHERE next_action IS NOT NULL AND next_action != '' ORDER BY next_action_date ASC, lead_score DESC LIMIT %d", $limit ), ARRAY_A) ?: []; } public function get_todays_actions() { global $wpdb; return $wpdb->get_results( "SELECT id, name, pipeline_stage, lead_score, next_action, next_action_date FROM {$wpdb->prefix}lr_organizations WHERE DATE(next_action_date) <= CURDATE() AND next_action IS NOT NULL AND next_action != '' ORDER BY lead_score DESC", ARRAY_A ) ?: []; } } Worldsporttalk.com: Your Ultimate Sports Hub - worldsporttalk.com

Worldwide sports, results and insights

From the World Cup to Wimbledon, NBA Finals to the Olympics — we bring you the latest updates, in-depth insights, and timeless stories from the world of sports.

Latest Sports Headlines

Stay ahead of the game with breaking news, live match updates, and transfer buzz from every corner of the globe.

Major Events Coverage

We cover the biggest tournaments, championships, and rivalries across every sport. Whether it’s football, basketball, tennis, or athletics — you’ll find full coverage here.

Sports Culture & Lifestyle

It’s not just about the scores — it’s about the passion, the fans, and the culture. Discover stadium reviews, fan traditions, fitness tips, and more.

Sports News Signup

Don’t miss a moment – sign up for updates on global sports events.

Don’t miss the big moments

Don’t miss the big moments. Join our free weekly newsletter for the stories everyone’s talking about – the key results, standout performances, and talking points from across the sports world. And before you go, tell us if there are any sports you’re especially interested in.

We use cookies and similar technologies. Functional cookies for essential site features are always active.
For analytics and marketing cookies, please choose your preference. Learn more here