Bài viết này áp dụng cho:
+ NukeViet 4.0.29 - 4.1
+ Module News.
+ Chức năng RSS.
Ảnh minh hoạ:
Xem ở bài dưới.
+++ Ý tưởng gốc từ bạn Quốc Đoàn.
+++ Hỗ trợ sâu sắc bởi anh Tứ
Các thức : Thông qua các bước sau.
01/ Sửa version.php
- Mục đích là để tạo 1 function mới độc lập, không ảnh hưởng tới RSS hiện tại.
Mở \modules\news\version.php
Tìm:
'modfuncs' => 'main,viewcat,topic,groups,detail,search,content,tag,rss', // Cac function co block
Thêm vào cuối nó instant. Có thể khao khảo bên dưới.
'modfuncs' => 'main,viewcat,topic,groups,detail,search,content,tag,rss,instant', // Cac function co block
02/ Khởi tạo instant.php
Do bên trên chúng ta thêm fuction là instant nên phải tạo file instant.php.
File này đặt trong \modules\news\func\
Nội dung sẽ như sau:
<?php /** * @Project NUKEVIET 4.x * @Author VINADES (contact@vinades.vn) * @Copyright (C) 2014 VINADES. All rights reserved * @License GNU/GPL version 2 or any later version * @Createdate Apr 20, 2010 10:47:41 AM */ if (! defined('NV_IS_MOD_NEWS')) { die('Stop!!!'); } /** * nv_instant_rss_generate() * * @param mixed $channel * @param mixed $items * @return void */ function nv_instant_rss_generate($channel, $items) { global $db, $global_config, $client_info, $module_name, $module_file; if (file_exists(NV_ROOTDIR . '/themes/' . $global_config['module_theme'] . '/modules/' . $module_file . '/instant_rss.tpl')) { $block_theme = $global_config['module_theme']; } else { $block_theme = 'default'; } $xtpl = new XTemplate('instant_rss.tpl', NV_ROOTDIR . '/themes/' . $block_theme . '/modules/' . $module_file); $xtpl->assign('CSSPATH', NV_BASE_SITEURL . NV_ASSETS_DIR . '/css/rss.xsl'); //Chi co tac dung voi IE6 va Chrome $channel['generator'] = 'NukeViet v4.0'; $channel['title'] = nv_htmlspecialchars($channel['title']); $channel['atomlink'] = str_replace('&', '&', $client_info['selfurl']); $channel['lang'] = $global_config['site_lang']; $channel['copyright'] = $global_config['site_name']; $channel['docs'] = nv_url_rewrite(NV_BASE_SITEURL . 'index.php?' . NV_LANG_VARIABLE . '=' . NV_LANG_DATA . '&' . NV_NAME_VARIABLE . '=rss', true); if (strpos($channel['docs'], NV_MY_DOMAIN) !== 0) { $channel['docs'] = NV_MY_DOMAIN . $channel['docs']; } if (preg_match('/^' . nv_preg_quote(NV_MY_DOMAIN . NV_BASE_SITEURL) . '(.+)$/', $channel['link'], $matches)) { $channel['link'] = NV_BASE_SITEURL . $matches[1]; } $channel['link'] = nv_url_rewrite($channel['link'], true); if (strpos($channel['link'], NV_MY_DOMAIN) !== 0) { $channel['link'] = NV_MY_DOMAIN . $channel['link']; } if (preg_match('/^' . nv_preg_quote(NV_MY_DOMAIN . NV_BASE_SITEURL) . '(.+)$/', $channel['atomlink'], $matches)) { $channel['atomlink'] = NV_BASE_SITEURL . $matches[1]; } $channel['atomlink'] = nv_url_rewrite($channel['atomlink'], true); if (strpos($channel['atomlink'], NV_MY_DOMAIN) !== 0) { $channel['atomlink'] = NV_MY_DOMAIN . $channel['atomlink']; } $channel['pubDate'] = 0; if (! empty($items)) { foreach ($items as $item) { if (! empty($item['title']) and ! empty($item['link'])) { $item['title'] = nv_htmlspecialchars($item['title']); if (isset($item['pubdate']) and ! empty($item['pubdate'])) { $item['pubdate'] = intval($item['pubdate']); $channel['pubDate'] = max($channel['pubDate'], $item['pubdate']); $item['pubdate'] = gmdate('D, j M Y H:m:s', $item['pubdate']) . ' GMT'; } if (preg_match('/^' . nv_preg_quote(NV_MY_DOMAIN . NV_BASE_SITEURL) . '(.+)$/', $item['link'], $matches)) { $item['link'] = NV_BASE_SITEURL . $matches[1]; } $item['link'] = nv_url_rewrite($item['link'], true); if (strpos($item['link'], NV_MY_DOMAIN) !== 0) { $item['link'] = NV_MY_DOMAIN . $item['link']; } $xtpl->assign('ITEM', $item); if (isset($item['guid']) and ! empty($item['guid'])) { $xtpl->parse('main.item.guid'); } if (isset($item['pubdate']) and ! empty($item['pubdate'])) { $xtpl->parse('main.item.pubdate'); } if (isset($item['related']) and ! empty($item['related'])) { foreach ($item['related'] as $related) { $related['link'] = nv_url_rewrite($related['link'], true); $xtpl->assign('RELATED', $related); $xtpl->parse('main.item.related.loop'); } $xtpl->parse('main.item.related'); } $xtpl->parse('main.item'); } } } $lastModified = NV_CURRENTTIME; if (! empty($channel['pubDate'])) { $lastModified = $channel['pubDate']; $channel['pubDate'] = gmdate('D, j M Y H:m:s', $channel['pubDate']) . ' GMT'; } $xtpl->assign('CHANNEL', $channel); if (! empty($channel['description'])) { $xtpl->parse('main.description'); } if (! empty($channel['pubDate'])) { $xtpl->parse('main.pubDate'); } $image = file_exists(NV_ROOTDIR . '/' . $global_config['site_logo']) ? NV_ROOTDIR . '/' . $global_config['site_logo'] : NV_ROOTDIR . '/' . NV_ASSETS_DIR . '/images/logo.png'; $image = nv_ImageInfo($image, 144, true, NV_UPLOADS_REAL_DIR); if (! empty($image)) { $resSize = nv_imageResize($image['width'], $image['height'], 144, 400); $image['width'] = $resSize['width']; $image['height'] = $resSize['height']; $image['title'] = $channel['title']; $image['link'] = $channel['link']; $image['src'] = nv_url_rewrite($image['src'], true); if (strpos($image['src'], NV_MY_DOMAIN) !== 0) { $image['src'] = NV_MY_DOMAIN . $image['src']; } $xtpl->assign('IMAGE', $image); $xtpl->parse('main.image'); } $xtpl->parse('main'); $content = $xtpl->text('main'); nv_xmlOutput($content, $lastModified); } $channel = array(); $items = array(); $array_other = array(); $channel['title'] = $module_info['custom_title']; $channel['link'] = NV_BASE_SITEURL . 'index.php?' . NV_LANG_VARIABLE . '=' . NV_LANG_DATA . '&' . NV_NAME_VARIABLE . '=' . $module_name; $channel['description'] = ! empty($module_info['description']) ? $module_info['description'] : $global_config['site_description']; $catid = 0; if (isset($array_op[1])) { $alias_cat_url = $array_op[1]; $cattitle = ''; foreach ($global_array_cat as $catid_i => $array_cat_i) { if ($alias_cat_url == $array_cat_i['alias']) { $catid = $catid_i; break; } } } function relToAbs($text, $base) { if (empty($base)) return $text; if (substr($base, -1, 1) != "/") $base .= "/"; $pattern = "/<a([^>]*) " . "href=\"[^http|ftp|https|mailto]([^\"]*)\"/"; $replace = "<a\${1} href=\"" . $base . "\${2}\""; $text = preg_replace($pattern, $replace, $text); $pattern = "/<img([^>]*) " . "src=\"[^http|ftp|https]([^\"]*)\"/"; $replace = "<img\${1} src=\"" . $base . "\${2}\""; $text = preg_replace($pattern, $replace, $text); return $text; } function origin_img($html){ preg_match_all( '/<img[^>]+>/i', $html, $result ); foreach( $result[0] as $tagimg ){ $preg = preg_match_all( '#<\s*img [^\>]*src\s*=\s*(["\'])(.*?)\1#im', $tagimg, $matches ); $newtag = '<img src="' . $matches[2][0] . '" />'; $html = str_replace( $tagimg, $newtag, $html ); } return $html; } function instant_body($id){ global $db, $module_data, $module_name; $sql = "SELECT bodyhtml FROM " . NV_PREFIXLANG . "_" . $module_data . "_detail WHERE id =" . $id; $result = $db->query( $sql ); $row = $result->fetch(); $bodytext = preg_replace( '/(\s)+(id|class|style|alt)="(.*)"(\s)*/U', ' ', $row['bodyhtml'] ); $bodytext = origin_img($bodytext); $bodytext = strip_tags( $bodytext,'<img><a><b><br><i><strong>' ); $bodytext = preg_replace('/<img\s+src="([^"]+)"[^>]+>/i', '</p><figure data-feedback="fb:likes, fb:comments"><img src="$1" /></figure><p>', $bodytext); $bodytext = str_replace(array('<div>','</div>','<p >','<div >','<p><p>','</p></p>','<p align="center"></p>','<p></p>','<br>','<br><br>','<br><br><br>','<span >'), array('', '','','','','','','','','','','<span>'), $bodytext); $bodytext = preg_replace("#<p>(\s| |</?\s?br\s?/?>)*</?p>#", '', $bodytext); $bodytext = preg_replace('/<[^\/>]*>([\s]?)*<\/[^>]*>/', ' ', $bodytext); $bodytext = relToAbs($bodytext, NV_MY_DOMAIN); return $bodytext; } $db_slave->sqlreset() ->select('id, catid, publtime, title, alias, hometext, homeimgthumb, homeimgfile') ->order('publtime DESC') ->limit(30); if (! empty($catid)) { $channel['title'] = $module_info['custom_title'] . ' - ' . $global_array_cat[$catid]['title']; $channel['link'] = NV_BASE_SITEURL . 'index.php?' . NV_LANG_VARIABLE . '=' . NV_LANG_DATA . '&' . NV_NAME_VARIABLE . '=' . $module_name . '&' . NV_OP_VARIABLE . '=' . $alias_cat_url; $channel['description'] = $global_array_cat[$catid]['description']; $db_slave->from(NV_PREFIXLANG . '_' . $module_data . '_' . $catid) ->where('status=1'); } else { $db_slave->from(NV_PREFIXLANG . '_' . $module_data . '_rows') ->where('status=1 AND inhome=1'); } if ($module_info['rss']) { $result = $db_slave->query($db_slave->sql()); $_this_id = array(); while (list($id, $catid_i, $publtime, $title, $alias, $hometext, $homeimgthumb, $homeimgfile) = $result->fetch(3)) { $catalias = $global_array_cat[$catid_i]['alias']; $_this_id[] = $id; if ($homeimgthumb == 1) { // image thumb $rimages = NV_MY_DOMAIN . NV_BASE_SITEURL . NV_UPLOADS_DIR . '/' . $module_upload . '/' . $homeimgfile; } elseif ($homeimgthumb == 2) { // image file $rimages = NV_MY_DOMAIN . NV_BASE_SITEURL . NV_UPLOADS_DIR . '/' . $module_upload . '/' . $homeimgfile; } elseif ($homeimgthumb == 3) { // image url $rimages = $homeimgfile; } else { // no image $rimages = ''; } $coverimage = (! empty($rimages)) ? $rimages : ''; $rimages = (! empty($rimages)) ? '<img src="' . $rimages . '" width="100" align="left" border="0">' : ''; $_array_id = implode(',',$_this_id); // Related in same Category if( !isset($array_other[$id]) ){ // Related $db_slave->sqlreset() ->select('id, publtime, title, alias') ->from(NV_PREFIXLANG . '_' . $module_data . '_' . $catid_i) ->where('status=1 AND publtime < ' . $publtime . ' AND id <> ' . $id . ' AND id NOT IN (' . $_array_id . ')') ->order('publtime DESC') ->limit(3); $_result = $db_slave->query($db_slave->sql()); while ($other = $_result->fetch()) { $other['link'] = $global_array_cat[$catid_i]['link'] . '/' . $other['alias'] . '-' . $other['id'] . $global_config['rewrite_exturl']; $array_other[$id][] = array( 'link' => $other['link'] ); $_this_id[] = $other['id']; } $_result->closeCursor(); unset($_result, $other); } $items[] = array( 'title' => $title, 'link' => NV_BASE_SITEURL . 'index.php?' . NV_LANG_VARIABLE . '=' . NV_LANG_DATA . '&' . NV_NAME_VARIABLE . '=' . $module_name . '&' . NV_OP_VARIABLE . '=' . $catalias . '/' . $alias . '-' . $id . $global_config['rewrite_exturl'], // 'guid' => $module_name . '_' . $id, // 'description' => $rimages . $hometext, // 'coverimage' => $coverimage, // 'hometext' => $hometext, 'bodytext' => instant_body($id), 'pubdate' => $publtime, 'time' => date('Y-m-d', $publtime ), // 'related' => $array_other[$id] ); } } nv_instant_rss_generate($channel, $items); die();
File này sẽ xử lý và xuất ra RSS.
Các tin liên quan cũng được xuất ra. Vui lòng không sửa gì trong nội dung này nếu không rõ ...
03/ Khởi tạo file TPL
Trong file PHP instant bên trên, chúng ta gọi tới file TPL tên là instant_rss.tpl.
Chúng ta hãy khởi tạo file với tên và định dạng như trên. Nội dung file này như sau:
<!-- BEGIN: main --> <rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"> <channel> <title>{CHANNEL.title}</title> <!-- BEGIN: description --> <description> <![CDATA[{CHANNEL.description}]]> </description> <!-- END: description --> <language>{CHANNEL.lang}</language> <!-- BEGIN: pubDate --> <lastBuildDate>{CHANNEL.pubDate}</lastBuildDate> <!-- END: pubDate --> <!-- BEGIN: item --> <item> <title>{ITEM.title}</title> <link>{ITEM.link}</link> <guid>{ITEM.link}</guid> <!-- BEGIN: pubdate --> <pubDate>{ITEM.pubdate}</pubDate> <!-- END: pubdate --> <description> <![CDATA[ {ITEM.description} ]]> </description> <content:encoded> <![CDATA[ <!doctype html> <html lang="vi" prefix="op: http://media.facebook.com/op#"> <head> <meta charset="utf-8"> <link rel="canonical" href="{ITEM.link}"> <meta property="op:markup_version" content="v1.0"> </head> <body> <article> <header> <figure> <img src="{ITEM.coverimage}" /> <figcaption>{ITEM.title}</figcaption> </figure> <h1>{ITEM.title}</h1> <h2>{ITEM.hometext}</h2> <h3 class="op-kicker"> LỜI GIỚI THIỆU NÀO ĐÓ ............. </h3> <address> TÁC GIẢ BÀI VIẾT HOẶC TÊN WEBSITE ............ </address> <time class="op-published" dateTime="{ITEM.time}">{ITEM.pubdate}</time> <time class="op-modified" dateTime="{ITEM.time}">{ITEM.pubdate}</time> </header> <p> {ITEM.bodytext} </p> <footer> <!-- BEGIN: related --> <ul class="op-related-articles"> <!-- BEGIN: loop --> <li><a href="{RELATED.link}"></a></li> <!-- END: loop --> </ul> <!-- END: related --> <aside>NỘI DUNG TUỲ CHỌN HIỂN THỊ Ở CHÂN TRANG.</aside> <small>© TÁC GIẢ NẮM BẢN QUYỀN BÀI VIẾT</small> </footer> </article> </body> </html> ]]> </content:encoded> </item> <!-- END: item --> </channel> </rss> <!-- END: main -->
File TPL cần được đặt vào \themes\default\modules\news\.
Lưu ý một chút là trong TPL có một số chỗ như:
TÁC GIẢ BÀI VIẾT HOẶC TÊN WEBSITE ............
Các bạn có thể điền tuỳ ý hoặc tự xử lý để có nội dung phù hợp.
+++ Vậy là chúng ta xong phần code.
04/ Cấu hình để Module nhận function mới.
Truy cập
=> domain_cua_ban.com/admin/index.php?language=vi&nv=modules
Click chọn module News.
Tại đây, click chọn mục Instant. Bạn sẽ thấy như ảnh dưới.
Nhấn Thực hiện.
Sau đó truy cập đường dẫn:
=> domain_cua_ban.com/vi/news/instant/
Nếu hiển thị được nội dung là đã xong.
+++ Sau khi hoàn tất công cụ thì bạn làm theo hướng dẫn của FB nhé.
https://developers.facebook.com/docs/instant-articles/publishing/setup-rss-feed#rss-import
05/ Các ghi chú quan trọng:
+ Sử dụng đường dẫn sau để gán lên nơi xét duyệt của Facebook.
=> domain_cua_ban.com/vi/news/instant/
news có thể thay thế tương ứng với modules ảo mà bạn sử dụng.
+ Hình ảnh phải nằm trong thẻ figure và không được nằm trong thẻ p. Text phải nằm trong thẻ p.
+ Bài viết xử lý giao diện bằng cách xoá tất cả các thẻ HTML trong bài và gán figure cho ảnh, gắn p cho text. Bạn phải định dạng bài viết bằng công cụ style mà Facebook cung cấp.
+ Có những bài viết bạn phải tự xử lý thủ công. Các bài quá nhiều lỗi thì hàm không thể làm sạch được. Nội dung hiển thị sẽ bị ảnh hưởng.
+ Số RSS xuất ra là 30 và nên giữ ở mức này. Nhiều hơn có thể lỗi.
+ Số bài liên quan của mỗi bài viết là 03 và phải ở mức này. Nhiều hơn sẽ không hiển thị.
+ Các bài nếu đã có Instant rồi thì có thể phải xoá đi và để Facebook crawl lại mới nhận được các nội dung mới. Có thể sửa thông qua công cụ của FB.
+ Lần đầu crawl, bạn có thể cần tắt chức năng chống Flood của NukeViet vì FB sẽ crawl rất rất nhiều. Có thể tham khảo link:
=> domain_cua_ban.com/admin/index.php?language=vi&nv=settings&op=security
+ Ảnh minh hoạ bài viết dùng làm cover cho Bài viết tức thời. Do đó nên có chất lượng tốt để khi hiển thị được đẹp.
+ Chưa thử với các post có Video hoặc nội dung nhúng bằng iframe.
Chúc các bạn thành công.