Element Set example?

Dear (er) Omekans,

Is there a full Element Set plugin example somwhere I could take a look at? I am trying to write a plugin that will integrate the ISO19115 Geographic Information metadata standard (element set) into Omeka. I've got its core elements in an $elements array, as illustrated on the Creating an Element Set page (http://omeka.org/codex/Creating_an_Element_Set), but having a full element set plugin (with directory structure, etc.) sure would help!

Best regards,

Mark Cyzyk
Johns Hopkins University

OK, it occurred to me earlier this morning that there already is a fine example of this: The Dublin Core Extended plugin. So looking at that now.

However, the code in the elements.php file is pretty different than what's posted to the official example: http://omeka.org/codex/Creating_an_Element_Set

The official example illustrates a simple array of elements, while this elements.php file uses an array of arrays. Not sure what to do. Also, the Dublin Core Extended plugin seems to model a hierarchy of elements via a "_refines" attribute. This is not mentioned in the official example, rather, we are told to build hierarchies by concatenating elements with a colon. Looking into this further...

Mark

Hi Mark,

In fact, the official example you linked to also uses an array of arrays, although it's possible to miss that because of the way the example is presented. The way it works is like this:

Each "inner array" represents one Element. So

array(
    'name'           => 'Element Name',
    'description'    => 'Element Description',
)

describes a single Element. Since you're adding an ElementSet, what you pass to insert_element_set is an array of those inner arrays.

Thanks, John!

So here is the content of my elements.php file:

<?php
$elements = array(
    array(
        'name'           => [(string) ISO19115 Core, required],
        'description'    => [(string) Core elements from the North American Profile of the ISO19115 metadata standard: Geographic information, optional],
		'MD_Metadata:MD_DataIdentification.citation:CI_Citation.title' => [(string) Dataset title, optional],
		'MD_Metadata.contact:CI_ResponsibleParty' => [(string) Metadata point of contact, optional],
		'MD_Metadata::MD_DataIdentification.citation:CI_Citation.date' => [(string) , optional],
		'MD_Metadata.dateStamp' => [(string) Dataset reference date, optional],
		'MD_Metadata:MD_DataIdentification.abstract' => [(string) Abstract describing the dataset, optional],
		'MD_Metadata:MD_DataIdentification.topicCategory' => [(string) Dataset topic category, optional],
		'MD_Metadata:MD_DataIdentification.language' => [(string) Dataset language, optional],
		'MD_Metadata:MD_DataIdentification.extent:EX_Extent:EX_GeographicExtent:EX_GeographicBoundingBox' => [(string) Geographic location of the dataset (by four coordinates), optional],
		'MD_Metadata:MD_DataIdentification.extent:EX_Extent:EX_GeographicExtent:EX_GeographicDescription' => [(string) Geographic location of the dataset (by geographic identifier), optional],
		'MD_Metadata.language' => [(string) Metadata language, optional],
		'MD_Metadata:MD_DataIdentification.characterSet' => [(string) Dataset character set, optional],
		'MD_Metadata.characterSet' => [(string) Metadata character set, optional],
		'MD_Metadata:MD_DataIdentification.extent:EX_Extent:EX_TemporalExtent' => [(string) Additional extent information for the dataset (temporal), optional],
		'MD_Metadata:MD_DataIdentification.extent:EX_Extent:EX_VerticalExtent' => [(string) Additional extent information for the dataset (vertical), optional],
		'MD_Metadata:MD_DataIdentification.pointOfContact:CI_ResponsibleParty' => [(string) Dataset responsible party, optional],
		'MD_Metadata:DQ_DataQuality.lineage:LI_Lineage' => [(string) Lineage, optional],
		'MD_Metadata:MD_Distribution:MD_DigitalTransferOption.onLine:CI_OnlineResource' => [(string) On-line resource, optional],
		'MD_Metadata:MD_DataIdentification.spatialRepresentationType' => [(string) Spatial representation type, optional],
		'MD_Metadata.fileIdentifier' => [(string) Metadata file identifier, optional],
		'MD_Metadata:MD_Distribution:MD_Format.name' => [(string) Distribution format name, optional],
		'MD_Metadata:MD_Distribution:MD_Format.version' => [(string) Distribution format version, optional],
		'MD_Metadata.metadataStandardName' => [(string) Metadata standard name, optional],
		'MD_Metadata.metadataStandardVersion' => [(string) Metadata standard version, optional],
		'MD_Metadata:MD_ReferenceSystem' => [(string) Reference system, optional],
		'MD_Metadata:MD_DataIdentification.spatialResolution:MD_Resolution.equivalentScale' => [(string) Spatial resolution of the dataset (equivalent scale), optional],
		'MD_Metadata:MD_DataIdentification.spatialResolution:MD_Resolution.distance' => [(string) Spatial resolution of the dataset (distance), optional]
    ),
);

Does this look correct?

After making a copy, I've gone through the codebase for the Dublin Core Extended plugin and have edited class names, variable names, etc, translating from, e.g., 'DublinCoreExtended' to 'ISO19115Core' where needed, I've installed this new directory tree/codebase in my plugins directory, and have installed it from within the Omeka interface. And yet, it does not show as a registered Element Set. All I got was a blank screen when installing it, so I guess something is wrong. Looking for a log now...

Mark

This is another case of the format of the documentation getting in the way a little.

What you want should look a little more like this:

<?php
$elementSetMetadata = array(
    'name' => 'ISO19115 Core',
    'description' => 'Core elements from the North American Profile of the ISO19115 metadata standard.');

$elements = array(
    array(
        'name' => 'Name of your metadata element goes here',
        'description' => 'Description of your element goes here'
    ),
    array(
        'name' => 'Name of the 2nd metadata element',
        'description' => 'Description of the 2nd element'
    )
    // There should be an array inside the bigger array for each
    // Element you're trying to add.
);

//Then, you would call this function to actually add the element set
insert_element_set($elementSetMetadata, $elements);

The portions of the documentation containing text in brackets are simply for the benefit of the reader; they tell you which array elements must be included and which are optional.

I hope this makes the situation somewhat more clear.

Sigh.

Apologies, the code block above got a little mangled when I input it. What you want is:

<?php
$elementSetMetadata = array(
    'name' => 'ISO19115 Core',
    'description' => 'Core elements from the North American Profile of the ISO19115 metadata standard.');

$elements = array(
    array(
        'name' => 'Name of your metadata element goes here',
        'description' => 'Description of your element goes here',
    ),
    array(
        'name' => 'Name of the 2nd metadata element',
        'description' => 'Description of the 2nd element',
    )
    // There should be an array inside the bigger array for each
    // Element you're trying to add.
);

//Then, you would call this function to actually add the element set
insert_element_set($elementSetMetadata, $elements);

Thanks again, John! Much clearer now.

So this would then be in my plugin.php file?:

insert_element_set($elementSetMetadata, $elements);

Mark

Right. The variable names of the arrays you create in element.php should be the same names in the call to insert_element_set in your plugin.php.

So, if you've kept the same names as my example above, then your line is perfect.

I am attempting to add some Element Set fields, actually just one, to the DC and Extended DC plugin. Trying to get my head around how to accomplish this.

Have reviewed the Creating an Element Set How To and the concepts make sense. Now for the duh questions.

One creates a plugin. In the How To, does that mean I just need to create a single file that will suffice as a plugin?

Or, do I need to copy the DC Extended Plugin file structure and edit elements.php and plugins.php, so that I end up with the same framework as the DC Extended Plugin?

Am not quite getting my head around this yet.

All I am trying to accomplish for the moment is a demo that adds a single 'Location' field after Identifier. My next thought, which I will attempt in a few hours, is to just add to the DC Extended code and insert these lines. However, having not done this yet, and will build a temp Omeka to practice on... if I add some Element Sets to the existing DC Extended plugin, I have not yet discovered if this will work. Would I need to Deactivate and Reactivate the Plugin and would the additional Elements be added?

Or, do I need to Uninstall and Reinstall the DC Extended Plugin, and would that 'read in' the additional Elements?

My concern with Uninstalling and Reinstalling is I believe I read that doing this would remove all data that has been added to these extended fields. This true?

Hopefully someone can shed some light on how to create a Element Set plugin from my questions above... whether it is a single file, or is it using the same DC Extended set of files that I just vanquish and add only the additional fields, or... something else. Don't quite have my head around it yet.

Help?

I will of course pass along my education to the next folks who struggle, and will continue the knowledge transfer.

tx

> One creates a plugin. In the How To, does that mean I just need to create
> a single file that will suffice as a plugin? Or, do I need to copy the DC
> Extended Plugin file structure and edit elements.php and plugins.php, so
> that I end up with the same framework as the DC Extended Plugin?

We recommend using existing plugins as templates for new ones. They often have similar structures and commonly used hooks/filters needed to build something functional. But, at the very least, you need a plugin directory containing a file named plugin.php.

> All I am trying to accomplish for the moment is a demo that adds a single
> 'Location' field after Identifier.

Instead of adding a "Location" element, you could use the "Spatial Coverage" or "Bibliographic Citation" elements (depending on your meaning of "Location") that come with the Dublin Core Extended plugin.

> if I add some Element Sets to the existing DC Extended plugin, I have not
> yet discovered if this will work. Would I need to Deactivate and Reactivate
> the Plugin and would the additional Elements be added? Or, do I need to
> Uninstall and Reinstall the DC Extended Plugin, and would that 'read in'
> the additional Elements?

I'm not sure I know what you're trying to accomplish. Element sets are predefined collections of elements (fields). To be clear, are you looking to add a new element set via the DC Extended plugin? If so it would be wiser to create a new plugin with the sole purpose of adding the element set. Just use the insert_element_set() function in the plugin's "install" hook. (The DC Extended plugin does not create an element set in this manner; rather, it adds additional elements directly to the existing Dublin Core element set.)

Or are you looking to add an element to the DC element set via the DC Extended plugin? Conceivably, you could try this by describing your "Location" element in the $elements array in elements.php; though I don't recommend it. Modifying released and stable plugins may result in unexpected behavior. Moreover, there are no guarantees that future releases of the plugin will work with your modified (forked) version. Instead, you can create a new plugin with the sole purpose of adding the element. In the "install" hook, just instantiate a new Element record, assign it the necessary properties, and save it. There's an example of this in DublinCoreExtendedPlugin::_addElements().

Jim

Thank you for your response. I will absorb this information and see if I can add to the existing nomenclature.

While it is not important for the immediate term, I will need to revise, which means I will need to "add" fields to the existing DC structure. I am working with a museum that has utilized a homebrewed set of naming conventions, and I will have to integrate their naming conventions with the DC Core.

I know I know... why not just have them ameliorate into the existing standards? Easier said than done. There are some fixed in their ways people who are grudgingly going along with this, and I getting this far with marrying up existing standards with their few homegrown fields has been work.

I have not digested your response yet but if I can take liberty and ask, tho I hopefully will discover the answer in reading your response...

There is an internal DC Core, and DC Extended Plugin... your instructions indicated that I can create and additional Plugin that 'appends' to these two Element Sets, yes? A completely different plugin that gets 'called'.

One thing I ran into was, when I tried to Deactivate the DC Extended, the fields remained in all the Items. So I tried to Uninstall the DC Extended and it went to a blank screen. Refreshing went no where, but when I circled back around to see if the Plugin indeed Uninstalled, it did not. I could never get it to Uninstall. Just an FYI.

Anyway, thank you very much for your response. I will press forward and see if I can create a new plugin. Having just enough skills to be dangerous, I can see this is an area that others will also stumble on and trust Omeka folks are reviewing how this functionality can be approached by newbies, or slightly dangerous folks with minimal skillsets like me.

Omeka is terrific.

regards, david

Also, John, you are correct. I set up a second test Omeka install and fiddled with altering the DC Extended as well. It blew up in face. Is why we create alternate test domains yes?

Something occurred to me, which may be recommended against. But dawned on me that being able to alter, not the Element Set, but at least the human readable part of the sets. Since the DC Extended fields are reasonably granular, thought it might be better served to add text, like examples, to help the mom and pop crews that will be adding metadata to these fields.

One way of course is to hand them some training and a printed cheat sheet. Would be nice tho to be able to add some additional text to the existing text, and even say some external links to video tutorial examples.

It gets into altering the existing DC Extended plugin and I have already found this is NOT advisable. But, is there a way to not alter the existing array, but add to the human readable examples that parallel the array of fields?

Let me know when this gets annoying. I can't help but think others will follow and have similar questions...

I tried following the code examples in this thread to create a plugin for adding a few new elements.

When I installed the plugin (just the single plugin.php file in a folder) I got a white screen. Could not get back to admin screen at all.

I had backed up homedir and sql and restored, but don't know how I can add these extra fields.

Reason for wanting to add:

We want to have several different groups of controlled vocab options for the Subject field.

For some items it will be appropriate for the Subject field to be a period of history, for others, there should be a dropdown of traditional dance styles, others will choose from a dropdown of modern western dance styles -- all controlled vocab. Some items will have a person's name as the subject.

Should we just build one mega-list for controlled vocab? We were trying to add the following: Subject_historical, Subject_traditional, Subject_modern-western.

Has the syntax changed in the year since this thread shared the syntax for an element-set plugin? We have the most recent version of Omeka (1.5)

Thanks!

Should the <?php for the plugin.php file have a closing ?> ?

A white screen probably indicates that you have a syntax error somewhere, if you post the exact code you used it'd be easier to see what's going wrong.

You don't need a closing ?> at the end of a PHP file, and I wouldn't generally recommend putting them in, because they make it much easier for unwanted newlines and whitespace to creep in.

A new element set likely isn't the best way to handle the case you're facing though. A plugin (or an enhancement to an existing plugin) could allow you to first pick a category before deciding which controlled vocab options should be available (or decide based on a tag or Item Type), which wouldn't then require any additional elements to have different vocabs.

Staying in the realm of elements though, have you considered using Item Types to have your different elements in? This would have the advantages of not requiring plugin code and making sure the different Subject-like "sub-elements" aren't all simultaneously available on every Item (as would be the case as an Element Set).

Thanks John!

Does such a plugin exist -- to allow picking a category, or tag before displaying different sets of controlled vocab options?

As for using Item Types -- we'd need a whole matrix of item types:

still image - historical dance
still image - traditional dance
still image - modern western
still image - person
video - etc.
document - etc.
audio - etc.

That seems overly cumbersome.

I'm back to thinking we'll just have one long dropdown with some numbering scheme to group options in the different categories.

DTT - dance type traditional
DTW - dance type western

DTT000 - line dances
DTT010 - four couple squares
DTT020 - etc.
DTW - etc.

If we could modify the prompts on the backend we could guide volunteer curators to add additional subject fields when appropriate -- using one for
Dance Type and another for personal name (of dance caller, musician or interviewee)

If we use controlled vocabulary is there anyway to allow entering a person's name or will all names have to be entered into the controlled vocab lists?

Related question:
If we want just a few of the Extended Dublin Core fields -- coverage_spatial and coverage_temporal how would we load those without all of the rest of the Extended DC fields which would be overkill for our project?

Love to know what was wrong with syntax -- even if we decide not to use these extra fields.
Thanks for taking a look!


<?php
$elementSetMetadata = array(
'name' => 'SDH Extra fields',
'description' => 'Extra DC fields for squaredance history site');

$elements = array(
array(
'name' => 'Subject_Historical',
'description' => 'Controlled vocab list of Historical periods of dance',
),
array(
'name' => 'Subject_Traditional',
'description' => 'Controlled vocab list of Traditional dance styles',
)
array(
'name' => 'Subject_MWSD',
'description' => 'Controlled vocab list of Modern Western dance styles',
)
// There should be an array inside the bigger array for each
// Element you're trying to add.
);

//Then, you would call this function to actually add the element set
insert_element_set($elementSetMetadata, $elements);

Your inner array for 'Subject_Traditional' and the following one for 'Subject_MWSD' don't have a comma between them, and they need to (like the one between the first two sub-arrays).

That said, you wouldn't want a plugin.php to be just this. The code in plugin.php gets run on every page hit for an activated plugin, so you'd be trying to add an element set any time anybody went to any page.

You want to have your set-adding code in a function, then attach that function an "install" hook, so it will only run once, when the plugin is installed.

I'm modifying the Dublin Core extended Plugin. At present, all my new elements appear in the Dublin Core tab, but some are only relevant to Item Type Metadata, so I'd like to send them to existing item types instead.

Is it possible to do that all in one element set? Also, where and how do I specify where my elements should appear?

baileyspace, there is no way to transfer elements that belong to an element set to an item type. Instead, assign a new element to the item type.

Can I assign a new element to the item type using a plugin?

Yes. In the admin interface click on "Item Types" then click on "Edit" beside the item type you want to edit. Near the bottom of the edit page select "New" and click "Add Element". Enter an element name and description and click on "Save Changes".

Sorry, I should clarify, I'm working on a system to customize Omeka for radio producers. I don't want every radio producer that installs this system to have to go to the GUI to manually add a new element. So, I'd like to be able to add an element to an item type by creating a plugin.

Yes. In the plugin's install hook use ItemTypeTable::findByName() to get the particular ItemType record you need, and use ItemType::addElements() to add the element to the item type.

Thanks! That's just what I was looking for.

I couldn't find findByName in the documentations. So, I tried to pull the table another way. Here's what I have so far. Do you have any suggestions?

<?php
add_plugin_hook('install', 'OralHistoryPlugin::install');
add_plugin_hook('uninstall', 'OralHistoryPlugin::uninstall');

class OralHistoryPlugin
{
	$elements(

		array(
	            'name'           => 'Broadcast Date',
	            'description'    => 'Description of First Element',
	            'record_type'    => 'Item',
	            'data_type'      => 'Tiny Text',
				'element_set'	 =>	'Oral History'
			),

		array(
	            'name'           => 'Host',
	            'description'    => 'Description of Second Element',
	            'record_type'    => 'Item',
	            'data_type'      => 'Tiny Text',
		    'element_set'	 =>	'Oral History'
	        ),
	    );

    public static function install()
    {
		$oralHistory = get_db()->getTable('Item Type Metadata')->findBySQL('name=Oral History');
		addElements($elements, $oralHistory);
	}

	public static function uninstall()
	{
		// $oralHistory = ItemType::getItemTypeElementSet('Oral History');
//		$oralHistory->removeElements($elements);
	}
}

If you're using Omeka 1.5 something like this should work (I haven't tested it):

class OralHistoryPlugin extends Omeka_Plugin_Abstract
{
    const ITEM_TYPE_NAME = 'Oral History';
    protected $_hooks = array('install', 'uninstall');
    protected $_elements = array(
        array('name'        => 'Broadcast Date',
              'description' => 'Description of First Element',
              'data_type'   => 'Tiny Text'),
        array('name'        => 'Host',
              'description' => 'Description of Second Element',
              'data_type'   => 'Tiny Text'),
    );

    public function hookInstall()
    {
        $itemType = $this->_db->getTable('ItemType')->findByName(self::ITEM_TYPE_NAME);
        $itemType->addElements($this->_elements);
        $itemType->save();
    }

    public function hookUninstall()
    {
        $elementTable = $this->_db->getTable('Element');
        foreach ($this->_elements as $e) {
            $element = $elementTable->findByElementSetNameAndElementName(ELEMENT_SET_ITEM_TYPE, $e['name']);
            $element->delete();
        }
    }
}

@jsafley thanks again for your help! Unfortunately, the code you shared isn't working for me. I've been fiddling with it and looking through the MySQL tables.

It seems that all the Item Type elements are contained in a single table called Item_Types_Elements. The plugin, on the other hand, seems like it's written to add the new elements to an Oral History table, and from what I can tell, this table doesn't exist. Could that be the problem?

Would it be better to try to add the new elements directly to the Item_Types_Elements table? The only problem there is that I don't know how to indicate which elements are associated with each Item Type.

I did not test the above code, but something similar should work. Make sure you're using Omeka 1.5. You shouldn't have to look at MySQL directly; just use the plugin API. I recommend looking at ItemType.php, ItemTypeTable.php, and Element.php in application/models to see what's going on.

I'm still having problems with the plugin. It does not cause an error but also does not add the elements. How can I implement debug logging within the install function? I only see error logging references in the documentation.

The easiest way to log some arbitrary stuff to Omeka's log is with the debug function.