For my work with AdHack, I've started using Managing News as a Drupal-based solution for brand monitoring. As with most Development Seed products, it's a well-designed piece of software that is a joy to work with and enhance.
One of my first tasks was to allow users to mark articles with a star, and to find those starred items in their own channel. In MN, channels are lists of articles that are tagged with a specific set of tags. The channel is defined by its tags, and the MN views logic dynamically creates the list by matching a channel's tags with existing articles.
Of course, the starring logic is different: an article's star has nothing to do with tags. But from a usability perspective, we felt that users would intuitively search for their starred items in the channels, since this is the section where content is manually organized. That's why we decided to have a "Starred" channel that would list all starred articles. What follows is a description of how I implemented this feature.
Fortunately, MN already uses a marking mechanism, namely the Mark module, based on the flexible Voting API. It is used in MN to mark items as trashed, so I created a new mark called "star" and associated it with the Data table "feeds_data_syndication" (at admin/settings/mark).
I then added the "Syndication: star" field to all the views where I want the Star icon to appear:
When I edited these views, I noticed there are many displays, so I made sure to add the new field everywhere the "Syndication: trash" appears. I also removed the label from the field, because the theme will take care of displaying the Star icon where necessary.
This is where things started to get interesting. I wanted to modify the articles display to display a star above the trash icon, like so:

profiles/managingnews/themes/jake/templates/mn-feeditem.tpl.php to display the star among the right-hand side icons:- $links = jake_views_render_field($fields['simpleshare_link']) . jake_views_render_field($fields['mark_trash']);
+ $links = jake_views_render_field($fields['simpleshare_link']) . jake_views_render_field($fields['mark_star']) . jake_views_render_field($fields['mark_trash']);profiles/managingnews/themes/jake/js/theme.js to prevent star-clicking from hiding the article (which is the behaviour for the trash):- $('.mark-link > a').bind('mark.drupalMark', function() { $(this).parents('li.views-row').hide(600);});
+ $('.views-field-mark-trash a').bind('mark.drupalMark', function() { $(this).parents('li.views-row').hide(600);});/**
* @file mymodule.css
*/
div.feeditem-links div.views-field-mark-star div.mark-link.unmarked a {
background:transparent url(../../../../profiles/managingnews/themes/jake/images/sprite.png) no-repeat scroll -370px 0px;
}
div.feeditem-links div.views-field-mark-star div.mark-link.marked a {
background:transparent url(../../../../profiles/managingnews/themes/jake/images/sprite.png) no-repeat scroll -370px -30px;
}
div.feeditem-links div.views-field-mark-star div.mark-link a:hover {
background-color:#444;
width:160px;
text-indent:0px;
overflow:hidden;
padding-left:30px;
}// @file mymodule.js
Drupal.behaviors.mymodule = function(context) {
$('.views-field-mark-star a').bind('mark.drupalMark', function() {
if ($(this).parents('.mark-link').hasClass('marked')) {
$(this).css('background-position', '-370px -30px');
}
else {
$(this).css('background-position', '-370px 0px');
}
});
}<?php
// @file mymodule.module
function mymodule_init() {
drupal_add_js(drupal_get_path('module', 'mymodule') . '/mymodule.js');
drupal_add_css(drupal_get_path('module', 'mymodule') . '/mymodule.css');
}
?>At this point, I had a functional starring mechanism. What was missing was the hard-coded Starred channel that would display all starred items. It did involve some hacking...
Create a new channel entitled "Starred". The title will be important later on. Provide any tag (e.g. star) although it will not be used.
Clone the view mn_channel_news into a new view called starred_channel_news that will display the starred items. Perform the following modifications:
channel/starredchannel/starred/rss.xmlModify context mn-section-channels to apply to the new view as well:
starred_channel_news.Clone context mn-section-channels-notrash into a new context for the Starred channel. Perform the following modifications:
starred_channel_news instead of mn_channels_news.Modify profiles/managingnews/modules/features/mn_channels/mn_channels.module to invoke our new view when opening the starred channel:
<?php
function mn_channels_node_page_view($node, $cid = NULL) {
+ $starred = strcasecmp($node->title, 'starred') == 0; // Starred channel is a special case
if (isset($_GET['display']) && $_GET['display'] != 'default') {
- drupal_goto('channel/'. $node->nid, 'display='. urlencode($_GET['display']));
+ drupal_goto('channel/'. ($starred ? 'starred' : $node->nid), 'display='. urlencode($_GET['display']));
}
$terms = array();
foreach ($node->taxonomy as $term) {
if ($plugin = context_get_plugin('condition', 'node')) {
$plugin->execute($node, 'view');
}
- $view = views_get_view('mn_channels_news');
+ $view = views_get_view($starred ? 'starred_channel_news' : 'mn_channels_news');
$output = $view->execute_display('page_1', array($node->nid));
if ($view->total_rows != 0) {
return $output;
...
?>profiles/managingnews/modules/features/mn_channels/views/mn_channels_views_handler_field_item_count.inc to display the correct item count for Starred channel:<?php
- if ($this->view->base_table == 'node') {
- $this->items[$tid] = db_result(db_query("SELECT COUNT(DISTINCT dt.id) AS count FROM {node} n LEFT JOIN {term_node} tn ON tn.nid = n.nid LEFT JOIN {data_taxonomy} dt ON dt.tid = tn.tid INNER JOIN {feeds_data_syndication} fds ON fds.id = dt.id LEFT JOIN {votingapi_vote} vapi ON fds.id = vapi.content_id AND vapi.content_type = 'feeds_data_syndication' WHERE n.nid = %d AND vapi.value IS NULL", $tid));
- } else {
- $this->items[$tid] = db_result(db_query("SELECT COUNT(dt.id) AS count FROM {data_taxonomy} dt INNER JOIN {feeds_data_syndication} fds ON fds.id = dt.id LEFT JOIN {votingapi_vote} vapi ON fds.id = vapi.content_id AND vapi.content_type = 'feeds_data_syndication' WHERE tid = %d AND vapi.value IS NULL", $tid));
- }
+ if ($this->view->base_table == 'node' && strcasecmp($row->node_title, 'starred') == 0) { // Starred channel behaves by counting starred items
+ $this->items[$tid] = db_result(db_query("
+ SELECT COUNT(*)
+ FROM {votingapi_vote} v1
+ WHERE v1.value_type='mark'
+ AND v1.tag='star'
+ AND NOT EXISTS (
+ SELECT v2.vote_id
+ FROM {votingapi_vote} v2
+ WHERE v1.content_id = v2.content_id
+ AND v2.value_type='mark'
+ AND v2.tag='trash'
+ )
+ "));
+ }
+ else {
+ if ($this->view->base_table == 'node') {
+ $this->items[$tid] = db_result(db_query("
+ SELECT COUNT(DISTINCT dt.id) AS count
+ FROM {node} n
+ LEFT JOIN {term_node} tn ON tn.nid = n.nid
+ LEFT JOIN {data_taxonomy} dt ON dt.tid = tn.tid
+ INNER JOIN {feeds_data_syndication} fds ON fds.id = dt.id
+ WHERE n.nid = %d
+ AND NOT EXISTS (
+ SELECT vapi.vote_id
+ FROM {votingapi_vote} vapi
+ WHERE fds.id = vapi.content_id
+ AND vapi.content_type = 'feeds_data_syndication'
+ AND vapi.value_type= 'mark'
+ AND vapi.tag = 'trash'
+ )
+ ", $tid));
+ } else {
+ $this->items[$tid] = db_result(db_query("
+ SELECT COUNT(dt.id) AS count
+ FROM {data_taxonomy} dt
+ INNER JOIN {feeds_data_syndication} fds ON fds.id = dt.id
+ WHERE tid = %d
+ AND NOT EXISTS (
+ SELECT vapi.vote_id
+ FROM {votingapi_vote} vapi
+ WHERE fds.id = vapi.content_id
+ AND vapi.content_type = 'feeds_data_syndication'
+ AND vapi.value_type= 'mark'
+ AND vapi.tag = 'trash'
+ )
+ ", $tid));
+ }
+ }
?>That's it! I didn't particularly enjoy hacking into MN's modules, so please let me know if you see a better way!
| Attachment | Size |
|---|---|
| star.png | 66.44 KB |
Comments
Nice tutorial. Rather than
Nice tutorial. Rather than hack mn_channels_views_handler_field_item_count, you could duplicate it, include the duplicate in your custom module, and use a views default alter hook to switch the default views in MN to use your custom handler. This would get you closer to the point of wrapping this hack into a downloadable feature that can simply be dropped in and turned on for any MN site.
Will
Updated some code
I updated the code for
profiles/managingnews/modules/features/mn_channels/views/mn_channels_views_handler_field_item_count.inc. Adding the star mark had caused the original channel count to fail. It happens!great hack
hello,
I follow your hack but i have an error:
Fatal error: Call to a member function execute_display() on a non-object in htdocs\managingnews\profiles\managingnews\modules\features\mn_channels\mn_channels.module on line 72
any idea?
i found, i have
i found, i have starred_channelS_news instead of starred_channel_news
;)
Id love to get hold of the
Id love to get hold of the update
The updated code is in the
The updated code is in the article body.