4. This is Code Heavy
• We will be discussing
code
• If you are not a coder this
will probably be
incredibly boring to you
5. This is Code Heavy
• We will be discussing
code
• If you are not a coder this
will probably be
incredibly boring to you
• We are not responsible
for what may happen to
you if you fall asleep.
7. The Next Hour
• Lots of content and fast talking. Save questions
until the end
8. The Next Hour
• Lots of content and fast talking. Save questions
until the end
• Discuss key concepts in Drupal 7: Bundles,
Entities and Fields
9. The Next Hour
• Lots of content and fast talking. Save questions
until the end
• Discuss key concepts in Drupal 7: Bundles,
Entities and Fields
• Walk through the creation of a content type
that will add a Bundle of Fields complete
with custom Formatters to the node Entity
10. The Next Hour
• Lots of content and fast talking. Save questions
until the end
• Discuss key concepts in Drupal 7: Bundles,
Entities and Fields
• Walk through the creation of a content type
that will add a Bundle of Fields complete
with custom Formatters to the node Entity
• Explain WTH that last comment meant
11. The Next Hour
• Lots of content and fast talking. Save questions
until the end
• Discuss key concepts in Drupal 7: Bundles,
Entities and Fields
• Walk through the creation of a content type
that will add a Bundle of Fields complete
with custom Formatters to the node Entity
• Explain WTH that last comment meant
• Introduce the most excellent node_example
module
13. Key Concept
Entity
• An Entity is a container for Bundles.
14. Key Concept
Entity
• An Entity is a container for Bundles.
• Entities can contain multiple Bundles.
15. Key Concept
Entity
• An Entity is a container for Bundles.
• Entities can contain multiple Bundles.
• Examples are Node, User, File, Taxonomy Term,
Taxonomy Vocabulary
16. Key Concept
Entity
• An Entity is a container for Bundles.
• Entities can contain multiple Bundles.
• Examples are Node, User, File, Taxonomy Term,
Taxonomy Vocabulary
• Why not make everything an Entity?
18. Key Concept
Bundles
• A Bundle is a set of fields that are treated as a
group by the Field API
19. Key Concept
Bundles
• A Bundle is a set of fields that are treated as a
group by the Field API
• Bundles are similar in concept to a node type in
Drupal 6
21. Key Concept
Fields
• A field defines a particular type of data that can
be attached to any entity and can be shared
between entities
22. Key Concept
Fields
• A field defines a particular type of data that can
be attached to any entity and can be shared
between entities
• A field can have Widgets. A widget is the UI
element that allows a user to enter data into the
field
23. Key Concept
Fields
• A field defines a particular type of data that can
be attached to any entity and can be shared
between entities
• A field can have Widgets. A widget is the UI
element that allows a user to enter data into the
field
• A field can have Formatters. A formatter defines
how a fields data gets displayed in a view mode
25. The Examples Module
• In my mind, the best resource for learning is the
Examples Modue
26. The Examples Module
• In my mind, the best resource for learning is the
Examples Modue
• This module used to live exclusively in CVS but is
now maintained by rfay, Dave Reid, katbailey
and ilo in contrib
27. The Examples Module
• In my mind, the best resource for learning is the
Examples Modue
• This module used to live exclusively in CVS but is
now maintained by rfay, Dave Reid, katbailey
and ilo in contrib
• Documentation can be viewed from
api.drupal.org by following the Examples link
28. The Examples Module
• In my mind, the best resource for learning is the
Examples Modue
• This module used to live exclusively in CVS but is
now maintained by rfay, Dave Reid, katbailey
and ilo in contrib
• Documentation can be viewed from
api.drupal.org by following the Examples link
• drupal.org/project/examples - not just the node
module
32. D7 *.install
• We still implement hook_install() and
hook_uninstall()
33. D7 *.install
• We still implement hook_install() and
hook_uninstall()
• hook_schema() no longer needs to be explicitly
called
34. D7 *.install
• We still implement hook_install() and
hook_uninstall()
• hook_schema() no longer needs to be explicitly
called
• Database structure will resemble D6 CCK tables
35. D7 *.install
• We still implement hook_install() and
hook_uninstall()
• hook_schema() no longer needs to be explicitly
called
• Database structure will resemble D6 CCK tables
• Database Entity revisions are provided
automatically
38. /**
* Implements hook_install().
*
*/
function node_example_install() {
...
}
/**
* Return a structured array defining the fields created by this content type.
*
* This is packaged in a function so it can be used in both hook_install()
* and hook_uninstall().
*/
function _node_example_installed_fields() {
...
}
39. /**
* Implements hook_install().
*
*/
function node_example_install() {
...
}
/**
* Return a structured array defining the fields created by this content type.
*
* This is packaged in a function so it can be used in both hook_install()
* and hook_uninstall().
*/
function _node_example_installed_fields() {
...
}
/**
* Return a structured array defining the instances for this content type.
*
* The instance lets Drupal know which widget to use to allow the user to enter
* data and how to react in different view modes.
* This is provided as a function so that it can be used in both hook_install()
* and hook_uninstall().
*/
function _node_example_installed_instances() {
...
}
40. /**
* Implements hook_install().
*
*/
function node_example_install() {
...
}
/**
* Return a structured array defining the fields created by this content type.
*
* This is packaged in a function so it can be used in both hook_install()
* and hook_uninstall().
*/
function _node_example_installed_fields() {
...
}
/**
* Return a structured array defining the instances for this content type.
*
* The instance lets Drupal know which widget to use to allow the user to enter
* data and how to react in different view modes.
* This is provided as a function so that it can be used in both hook_install()
* and hook_uninstall().
*/
function _node_example_installed_instances() {
...
}
/**
* Implements hook_uninstall().
*
*/
function node_example_uninstall() {
...
}
43. D7 *.install
• hook_install() will set up our content type
• hook_install() is where we create our fields, if
needed
44. D7 *.install
• hook_install() will set up our content type
• hook_install() is where we create our fields, if
needed
• hook_install() is used to tie our fields to an
Entity as a Bundle
47. function node_example_install() {
$types = node_type_get_types();
node_add_body_field($types['node_example']);
// Load the instance definition for our content type's body
// http://api.drupal.org/api/function/field_info_instance/7
$body_instance = field_info_instance('node', 'body', 'node_example');
}
48. function node_example_install() {
$types = node_type_get_types();
node_add_body_field($types['node_example']);
// Load the instance definition for our content type's body
// http://api.drupal.org/api/function/field_info_instance/7
$body_instance = field_info_instance('node', 'body', 'node_example');
// Add our example_node_list view mode to the body instance display by
// instructing the body to display as a summary
$body_instance['type'] = 'text_summary_or_trimmed';
}
49. function node_example_install() {
$types = node_type_get_types();
node_add_body_field($types['node_example']);
// Load the instance definition for our content type's body
// http://api.drupal.org/api/function/field_info_instance/7
$body_instance = field_info_instance('node', 'body', 'node_example');
// Add our example_node_list view mode to the body instance display by
// instructing the body to display as a summary
$body_instance['type'] = 'text_summary_or_trimmed';
// Save our changes to the body field instance.
// http://api.drupal.org/api/function/field_update_instance/7
field_update_instance($body_instance);
}
50. function node_example_install() {
$types = node_type_get_types();
node_add_body_field($types['node_example']);
// Load the instance definition for our content type's body
// http://api.drupal.org/api/function/field_info_instance/7
$body_instance = field_info_instance('node', 'body', 'node_example');
// Add our example_node_list view mode to the body instance display by
// instructing the body to display as a summary
$body_instance['type'] = 'text_summary_or_trimmed';
// Save our changes to the body field instance.
// http://api.drupal.org/api/function/field_update_instance/7
field_update_instance($body_instance);
// Create all the fields we are adding to our content type.
// http://api.drupal.org/api/function/field_create_field/7
foreach (_node_example_installed_fields() as $field) {
field_create_field($field);
}
}
51. function node_example_install() {
$types = node_type_get_types();
node_add_body_field($types['node_example']);
// Load the instance definition for our content type's body
// http://api.drupal.org/api/function/field_info_instance/7
$body_instance = field_info_instance('node', 'body', 'node_example');
// Add our example_node_list view mode to the body instance display by
// instructing the body to display as a summary
$body_instance['type'] = 'text_summary_or_trimmed';
// Save our changes to the body field instance.
// http://api.drupal.org/api/function/field_update_instance/7
field_update_instance($body_instance);
// Create all the fields we are adding to our content type.
// http://api.drupal.org/api/function/field_create_field/7
foreach (_node_example_installed_fields() as $field) {
field_create_field($field);
}
// Create all the instances for our fields.
// http://api.drupal.org/api/function/field_create_instance/7
foreach (_node_example_installed_instances() as $instance) {
$instance['entity_type'] = 'node';
$instance['bundle'] = 'node_example';
field_create_instance($instance);
}
}
53. D7 *.install
• The node_example module defines and invokes
3 distinct fields
54. D7 *.install
• The node_example module defines and invokes
3 distinct fields
• We place these in a helper function so that it can
be called as needed in functions like
hook_install() and hook_uninstall()
66. D7 *.install
• hook_uninstall() is used to clean up the data
created with the node_example module
• hook_uninstall() deletes our fields and their
instances
67. D7 *.install
• hook_uninstall() is used to clean up the data
created with the node_example module
• hook_uninstall() deletes our fields and their
instances
• hook_uninstall() deletes our content type
68. D7 *.install
• hook_uninstall() is used to clean up the data
created with the node_example module
• hook_uninstall() deletes our fields and their
instances
• hook_uninstall() deletes our content type
• hook_uninstall purges field data from the system
70. function node_example_uninstall() {
// Gather all the example content that might have been created while this
// module was enabled. Simple selects still use db_query().
// http://api.drupal.org/api/function/db_query/7
$sql = 'SELECT nid FROM {node} n WHERE n.type = :type';
$result = db_query($sql, array(':type' => 'node_example'));
$nids = array();
foreach ($result as $row) {
$nids[] = $row->nid;
}
}
71. function node_example_uninstall() {
// Gather all the example content that might have been created while this
// module was enabled. Simple selects still use db_query().
// http://api.drupal.org/api/function/db_query/7
$sql = 'SELECT nid FROM {node} n WHERE n.type = :type';
$result = db_query($sql, array(':type' => 'node_example'));
$nids = array();
foreach ($result as $row) {
$nids[] = $row->nid;
}
// Delete all the nodes at once
// http://api.drupal.org/api/function/node_delete_multiple/7
node_delete_multiple($nids);
}
72. function node_example_uninstall() {
// Gather all the example content that might have been created while this
// module was enabled. Simple selects still use db_query().
// http://api.drupal.org/api/function/db_query/7
$sql = 'SELECT nid FROM {node} n WHERE n.type = :type';
$result = db_query($sql, array(':type' => 'node_example'));
$nids = array();
foreach ($result as $row) {
$nids[] = $row->nid;
}
// Delete all the nodes at once
// http://api.drupal.org/api/function/node_delete_multiple/7
node_delete_multiple($nids);
// Loop over each of the fields defined by this module and delete
// all instances of the field, their data, and the field itself.
// http://api.drupal.org/api/function/field_delete_field/7
foreach (array_keys(_node_example_installed_fields()) as $field) {
field_delete_field($field);
}
}
73. function node_example_uninstall() {
// Gather all the example content that might have been created while this
// module was enabled. Simple selects still use db_query().
// http://api.drupal.org/api/function/db_query/7
$sql = 'SELECT nid FROM {node} n WHERE n.type = :type';
$result = db_query($sql, array(':type' => 'node_example'));
$nids = array();
foreach ($result as $row) {
$nids[] = $row->nid;
}
// Delete all the nodes at once
// http://api.drupal.org/api/function/node_delete_multiple/7
node_delete_multiple($nids);
// Loop over each of the fields defined by this module and delete
// all instances of the field, their data, and the field itself.
// http://api.drupal.org/api/function/field_delete_field/7
foreach (array_keys(_node_example_installed_fields()) as $field) {
field_delete_field($field);
}
// Loop over any remaining field instances attached to the node_example
// content type (such as the body field) and delete them individually.
// http://api.drupal.org/api/function/field_delete_field/7
$instances = field_info_instances('node', 'node_example');
foreach ($instances as $instance_name => $instance) {
field_delete_instance($instance);
}
}
74. function node_example_uninstall() {
// Gather all the example content that might have been created while this
// module was enabled. Simple selects still use db_query().
// http://api.drupal.org/api/function/db_query/7
$sql = 'SELECT nid FROM {node} n WHERE n.type = :type';
$result = db_query($sql, array(':type' => 'node_example'));
$nids = array();
foreach ($result as $row) {
$nids[] = $row->nid;
}
// Delete all the nodes at once
// http://api.drupal.org/api/function/node_delete_multiple/7
node_delete_multiple($nids);
// Loop over each of the fields defined by this module and delete
// all instances of the field, their data, and the field itself.
// http://api.drupal.org/api/function/field_delete_field/7
foreach (array_keys(_node_example_installed_fields()) as $field) {
field_delete_field($field);
}
// Loop over any remaining field instances attached to the node_example
// content type (such as the body field) and delete them individually.
// http://api.drupal.org/api/function/field_delete_field/7
$instances = field_info_instances('node', 'node_example');
foreach ($instances as $instance_name => $instance) {
field_delete_instance($instance);
}
// Delete our content type
// http://api.drupal.org/api/function/node_type_delete/7
node_type_delete('node_example');
}
75. function node_example_uninstall() {
// Gather all the example content that might have been created while this
// module was enabled. Simple selects still use db_query().
// http://api.drupal.org/api/function/db_query/7
$sql = 'SELECT nid FROM {node} n WHERE n.type = :type';
$result = db_query($sql, array(':type' => 'node_example'));
$nids = array();
foreach ($result as $row) {
$nids[] = $row->nid;
}
// Delete all the nodes at once
// http://api.drupal.org/api/function/node_delete_multiple/7
node_delete_multiple($nids);
// Loop over each of the fields defined by this module and delete
// all instances of the field, their data, and the field itself.
// http://api.drupal.org/api/function/field_delete_field/7
foreach (array_keys(_node_example_installed_fields()) as $field) {
field_delete_field($field);
}
// Loop over any remaining field instances attached to the node_example
// content type (such as the body field) and delete them individually.
// http://api.drupal.org/api/function/field_delete_field/7
$instances = field_info_instances('node', 'node_example');
foreach ($instances as $instance_name => $instance) {
field_delete_instance($instance);
}
// Delete our content type
// http://api.drupal.org/api/function/node_type_delete/7
node_type_delete('node_example');
// Purge all field information
// http://api.drupal.org/api/function/field_purge_batch/7
field_purge_batch(1000);
}
78. D7 *.module
• Finally on to the module file!
• Let’s start with the hooks we will recognize from
D6
79. D7 *.module
• Finally on to the module file!
• Let’s start with the hooks we will recognize from
D6
• hook_node_info() informs Drupal about our
content type
80. D7 *.module
• Finally on to the module file!
• Let’s start with the hooks we will recognize from
D6
• hook_node_info() informs Drupal about our
content type
• hook_menu() tells Drupal where our custom
page is going to live and how to build it
81. D7 *.module
• Finally on to the module file!
• Let’s start with the hooks we will recognize from
D6
• hook_node_info() informs Drupal about our
content type
• hook_menu() tells Drupal where our custom
page is going to live and how to build it
• hook_help() provides help information for our
users
82.
83. /**
* Implements hook_node_info() to provide our node_example type.
*/
function node_example_node_info() {
return array(
'node_example' => array(
'name' => t('Example Node'),
'base' => 'node_example',
'description' => t('This is an example node type with a few fields.'),
'has_title' => TRUE,
),
);
}
84. /**
* Implements hook_node_info() to provide our node_example type.
*/
function node_example_node_info() {
return array(
'node_example' => array(
'name' => t('Example Node'),
'base' => 'node_example',
'description' => t('This is an example node type with a few fields.'),
'has_title' => TRUE,
),
);
}
/**
* Implements hook_menu().
*
* We are providing a default page to illustrate the use of our custom node view
* mode that will live at http://example.com/?q=examples/node_example
*/
function node_example_menu() {
$items['examples/node_example'] = array(
'page callback' => 'node_example_page',
'access arguments' => array('access content'),
'title' => 'Node Example',
);
return $items;
}
85. /**
* Implements hook_node_info() to provide our node_example type.
*/
function node_example_node_info() {
return array(
'node_example' => array(
'name' => t('Example Node'),
'base' => 'node_example',
'description' => t('This is an example node type with a few fields.'),
'has_title' => TRUE,
),
);
}
/**
* Implements hook_menu().
*
* We are providing a default page to illustrate the use of our custom node view
* mode that will live at http://example.com/?q=examples/node_example
*/
function node_example_menu() {
$items['examples/node_example'] = array(
'page callback' => 'node_example_page',
'access arguments' => array('access content'),
'title' => 'Node Example',
);
return $items;
}
/**
* Implements hook_help().
*/
function node_example_help($path, $arg) {
switch ($path) {
case 'examples/node_example':
return "<p>" . t(
"The Node Example module provides a custom node type.
You can create new nodes using the <a href='!nodeadd'>node add form</a>.
Nodes that you create will be displayed here.",
array('!nodeadd' => url('node/add/node-example'))
) . "</p>";
}
}
88. d7 *.module
• hook_form() is used to create the basic content
form
• hook_theme() informs Drupal of our theme
callbacks
89.
90. /**
* Implement hook_form() with the standard default form.
*/
function node_example_form($node, $form_state) {
return node_content_form($node, $form_state);
}
91. /**
* Implement hook_form() with the standard default form.
*/
function node_example_form($node, $form_state) {
return node_content_form($node, $form_state);
}
/**
* Implements hook_theme().
*
* This lets us tell Drupal about our theme functions and their arguments.
*/
function node_example_theme($existing, $type, $theme, $path) {
return array(
'example_node_color' => array(
'variables' => array('color' => NULL),
),
);
}
92. /**
* Implement hook_form() with the standard default form.
*/
function node_example_form($node, $form_state) {
return node_content_form($node, $form_state);
}
/**
* Implements hook_theme().
*
* This lets us tell Drupal about our theme functions and their arguments.
*/
function node_example_theme($existing, $type, $theme, $path) {
return array(
'example_node_color' => array(
'variables' => array('color' => NULL),
),
);
}
/**
* A custom theme function.
*
* By using this function to format our node-specific information, themes
* can override this presentation if they wish. This is a simplified theme
* function purely for illustrative purposes.
*/
function theme_example_node_color($variables) {
$output = '<span style="background-color: #ccc; padding: 1em; margin-bottom: 1em; float: left; color: ' .
$variables['color'] . '">' . $variables['color'] . '</span>';
return $output;
}
95. D7 *.module
• Now for the juicy D7 changes!!!
• hook_entity_info_alter() lets us modify the
node_entity to use our custom view mode
96. D7 *.module
• Now for the juicy D7 changes!!!
• hook_entity_info_alter() lets us modify the
node_entity to use our custom view mode
• hook_field_formatter_view() is where we place
the details of our custom view mode
97.
98. /**
* Implements hook_entity_info_alter().
*
* We need to modify the default node entity info by adding a new view mode to
* be used in functions like node_view() or node_build_content().
*
*/
function node_example_entity_info_alter(&$entity_info) {
$entity_info['node']['view modes']['example_node_list'] = array(
'label' => t('Example Node List'),
'custom settings' => TRUE,
);
}
99. /**
* Implements hook_entity_info_alter().
*
* We need to modify the default node entity info by adding a new view mode to
* be used in functions like node_view() or node_build_content().
*
*/
function node_example_entity_info_alter(&$entity_info) {
$entity_info['node']['view modes']['example_node_list'] = array(
'label' => t('Example Node List'),
'custom settings' => TRUE,
);
}
/**
* Implements hook_field_formatter_info().
*/
function node_example_field_formatter_info() {
return array(
'node_example_colors' => array(
'label' => t('Node Example Color Handle'),
'field types' => array('text'),
),
);
}
102. D7 *.module
• Last ... but certainly not least
• hook_field_formatter_view() is where we place
the details of our custom view mode
103.
104. /**
* Implements hook_field_formatter_view().
*
* @todo: We need to provide a formatter for the colors that a user is allowed to enter
* during node creation.
*/
function node_example_field_formatter_view($object_type, $object, $field, $instance, $langcode, $items, $display) {
$element = array();
switch ($display['type']) {
case 'node_example_colors':
foreach ($items as $delta => $item) {
$element[$delta]['#type'] = 'markup';
$color = $item['safe_value'];
$element[$delta]['#markup'] = theme('example_node_color', array('color' => $color));
}
break;
}
return $element;
}
105. Informative Links
• The field API Tutorial - http://drupal.org/node/707832
• The Field API Glossary - http://drupal.org/node/443540
• Adding and Reusing a Field - http://drupal.org/node/
474420
• Making an Entity Fieldable - http://drupal.org/node/
474582
• The Examples Module - http://drupal.org/project/
examples
• Drupal API - http://api.drupal.org/
• Joachim’s http://drupal.org/project/field_convert