Joomla 4.x Tutorial - Extension Development - Tags

Modify this post

Tags or Keywords are a flexible solution to organise content in Joomla! A keyword can be assigned to many different elements of different content types. Each element can have unlimited tags.

Das Tagging-System von Joomla wird in allen Kern-Erweiterungen verwendet. Es ist so konzipiert, dass es leicht in andere Erweiterungen integriert werden kann, die Standard-Joomla-Design-Muster verwenden. Die Verwendung von Tags in einer Drittanbieter-Erweiterung ist ziemlich einfach. Für die Verwendung in einer eigenen Erweiterung sind die hier erläuterten Änderungen erforderlich.

For impatient people

View the changed program code in the Diff Viewgithub.com/astridx/boilerplate/compare/t28...t29 and incorporate these changes into your development version.

Step by step

In the following overview, the newly added files are marked with a background and the changed ones are outlined.

Overview of the files edited in this chapter

New files

No new files.

Modified files

administrator/components/comfoos/ forms/filterfoos.xml

The form through which the search tools are managed receives an entry for the keywords.

administrator/components/comfoos/ forms/filterfoos.xml

 			<option value="*">JALL</option>
 		</field>

		<field
			name="tag"
			type="tag"
			label="JTAG"
			multiple="true"
			mode="nested"
			custom="false"
			hint="JOPTION_SELECT_TAG"
			onchange="this.form.submit();"
		/>
 	</fields>

 	<fields name="list">

administrator/components/com_foos/ forms/foo.xml

In the XML form, we add the form field that contains the information about the tag. Since we use Joomla Standard, we can use many ready-made functions out-of-the-box.

administrator/components/com_foos/ forms/foo.xml

 			label="JFIELD_ORDERING_LABEL"
 			content_type="com_foos.foo"
 		/>

		<field
			name="tags"
			type="tag"
			label="JTAG"
			class="advancedSelect"
			multiple="true"
		/>
 	</fieldset>
 	<fields name="params" label="JGLOBAL_FIELDSET_DISPLAY_OPTIONS">
 		<fieldset name="display" label="JGLOBAL_FIELDSET_DISPLAY_OPTIONS">

administrator/components/com_foos/ script.php

In the installation script, we make sure that our extension is recognised as a separate content type in Joomla.

administrator/components/com_foos/ script.php

 	{
 		echo Text::_('COM_FOOS_INSTALLERSCRIPT_POSTFLIGHT');

		$this->saveContentTypes();

 		return true;
 	}



 		return $id;
 	}

	/**
	 * Adding content_type for tags.
	 *
	 * @return  integer|boolean  One Administrator ID.
	 *
	 * @since   __BUMP_VERSION__
	 */
	private function saveContentTypes()
	{
		$table = Table::getInstance('Contenttype', 'JTable');

		$table->load(['type_alias' => 'com_foos.foo']);

		$tablestring = '{
			"special": {
			  "dbtable": "#__foos",
			  "key": "id",
			  "type": "FooTable",
			  "prefix": "Joomla\\\\Component\\\\Foos\\\\Administrator\\\\Table\\\\",
			  "config": "array()"
			},
			"common": {
			  "dbtable": "#__ucm_content",
			  "key": "ucm_id",
			  "type": "Corecontent",
			  "prefix": "JTable",
			  "config": "array()"
			}
		  }';

		$fieldmapping = '{
			"common": {
			  "core_content_item_id": "id",
			  "core_title": "name",
			  "core_state": "published",
			  "core_alias": "alias",
			  "core_publish_up": "publish_up",
			  "core_publish_down": "publish_down",
			  "core_access": "access",
			  "core_params": "params",
			  "core_featured": "featured",
			  "core_language": "language",
			  "core_ordering": "ordering",
			  "core_catid": "catid",
			  "asset_id": "null"
			},
			"special": {
			}
		  }';

		$contenttype = [];
		$contenttype['type_id'] = ($table->type_id) ? $table->type_id : 0;
		$contenttype['type_title'] = 'Foos';
		$contenttype['type_alias'] = 'com_foos.foo';
		$contenttype['table'] = $tablestring;
		$contenttype['rules'] = '';
		$contenttype['router'] = 'RouteHelper::getFooRoute';
		$contenttype['field_mappings'] = $fieldmapping;
		$contenttype['content_history_options'] = '';

		$table->save($contenttype);

		return;
	}
 }

administrator/components/com_foos/ src/Model/FooModel.php

In the model of the element, we insert the tags into the batch processing batch and ensure that the associated tags are loaded.

administrator/components/com_foos/ src/Model/FooModel.php

use Joomla\CMS\Language\LanguageHelper;
 use Joomla\Database\ParameterType;
 use Joomla\Utilities\ArrayHelper;
use Joomla\CMS\Helper\TagsHelper;

 /**
  * Item Model for a Foo.

 	protected $batch_commands = [
 		'assetgroup_id' => 'batchAccess',
 		'language_id'   => 'batchLanguage',
		'tag'           => 'batchTag',
 		'user_id'       => 'batchUser',
 	];


 			}
 		}

		// Load item tags
		if (!empty($item->id)) {
			$item->tags = new TagsHelper;
			$item->tags->getTagIds($item->id, 'com_foos.foo');
		}

 		return $item;
 	}

administrator/components/com_foos/ src/Model/FoosModel.php

We change the model of the overview list of our extension in the backend regarding the filters and the database query.

administrator/components/com_foos/ src/Model/FoosModel.php

 				'publish_down', 'a.publish_down',
 			];

			$assoc = Associations::isEnabled();

 			if ($assoc) {
 				$config['filter_fields'][] = 'association';
 			}

 			$query->where($db->quoteName('a.language') . ' = ' . $db->quote($language));
 		}

		// Filter by a single or group of tags.
		$tag = $this->getState('filter.tag');

		// Run simplified query when filtering by one tag.
		if (\is_array($tag) && \count($tag) === 1) {
			$tag = $tag[0];
		}

		if ($tag && \is_array($tag)) {
			$tag = ArrayHelper::toInteger($tag);

			$subQuery = $db->getQuery(true)
				->select('DISTINCT ' . $db->quoteName('content_item_id'))
				->from($db->quoteName('#__contentitem_tag_map'))
				->where(
					[
						$db->quoteName('tag_id') . ' IN (' . implode(',', $query->bindArray($tag)) . ')',
						$db->quoteName('type_alias') . ' = ' . $db->quote('com_foos.foo'),
					]
				);

			$query->join(
				'INNER',
				'(' . $subQuery . ') AS ' . $db->quoteName('tagmap'),
				$db->quoteName('tagmap.content_item_id') . ' = ' . $db->quoteName('a.id')
			);
		} else if ($tag = (int) $tag) {
			$query->join(
				'INNER',
				$db->quoteName('#__contentitem_tag_map', 'tagmap'),
				$db->quoteName('tagmap.content_item_id') . ' = ' . $db->quoteName('a.id')
			)
				->where(
					[
						$db->quoteName('tagmap.tag_id') . ' = :tag',
						$db->quoteName('tagmap.type_alias') . ' = ' . $db->quote('com_foos.foo'),
					]
				)
				->bind(':tag', $tag, ParameterType::INTEGER);
		}

 		// Filter by access level.
 		if ($access = $this->getState('filter.access')) {
 			$query->where($db->quoteName('a.access') . ' = ' . (int) $access);

administrator/components/com_foos/ src/View/Foo/HtmlView.php

In the data organisation of the view, we ensure that the keywords matching the language are loaded.

administrator/components/com_foos/ src/View/Foo/HtmlView.php

 			// Only allow to select categories with All language or with the forced language.
 			$this->form->setFieldAttribute('catid', 'language', '*,' . $forcedLanguage);

			// Only allow to select tags with All language or with the forced language.
			$this->form->setFieldAttribute('tags', 'language', '*,' . $forcedLanguage);
 		}

 		$this->addToolbar();

Test your Joomla component

  1. install your component in Joomla version 4 to test it:

Copy the files in the administrator folder into the administrator folder of your Joomla 4 installation.

  1. install your component as described in part one, after copying all files. As we have changed things in the installation script, this is necessary.
  2. create a tag using the keyword component.

Create a tag in Joomla 4

  1. set the just created keyword at a Foo element.

A keyword in a custom Joomla 4 extension

  1. convince yourself that filtering by keywords works.

A keyword filtering in the list view of a Joomla 4 extension](/images/j4x34x3.png)

  1. create a menu item that shows all elements that are assigned to a certain keyword and see the display in the frontend.

In the frontend view you only see published elements.

A keyword in a custom Joomla 4 extension via menu item

A keyword in a custom Joomla 4 extension in a frontend view

I leave it up to you to decide how and where you display the keywords in frontend views of your own extension.

Links

Using Tags in a Extensionhttps://docs.joomla.org/j3.x:using_tags_in_an_extension

Modify this post

Comments