0

I'm using Joomla custom fields for articles and have created a custom field of type "media".

Also, because I want to setup my own rules on where and how uploaded files are stored, I've created a custom filesystem plugin.

I'd like to limit the "media" custom field to use only that custom filesystem plugin and not the default Joomla local filesystem plugin.

Is that possible?

0

1 Answer 1

0

With the solution below I'm assuming that you're wanting to use your custom filesystem plugin just for the custom media field alone, So that if you select an image in the Article Images and Links tab instead then for that you want to use the default joomla filesystem plugin.

Solution Background

Within the admin Article edit form, in the Images and Links tab, when you click on the Select button it generates an HTTP GET to the server with query parameters something like

option=com_media&view=media&tmpl=component&mediatypes=0&asset=91&author=604
&fieldid={field-media-id}&path=local-images:/sampledata/cassiopeia

The response enables the javascript code in media-manager.js to create the modal window for displaying the images which the user can select. On the left hand side are shown the folders, which are generated by the filesystem plugins (known as providers), and the information for displaying these is returned in the response to the above HTTP GET.

The Joomla field type within the edit Article Images and Links tab is a media field. So if you define a custom field as a 'media' type field, you're going to get the same media field underneath, and you'll get the same providers back.

So the solution proposed is the following:

  1. Create a new custom field type – I've called my 'mymedia', based on a new field type which I've called restrictedmedia.
  2. Define the restrictedmedia field type (piggy-backing on the Joomla media field type) and get it to send a different HTTP request to the server – so that the server can determine whether the request is from an ordinary media field, or from the restrictedmedia field. To do this I've injected an extra query parameter "restrictedmedia=1" in the URL when it's the restrictedmedia field type.
  3. Change code on the server to recognise the extra URL query parameter and adjust what providers get returned to the client js code.

Create a mymedia custom field type

This involves writing a plugin which creates a subfolder mymedia under plugins/fields. In a folder plg_mymedia, I have got mymedia.xml which has:

<?xml version="1.0" encoding="UTF-8"?>
<extension type="plugin" group="fields" method="upgrade">
    <name>plg_fields_mymedia</name>
    <author>Robbie</author>
    <description>My media plugin</description>
    <namespace path="src">Robbie\Plugin\Fields\Mymedia</namespace>
    <files>
        <folder plugin="mymedia">services</folder>
        <folder>src</folder>
    </files>
</extension>

And in plg_mymedia/services/provider.php – almost identical to plugins/fields/media/services/provider.php:

use Joomla\CMS\Extension\PluginInterface;
use Joomla\CMS\Factory;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\DI\Container;
use Joomla\DI\ServiceProviderInterface;
use Joomla\Event\DispatcherInterface;
use Robbie\Plugin\Fields\Mymedia\Extension\Mymedia;

return new class () implements ServiceProviderInterface {

    public function register(Container $container)
    {
        $container->set(
            PluginInterface::class,
            function (Container $container) {
                $dispatcher = $container->get(DispatcherInterface::class);
                $plugin     = new Mymedia(
                    $dispatcher,
                    (array) PluginHelper::getPlugin('fields', 'mymedia')
                );
                $plugin->setApplication(Factory::getApplication());

                return $plugin;
            }
        );
    }
};

The main plugin code is in plg_mymedia/src/Extension/Mymedia.php. This is basically the same as in plugins/fields/media/src/Extension/Media.php, except make the following changes.

At the top add your namespace and the fully qualified classname of FormHelper:

namespace Robbie\Plugin\Fields\Mymedia\Extension;
use Joomla\CMS\Form\FormHelper;

and in the function onCustomFieldsPrepareDom replace

$fieldNode->setAttribute('type', 'media');

with

$fieldNode->setAttribute('type', 'restrictedmedia');
FormHelper::addFieldPrefix('Robbie\Plugin\Fields\Mymedia\Field');

This means that we're basing the mymedia custom field type upon a custom field type of 'restrictedmedia'. (Yes, it's unfortunate that 'custom field type' is used to mean different things in Joomla).

We also need to tell the Joomla Form where to find the definition of the restrictedmedia field type, via the addFieldPrefix call. From the manifest file line

<namespace path="src">Robbie\Plugin\Fields\Mymedia</namespace>

'Robbie\Plugin\Fields\Mymedia' will map to plugins/fields/mymedia/src. So Joomla will expect to find the class Robbie\Plugin\Fields\Mymedia\Field\RestrictedmediaField in the file plugins/fields/mymedia/src/Field/RestrictedmediaField.php.

Define the RestrictedmediaField type

The definition of the 'restrictedmedia' field type is in plg_mymedia/src/Field/RestrictedmediaField.php. It's defined to be the same as the MediaField class in libraries/src/Form/Field/MediaField.php except that we inject an extra item into the $data.

namespace Robbie\Plugin\Fields\Mymedia\Field;

use Joomla\CMS\Form\Field\MediaField;

class RestrictedmediaField extends MediaField
{
    protected $type = 'Restrictedmedia';
    
    public function getLayoutData()
    {
        $data = parent::getLayoutData();
        $data['restrictedmedia'] = true;
        return $data;
    }
}

The media field type (and our restrictedmedia field type) is rendered in layouts/joomla/form/field/media.php, so we just need to change this so that the URL sent has the extra parameter if it's our restrictedmedia field type. With the admin System / Templates / Atum Details and File create an override for that layout, and change the code as follows.

Below the lines

// The url for the modal
$url = ($readonly ? ''
    : ($link ?: 'index.php?option=com_media&view=media&tmpl=component&mediatypes=' . $mediaTypes
        . '&asset=' . $asset . '&author=' . $authorId)
    . '&fieldid={field-media-id}&path=' . $folder);

add the lines:

if (isset($restrictedmedia)) {
  $url .= '&restrictedmedia=1';
}

When the user clicks on the Select button then this is the URL which is sent to the server to get the data to build the modal window.

Adjust the providers sent in the response

The response to the HTTP GET is in administrator/components/com_media/tmpl/media/default.php. The data includes the filesystem providers, which are sent down to the javascript code in a $config array using addScriptOptions.

So you need to create another override for that file. Above the line populating the media $config, add the lines:

if ($input->getCmd('restrictedmedia')) {
  foreach ((array)$this->providers as $key => $provider) {
    if ($provider->name === "local") {
      unset ($this->providers[$key]);
    }
  }
}

So if it's the case that the URL has "restrictedmedia=1" then these lines will remove the default local filesystem provider.

Inside your custom filesystem plugin, within onSetupProviders you could also examine the URL and determine whether you wanted to register your filesystem provider.

By the way, testing this code I found at one point an error reported in the modal window "Account not found". If this occurs, then clear your session cookies via your browser devtools. There was a Joomla bug which caused this message, and it's maybe not totally sorted.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.