From 4b92768e273d790496bbe6e3296e5552e30320d8 Mon Sep 17 00:00:00 2001 From: Casey Kulm Date: Tue, 17 Dec 2024 23:12:47 -0700 Subject: [PATCH 1/3] [MerchantAndMillsBridge] Add new bridge --- bridges/MerchantAndMillsBridge.php | 92 ++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 bridges/MerchantAndMillsBridge.php diff --git a/bridges/MerchantAndMillsBridge.php b/bridges/MerchantAndMillsBridge.php new file mode 100644 index 00000000000..380f9cc01d9 --- /dev/null +++ b/bridges/MerchantAndMillsBridge.php @@ -0,0 +1,92 @@ + [ + 'name' => 'Country', + 'type' => 'list', + 'values' => [ + 'European Union' => 0, + 'United Kingdom' => 1, + 'United States' => 2, + 'Other' => 3 + ] + ] + ]]; + + private function getCountryBlogPath($countryName): string + { + if ($countryName === 'European Union') { + return '/eu/blog'; + } + + if ($countryName === 'United Kingdom') { + return '/uk/blog'; + } + + if ($countryName === 'United States') { + return '/us/blog'; + } + + return '/rw/blog'; + } + + public function collectData() + { + $selectedCountryKey = $this->getKey('selected_country_id'); + $selectedCountryBlogPath = $this->getCountryBlogPath($selectedCountryKey); + $url = self::URI . $selectedCountryBlogPath; + $html = getSimpleHTMLDOM($url) + or returnServerError('Could not request ' . $url); + + foreach ($html->find('.products .post') as $post) { + $item = []; + + // Extract image + $image = $post->find('.post_image img', 0); + if ($image) { + // Resolve the relative image URL + $imageUrl = $image->src; + if (!str_starts_with($imageUrl, 'http')) { + $imageUrl = rtrim(self::URI, '/') . '/' . ltrim($imageUrl, '/'); + } + $item['image'] = $imageUrl; + } else { + $item['image'] = ''; + } + + // Extract title + $titleLink = $post->find('.post_name a', 0); + $item['title'] = $titleLink ? trim($titleLink->plaintext) : ''; + $item['uri'] = $titleLink ? self::URI . $titleLink->href : ''; + + // Extract date and views + $dateAndViews = $post->find('.post_date span'); + $item['date'] = isset($dateAndViews[0]) ? trim($dateAndViews[0]->plaintext) : ''; + $item['views'] = isset($dateAndViews[1]) ? trim(str_replace('Viewed:', '', $dateAndViews[1]->plaintext)) : ''; + + // Extract description + $description = $post->find('.post_desc', 0); + $item['content'] = ''; + + // Add the image and description to content + if (!empty($item['image'])) { + $item['content'] .= '
' + . '' . htmlspecialchars($titleLink->plaintext ?? '') . '' + . '

'; + } + if ($description) { + $item['content'] .= trim($description->plaintext); + } + + // Add item to the feed + $this->items[] = $item; + } + } +} From 0459101180107a371840a8e5def330820376b1d7 Mon Sep 17 00:00:00 2001 From: Casey Kulm Date: Sat, 11 Jan 2025 14:22:27 -0700 Subject: [PATCH 2/3] more --- bridges/MerchantAndMillsBridge.php | 97 ++++++++++++++++++------------ 1 file changed, 59 insertions(+), 38 deletions(-) diff --git a/bridges/MerchantAndMillsBridge.php b/bridges/MerchantAndMillsBridge.php index 380f9cc01d9..dca043b669b 100644 --- a/bridges/MerchantAndMillsBridge.php +++ b/bridges/MerchantAndMillsBridge.php @@ -6,6 +6,7 @@ class MerchantAndMillsBridge extends BridgeAbstract { const DESCRIPTION = 'The latest blog posts from Merchant and Mills.'; const MAINTAINER = 'caseykulm'; const CACHE_TIMEOUT = 43200; // 12h + const POST_LIMIT = 10; // Maximum number of blog posts to fetch const PARAMETERS = [[ 'selected_country_id' => [ 'name' => 'Country', @@ -19,8 +20,7 @@ class MerchantAndMillsBridge extends BridgeAbstract { ] ]]; - private function getCountryBlogPath($countryName): string - { + private function getCountryBlogPath($countryName): string { if ($countryName === 'European Union') { return '/eu/blog'; } @@ -36,57 +36,78 @@ private function getCountryBlogPath($countryName): string return '/rw/blog'; } - public function collectData() - { + public function collectData() { $selectedCountryKey = $this->getKey('selected_country_id'); $selectedCountryBlogPath = $this->getCountryBlogPath($selectedCountryKey); $url = self::URI . $selectedCountryBlogPath; $html = getSimpleHTMLDOM($url) or returnServerError('Could not request ' . $url); + // Limit processing to POST_LIMIT blog posts + $counter = 0; foreach ($html->find('.products .post') as $post) { - $item = []; - - // Extract image - $image = $post->find('.post_image img', 0); - if ($image) { - // Resolve the relative image URL - $imageUrl = $image->src; - if (!str_starts_with($imageUrl, 'http')) { - $imageUrl = rtrim(self::URI, '/') . '/' . ltrim($imageUrl, '/'); - } - $item['image'] = $imageUrl; - } else { - $item['image'] = ''; + if ($counter >= self::POST_LIMIT) { + break; // Stop when the limit is reached } - // Extract title + $item = []; + + // Extract title and URI $titleLink = $post->find('.post_name a', 0); - $item['title'] = $titleLink ? trim($titleLink->plaintext) : ''; + $item['title'] = $titleLink ? trim($titleLink->plaintext) : 'No title'; $item['uri'] = $titleLink ? self::URI . $titleLink->href : ''; - // Extract date and views - $dateAndViews = $post->find('.post_date span'); - $item['date'] = isset($dateAndViews[0]) ? trim($dateAndViews[0]->plaintext) : ''; - $item['views'] = isset($dateAndViews[1]) ? trim(str_replace('Viewed:', '', $dateAndViews[1]->plaintext)) : ''; - - // Extract description - $description = $post->find('.post_desc', 0); - $item['content'] = ''; - - // Add the image and description to content - if (!empty($item['image'])) { - $item['content'] .= '
' - . '' . htmlspecialchars($titleLink->plaintext ?? '') . '' - . '

'; - } - if ($description) { - $item['content'] .= trim($description->plaintext); + // Extract date + $dateElement = $post->find('.post_date span', 0); + $item['timestamp'] = $dateElement ? strtotime(trim($dateElement->plaintext)) : null; + + // Extract and fetch content + if ($item['uri']) { + $item['content'] = $this->getPostContent($item['uri']); + } else { + $item['content'] = 'No content available.'; } - // Add item to the feed $this->items[] = $item; + $counter++; + } + } + + /** + * Fetch and parse the content of a single blog post. + * + * @param string $url The URL of the single blog post. + * @return string The HTML content of the post. + */ + private function getPostContent(string $url): string + { + try { + $postHtml = getSimpleHTMLDOM($url) + or returnServerError('Could not fetch content from ' . $url); + + $contentElement = $postHtml->find('.box.w-blog-widget-post-description', 0); + + // Adjust relative URLs for images and add scaling style + if ($contentElement) { + foreach ($contentElement->find('img') as $img) { + $src = $img->src; + if (strpos($src, 'http') !== 0) { // If it's a relative path + $img->src = self::URI . $src; + } + + // Add inline styles for proper scaling + $img->style = 'max-width: 100%; height: auto; display: block; margin: auto;'; + } + } + + return $contentElement ? $contentElement->innertext : 'Content not found.'; + } catch (Exception $e) { + return 'Failed to fetch content: ' . $e->getMessage(); } } + + public function getIcon(): string + { + return 'https://merchantandmills.com/uk/themes/theme-1/icons/apple-icon-57x57.png?6763'; + } } From 5728ef759578891e5a908a7de38ad42b0bd20da9 Mon Sep 17 00:00:00 2001 From: Casey Kulm Date: Sat, 11 Jan 2025 15:36:18 -0700 Subject: [PATCH 3/3] lint --- bridges/MerchantAndMillsBridge.php | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/bridges/MerchantAndMillsBridge.php b/bridges/MerchantAndMillsBridge.php index dca043b669b..74d0758d22b 100644 --- a/bridges/MerchantAndMillsBridge.php +++ b/bridges/MerchantAndMillsBridge.php @@ -1,12 +1,13 @@ [ 'name' => 'Country', @@ -20,7 +21,8 @@ class MerchantAndMillsBridge extends BridgeAbstract { ] ]]; - private function getCountryBlogPath($countryName): string { + private function getCountryBlogPath($countryName): string + { if ($countryName === 'European Union') { return '/eu/blog'; } @@ -36,7 +38,8 @@ private function getCountryBlogPath($countryName): string { return '/rw/blog'; } - public function collectData() { + public function collectData() + { $selectedCountryKey = $this->getKey('selected_country_id'); $selectedCountryBlogPath = $this->getCountryBlogPath($selectedCountryKey); $url = self::URI . $selectedCountryBlogPath;