Elemental in Data Object results in I can't handle sub-URLs

Silverstripe Version: 4.4

I have the same problem as: Element in ModelAdmin DataObjects results 'I can't handle sub-URLs on class SilverStripe\Admin\LeftAndMainFormRequestHandler.' · Issue #718 · dnadesign/silverstripe-elemental · GitHub but the fixes by @kinglozzer don’t work or I’m applying them incorrectly.

I have a NewsPost DataObject and I’ve added the following to it:

	public function CMSEditLink($link = false)
    {
        $admin = NewsPostsAdmin::singleton();
        $urlClass = str_replace('\\', '-', self::class);
        return $admin->Link("/{$urlClass}/EditForm/field/{$urlClass}/item/{$this->ID}/edit");
	}

I can see the blocks listed and inline blocks work fine.

When I click on the Accordion Element I get the url “somesite.co.nz/admin/pages/edit/EditForm/8/field/ElementalArea/item/45/edit” and the message:

I can’t handle sub-URLs on class SilverStripe\Admin\LeftAndMainFormRequestHandler.

Accordion code:

<?php

use DNADesign\Elemental\Models\BaseElement;
use SilverStripe\Forms\GridField\GridField;
use SilverStripe\Forms\GridField\GridFieldConfig_RecordEditor;
use Symbiote\GridFieldExtensions\GridFieldOrderableRows;

class Accordion extends BaseElement
{
    private static $singular_name = 'Accordion';

    private static $plural_name = 'Accordions';

    private static $description = 'Displays slideable accordion content.';

    private static $icon = 'font-icon-menu';

    private static $has_many = [
        'AccordionItems' => AccordionItem::class
    ];
    
    private static $owns = [
        'AccordionItems',
    ];

    private static $inline_editable = false;

	public function getCMSFields()
    {
        $fields = parent::getCMSFields();

        $contentItems = $this->AccordionItems();
        $GridConfig = GridFieldConfig_RecordEditor::create();
        $GridConfig->addComponent(new GridFieldOrderableRows('SortOrder'));
        $GridField = GridField::create('AccordionItems', 'Single accordion items', $contentItems, $GridConfig);

        $fields->addFieldsToTab('Root.Main',  $GridField);

        return $fields;
    }

    public function getType()
    {
        return 'Accordion';
    }
	
	public function canView($member = null)
	{
		return true;
	}

	public function canCreate($member = null, $context = [])
	{
		return true;
	}

	public function canEdit($member = null)
	{
		return true;
	}

	public function canDelete($member = null)
	{
		return true;
	}
}

I haven’t applied step 3 of the fix in that link, this code:


	public function updateCMSEditLink($link = false)
    {
        if (!$this->owner->inlineEditable()) {
            $page = $this->owner->getPage();

            if (!$page || $page instanceof SiteTree) {
                return;
            }

            // As non-page DataObject's are managed via GridFields, we have to grab their CMS edit URL
            // and replace the trailing /edit/ with a link to the nested ElementalArea edit form
            $relationName = $this->owner->getAreaRelationName();
            $link = preg_replace(
                '/edit\/?$/',
                "ItemEditForm/field/{$relationName}/item/{$this->owner->ID}/edit/",
                $page->CMSEditLink()
			);
        }
    }

If I add it to the NewsPost DataObject it has no effect.
If I add it to the Accordion element it has no effect.
If I add it to the NewsPostsAdmin admin it has no effect.

The extension containing updateCMSEditLink needs to be applied to BaseElement. Also, the snippet you shared is missing the ampersand (&) from the parameter, it should be updateCMSEditLink(&$link).

The extension containing updateCMSEditLink needs to be applied to BaseElement

I’m not 100% on what that refers to? Do you mean the Accordion:

class Accordion extends BaseElement

from above or is this an extension I don’t have that I need to create?

To complete this answer for anyone finding this forum entry: You have to create an extension with the method and apply it to the BaseElement class itself. Like this:

<?php
namespace App\Elements;

use SilverStripe\ORM\DataExtension;

class BaseElementExtension extends DataExtension {
    /**
    * @param $link
    */
    public function updateCMSEditLink(&$link): void
    {
        if (!$this->owner->inlineEditable()) {
            $page = $this->owner->getPage();

            if (!$page || $page instanceof SiteTree) {
                return;
            }

            // As non-page DataObject's are managed via GridFields, we have to grab their CMS edit URL
            // and replace the trailing /edit/ with a link to the nested ElementalArea edit form
            $relationName = $this->owner->getAreaRelationName();
            $link = preg_replace(
                '/edit\/?$/',
                "ItemEditForm/field/{$relationName}/item/{$this->owner->ID}/edit/",
                $page->CMSEditLink()
            );
        }
    }
}

And in your config.yml:

DNADesign\Elemental\Models\BaseElement:
  extensions:
    - App\Elements\BaseElementExtension