// ============================= // 3. Fetch & Save News Logic // ============================= /** * Fetches news from SerpAPI based on configured project types and country, * then saves them as draft posts, preventing duplicates. * The fetch is strictly limited to the last 24 hours. * * @return array An array of status/error messages for display. */ function serpapi_fetch_and_save_energy_news() { $status = []; $api_key = get_option('serpapi_api_key'); if (!$api_key) { $status[] = ['type' => 'error', 'message' => 'SerpAPI Key is missing in settings. Please configure it.']; error_log('SerpAPI News Importer: API key is missing. Skipping fetch.'); return $status; } $project_types = get_option('serpapi_project_types', 'affordable housing, stadium, arena, solar, wind, airport, seaport, BESS, datacenters'); $types_array = array_map('trim', explode(',', $project_types)); if (empty(array_filter($types_array))) { $status[] = ['type' => 'notice', 'message' => 'Project Types are empty. Please specify comma-separated project types in settings.']; return $status; } // Wrap each type in quotes for exact phrase matching $quoted_types = array_map(function($type) { $sanitized_type = sanitize_text_field($type); return !empty($sanitized_type) ? '"' . $sanitized_type . '"' : ''; }, $types_array); $quoted_types = array_filter($quoted_types); if (empty($quoted_types)) { $status[] = ['type' => 'notice', 'message' => 'No valid project types found after sanitization.']; return $status; } $query = '(' . implode(' OR ', $quoted_types) . ') project'; $country = sanitize_text_field(get_option('serpapi_country', '')); if (!empty($country)) { $query .= ' "' . $country . '"'; } // 1. API Level Filter: Add '&tbs=qdr:d' to instruct Google News to only return results from the last day. // Also add '&num=100' to instruct SerpAPI to return 100 results. $url = "https://serpapi.com/search?engine=google_news&q=" . urlencode($query) . "&tbs=qdr:d&num=100&hl=en&lr=lang_en&api_key=$api_key"; // DEBUG: Add the query URL to the status messages $status[] = ['type' => 'query_url', 'message' => $url]; $response = wp_remote_get($url, ['timeout' => 30]); if (is_wp_error($response)) { $status[] = ['type' => 'error', 'message' => 'WordPress HTTP Error: Could not connect to SerpAPI. Message: ' . $response->get_error_message()]; error_log('SerpAPI News Importer: WP_Error encountered: ' . $response->get_error_message()); return $status; } $http_status = wp_remote_retrieve_response_code($response); if ($http_status !== 200) { $status[] = ['type' => 'error', 'message' => "SerpAPI HTTP Error: Request failed with status code $http_status. Check API key validity."]; error_log("SerpAPI News Importer: HTTP Error: $http_status. URL: $url"); return $status; } $body = wp_remote_retrieve_body($response); $data = json_decode($body, true); if (isset($data['error'])) { $status[] = ['type' => 'error', 'message' => 'SerpAPI returned an error: ' . $data['error']]; error_log('SerpAPI News Importer: API Error: ' . $data['error']); return $status; } if (!isset($data['news_results']) || !is_array($data['news_results'])) { $status[] = ['type' => 'notice', 'message' => 'SerpAPI returned no news results for the current query/settings.']; return $status; } $total_articles_fetched = count($data['news_results']); $filtered_by_time = 0; $filtered_by_duplicate = 0; $cutoff = strtotime('-1 day'); $post_count = 0; $max_posts = 100; // 🎯 CHANGED FROM 50 TO 100 foreach ($data['news_results'] as $article) { if ($post_count >= $max_posts) break; if (!isset($article['title']) || !isset($article['link'])) continue; $title = sanitize_text_field($article['title']); $link = esc_url_raw($article['link']); $summary = isset($article['snippet']) ? wp_strip_all_tags($article['snippet']) : 'No summary available.'; $published_str = isset($article['date']) ? $article['date'] : ''; if (empty($title) || empty($link)) continue; // --- ROBUST DATE PARSING AND SECONDARY PHP TIME CHECK --- // Date format from SerpAPI is "MM/DD/YYYY, HH:MM PM/AM, +0000 UTC" $date_format = 'm/d/Y, h:i A, P T'; $datetime_obj = DateTime::createFromFormat($date_format, $published_str); $published_time = false; if ($datetime_obj) { // Get the Unix timestamp from the successfully parsed object $published_time = $datetime_obj->getTimestamp(); } // If parsing failed (returns false) OR the date is older than 24 hours, skip. if (!$published_time || $published_time < $cutoff) { $filtered_by_time++; continue; } // -------------------------------- // Prevent duplicate via URL meta key $existing = get_posts([ 'meta_key' => 'serpapi_source_url', 'meta_value' => $link, 'post_type' => 'post', 'fields' => 'ids', 'posts_per_page' => 1 ]); if ($existing) { $filtered_by_duplicate++; continue; } // Construct the post content $post_content = wpautop( 'Summary: ' . esc_html($summary) . '

' . 'Source: ' . esc_html($link) . '' ); $author_id = intval(get_option('serpapi_post_author', get_current_user_id())); $post_id = wp_insert_post([ 'post_title' => $title, 'post_content' => $post_content, 'post_status' => 'draft', // Save as draft for review 'post_author' => $author_id, ], true); if (!is_wp_error($post_id)) { update_post_meta($post_id, 'serpapi_source_url', $link); $post_count++; } else { $status[] = ['type' => 'error', 'message' => 'Error inserting post into database: ' . $post_id->get_error_message()]; error_log('SerpAPI News Importer: Error inserting post: ' . $post_id->get_error_message()); } } // UPDATED: Include filtering counts in the success message $status[] = ['type' => 'success', 'message' => "News import process completed. Fetched {$total_articles_fetched} articles from API. Imported {$post_count} posts as Drafts. Filtered {$filtered_by_time} by age and {$filtered_by_duplicate} as duplicates."]; return $status; } South Africa to add US $7m office and residential complex in La Lucia Mall
Last Updated: Aug 15, 2021
Home » Buildings » Malls/Parks » South Africa to add US $7m office and residential complex in La Lucia Mall

South Africa to add US $7m office and residential complex in La Lucia Mall

Home » Buildings » Malls/Parks » South Africa to add US $7m office and residential complex in La Lucia Mall

South Africa is set to add a US $7m office development and a seven-floor high residential complex in La Lucia Mall site in KwaZulu at the site of a free parking lot of the mall. Regional Head of owners of of the mall Growthpoint Properties, Greg de Klerk revealed the reports and said that the idea behind the developments, which are still under consideration.

“Both of these developments are very much in the design concept stage. The architect’s impressions are subject to refinement and provided we get the necessary approvals from council, the developments are still at this stage under consideration. We also are yet to have the developments approved through our investment committee before going to the marketplace,” said Greg.
La Lucia Mall

The Regional head explained that office development, situated next to the gym at the La Lucia Mall site, will be tenant-driven. It will be around 4,200 square metres and will be a green star-rated building. The mall site is zoned for offices and we’ve had to apply for a height relaxation on the business side as well as the residential side,

“We have done extensive market research, and we feel there is a need for higher density residential flats in that node. At this early stage, the apartment would be seven levels high with three levels of parking above ground. All the apartments will have sea views,” said Mr Greg.
Upon receiving the necessary approvals the project is likely to commence with office development in January 2020 and completed by December same year. Greg added that in regards to the residential development, it will begin with laying the groundwork in September and construction likely to commence in January next year and completed by April 2021.
He also affirmed that the company had applied for residential rights as well as a height relaxation on the development. “We have advertised the proposals and circulated letters informing the immediate neighbours of the development and nothing has yet been decided as we are awaiting the go-ahead from council. As far as the residential complex is concerned, the plan is to have 62 apartments, which will be a mixture of two bed, two bath, one bed, one bath, and a few studio apartments.”

 

Leave a Comment