Jump to content

basic questions about plugin development for own plugins (ajax request with json response, Hooks in admin module)


Recommended Posts

Hi,

I'm trying to get some basic knowledge of Processwire module development. I've read the beginner guides and I've done a lot of research.

My current use case is to extend a custom admin template for pages with an update button in the "settings" tab of this template. The update button should then update the page's data through an external API on this page using its metadata that this template type has when you edit the page in the admin.

Here's the shortened PHP code (yes, I've build own classes for the hooks) of what I trying to achieve that comes along with a few problems:

<?php

namespace ProcessWire;

class TestUpdate extends Process implements ConfigurableModule
{
    public const XHR_PAGE_NAME = 'test-update';

    public const JSON_TPL_NAME = 'json';

    public static function getModuleInfo()
    {
        return [
            'title' => 'My Admin Extender',
            'summary' => 'An admin module to easily bring test data up-to-date',
            'version' => '0.0.1',
            'permission' => 'test-update',
            'permissions' => [
                'test-update' => 'View the button in the template',
                'test-update-save' => 'Permission to perform the actual update from API',
            ],
            'icon' => 'table',
            'author' => 'alpham8',
            'requires' => 'UpdatePlugin>=0.0.1, ProcessWire>=3.0.133',
            'page' => [
                'name' => self::XHR_PAGE_NAME,
                'title' => 'update-product',
                'template' => 'admin'
            ]
        ];
    }

    public function ready()
    {
        /** @var Page $page */
        $page = $this->wire('page');

        // add helper notices about ProCache to page and template editors
        if (static::isTemplate('admin', $page)) {
            $this->addHookAfter('ProcessPageEdit::buildFormSettings', $this, 'hookPageEdit');
        }
    }

    public function hookPageEdit(HookEvent $event)
    {

        /** @var WirePageEditor $process */
        $process = $event->object;
        $page = $process->getPage();

        if (static::isTemplate('product', $page)) {
            // TODO: maybe add $this->user->isSuperuser() check
            $form = $event->return;

            /** @var InputfieldMarkup $field */
            $field = $this->modules->get("InputfieldMarkup");
            $info = HaroImportProductPages::getModuleInfo();
            $field->label = $info['title'];
            $field->icon = $info['icon'];

            /** @var InputfieldButton $btn */
            $btn = $this->modules->get('InputfieldButton');
            $btn->attr('value', 'update product data');
            if ($page->hasField('param1') && $page->hasField('param2')) {
                $btn->attr(
                    'href',
                    '#'
                );
                $btn->addClass('update-link');
                $btn->attr('data-param1', $page->get('param1'));
                $btn->attr('data-url', 'https://' . $_SERVER['HTTP_HOST'] . '/processwire/test-update/save/');
            }
            $btn->icon = 'refresh';
            $btn->attr('id+name', 'UpdateProductPagesBtn');
            $btn->label = 'Update product data';
            $btn->collapsed = Inputfield::collapsedNever;

            $field->collapsed = Inputfield::collapsedNever;
            $field->attr('value', $btn->render());

            $form->add($field);
        }
    }

    /**
     * Does user have permission?
     *
     * @param string $name
     * @return bool
     * @throws WireException
     */
    protected function hasPermission(string $name): bool
    {
        $user = $this->wire()->user;
        if ($user->isSuperuser()) {
            return true;
        }

        return $user->hasPermission($name);
    }


    public function execute(): array|string
    {
        return 'test1';
    }

    public function executeSave(): array|string
    {
        $input = $this->wire()->input;
        $testparam = $input->post('testparam');
        $result = false;
        /** @var UpdatePlugin $module */
        $module = $this->wire->modules->get('UpdatePlugin');

        // possibly product number check:
        if ($testparam !== '' && is_numeric($testparam) && \mb_strlen($testparam, 'UTF-8') >= 4) {
            $result = $module->writeDataToPage($testparam);
        }

        return json_encode([
            'testparam' => $testparam,
            'success' => $result === 1,
        ]);
    }
}

My problems or questions are:

1st The ready method doesn't get called in an admin module, instead, I need to place it in another module like this:

<?php

namespace ProcessWire;

class UpdatePlugin extends Wire implements Module
{
    public static function getModuleInfo()
    {
        return [
            'title' => 'UpdatePlugin',
            'version' => '0.0.1',
            'summary' => 'Summary for UpdatePlugin ...',
            'author' => 'alpham8',
            'icon' => 'table',

            'autoload' => true,
            'requires' => 'ProcessWire>=3.0.123',
        ];
    }

    public function init()
    {
        $scriptUrl = $this->urls->$this . 'assets/product-update.js';
        $this->config->scripts->add($scriptUrl);
    }

    public function ready()
    {
        /** @var Page $page */
        $page = $this->wire('page');

        // add helper notices about ProCache to page and template editors
        if (static::isTemplate('admin', $page)) {
            $this->addHookAfter('ProcessPageEdit::buildFormSettings', $this, 'hookPageEdit');
        }
    }

    // [see above] ...
}

2nd Isn't there a way to just build an ajax request that returns plain JSON without that page / template skeleton? As far as I understood it, a page is mandatory in Processwire for this. That would be fine, if we can hide the page in the admin's navbar by using css. I thought that might be possible with creating an own template that just outputs JSON, right? But how to do a template without a parent one?

3rd How can I bring or access variables from modules in pages? Just by calling it without the knowledge that they are exist on the concrete (PHP) page?

4th Isn't there a way to get the absolute URL out of $config->urls ? I'd like to avoid that insecure $_SERVER['HTTP_HOST'] call.

We're currently on ProcessWire 3.0.210. An update is planned after that modules.

Any help to that above question would be great.

Thanks in advice,

alpham8

  • Like 1
Link to comment
Share on other sites

2 hours ago, alpham8 said:

2nd Isn't there a way to just build an ajax request that returns plain JSON without that page / template skeleton? As far as I understood it, a page is mandatory in Processwire for this. That would be fine, if we can hide the page in the admin's navbar by using css. I thought that might be possible with creating an own template that just outputs JSON, right? But how to do a template without a parent one?

Sorry don't have more time for the other questions but this one is quickly answered: https://processwire.com/blog/posts/pw-3.0.173/

  • Like 2
Link to comment
Share on other sites

3 hours ago, alpham8 said:

1st The ready method doesn't get called in an admin module

Can’t you autoload your Process module? https://processwire.com/docs/modules/development/#automatically-loading-modules

If you set 'autoload' => 'template=admin' in getModuleInfo() the ready() method should be called on every request within the PW admin. You can then determine if your hooks are needed as you’re already doing.

  

3 hours ago, alpham8 said:

3rd How can I bring or access variables from modules in pages? Just by calling it without the knowledge that they are exist on the concrete (PHP) page?

I'm not sure what you mean by this, but you can use $modules->get('TestUpdate') to get an instance of your module?

 

3 hours ago, alpham8 said:

4th Isn't there a way to get the absolute URL out of $config->urls ? I'd like to avoid that insecure $_SERVER['HTTP_HOST'] call.

Yes, you can use $config->urls->admin, for example, but since you're creating a Process module, you should be able to get the entire URL using $this->getProcessPage(). That should be way to go since users can theoretically move or rename your Process page (as well as the Admin itself). If you're inside a request to the Process page, it will get you the current Page. Otherwise it will get the first page using the Process.

Edited by Jan Romero
  • Like 2
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...