Plugin: (more) page metadata

Feed 26 posts, 6 voices

Avatar
70 posts

Hello all,

I’d like to announce the final revision (1.0.1) of the page metadata plugin.

About

This is a simple plug-in for the Frog CMS. It adds the ability to add more metadata to a page object. Metadata is stored as simple keyword-value pairs.

Whenever metadata is required on page level the page metdata plug-in allows the user to add more metadata fields as well as ‘hidden’ metadata that can be used by other plug-ins.

Motivation

For the page part forms plug-in I was searching for a way to store metadata information for a page (in this case the selected page part form). The core Frog ‘page’ table is very specific with its metadata (e.g. keywords, layout_id, is_protected, etc.). It is not possible to add additional fields without breaking with the core of Frog.

Instead of creating another specific mapping table only for the page part forms plug-in, I created this ‘page_metadata’ plug-in to add any keyword-value pairs (generic metadata) to a page.

As a side effect the metadata can either be created by the user in the edit interface (visible) or by a plug-in with a custom metadata handler (invisible).

Usage

The ‘visible’ part of the plug-in adds another tab to the page view: the ‘More Metadata’ tab. With this dialogue any metadata (keyword value pairs) can be added to an existing page. If the value left blank, the metadata gets removed, and there is also a delete button.

Attributes at the page object

The metadata is automatically attached as an associative array to the active page ($this in page, layout, or snippet context).

<?php echo $this->page_metadata["Keyword"]; ?>

If other pages where accessed (e.g. to generate a navigation menu) the plug-in does not expand the metadata to this pages. In this case the helper functions from the ‘PageMetadata’ model classes must be used. Instead of the $page object, the page_id can be used, too.

/* Returns only the specific value */
PageMetadata::FindOneByPageAndKeyword($page, $keyword);

/* Returns an associative array with all keywords and their values */
PageMetadata::FindAllByPageAsArray($page);

/* Returns the internal representation (active record) of the metadata */
PageMetadata::FindAllByPage($page);

Open topics

  • i18n (English and German available)
  • replace static getters and attach the metadata to the Page object
  • “delete a page, delete all metadata”-hook
  • hacks to the frog core

Download section at github.

Have fun
M

 
Avatar
1493 posts

Sounds helpful, M! I’m quite sure this will make some people happy! ;)

 
Avatar
70 posts

this will make some people happy! ;)

But this was not the intention and I’m not sure if this is what they need.

Maybe it will be clear if I contribute my next plugin.

BUT: this plugin may provide the infrastructure to generate such a SEO plugin. On the other hand would a ‘page_part’ not better fit their needs?

 
Avatar
70 posts

If someone is interested, I added the metadata as simple “key-value array” to the page object.

You are able to access it by simply using the property page_metadata:

Layout context: <?php echo $this->page_metadata["Keyword"]; ?>
or
Controller context: <?php echo $page->page_metadata["Keyword"]; ?>

Just resync with the latest head revision at github.

 
Avatar
70 posts

And the hook to delete the metadata if the page is deleted is implemented, too.

Just resync the latest version from github.

 
Avatar
17 posts

Is it possible to have a one-to-many key/value relationship? For my project (among other things, a database of game reviews) the subject games can be found on many platforms, and it would be useful to be able to eg. isolate games based on platform.

 
Avatar
70 posts

Hello JKing,

as far as I understand your use-case, I recommend you take a look into the tagging capabilities of Frog. There you’ll have the one-to-many relationship you might looking for.

Regards,
M

 
Avatar
17 posts

Thanks, M. I think I will be able to satisfy my requirements with tags and your metadata plug-in (thought it will be a wee bit of a hack, I think), and this is great, except that I can’t seem to get your plug-in to work quite right.

It enables, the tab in the edit page shows up and I can add as much metadata as my eager little heart wishes, but upon saving the document, none of the metadata remains.

Turning on debugging yields the following two errors:

Warning: mysql_fetch_object(): supplied argument is not a valid MySQL result resource in Z:\www\frog\libraries\do_lite_drivers\DoMysql.php on line 297
Warning: Missing argument 1 for PageMetadataController::Callback_view_page_edit_popup() in Z:\www\frog\plugins\page_metadata\PageMetadataController.php on line 177

The first error is hardly helpful at all; it occurs where “More metadata” would otherwise be. The second, which is printed below the submit buttons, at least gives a place to start, but I could find no other reference to the PageMetadataController::Callback_view_page_edit_popup() method in a quick scan of the plug-in’s files. Obviously I’m just missing it somehow, but I’m afraid I’m too green with Frog to really find out much.

Upon submission the first of the two errors is printed, along with a header() error and nothing else.

Any guidance?

 
Avatar
70 posts

Hello JKing,

sorry for the confusion. I’ve updated the code, please download the latest version.

PS: if you want to try my other plugin page_part_forms, too. You need to make an additional change to the frog core. I mention this, because the change I made is exactly the one that is causing your trouble with the old version. For simplicity I removed the dependency from page_metadata.

Regards,
M

 
Avatar
17 posts

Thanks for the quick response, M. I’d like to say it’s working, but sadly it is not. Fortunately, though, I was able to do a little debugging and I’ve discovered that the ‘page_metadata’ table was never created—no wonder it’s not working! Could you provide me with the table schema so I can at least get it working, or better yet a fix? ;)

 
Avatar
70 posts

Hello JKing,

please disable/enable the plugin.

 
Avatar
17 posts

Thanks for the help, M; it works beautifully now.
However, I thought I should mention a concern I have with the plug-in. I noticed that in enable.php and disable.php the metadata table is dropped. This seems like extremely poor design: an errant click by a well-meaning administrator who has not backed-up the database could very well destroy nigh-irreplaceable data necessary to the Web site. I would think it’d be a good idea rather to leave the table alone once it is created, perhaps unless it happens to be empty.

If you’re that concerned about cleanliness an option (with confirmation!) to wipe all metadata in a settings page seems the way to go to me.

 
Avatar
70 posts

Hallo JKing,

about the confirmation: I totally agree with you, see my recent feature request. But I did not receive any comment yet.

 
Avatar
70 posts

Hello JKing,

I’ve created a new version 0.0.4 history. As you suggested there is now a settings page that requests your confirmation to delete the table.

Regards
M

 
Avatar
17 posts

Sorry to be so needy ( :) ), M, but I have another concern:
There doesn’t seem to be any way to get metadata for any page but $this. For my current project I need to get metadata for arbitrary pages for an index, and I’m not finding any way to do this. I realise populating a page_metadata property for every page is impossible (or at least extremely impractical), but something like this would be nice:

$pages = $this->children(); 
foreach($pages as $page) {
 $meta = page_metadata($page);
 /* Do stuff with the metadata */
}
 
Avatar
70 posts

Hello JKing,

something like this?

PageMetadata::FindAllByPage($page);
or
PageMetadata::FindOneByPageAndKeyword($page, $keyword);
or
PageMetadata::FindAllByPageAsArray($page);

It’s already there. You can use the page object, or only the page_id.

Hope this helps
M

 
Avatar
17 posts

It does! I love you. :)

 
Avatar
17 posts

It seems I have a bug report for you, M: Since upgrading to 0.0.4, when adding metadata the following happens:


(here I added the keyword “Date”)

Can you reproduce this?

 
Avatar
70 posts

Hello JKing,

I’ve not yet tested this, but a wild guess would be, that you can not use SQL keywords as metadata (e.g. date).

I’ll look into this in a couple of hours.

BTW: I think you should look into the page_part_forms plug-in

 
Avatar
17 posts

Sorry, I should have specified that it happens for any keyword, not just ‘Date’.

I intend to look into the page-part metadata plug-in soon. Right now I have bigger fish to fry, however. ;)

 
Avatar
70 posts

Hello JKing,

sorry for the stupid bug. Fixed in 0.0.5.

Regards,
M

 
Avatar
70 posts

Hello,

I just released the 1.0.0 version of page_metadata and updated the first post of this thread.

Grab it while it’s hot ;)

M

 
Avatar
257 posts

Hi M, first off great plugin – I like your approach to the extra data, it works great and with very little extra work to do.

I’ve noticed a bug on line 237 of PageMetadataController.php

If I don’t have any additional metadata in the page, I kept getting an error when saving. This is solved by adding a check for POST data so the full Callback function reads:

  public static function Callback_page_page_updated($page) {
    // Get all posted metadata
    if($_POST[self::PLUGIN_ID]) {
	    foreach ($_POST[self::PLUGIN_ID] as $metadata) {
	      $value   = trim($metadata["value"]);
	      $keyword = $metadata["name"];
	      // Visible is more like a 'hack' to allow other plugins to style the metadata
	      // in their own way.
	      $visible = isset($metadata["visible"]) ? $metadata["visible"] : 1;

	      // If the metadata is not existing, create it.
	      $is_in_db = true;
	      if (!$obj = PageMetadata::FindOneByPageAndKeyword($page, $keyword)) {
	        $is_in_db = false;
	        // New value object
	        $obj = new PageMetadata(array(
	          "page_id" => $page->id,
	          "keyword" => $keyword,
	          "visible" => $visible,
	        ));
	      }
      }

      // Skip or delete empty values.
      if (empty($value)) {
          // Delete metadata if value is empty
          if ($is_in_db) {
            $obj->delete();
          }
          else {
            continue;
          }
        }
        else {
          // Update data and save.
          $obj->value = $value;
          $obj->visible = $visible;
          $obj->save();        
        }
    }
  }

Notice the addition of the:

if($_POST[self::PLUGIN_ID]) {

which fixes this bug. Just a quick sanity check :)

 
Avatar
70 posts

Hello Andy,

thanks for the finding! I changed this for version 1.0.1.

Please check if this is working for you, I did it a little bit different. As the commit message implies, I programmed too much Perl recently. This is the way you do it in Perl, but not in PHP ;)

M

 
Avatar
3 posts

Hey M!

Just wanted to say, your metadata plugin is absolutely awesome. :) I’m using it to power a bilingual site system; not sure what I would have done without it!

But – trying to get it running on the production server, and I get a
Warning: call_user_func_array() [function.call-user-func-array]: Unable to call PageMetadataController::Callback_view_page_edit_tabs() in /files/web-conference2010/frog/Framework.php on line 824
The table is created fine, and the “Settings” page works, but the tab doesn’t show up in the page editing UI and the above error displays instead. I’m trying to figure out what’s different between the two environments – would running 5.1.2 on the production server (instead of 5.2) be an issue? The “Dashboard” plugin isn’t working for that reason.

If you have any ideas they’d be very welcome – thanks a million for providing such a cool plugin.