Jump to content

Fieldtype Runtime Only


Robin S
 Share

Recommended Posts

This is a module that is similar in purpose to the Runtime Markup module. I made it primarily for my own use but am posting it here because I had a request to add it to the modules directory.

Fieldtype Runtime Only

Not a proper fieldtype because it doesn't save data to the database. The fieldtype only exists to provide a convenient way to add an inputfield to templates that will render some markup at runtime.

For a field named "my_field"...

  • Inputfield markup will be rendered from a file at /site/templates/RuntimeOnly/my_field.php. In addition to the standard ProcessWire variables this file receives:
    • $page - the page being edited.
    • $field - the Field object.
    • $inputfield - the Inputfield object.
  • JS file /site/templates/RuntimeOnly/my_field.js will be added to admin if that file exists.
  • CSS file /site/templates/RuntimeOnly/my_field.css will be added to admin if that file exists.

Tips

Output formatting

Output formatting for $page will be off in the context of Edit Page so if you want to use the formatted value of a field in your RuntimeOnly code you should use $page->getFormatted(). E.g.

$value = $page->getFormatted('some_field_name');

Repeaters

If the RuntimeOnly field is used inside a Repeater field then you can get the Repeater page it is on via $inputfield->hasPage. E.g.

$repeater_page = $inputfield->hasPage;
// Use $repeater_page as needed
echo "The name of the repeater page is $repeater_page->name";

 

https://github.com/Toutouwai/FieldtypeRuntimeOnly
https://modules.processwire.com/modules/inputfield-runtime-only/

  • Like 10
Link to comment
Share on other sites

  • 11 months later...

It may not be a 'proper' fieldtype, but it is very useful and a key part of my ProcessDbMigrate module.

However, I have a very slight problem which is really puzzling me. My module gets data from the database and exports to .json files (among other things). I use the standard Field::getExportData() for getting field data. The curious thing is, for certain fields, I get a different result from getExportData() depending on whether it is called from inside my module or from a RuntimeOnly script.

For example, the field phits (from the Page Hit Counter module) has visibility 'hidden' (i.e. collapsed = 4). Calling getExportData() from my module (see code below) returns the correct result.

$field = $this->wire()->fields->get('phits');
bd($field->getExportData(), 'getExportData in module class');

Calling it from with a RuntimeOnly script (see code below) returns collapsed = 0.

$field = $fields->get('phits');
bd($field->getExportData(), 'getExportData in RuntimeOnly');

See pic below for the Tracy debug:

312955781_FieldgetExportDataissueinRuntimeOnly.thumb.jpg.fa23186828b3e5d504b87e8f97326133.jpg

Examining the situation in a bit more detail shows the following:

  1. Field::getExportData() calls Fieldtype::exportConfigData() viz. $typeData = $this->type->exportConfigData($this, $data); and then merges the data, viz. $data = array_merge($data, $typeData);
  2. Fieldtype::exportConfigData() calls Inputfield::exportConfigData(), viz. $data = $inputfield->exportConfigData($data);

It is the second call which returns collapsed = 0 rather than collapsed = 4. It is arguable that the array_merge should be reversed - i.e. $data = array_merge($typeData, $data); so that the generic data does not over-ride the specific - not that this really helps, as I have no idea what is causing the problem in the first place.

Any ideas? In the meantime, I guess I will need to do a work-round by trying to move the code out of the RuntimeOnly script (note that the actual code I am using is much broader than the 'phits' snippet above - I have just used that to illustrate the problem).

Link to comment
Share on other sites

6 hours ago, MarkE said:

Calling it from with a RuntimeOnly script (see code below) returns collapsed = 0.

I can't reproduce that. It's showing collapsed => 4 when I dump the field in a FieldtypeRuntimeOnly render file.

2021-06-18_162817.png.a5f1f73d5699bb65b7018a99183fec65.png

This module doesn't do anything regarding inputfield visibility so I think your issue must be a general one relating to the PW API rather than specific to this module. Really all this module is doing is rendering a TemplateFile via $files->render().

One thing though... take note of the readme regarding the variables supplied to the render file:

On 6/21/2020 at 6:39 PM, Robin S said:

In addition to the standard ProcessWire variables this file receives:

  • $page - the page being edited.
  • $field - the Field object.
  • $inputfield - the Inputfield object.

I don't know if it relates to your issue but I suggest you avoid overwriting the $field variable by choosing a different name for the field you are getting.

  • Like 1
Link to comment
Share on other sites

6 hours ago, MarkE said:

a key part of my ProcessDbMigrate module.

Given how simple FieldtypeRuntimeOnly is, it might be good to avoid the dependency in your module and just render your own markup directly. I haven't looked closely at your module but it just seems like it would make sense to keep it self-contained and avoid any fragility due to the chance that FieldtypeRuntimeOnly changes in the future.

  • Like 1
Link to comment
Share on other sites

1 hour ago, Robin S said:

Given how simple FieldtypeRuntimeOnly is, it might be good to avoid the dependency in your module

Good idea. I used it as a shortcut. I’m just completing the planned functionality of my module, after which some tidying up will follow, so I’ll take the opportunity then. 

Link to comment
Share on other sites

  • 4 months later...

@Robin S - not sure if this is something that can / should be corrected in this module, or if it needs to be handled the core findRaw, but I am seeing this error:

Exception: SQLSTATE[42S02]: Base table or view not found: 1146 Table 'field_coupon_link' doesn't exist on line: 744 in /var/www/html/wire/core/PagesRaw.php

when I do a call like this:

$pages->findRaw('staff.count>0');

If I specify the fields I need like: $pages->findRaw('staff.count>0', 'staff'); it's fine because it prevents findRaw() from trying to find the table for RuntimeOnly fields.

My instinct is that it will needed to be fixed in the core.

Link to comment
Share on other sites

2 hours ago, adrian said:

If I specify the fields I need like: $pages->findRaw('staff.count>0', 'staff'); it's fine because it prevents findRaw() from trying to find the table for RuntimeOnly fields.

Been getting a similar error on a custom runtime module. Only way around it is to specify a field/fields to fetch as in your example.

Link to comment
Share on other sites

@adrian, it might be that every Fieldtype needs to create a table in the DB regardless of if it is used or not. For instance, FieldtypeFieldset creates a table that is never used. FieldtypeRuntimeOnly originally did create a DB table because I based it on FieldtypeFieldset, but later versions prevented the table from being created after a pull request from you.

You could open an issue on the PW repo to see if Ryan will add a check in findRaw for fieldtypes that do not have a corresponding table, but if he's not willing I think the only fix will be to go back to creating a table for FieldtypeRuntimeOnly fields on field creation.

Link to comment
Share on other sites

6 minutes ago, Robin S said:

it might be that every Fieldtype needs to create a table in the DB regardless of if it is used or not.

I don't think this is right. My runtime Fieldtype is based off  Ryan's Concatenate Fieldtype and that does not create a DB table.

See also his comments in the code, e.g. this one. No database table is necessary.

 

  • Like 1
Link to comment
Share on other sites

13 minutes ago, kongondo said:

My runtime Fieldtype is based off  Ryan's Concatenate Fieldtype and that does not create a DB table.

FieldtypeConcat causes the same error, so that will add to the argument for a core fix.

2021-11-04_101332.png.d6265b175b4bef57db08799917e098bc.png

  • Like 3
Link to comment
Share on other sites

  • 10 months later...

I guess your question depends very much on your goals... Is your goal to not write any code? Is your goal to have a nice GUI? Is your goal to use as little 3rd party modules as possible? Because adding markup to the PW page editor is only a few lines of code, so you don't need any other module for it (untested):

<?php
// site/ready.php
$wire->addHookAfter("ProcessPageEdit::buildFormContent", function($event) {
  $form = $event->return;
  
  $page = $event->object->getPage();
  if($page->template != 'foo') return;
  
  $title = $form->get('title');
  if(!$title) return;
  
  $f = $this->wire(new InputfieldMarkup());
  $f->label = 'foo markup field';
  $f->value = '<h1>i am a markup field</h1>';
  $form->insertAfter($f, $title);
});
  • Like 1
Link to comment
Share on other sites

3 hours ago, Ivan Gretsky said:

You mentioned RuntimeMarkup module in the 1st post, but did not mention, what are the differences between that module and yours. Could you please help me here and outline pros and cons of your module comparing to @kongondo's ?

I haven't been a regular user of the RuntimeMarkup module so I'm not qualified to talk about it. Maybe the best thing would be for you to try both modules and see which one suits you better.

  • Like 1
Link to comment
Share on other sites

13 hours ago, Ivan Gretsky said:

your module comparing to @kongondo's

The biggest difference is that Robi's module uses php files while Kongondo's module saves the php code into the database so you need to code in the admin.

I used them both, so I recommend Robi's module. I have already switched sites from Runtime Markup to Runtime Only.

12 hours ago, bernhard said:

Is your goal to not write any code? Is your goal to have a nice GUI? Is your goal to use as little 3rd party modules as possible?

These are possibilities for sure (BWT, I do not think Ivan is afraid of writing code so why the sarcasm?), but what a simple buildFormContent hook will not do for us is being able to use the rendered output anywhere where an Inputfiled can be used (in a Lister or a ProField Table, etc, for example). So we are comparing apples to bananas if we compare inputfields to code running in hooks. ;) Both can be valid options, we decide what to use depending on the requirements, of course.

  • Like 2
Link to comment
Share on other sites

Thanks for the answer @szabesz!

I've read the RuntimeMarkup module thread, and @kongondo also recommends to put the actual code in a file and just  wireRenderFile() it. So that must be the main difference. I also thought about the easy inclusion of js and css in Runtime only as a substantial difference.

By the way, I do not read any real sarcasm in @bernhard's post. I guess it is just a his style) He is always asking himself questions and answers them. Sort of inner dialog)

 

  • Like 2
Link to comment
Share on other sites

1 minute ago, Ivan Gretsky said:

easy inclusion of js and css in Runtime only

You are right. I forgot to mention that for sure.

2 minutes ago, Ivan Gretsky said:

I guess it is just a his style

I guess, too :) BTW, I do not think sarcasm is a wrong thing as such, I just felt it a bit off topic in this context but that was just my impression, of course.

Link to comment
Share on other sites

There was no sarcasm at all. I was just asking for more information to help everybody (being it me or robin or teppo or anybody else) to provide the best solution for his exact problem...

13 hours ago, Ivan Gretsky said:

I am choosing a module for markup in edit page.

That was all the information provided. And that's exactly what my hook does: markup in edit page.

"I want to add markup+css+js easily to page edit. I want to add field markup to page edit and also lister etc...". That are obviously different things and maybe not as easy to do as with just adding one simple hook.

You'd maybe need two. That was sarcasm ? 

  • Like 2
Link to comment
Share on other sites

On 9/8/2022 at 8:33 PM, Ivan Gretsky said:

Could you please help me here and outline pros and cons of your module comparing to @kongondo's ?

I have used both and now just use this one on new projects. They both work fine in normal circumstances (and are easy enough to just temporarily install and play with), but @Robin S's is simpler with less to go wrong - I had a few problems with @kongondo's in a multi-instance environment (which I think are fixed). On the other hand @kongondo's has a slightly more feature-rich GUI. You could always build your own simple module rather than just use hooks if you want more than the basic RuntimeOnly and want control over the code - I forked this module to include a custom Fieldtype in my ProcessDbMigrate module. As @bernhard says, it all depends what you are trying to do.

  • Like 3
Link to comment
Share on other sites

  • 4 weeks later...

Hi,

great module, just a little funny thing i've just ran into
i use it to render in the admin a square component made with pages that may contain an image or have a background-image
the image field is named squareimg and is set as a single image field, not an array

// if i use
echo $page->squareimg->url; // the usual pw way, it returns /site/assets/files/xxxx/
echo $page->squareimg; // returns the name of the image i've got to write
echo $page->squareimg->url . $page->squareimg // to get my full image path

just in case it may help ?

have a nice day

Link to comment
Share on other sites

8 hours ago, virtualgadjo said:

great module, just a little funny thing i've just ran into

This isn't anything specific to this module - it's just the effect of output formatting being on or off. Unfortunately there is no general documentation page explaining the idea of output formatting but the $page->of() docs gives you some info.

The rule of thumb is that output formatting is on in the frontend and off in the backend, particularly in a situation where field values are going to be saved like in the page editor.

You can set the formatted value of a single image field to be a Pageimage but when output formatting is on it will always be a Pageimages array.

image.png.2af93a85ee45fd1a8e1a7042e00bb9e4.png

So in FieldtypeRuntimeOnly you need to specifically ask for the formatted value of the field:

$image = $page->getFormatted('squareimg');
if($image) {
	// ...
}

 

  • Like 1
  • Thanks 1
Link to comment
Share on other sites

Hi @Robin S

and wow, thanks a lot for your answer and this greeat explanation!

funny enough, i've written a lot of modules for customers using this $page->of() function to allow validation of values submitted with a front end form to create pw pages but never had to deal with displaying images in the back end, thanks to you i won't be surprised when it happens ?

and thanks for the snippet too, cleaner and more pw like than my concatenation ? one more day i will go to bed a little less dumb ??

have a nice day

 

  • Like 2
Link to comment
Share on other sites

Hi @Robin S

apparently i'll need some more knowledge from you, running into a new little issue

i have a template to generate a block, let's call it a push
there is again an image depending of the type of push  and i call it this way (the way you teached me ? )
 

$image = $page->getFormatted('square_fr');


if i put an image in the field, everything goes fine
if ever i save the page forgetting to fill this field, impossible to add it afterwards and save again, the field stays desesparatly empty and doesn't save my image, no matter the type of condition i try before getting this image
if i remove the runtime field from the template, i can put an image and save it again it works; i'm sure i've missed something but honesty i can't find out what, i looks like the runtime field has also an impact on the whole admin page and prevents the image field from working once the page is saved with an empty field

any idea would be very welcome ?

have a nice day
 

Link to comment
Share on other sites

19 hours ago, virtualgadjo said:

if ever i save the page forgetting to fill this field, impossible to add it afterwards and save again, the field stays desesparatly empty and doesn't save my image, no matter the type of condition i try before getting this image

Hmm, I guess the field is getting output formatting turned on during the save process and the page editor doesn't explicitly turn it off.

I can think of a couple of ways around this. You could get the formatted value and output the markup only if the Page Edit form is not in the process of being submitted (as detected by "submit_save" button value not being present in $input->post):

if(!$input->post('submit_save')) {
	$image = $page->getFormatted('your_image_field');
	if($image) {
		// ...
	}
}

Or you could deliberately get the unformatted value which will be a Pageimages WireArray.

$pageimages = $page->getUnformatted('your_image_field');
$image = $pageimages->first();
if($image) {
	//...
}

 

Edited by Robin S
Made the check for Page Edit form submission more specific
  • Thanks 1
Link to comment
Share on other sites

Hi @Robin S

and again, thanks so much for your answer, it works!! and, not only does it work but it helps me understand even deeper how pw back office works
i went for the first solution

if(!$input->is('post')) { // works fine too :)

as it may help for other kinds of fields that need formatting to be used in the back office the same way as on the front end like, in my case, @kixe's FiedtypeColor to get the formatted output # included

again, thank you very much for your time and insight

have a nice day

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...