► 主要利用 hook_node_view() 在呈現時加入投票機制
► 投票樣式處理 theme// 實作 hook_node_view, 動態增加 node 顯示資料 function plusone_node_view($node, $view_mode) { global $user; $total = plusone_get_total($node->nid); $is_author = db_query('SELECT uid from {node} where nid = :nid AND uid = :uid', array(":nid" => $node->nid, ":uid" => $user->uid))->fetchField(); if ($is_author) { $is_author = TRUE; } else { $is_author = FALSE; } $voted = plusone_get_vote($node->nid, $user->uid); if ($view_mode == 'full') {//增加顯示資料 $variables = array('nid' => (int) $node->nid, 'total' => (int) $total, 'is_author' => $is_author, 'voted' => $voted); $node->content['plusone_vote'] = array(//加入自訂元素 '#markup' => theme('plusone_widget', $variables),//組成資料 '#weight' => 100, ); } }
► 資料處理// Implementation of hook_theme(). 註冊 theme function. function plusone_theme() { return array( 'plusone_widget' => array( //'template' => 'plusone_widget', //使用模板方式呈現樣式 tpl.php ), ); } //投票 顯示樣式(Theme) 非 template 形式 function theme_plusone_widget($variables) { drupal_add_js(drupal_get_path('module', 'plusone') . '/plusone.js'); drupal_add_css(drupal_get_path('module', 'plusone') . '/plusone.css'); $output = '<div class="plusone-widget">'; $output .= '<div class="score">' . $variables['total'] . '</div>'; if (user_access('rate content') && !$variables['is_author']) {//許可投票者才顯示連結 $output .= '<div class="vote">'; if ($variables['voted']) { $output .= t('已投票'); } else { //加入投票連結. $output .= l(t('投一票'), "plusone/vote/" . $variables['nid'], array( 'attributes' => array('class' => 'plusone-link') )); } $output .= '</div>'; // Close div with class "vote". } $output .= '</div>'; // Close div with class "plusone-widget". return $output; }
► javascript 使用AJAX傳送投票請求 plusone.js// 增加投票紀錄 function plusone_vote($nid) { global $user; $nid = (int) $nid; // 檢查該node是否為作者本人 $is_author = db_query('SELECT uid from {node} where nid = :nid AND uid = :uid', array(":nid" => (int) $nid, ":uid" => (int) $user->uid))->fetchField(); if ($nid > 0 && !$is_author) { $vote_count = plusone_get_vote($nid, $user->uid); if (!$vote_count) {//該使用怎若無投票紀錄則增加票數儲存 db_delete('plusone_votes') ->condition('uid', $user->uid) ->condition('nid', $nid)->execute(); db_insert('plusone_votes') ->fields(array( 'uid' => $user->uid, 'nid' => $nid, 'vote_count' => $vote_count + 1, ))->execute(); } } $total_votes = plusone_get_total($nid); // 確認是否為 AJAX 呼叫, 若是則POST請求中會含 js=1(自行定義) 資訊 if (!empty($_POST['js'])) {//採用 JavaScript 呼叫時以 JSON 回應更新頁面資訊 drupal_json_output(array( 'total_votes' => $total_votes, 'voted' => t('You Voted') ) ); exit(); } // 若不是使用 JavaScript 呼叫則採用轉向方式更新頁面 $path = drupal_get_path_alias('node/' . $nid); drupal_goto($path); } //取得當前使用者該node投票紀錄 function plusone_get_vote($nid, $uid) { $vote_count = db_query('SELECT vote_count FROM {plusone_votes} WHERE nid = :nid AND uid = :uid', array(':nid' => $nid, ':uid' => $uid))->fetchField(); return $vote_count; } // 傳回node總票數 function plusone_get_total($nid) { $total_count = (int) db_query('SELECT SUM(vote_count) from {plusone_votes} where nid = :nid', array(':nid' => $nid))->fetchField(); return ($total_count); }
► CSS plusone.css// jQuery 雖可用 $ 代替簡化, 但若同時載入多個 js 時,其內部也定義 $ 時, 則當下 $ 是否代表為 jQuery 就不一定 // 多重載入 js 時, $ 表示為呼叫前最後一個載入的 js, 因此還是不用使用 $ 為佳 jQuery(document).ready(function() { // 為 連結類別 "plusone-link" 增加 按鍵事件 for the . jQuery('a.plusone-link').click(function() { // When clicked, first define an anonymous function to the variable voteSaved. var voteSaved = function(data) {// Update data. jQuery('div.score').html(data.total_votes); jQuery('div.vote').html(data.voted); } // 使用 AJAX 方式投票 jQuery.ajax({ type: 'POST', // 使用 POST 請求. url: this.href, dataType: 'json', success: voteSaved, data: 'js=1' // 傳送 js=1 告訴處理者以 JSON 方式回應資料 }); // Prevent the browser from handling the click. return false; }); });
選單,權限登錄div.plusone-widget { width: 100px; margin-bottom: 5px; text-align: center; } div.plusone-widget .score { padding: 10px; border: 1px solid #999; background-color: #eee; font-size: 175%; } div.plusone-widget .vote { padding: 1px 5px; margin-top: 2px; border: 1px solid #666; background-color: #ddd; }
► 使用模板方式呈現 plusone_widget.tpl.php//hook_permission(). function plusone_permission() { $perms = array( 'rate content' => array( 'title' => t('rate content'), ), ); return $perms; } // hook_menu() 投票action function plusone_menu() { $items['plusone/vote/%'] = array( 'title' => 'Vote', 'page callback' => 'plusone_vote', 'page arguments' => array(2), 'access arguments' => array('rate content'), 'type' => MENU_CALLBACK, ); return $items; }
drupal_add_js(drupal_get_path('module', 'plusone') . '/plusone.js'); drupal_add_css(drupal_get_path('module', 'plusone') . '/plusone.css'); $output = '<div class="plusone-widget">'; //$variables[] 內 key值 均可以變數型態直接取值$key //$variables['total'] 與 $total 是相同的 $output .= '<div class="score">' . $total . '</div>'; if (user_access('rate content') && !$is_author) {//有投票權才顯示連結 $output .= '<div class="vote">'; if ($voted > 0) { $output .= t('已投票'); } else { $output .= l(t('投一票'), "plusone/vote/$nid", array( 'attributes' => array('class' => 'plusone-link') )); } $output .= '</div>'; // Close div with class "vote". } $output .= '</div>'; // Close div with class "plusone-widget". print $output;