There are several patterns that modules exposing a content type to Drupal Commons 3.x should expect to do.
I've been experimenting with Commons_Posts in a sandbox to get a sense of what these are. Checkout the latest status of the codebase at
http://drupalcode.org/sandbox/ezrag/1721532.git/tree/refs/heads/7.x-3.x
Here's an initial list:
- Add your content type to the Commons browsing widget:
Group home pages include a combination browsing/content creation widget.
Content types (Except for Events) should add themselves to this browsing widget. Notwithstanding #1782656: Panels exports don't revert, group home pages are panelized and include the browsing widget, which is powered by http://drupal.org/project/commons_bw.
Modules can add a tab to the widget by implementing hook_commons_bw() and returning an array of QuickTabs module formatted tabs.
This allows each content type to have its own unique view/presentation for how it should be displayed within its tab on the group homepage.
For example, Commons posts defines a simple view, and adds it as a tab on the group homepage like so:
/**
* Implements hook_commons_bw_group_widget().
*/
function commons_posts_commons_bw_group_widget() {
return array(
'commons_posts' => array(
'title' => 'Posts',
'type' => 'view',
'vid' => 'commons_bw_posts',
'display' => 'page_1',
'weight' => 5,
),
);
}
It exports the commons_bw_posts view (which would probably be better namespaced as commons_posts_group_bw).
We also implement hook_views_pre_render() to add the "Create a post" link to the tab for users who have access to do so:
/**
* Implements hook_views_pre_render().
*/
function commons_posts_views_pre_render(&$view) {
if ($view->name == 'commons_bw_posts' && user_access('Post: Create new content')) {
$group_id = $view->args[0];
$view->attachment_before = l('Create a post', 'node/add/post', array('query' => array('og_group_ref' => $group_id)));
}
}
We implement hook_strongarm_alter() in 2 places to integrate Commons content types with other Commons subsystems: Radioactivity, Liking and Groups:
Expose your content type to Commons Radioactivity
We alter the rate_widgets variable so that it is configured to include our content type and comments on that content type. For example:
/**
* Implements hook_strongarm_alter().
*/
function commons_posts_strongarm_alter(&$items) {
// Expose the Post content type for 'liking' via the Commons_like module
// by altering the configuration for the Rate.module widget that it provides.
if (!empty($items['rate_widgets']->value)) {
foreach($items['rate_widgets']->value as $key => $widget) {
if ($widget->name == 'commons_like') {
if (!in_array('post', $items['rate_widgets']->value[$key]->node_types)) {
$items['rate_widgets']->value[$key]->node_types[] = 'post';
}
if (!in_array('post', $items['rate_widgets']->value[$key]->comment_types)) {
$items['rate_widgets']->value[$key]->comment_types[] = 'post';
}
}
}
}
Expose your content type to "Liking" via Commons Like and as group content via Commons Groups
We expose our content type to Commons_radioactivity by overriding the commons_radioactivity_entity types variable. Currently, we also expose content types to Commons_groups in another variable with the same format, so we can do (in the same function):
// Expose the post content type for integration with Commons Radioactivity
// and Commons Groups.
foreach (array('commons_radioactivity_entity_types', 'commons_groups_entity_types') as $key) {
if (isset($items[$key])) {
$items[$key]->value['node']['post'] = 1;
}
}
Note: You may need to revert features after enabling a module that alters a strong-arm value that has been stored to the database. We should consider automatically reverting these components or prompting the user to do so. The intended benefit of using Strongarm vs a simple hook to expose our content types is that it makes it easier to expose the variable to configuration through the UI in the future.
Commons Radioactivity and Commons Groups each looks for its respective variable and add its respective field instance onto the content type that requests it.
As a developer of a module that integrates with Commons that's all you need to know ;). However, if you're interested in seeing how this works in practice, for example, see Commons Radioactivity:
/**
* Implements hook_system_info_alter().
*/
function commons_radioactivity_system_info_alter(&$info, $file, $type) {
// Commons Radioactivity dynamically adds field_radioactivity to
// content types that implement commons_radioactivity_field.
// We must add a corresponding line for each field instance
// to commons_radioactivity.info so that Features is aware of the instance
// and can sucessfully revert the field_instance component back
// to its default state.
if ($file->name == 'commons_radioactivity') {
$commons_radioactivity_entity_types = variable_get('commons_radioactivity_entity_types', array());
if (!empty($commons_radioactivity_entity_types['node'])) {
foreach ($commons_radioactivity_entity_types['node'] as $type => $status) {
if ($status) {
$info['features']['field_instance'][] = "node-$type-field_radioactivity";
}
}
}
}
}
/**
* Implements hook_field_default_field_instances().
*/
function commons_radioactivity_field_default_field_instances() {
// Get a list of content types that should have the Radioactivity field added.
// Modules can alter this list by implementing hook_strongarm_alter().
$commons_radioactivity_entity_types = variable_get('commons_radioactivity_entity_types', array());
if (!empty($commons_radioactivity_entity_types['node'])) {
$field_instances = array();
foreach($commons_radioactivity_entity_types['node'] as $type => $status) {
if ($status) {
commons_radioactivity_field_definition($field_instances, $type);
}
}
return $field_instances;
}
}
Panelized content type landing page as a submodule
It would be ideal for each content type to be panelized, to support customization to the page layout through the UI via Panelizer. To make it easier for site administrators to replace the default Commons panelized pages with their own configuration, each module that defines a content type should ideally export any landing pages or panelized content type pages into its own separate feature as a submodule in the main feature's Drupal.org.project.
As an alternative, we could include the default configuration as part of the main content type feature but encourage folks who define alternative Panels pages to alter the Commons default ones and make them disabled.
Comments
Comment #1
ezra-g CreditAttribution: ezra-g commentedComment #1.0
ezra-g CreditAttribution: ezra-g commentedAdd documentation of Panels exports.
Comment #2
ezra-g CreditAttribution: ezra-g commentedI added a note about Panelized content types and Panels landing pages.
Comment #2.0
ezra-g CreditAttribution: ezra-g commentedAdd note about disabled content type landing pages.
Comment #3
ezra-g CreditAttribution: ezra-g commentederikwebb pointed out that we could simplify the developer experience by having a single commons content type hook that modules could use to expose their content type(s) to the various integration points that Commons provides.
So, something like
It seems like content types could simply implement this hook, and if they're interacting with the group homepage browsing widget, also implement hook_views_pre_render() and hook_commons_bw() as appropriate.
Comment #4
erikwebb CreditAttribution: erikwebb commentedThis greatly simplifies the documentation as well as the developer experience. Especially for newer Drupal developers, this signifies Commons as more of a distinct, developer-friendly product, rather than requiring several uses of
hook_strongarm_alter()
,hook_flag_alter()
, etc. to implement the equivalent features.Since we will always know the available features in Commons, new features can be easily added to custom content types with a single line of code.
Comment #5
ezra-g CreditAttribution: ezra-g commentedThanks for the feedback - Updating the issue title to reflect the new action item here.
Comment #6
ezra-g CreditAttribution: ezra-g commentedAs we've used the current pattern so far, it seems like using a variable to store which content types are group-enabled may not be the best approach. The original motivation for this was because it would provide a natural place for us to add a UI that controls which content types are Radioactivity and Groups-enabled.
However, because of the nature of Strongarm, we've got to do additional feature reverts. For example, Commons posts alters the commons_radioactivity_entity_types variable, but we need to revert the Variable component on Commons radioactivity for this to be recognized. Then, once it is recognized by Commons Radioactivity, we may need to revert the field_instance component to define the field.
As an alternative, we could just use a hook implementation, rather than putting a variable on top of this.
Comment #7
ezra-g CreditAttribution: ezra-g commentedI've done this refactoring. Clearly, this needs review -- Let's get this review in the form of new issues around code content and bug reports of any broken functionality -- In my initial testing, this refactoring is successful so far.
Leaving this open for the remaining task: documentation.
http://drupalcode.org/project/commons_groups.git/commitdiff/55e1ce2?hp=e...
http://drupalcode.org/project/commons_radioactivity.git/commitdiff/f9ba7...
http://drupalcode.org/project/commons_follow.git/commitdiff/d794de8?hp=f...
http://drupalcode.org/project/commons_like.git/commitdiff/refs/heads/7.x...
http://drupalcode.org/project/commons_posts.git/commitdiff/883349c?hp=b3...
http://drupalcode.org/project/commons_q_a.git/commitdiff/ab1466f?hp=3024...
http://drupalcode.org/project/commons_wikis.git/commitdiff/3c5d344?hp=01...
http://drupalcode.org/project/commons_documents.git/commitdiff/6d52e4c?h...
Comment #8
Anonymous (not verified) CreditAttribution: Anonymous commentedezra-g,
Thanks for this page. It would be really nice to have a way to activate a Content Type in commons through the admin screen but I found it fairly easy to copy commons posts files and update to my Content Types. Thanks!
Comment #9
RobKoberg CreditAttribution: RobKoberg commentedCould we add an alter to affect the $settings and $tabs for quicktabs? I opened an issue with a patch here:
http://drupal.org/node/2003006
Comment #10
Anonymous (not verified) CreditAttribution: Anonymous commentedI dont know if this is the right place to write this... but i'm just approaching tho drupal and followed link landing here...
This means there's a way to add other tabs (wit their own views) to the default group homepage tabbed widget?
can someone explain me how to do it?
thanks, and tell me if this is the wrong place asking for (i will delete the post)
Comment #11
BarisW CreditAttribution: BarisW commentedAlso, please add a way to alter these hooks. Like #1990970: Add a way to alter hook_commons_entity_integration() implementations..
Comment #12
KarlKedrovsky CreditAttribution: KarlKedrovsky commentedI believe the first code sample should read:
Changing the 'display' from 'page_1' to 'default'. Without that change I was getting an access denied error which I believe was the same as what is described in https://drupal.org/node/1855254.
Comment #13
RobKoberg CreditAttribution: RobKoberg commentedPlease add the alter so we are not forced to use the commons quicktabs styling. Currently there is not way to affect quicktabs other than basic css which is not sufficient. I don't understand why this hasn't been done yet. It is a simple one line addition that does not affect how it operates if someone is happy with the default behavior and look and feel. Can there at least be a response as to why this won't get done?
Comment #14
ezra-g CreditAttribution: ezra-g commentedAdding to our 3.*5* radar. Let's finalize a documentation page based on this issue.
Comment #15
charlie charles CreditAttribution: charlie charles commentedSorry, where's the file I would I add this code to get a new tab please?
Comment #16
BetaTheta CreditAttribution: BetaTheta commented@post #15, I might be mistaken but I believe you have to put that code into a custom module.
Comment #17
charlie charles CreditAttribution: charlie charles commentedThanks BetaTheta
Comment #18
charlie charles CreditAttribution: charlie charles commentedHi,where is it in the documentation
how to create a custom module for your own Commons browsing widget please?
https://docs.acquia.com/commons/
Comment #18.0
charlie charles CreditAttribution: charlie charles commentedCorrect closing tag.
Comment #19
thatguy CreditAttribution: thatguy commentedI am trying to add a tab to the browsing widget but when I made a custom module with this code in the .module file:
it still doesnt show new tab in the browsing widget. What could I be doing wrong?
Comment #20
ceepeebee CreditAttribution: ceepeebee commented@thatguy: have a look at the step-by-step guide I wrote a couple of days ago, that should help
btw, you shouldn't use 'commons_posts' as an array key, because it's already taken by commons_posts... and maybe try changing the title as well and use the proper hook name. ;) but I guess, you did that, even though you posted differently, didn't you?
Comment #21
Devin Carlson CreditAttribution: Devin Carlson commentedI've just released an initial beta of the Commons Browsing Widget User Interface module which provides a basic user interface for configuring the browsing widget tabs, including their settings and associated content types.
I'm hoping that it makes configuring the browsing widget easier for non-technical folks and serves as a reference for developers (which can also just export its configuration if they don't want to write the code themselves).
Comment #22
iaminawe CreditAttribution: iaminawe commentedDevin - awesome module thank you - simplifies this process significantly of integrating other content types into Commons.