<p>Since this is a module rather than a plugin, you need to register control panel template roots, like so:</p>
<pre><code>  Event::on(
    View::class,
    View::EVENT_REGISTER_CP_TEMPLATE_ROOTS,
    function (RegisterTemplateRootsEvent $e) {
        $e-&gt;roots['app-module'] = __DIR__ . '/templates/cp';
    }
  );
</code></pre>
<p>(I've swapped 'custom' for 'app-module' as I think it's a little more clear, but feel free to keep it as 'custom') If your module's <code>src</code> folder does not have a <code>templates/cp</code> directory, create one and add an <code>index.twig</code> to it. Now going to <code>admin/app-module</code> should load the index file you've created. (You'll need to update the <code>EVENT_REGISTER_CP_NAV_ITEMS</code> from 'custom' to 'app-module' to have the CP url match the change I've made here.) However, since you're working with an element, it's probably better to create another directory named after your element. Let's use &quot;Item&quot; as a generic element class name, you might have <code>templates/cp/items/index.twig</code> who's contents might look like this:</p>
<pre><code>{% extends elementType is defined ? '_layouts/elementindex' : '_layouts/cp' %}

{% set elementType = 'modules\\appmodule\\elements\\ItemElement' %}
{% set title = 'My Custom Items'|t('app-module') %}

{% block actionButton %}
 &lt;div id=&quot;extra-headers&quot;&gt;
    &lt;div class=&quot;buttons right&quot;&gt;
      &lt;a href=&quot;{{ url('app-module/items/new') }}&quot; class=&quot;btn submit add icon&quot;&gt;
       {{ &quot;New custom item&quot;|t('app-module')}}
      &lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
{% endblock %}
</code></pre>
<p>You don't need to register this URL via the <code>EVENT_REGISTER_CP_URL_RULES</code>, but you will want to for the element edit and creation page. e.g.</p>
<pre><code>Event::on(
    UrlManager::class,
    UrlManager::EVENT_REGISTER_CP_URL_RULES,
    function (RegisterUrlRulesEvent $event) {
        $event-&gt;rules['app-module/items/new'] = 'app-module/items/edit-item';
        $event-&gt;rules['app-module/items/&lt;itemId:\d+&gt;' =&gt; 'app-module/items/edit-item']
    }
);
</code></pre>
<p>Here, the key is the URL you will hit in the control panel and the value is the action URL you'll need to create in your module. <code>src/controllers/ItemsController.php</code>, which will have an <code>actionEditItem</code> function.</p>
<p>Hope this helps!</p>

CC BY-SA 4.0
2020-12-28T16:00:47.517Z
2020-12-28T16:00:47.517Z
andrewmenich
<p>Hello I've created a new element type in a module (a web app within Craft) that I'm developing.
I have initially created my models to be <code>craft\db\ActiveRecord</code> and save directly to their tables, but that is not the &quot;craft&quot; way.</p>
<p>I decided to extend from <code>craft\base\Element</code> and do the needful in order to leverage elementindex.html (search, sort, filter), but going to <code>/admin/custom/index</code> gives a &quot;404 Not Found&quot;. Do I need to create my own CustomController.php ?</p>
<p>I did the configuration needed in my Module class, as well as creating the Custom.php and CustomQuery.php according to the <a href="https://craftcms.com/docs/3.x/extend/element-types.html" rel="nofollow noreferrer">documentation here</a></p>
<pre><code>   // CP Routes
    Event::on(
        UrlManager::class,
        UrlManager::EVENT_REGISTER_CP_URL_RULES,
        function (RegisterUrlRulesEvent $event) {
            $event-&gt;rules['custom'] = '/app-module/custom/index';
        }
    );

    // CP Nav Items
    Event::on(
        Cp::class,
        Cp::EVENT_REGISTER_CP_NAV_ITEMS,
        function (RegisterCpNavItemsEvent $event) {
            $event-&gt;navItems[] = [
                'url' =&gt; 'custom',
                'label' =&gt; 'Custom',
                'icon' =&gt; 'share',
            ];
        }
    );

    // Custom Element Types
    Event::on(Elements::class,
        Elements::EVENT_REGISTER_ELEMENT_TYPES,
        function(RegisterComponentTypesEvent $event) {
            $event-&gt;types[] = Custom::class;
        }
    );
</code></pre>

<control-panel><modules><elementtype><elementquery><index>
Custom Module: new element type index page access
# Custom Module: new element type index page access

(Asked by: username_0 on 2020-12-28)

Hello I've created a new element type in a module (a web app within Craft) that I'm developing.
I have initially created my models to be craft\db\ActiveRecord and save directly to their tables, but that is not the "craft" way.
I decided to extend from craft\base\Element and do the needful in order to leverage elementindex.html (search, sort, filter), but going to /admin/custom/index gives a "404 Not Found". Do I need to create my own CustomController.php ?
I did the configuration needed in my Module class, as well as creating the Custom.php and CustomQuery.php according to the documentation here
   // CP Routes
    Event::on(
        UrlManager::class,
        UrlManager::EVENT_REGISTER_CP_URL_RULES,
        function (RegisterUrlRulesEvent $event) {
            $event->rules['custom'] = '/app-module/custom/index';
        }
    );

    // CP Nav Items
    Event::on(
        Cp::class,
        Cp::EVENT_REGISTER_CP_NAV_ITEMS,
        function (RegisterCpNavItemsEvent $event) {
            $event->navItems[] = [
                'url' => 'custom',
                'label' => 'Custom',
                'icon' => 'share',
            ];
        }
    );

    // Custom Element Types
    Event::on(Elements::class,
        Elements::EVENT_REGISTER_ELEMENT_TYPES,
        function(RegisterComponentTypesEvent $event) {
            $event->types[] = Custom::class;
        }
    );

**Tags:** control-panel, modules, elementtype, elementquery, index

---

## 1 answers

### Answer by username_1 on 2020-12-28. Score: 2 | Accepted answer

Since this is a module rather than a plugin, you need to register control panel template roots, like so:
  Event::on(
    View::class,
    View::EVENT_REGISTER_CP_TEMPLATE_ROOTS,
    function (RegisterTemplateRootsEvent $e) {
        $e->roots['app-module'] = __DIR__ . '/templates/cp';
    }
  );

(I've swapped 'custom' for 'app-module' as I think it's a little more clear, but feel free to keep it as 'custom') If your module's src folder does not have a templates/cp directory, create one and add an index.twig to it. Now going to admin/app-module should load the index file you've created. (You'll need to update the EVENT_REGISTER_CP_NAV_ITEMS from 'custom' to 'app-module' to have the CP url match the change I've made here.) However, since you're working with an element, it's probably better to create another directory named after your element. Let's use "Item" as a generic element class name, you might have templates/cp/items/index.twig who's contents might look like this:
{% extends elementType is defined ? '_layouts/elementindex' : '_layouts/cp' %}

{% set elementType = 'modules\\appmodule\\elements\\ItemElement' %}
{% set title = 'My Custom Items'|t('app-module') %}

{% block actionButton %}
 
    
      
       {{ "New custom item"|t('app-module')}}
      
    
  
{% endblock %}

You don't need to register this URL via the EVENT_REGISTER_CP_URL_RULES, but you will want to for the element edit and creation page. e.g.
Event::on(
    UrlManager::class,
    UrlManager::EVENT_REGISTER_CP_URL_RULES,
    function (RegisterUrlRulesEvent $event) {
        $event->rules['app-module/items/new'] = 'app-module/items/edit-item';
        $event->rules['app-module/items/' => 'app-module/items/edit-item']
    }
);

Here, the key is the URL you will hit in the control panel and the value is the action URL you'll need to create in your module. src/controllers/ItemsController.php, which will have an actionEditItem function.
Hope this helps!


---

