Actions

J3.x

Difference between revisions of "Using Tags in an Extension"

From Joomla! Documentation

(Created page with "Joomla's tagging system is used in all core content extensions and is designed to be be easy to integrate into other extensions that use standard Joomla design patterns. Us...")
 
Line 8: Line 8:
  
 
First identify which tables contain data that will be tagged and what the name of the single item view displaying each of these tables. For example:
 
First identify which tables contain data that will be tagged and what the name of the single item view displaying each of these tables. For example:
  * #__contact_details  is the table displayed in the view contact of component com_contact with table class ContactTableContact.
+
# #__contact_details  is the table displayed in the view contact of component com_contact with table class ContactTableContact.
* #__weblinks is the table displayed in the view weblink of com_weblinks so WeblinksTableWeblink.  
+
# #__weblinks is the table displayed in the view weblink of com_weblinks so WeblinksTableWeblink.  
+
 
  
 
  <source lang="sql">
 
  <source lang="sql">
Line 33: Line 33:
 
    
 
    
  
'''Important note'''
+
'''Important note''' : Please note that the table name for the common table is #__ucm_content. This is INCORRECT in 3.1 and 3.1.1 data but is not currently used.  The data will be updated in 3.1.2.
  
Please note that the table name for the common table is #__ucm_content. This is INCORRECT in 3.1 and 3.1.1 data but is not currently used.  The data will be updated in 3.1.2.
 
  
  
Line 45: Line 44:
 
The '''type_title''' field would potentially be used for display although this is not implemented currently except in the contentttype field.  Usually it should begin with an upper case letter if it is in English. See note about how to make this translatable.  
 
The '''type_title''' field would potentially be used for display although this is not implemented currently except in the contentttype field.  Usually it should begin with an upper case letter if it is in English. See note about how to make this translatable.  
  
note: To make your type names translatable add  
+
note:
 +
To make your type names translatable add  
 
<source lang="php">
 
<source lang="php">
 
COM_TAGS_CONTENT_TYPE_ + the type_title
 
COM_TAGS_CONTENT_TYPE_ + the type_title
 +
</source>
 +
in both the ini and sys.ini files.
  
</source>in both the ini and sys.ini files.
+
'''Rules''' is currently not used. It will likely be removed in favor of an asset_id for each type, but currently you can ignore this field which will be managed by JTable.  
 
+
Rules  iscurrently not used. It will likely be removed in favor of an asset_id for each type, but currently you can ignore this field which will be managed by JTable.  
+
  
 
'''field_mappings''' maps the names of specific fields in your table to a set of standard names. This mapping is stored as a JSON array with the first element mapping to the common fields and the second one mapping the other fields from the table.
 
'''field_mappings''' maps the names of specific fields in your table to a set of standard names. This mapping is stored as a JSON array with the first element mapping to the common fields and the second one mapping the other fields from the table.
  
==== Important note ====
+
'''Important note''' The JHelperTags and JUcm APIS currently (at 3.1.1) support arrays for this field, but our intention is to change this to support either arrays or objects with a default of objects.  This is planned for implementation for 3.1.2.   
 
+
  The JHelperTags and JUcm APIS currently (at 3.1.1) support arrays for this field, but our intention is to change this to support either arrays or objects with a default of objects.  This is planned for implementation for 3.1.2.   
+
  
 
<source lang="php">
 
<source lang="php">
Line 65: Line 63:
 
is the field mapping for the Article type. Note that article uses the name attribs for the core field called params.  If your table does not contain a field, put “null” instead.  Leaving it blank may cause SQL issues. The special fields are optional.  At a minimum for common fields you need to map: content_item_id, alias and title in order to successfully create urls in the tagged items list.  You also will probably want: access, status, and language.
 
is the field mapping for the Article type. Note that article uses the name attribs for the core field called params.  If your table does not contain a field, put “null” instead.  Leaving it blank may cause SQL issues. The special fields are optional.  At a minimum for common fields you need to map: content_item_id, alias and title in order to successfully create urls in the tagged items list.  You also will probably want: access, status, and language.
  
**Router** is an optional name of a static helper router method for this type found in its front end helpers folder.  
+
'''Router''' is an optional name of a static helper router method for this type found in its front end helpers folder.  
 
If you only store data in #__ucm_content you will eventually be able to leave the router field blank although this option is not currently implemented. If you do not have a custom router tags falls back to the rules found in JHelperRoute.
 
If you only store data in #__ucm_content you will eventually be able to leave the router field blank although this option is not currently implemented. If you do not have a custom router tags falls back to the rules found in JHelperRoute.
  
Line 72: Line 70:
 
This has several parts.
 
This has several parts.
  
=== Add a property
+
=== Add a property ===
===
+
 
 
<source lang="php">
 
<source lang="php">
 
/**
 
/**
Line 85: Line 83:
 
This property helps to manage change in tags.
 
This property helps to manage change in tags.
  
#### Modify your constructor
+
=== Modify your constructor ===
  
 
Follow this example to modify your consructor which provides substantial reduction in duplicate code.
 
Follow this example to modify your consructor which provides substantial reduction in duplicate code.
Line 93: Line 91:
 
</source>
 
</source>
  
#### Modify your store() method  
+
=== Modify your store() method ===
 
Management of tagging and associated data is largely handled through the store() method. This provides maximum flexibility for the handling of tags across many extensions.  
 
Management of tagging and associated data is largely handled through the store() method. This provides maximum flexibility for the handling of tags across many extensions.  
  
Line 112: Line 110:
  
  
#### Add or modify a delete() method
+
=== Add or modify a delete() method ===
  
 
The basic structure:
 
The basic structure:
Line 143: Line 141:
  
  
### 3.Add tags to the getItem() method of the model
+
=== Add tags to the getItem() method of the model ===
  
 
In the getItem() (or similar) method of your model add  
 
In the getItem() (or similar) method of your model add  
Line 157: Line 155:
 
changing to your component and alias name, matching what is in the type table.and changing the name of id property to the name of your primary key.
 
changing to your component and alias name, matching what is in the type table.and changing the name of id property to the name of your primary key.
  
### 4. Add a tag field to edit screens
+
=== Add a tag field to edit screens ===
 
In any edit layouts where you want to allow tagging, you need to add the field to the xml and the appropriate layouts if necessary.
 
In any edit layouts where you want to allow tagging, you need to add the field to the xml and the appropriate layouts if necessary.
  
Line 173: Line 171:
  
 
The field supports two modes:   
 
The field supports two modes:   
* **Nested tags mode.** Hierarchical tag list. Doesn't support on the fly tag creation.
+
* '''Nested tags mode.''' Hierarchical tag list. Doesn't support on the fly tag creation.
* **AJAX mode.** Tags are searched while user types (3 min. chars required to launch the AJAX search). Custom tags are added by pressing ENTER or COMMA keys. Tags show the global route/path. Example: <code>grandpa/parent/tag</code>
+
*  
 +
=== AJAX mode. ===
 +
Tags are searched while user types (3 min. chars required to launch the AJAX search). Custom tags are added by pressing ENTER or COMMA keys. Tags show the global route/path. Example: <code>grandpa/parent/tag</code>
  
 
The field mode can be forced or use the com_tags setting <code>Tag field mode</code> to determine its mode. To set/force the field mode we have to add **mode="ajax"** or **mode="nested"** to the tag field definition.   
 
The field mode can be forced or use the com_tags setting <code>Tag field mode</code> to determine its mode. To set/force the field mode we have to add **mode="ajax"** or **mode="nested"** to the tag field definition.   
Line 232: Line 232:
 
<?php endif; ?></source>
 
<?php endif; ?></source>
  
### 7. Batch processing
+
== Batch processing ==
 
If you want to add the ability to do batch tagging to a backend list view do the following.
 
If you want to add the ability to do batch tagging to a backend list view do the following.
  

Revision as of 20:10, 28 April 2013

Joomla's tagging system is used in all core content extensions and is designed to be be easy to integrate into other extensions that use standard Joomla design patterns.

Using tags in an extension is relatively straightforward but it requires small changes in a number of specific places.


Contents

Create a content type for each view

Note: Types can be added using either sql or postflight by creating a JTableContenttype instance and adding a row.

First identify which tables contain data that will be tagged and what the name of the single item view displaying each of these tables. For example:

  1. #__contact_details is the table displayed in the view contact of component com_contact with table class ContactTableContact.
  2. #__weblinks is the table displayed in the view weblink of com_weblinks so WeblinksTableWeblink.


 CREATE TABLE IF NOT EXISTS `#__content_types` (
  `type_id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  `type_title` varchar(255) NOT NULL DEFAULT '',
  `type_alias` varchar(255) NOT NULL DEFAULT '',
  `table` varchar(255) NOT NULL DEFAULT '',
  `rules` text NOT NULL,
   `field_mappings` text NOT NULL,
 `router` varchar(255) NOT NULL DEFAULT '',

For each table/option/view you will need to make an entry in #__content_types. You can do this either using sql or postflight by creating an instance of JTableContenttype. Don't forget a category type if you use the Joomla categories API.

A string giving component.view (that would be in the page request, typically matching the model name) goes in the **type_alias** field.

table gives the complete table class information for the table class stored as a JSON object in which the first element represents your "special" table and the second an optional common table (otherwise it will default the JTableCorecontent. This includes the name of the database table, the name of the primary key, the prefix, the name, an option array as used in your constructor and getInstance() methods. This enables the tagging system (and other APIs) to access your table easily.

If you are using Joomla categories make sure to create a category type so that they can be tagged. In Joomla 3.1 and 3.1.1 there is an error where the tag field will show even if there is not a type, but this will be corrected in 3.1.2.


Important note : Please note that the table name for the common table is #__ucm_content. This is INCORRECT in 3.1 and 3.1.1 data but is not currently used. The data will be updated in 3.1.2.


{"special":{"dbtable":"#__content","key":"id","type":"Content","prefix":"JTable","config":"array()"},"common":{"dbtable":"#__ucm_content","key":"ucm_id","type":"Corecontent","prefix":"JTable","config":"array()"}}


The type_title field would potentially be used for display although this is not implemented currently except in the contentttype field. Usually it should begin with an upper case letter if it is in English. See note about how to make this translatable.

note:
To make your type names translatable add 
COM_TAGS_CONTENT_TYPE_ + the type_title

in both the ini and sys.ini files.

Rules is currently not used. It will likely be removed in favor of an asset_id for each type, but currently you can ignore this field which will be managed by JTable.

field_mappings maps the names of specific fields in your table to a set of standard names. This mapping is stored as a JSON array with the first element mapping to the common fields and the second one mapping the other fields from the table.

Important note The JHelperTags and JUcm APIS currently (at 3.1.1) support arrays for this field, but our intention is to change this to support either arrays or objects with a default of objects. This is planned for implementation for 3.1.2.

'{"common":[{"core_content_item_id":"id","core_title":"title","core_state":"published","core_alias":"alias","core_created_time":"created_time","core_modified_time":"modified_time","core_body":"description", "core_hits":"hits","core_publish_up":"null","core_publish_down":"null","core_access":"access", "core_params":"params", "core_featured":"null", "core_metadata":"metadata", "core_language":"language", "core_images":"null", "core_urls":"null", "core_version":"version", "core_ordering":"null", "core_metakey":"metakey", "core_metadesc":"metadesc", "core_catid":"parent_id", "core_xreference":"null", "asset_id":"asset_id"}], "special": [{"parent_id":"parent_id","lft":"lft","rgt":"rgt","level":"level","path":"path","extension":"extension","note":"note"}]}'

is the field mapping for the Article type. Note that article uses the name attribs for the core field called params. If your table does not contain a field, put “null” instead. Leaving it blank may cause SQL issues. The special fields are optional. At a minimum for common fields you need to map: content_item_id, alias and title in order to successfully create urls in the tagged items list. You also will probably want: access, status, and language.

Router is an optional name of a static helper router method for this type found in its front end helpers folder. If you only store data in #__ucm_content you will eventually be able to leave the router field blank although this option is not currently implemented. If you do not have a custom router tags falls back to the rules found in JHelperRoute.

Modify your component's table class (or classes if you have multiple tables)

This has several parts.

Add a property

        /**
         * Indicator that the tags have been changed
         *
         * @var    JHelperTags
         * @since  3.1
         */
        protected $tagsHelper = null;

This property helps to manage change in tags.

Modify your constructor

Follow this example to modify your consructor which provides substantial reduction in duplicate code.

                $this->tagsHelper = new JHelperTags();
                $this->tagsHelper->typeAlias = 'com_contact.contact';

Modify your store() method

Management of tagging and associated data is largely handled through the store() method. This provides maximum flexibility for the handling of tags across many extensions.

If you don't have a store() method you will need to add one.  The assumption is that tables will inherit from JTable. 

The handling involves preStoreProcess(), a call to the parent store() method, and then a postStoreProcess().

                $this->tagsHelper->preStoreProcess($this);
                $result = parent::store($updateNulls);
 
                return $result && $this->tagsHelper->postStoreProcess($this);

It is important that this be in the correct order since completion of tag processing depends on having primary key data from the parent store() method.

Note that much of this code is designed to prevent storage in in #__ucm_content when items are not tagged. If you want to always store in #__ucm_content you should modify the handling appropriately.


Add or modify a delete() method

The basic structure:


        /**
         * Method to delete a row from the database table by primary key value.
         *
         * @param   integer  $pk  Primary key to delete.
         *
         * @return  boolean  True on success.
         *
         * @since   3.1
         * @throws  UnexpectedValueException
         */
        public function delete($pk = null)
        {
                $return = parent::delete($pk, $children);
                if ($return)
                {
                        $helper = new JHelperTags;
                        $helper->tagDeleteInstances($pk);
                }
                return $return; }

This manages the deletion of all related data if a content item is deleted.


Add tags to the getItem() method of the model

In the getItem() (or similar) method of your model add

                // Load item tags
                if (!empty($item->id))
                {
                        $item->tags = new JHelperTags;
                        $item->tags->getTagIds($item->id, 'com_contact.contact');
                        $item->metadata['tags'] = $item->tags;
                }

changing to your component and alias name, matching what is in the type table.and changing the name of id property to the name of your primary key.

Add a tag field to edit screens

In any edit layouts where you want to allow tagging, you need to add the field to the xml and the appropriate layouts if necessary.

Update: Note that there is new handling of this in the core. Tags in the edit screen should be part of a metadata <fields></fields> group. The core provides two JLayouts to help you manage standard layouts, one (details) for the metadata and one for the sidebar that includes the tabs.


                <field name="tags" type="tag"
                        label="JTAG" description="JTAG_DESC"
                        class="inputbox span12 small" multiple="true"
                >
                </field>

The field loads all the Javascript libraries required. You don't need to worry about that.

The field supports two modes:

  • Nested tags mode. Hierarchical tag list. Doesn't support on the fly tag creation.

AJAX mode.

Tags are searched while user types (3 min. chars required to launch the AJAX search). Custom tags are added by pressing ENTER or COMMA keys. Tags show the global route/path. Example: grandpa/parent/tag

The field mode can be forced or use the com_tags setting Tag field mode to determine its mode. To set/force the field mode we have to add **mode="ajax"** or **mode="nested"** to the tag field definition.

Example of forced AJAX mode:


                <field name="tags" type="tag" mode="ajax"
                        label="JTAG" description="JTAG_DESC"
                        class="inputbox span12 small" multiple="true"
                >
                </field>

The field also includes an attribute to allow/deny the user to enter custom values. Currently this only works in AJAX mode. The attribute has to be added to the field definition like **custom="allow"** or **custom="deny"**

Example field definition with custom tags denied:

                <field name="tags" type="tag" mode="ajax" custom="denied"
                        label="JTAG" description="JTAG_DESC"
                        class="inputbox span12 small" multiple="true"
                >
                </field>

if it is not already there. Usually multiple should be true unless you have a specific reason for it not to be. In the core components in administrator, the field is in the group shown on the right, below the language field.

      1. 5. Prepare the view

Add an appropriate version of this to your view.html.php file before loading the layout:

$item->tags = new JHelperTags;
$item->tags->getItemTags('com_newsfeeds.newsfeed.' , $this->item->id);

The first parameter should match a type in the types table. The second parameter is the primary key under which this record is stored in your table. This would be used in any display in any view where you want the tags associated with the item to display.


      1. 6. Set up the display

In any layout where you want to display the tags associated with an item add:

                <?php $this->item->tagLayout = new JLayoutFile('joomla.content.tags'); ?>
                <?php echo $this->item->tagLayout->render($this->item->tags->itemTags); ?>

Changing the object and property names as appropriate.

You will most likely want to add the show_tags parameter to the item parameters, the menu item parameters and component configuration as appropriate for your use case.

        <?php if ($this->params->get('show_tags', 1) && !empty($this->item->tags)) : ?>
                <?php $this->item->tagLayout = new JLayoutFile('joomla.content.tags'); ?>
                <?php echo $this->item->tagLayout->render($this->item->tags->itemTags); ?>
        <?php endif; ?>

Batch processing

If you want to add the ability to do batch tagging to a backend list view do the following.

Add tag to the default_batch layout


        <div class="control-group">
                        <div class="controls">
                                <?php echo JHtml::_('batch.tag');?>
                        </div>
                </div>

And add tag to the button class in the modal footer (Not totally necessary at this point, but good for potential future changes e.g. if unTag is added.)

<button class="btn" type="button" onclick="document.id('batch-category-id').value='';document.id('batch-access').value='';document.id('batch-language-id').value='';document.id('batch-user-id').value='';document.id('batch-tag-id)').value=''" data-dismiss="modal">
      1. Add a batch method to your model if you are not extending JModelAdmin or overriding the batch method._


        /**
         * Batch tag a list of item.
         *
         * @param   integer  $value     The value of the new tag.
         * @param   array    $pks       An array of row IDs.
         * @param   array    $contexts  An array of item contexts.
         *
         * @return  void.
         *
         * @since   3.1
         */
        protected function batchTag($value, $pks, $contexts)
        {
                $tagsHelper = new JHelperTags();
                $tagsHelper->tagItems($value, $pks, $contexts);
 
                return true;
        }

_And modify your batch method by adding_

                if (!empty($commands['tag']))
                {
                        if (!$this->batchTag($commands['tag'], $pks, $contexts))
                        {
                                return false;
                        }
 
                        $done = true;
                }

Pay attention to any JSON encoded strings that you need special handling for in batch processing -- remember that you are saving a copy of the core fields and you need save to work as expected.


_That’s it, now create some tags, tag some items and you are set._


DeveloperTags3.1