Bludit: Custom fields for new content

Created on 27 Dec 2018  路  7Comments  路  Source: bludit/bludit

Idea:

  • The user can add new fields meanwhile is creating a new page
  • The fields is an structure of key => value
  • The fields need to be propagate to all pages at least with empty value

Get the value of a custom field.

$page->custom(key);

Missing:

  • How the user can delete a custom field ? and what happen with all pages who has this custom field ?

EDIT - 02/09/2019

Documentation link: https://docs.bludit.com/en/content/custom-fields

Screenshot
Bludit custom fields - New custom field

Bludit custom fields - Content editor

EDIT - 04/09/2019

Support for boolean type.

{
    "product": {
        "type": "string",
        "label": "Product",
        "tip": "Write the product name."
    },
    "inStock": {
        "type": "bool",
        "label": "In Stock",
        "tip": "Select this field if you have stock."
    }
}

Screenshot 2019-09-04 at 22 04 50

Screenshot 2019-09-04 at 22 05 44

EDIT - 09/09/2019

Support position to change the position in the editor.

{
    "product": {
        "type": "string",
        "placeholder": "Product name",
        "position": "top"
    },
    "inStock": {
        "type": "bool",
        "tip": "Select this field if you have stock.",
        "position": "top"
    },
    "imageURL": {
        "type": "string",
        "placeholder": "Image URL",
        "position": "bottom"
    }
}

Screenshot 2019-09-09 at 20 33 45

Brainstorming New request

Most helpful comment

Some documentation about custom fields is here https://docs.bludit.com/en/content/custom-fields

All 7 comments

I had a look at the database right now.. so I edit my idea:

Basically, I guess what is needed is a custom fields management where all custom fields are listed (so you know which fields have to be considered at all). When using a page record simply have a function to "clean" it before you use it. That is where you can iterate through all custom fields and assign default values ...

I had a closer look to the whole framework and understand now what is missing for my idea to work. I guess finally it goes in the same directions as #906

I think in order to do this, this will need some refactoring of the "content" admin part, the rest seems already given ...

Let's assume this usecase that will be provided with a plugin:

I want to extend the Page class to allow me to set a longitude and latitude so I can show the content linked to a map.

Brief list of what is needed to do this

  • CRUD values in the backend when CRUDING content
  • Allow the data to be placed as metadata in a remote file
  • crud the values in the page database
  • use the values in the view to do FE-Stuff with it

What is currently missing to achieve this

(actually not that much I think)

Content Type and Backend Rendering

  • In a Plugin, I can create class for each content type that extends the Page class and implements an Interface for standardization (this is necessary to ensure full compatibility with the basic workflow)

    • I will use a hook 'registerContentType' to let the system know, that the class is there

  • via the interfaced method 'getCustomFields' I can provide an array of fields and default values, which will be sanitized by the kernel as far as possible. These will be used whenever the $this->dbfields are used for iteration etc.
  • I can provide custom getter-methods and also specific functions or include any additional needed PHP Code (let's say they have to work similar to magic functions, so if I know, that there is a field 'longitude' ther should be a method 'longitude($conf)' to grab the value, using $conf to provide system-wide settings such as date formats etc. (if that is needed, resp. I think this is what $Site is providing)
  • via the new hook 'beforeRenderingPageForm' a protected method from the Page class is used to iterate through the customFields and provide inputs in a tab such as the "SEO" metadata tab (I personally suggest to lose the sidebar and work this into the main form as tabs) and also some custom css and js if needed for the inputs
  • as far as I have seen, the $pages->add() and createPage() methods do not restrict the metadata, so no changes needed there.

Views

  • I think here it is 'only' necessary to check for the content type when getting the page from the database and instanciate the correct class provided by the plugin, in order to use the custom getter methods on $page

This shouldn't be too hard to implement, I think, if one keeps it simple! And it'd be super useful :)

My ideas on implementing:

UI

The editor sidebar's "Advanced" tab can be extended to present a dictionary of key--value-pairs at the bottom. The UI to add, edit, and remove rows should be pretty simple with some JavaScript.

Backend storage

First, I think user-customizable fields should all be optional. You should be able to freely set and delete key/value pairs. The opposite would be to have a plugin register a key--value-pair as required for it to function, but when the user messes around, things might blow up.

For simplicity, instead of typing the values, one could start with strings only. Plugins have to be very defensive then: the value might be null, because it isn't set; and if it is set, it has to cast the value and check it, because the contents might be useless.

Examples

  • 'menuTitle' => 'Short Title' to customize how static pages with long page titles are displayed in navigation menus
  • 'lat' => '50.123', 'long' => '44.44' to specify geolocations work just as well

Note on Disambiguation: It might turn out to be good practice to prefix the keys to avoid clashes. The GeoLocation plugin might then require the prefix gl_, so users will specify gl_lat instead of just lat.

Plugin devs could easily fallback to lat in case users _want_ to share the info with multiple plugins and don't want to duplicate the same key--value-pairs just to satisy each plugin's need for a prefix.

<?php
$prefix = 'gl_';

function geoLocation_getValueForKey($page, $key) {
    // Favor the plugin-specific key if it exists
    if ($page->custom($prefix . $key)) {
        return $page->custom($prefix . $key);
    }
    // Fallback to a non-prefixed value
    return $page->custom($key);
}

This helper could just as well be bundled with Bludit to encourage the practice as an optional 2nd parameter to custom($key, $prefix = false).

Deleting custom values

Deleting key--value pairs per page is as simple as removing a row from the editor sidebar.

Deleting _all_ occurrences of keys in all pages should best be relegated to a plugin or advanced admin setting. The potential data-loss is huge. The setting page could fetch all keys from all pages by iterating over the results of $allITems = $pages->getList(0, -1, 0) and creating a set union of all custom keys. Deleting the key from the database is a pretty simple bulk change operation then. You can iterate over all pages again, remove the key, then save the result as an update (like you would when saving individual page changes in the editor).

It looks like customizing the page DB is possible already from a plugin in a very simple manner: https://github.com/ange007/bludit-posters/blob/master/plugin.php#L287

So the editor UI seems to be the biggest struggle, right?

@dignajar How do you want to tackle the feature? I could help collaborate on a PR.

Some documentation about custom fields is here https://docs.bludit.com/en/content/custom-fields

Next to string and bool it would also be awesome adding a select type too, which can be customized using an additional options tag for the selectable elements.

Next to string and bool it would also be awesome adding a select type too, which can be customized using an additional options tag for the selectable elements.

I back this idea.

Was this page helpful?
0 / 5 - 0 ratings