Jump to content
adrian

Tracy Debugger

Recommended Posts

Hi @adrian

today Tracy cost me 1 hour of work 😞 

$this->addHookAfter('Session::loginSuccess', function(HookEvent $event) {
  bd('Session::loginSuccess');
});

No matter what hook I tried (Session::login, ProcessLogin::loginSuccess etc) tracy did not dump anything. It seemed that the hook did never fire. I even placed a bd('Session.php') in Session.php... nothing! 😮

I tried different Session Handlers (DB, default), tried hooking ::logout (which worked) etc etc.

Then I found:

$this->addHookAfter('Session::loginSuccess', function(HookEvent $event) {
  bd('Session::loginSuccess');
  $this->message('Session::loginSuccess');
});

H6XN4mh.png

So the hook fires, but the BD() call get's lost somewhere! The dumps recorder is also empty (not shown in the screenshot)!

Any ideas what could be going on?

 

PS: My new balance

  • Tracy time costs: 1h
  • Tracy time savings: 500h+ (thx once more!! 🙂 )
  • Like 1

Share this post


Link to post
Share on other sites

Hey @bernhard - I just tested here with all combinations of the following on my local dev setup (MacOS)

1) SessionHandlerDB on and off
2) Your hook in init.php and ready.php and in the Console panel injected at init and ready

In all cases, the bd() shows up in one of the Tracy redirect bars.

Then I tried on one of my linux servers and in all tests, the bd() call was never activated. My thought is that it must be something to do with when Tracy is loaded. Because Tracy is loaded by PW's module system, it isn't loaded until site modules get loaded. Ryan made it so that it is the first of these site modules to be loaded which means we can always reliably use it to test development of other modules, but it doesn't load before the PW core which is why it's sometimes impossible to use it to debug the core. 

All that said, I don't know if load order is the problem in this case, or if it's something else. I'd actually love to know if you see a difference on different servers / PW installs. And anyone else who'd like to test also - it would be good to figure out if there is something consistent with when it does and doesn't work.

  • Like 1

Share this post


Link to post
Share on other sites

Thx @adrian

the strange thing is. If the load order of the modules was the problem, shouldn't the bd() throw an error that the function does not exist? The hook seems to be fired, because the $this->message() shows up. 🤔

  • Like 1

Share this post


Link to post
Share on other sites
57 minutes ago, bernhard said:

the strange thing is. If the load order of the modules was the problem, shouldn't the bd() throw an error that the function does not exist? The hook seems to be fired, because the $this->message() shows up. 🤔

Yeah, that makes sense 🙂

Ok, so after spending way too much time, it's not specifically a Tracy issue. If you do a Tracy log call, eg:

$this->addHookAfter('Session::loginSuccess', function(HookEvent $event) {
    l('Session::loginSuccess');
});

then it works fine. The issue is that dumps are stored in a variable and added to as needed during the current request. But it seems like PW hasn't actually started its session at Session::loginSuccess. If you try the same bd() call at Session::init then it works as expected.

$this->addHookAfter('Session::init', function(HookEvent $event) {
    bd('Session::init'); // works
});

So, I looked into the possibility of making it possible to do bd() calls and have them carry over to the next PW session (after the login has actually started the session) and there are possibilities, but I think they all come with downsides. I think it might help the Dumps Recorder panel though in that I'll be able to make it keep data over sessions, so I might consider that. I'll mull it over for a bit.

As a reminder (almost just for myself), Session::loginSuccess does work on some setups (eg my local dev environment), so there must be some differences in how sessions are handled that is impacting this.

  • Thanks 1

Share this post


Link to post
Share on other sites

Just a quick update to you all know that there is a new keyboard shortcut for reloading a snippet from disk, clearing previous output, and running the code which should be a nice time saver and also prevent you from accidentally running old code in the console that hasn't been updated from the disk version when you are using an external editor.

image.png.6d6d7b0e97ad966ef651f65f2d096ef9.png

I have also rejigged the execution of code when "Run" is called vs injecting. Hopefully the visual cues of the button changing from "Run" to "Inject" and the status in the header showing "Inject @ Ready" makes it more obvious what is going to happen when.

Another update is that the Dumps Recorder panel now stores its data in a file so that it will survive across sessions which may be useful if you are hooking certain session methods and other scenarios where the normal Dumps panel is not showing your bd() calls.

  • Like 5

Share this post


Link to post
Share on other sites

New toggle arrow to collapse / show the snippets side pane with the state remembered via cookie.

image.thumb.png.42b1fdba3b216cbca94919b935553c1c.png

VS

image.thumb.png.458796aa658f7f957069808dfc7cb72d.png

  • Like 2

Share this post


Link to post
Share on other sites

If you work with deeply nested / large JSON data and you use Adminer, the latest update will allow you to speed things up significantly with a few new config options. I've also included a PR to the JSON preview plugin which this functionality relies on - my changes ensure the max text length setting is applied to json that is kept as a string due to the max level setting. 

image.thumb.png.21dd7e8af779db08b729e882c6bb5f5e.png

  • Like 3

Share this post


Link to post
Share on other sites

Hey @adrian unfortunately I have some very strange issues with the dumps feature 😞 

This is the code I have (using Nette Forms):

[...]

    l('renderMail');
    bd('renderMail');

    // submit
    if($form->isSuccess()) {
      l('success!');
      bd('success!');
      $session->redirect('thank-you-page');

[...]

I have several problems:

1) The bd() calls do only show up in the dumps recorder, not in the regular AJAX bar dump.

2) The dumps recorder shows the entries twice whereas the tracy logs show them only once.

ZawHTd4.png

The tracy logs should be the correct results, because after the form success I do a session redirect to the thank you page. No idea why things show up twice in the dumps recorder. Of course I have cleared the dumps before submitting the form 😉 And it's the latest version of tracy from today (4.21.10)

Explanation of the dumps recorder:

1) renderMail is called on the initial page view (correct, logs at 18:10:12)

2) renderMail is called when the form was submitted (correct, logs at 18:10:21)

3) success is fired because the form was successfully submitted (correct)

4) send mail is fired correctly

5) 2, 3 and 4 are dumped again (not correct)

 

Here another dump showing timestamps:

CSaF8jm.png

 

Any ideas? 😞 

Edit:

I checked by sending an email additionally to the "send mail" dump:

  public function send($message, $contact) {
    bd("send $message to $contact");
    $mail = new WireMail();
    $mail->to('foo@bar.com');
    $mail->from('foo@bar.com');
    $mail->subject("Test @ ".date('d.m.Y H:i:s'));
    $mail->send();
  }

The mail was actually sent twice, so it seems that the tracy dump is correct. So what about the tracy log? Shouldn't that also be listed twice then? No idea why that send() call fires twice at all... there is a session redirect that should prevent this 😞 

Share this post


Link to post
Share on other sites
3 minutes ago, bernhard said:

1) The bd() calls do only show up in the dumps recorder, not in the regular AJAX bar dump.

Is a new AJAX bar showing at all (even without a Dumps panel entry). If it's not, then it's probably an issue with Nette forms not sending the 'X-Requested-With': 'XMLHttpRequest'

8 minutes ago, bernhard said:

after the form success I do a session redirect to the thank you page

Or maybe it's related to that - if it's an AJAX form submission and then you do a redirect afterwards, that a) seems to defeat the reason for an ajax submission, and b) is probably why the AJAX bar is lost. Does it show in the ajax bar if you don't do the redirect?

11 minutes ago, bernhard said:

2) The dumps recorder shows the entries twice whereas the tracy logs show them only once.

Not sure about that - I'll look a little later and after I hear back about those possible reasons for #1

Share this post


Link to post
Share on other sites
2 hours ago, adrian said:

Is a new AJAX bar showing at all (even without a Dumps panel entry). If it's not, then it's probably an issue with Nette forms not sending the 'X-Requested-With': 'XMLHttpRequest'

There's only one single bar. But it's not an AJAX request. I'm submitting the form as regular POST and then doing a session->redirect to a new page. But usually tracy also log's redirected requests (like after page save).

Sorry about the ajax confusion! I meant those redirect bars:

bIxCZSn.png

Share this post


Link to post
Share on other sites
On 5/4/2020 at 6:24 PM, bernhard said:

The mail was actually sent twice, so it seems that the tracy dump is correct. So what about the tracy log? Shouldn't that also be listed twice then? No idea why that send() call fires twice at all... there is a session redirect that should prevent this 😞 

I found the reason for this: I'm rendering a repeater with several blocks. There are two subscription blocks with nette forms. A form submit triggers the redirect but the redirect does not happen immediately because it does finish() the active process, hence renders the other blocks as well. That's why I got 2 dumps (one for each block). I added a custom instandRedirect method to my repeater blocks:

public function instantRedirect($url) {
  header("Location: $url");
  exit(0);
}

 

Share this post


Link to post
Share on other sites

Hi @adrian, I'm getting the following error in the RequestInfo panel with  many of my custom modules, do you know what's causing this?

ProcessWire\WireException: Method TrelloWire::getArray does not exist or is not callable in this context in /var/www/vhosts/klforexpats.preview-server.dev/httpdocs/public/wire/core/Wire.php:529
Stack trace:
#0 /var/www/vhosts/klforexpats.preview-server.dev/httpdocs/public/wire/core/Wire.php(386): ProcessWire\Wire->___callUnknown()
#1 /var/www/vhosts/klforexpats.preview-server.dev/httpdocs/public/wire/core/WireHooks.php(823): ProcessWire\Wire->_callMethod()
#2 /var/www/vhosts/klforexpats.preview-server.dev/httpdocs/public/wire/core/Wire.php(450): ProcessWire\WireHooks->runHooks()
#3 /var/www/vhosts/klforexpats.preview-server.dev/httpdocs/public/wire/core/Wire.php(453): ProcessWire\Wire->__call()
#4 /var/www/vhosts/klforexpats.preview-server.dev/httpdocs/public/site/assets/cache/FileCompiler/site/modules/TracyDebugger/panels/RequestInfoPanel.php(295): ProcessWire\Wire->__call()
#5 /var/www/vhosts/klforexpats.preview-server.dev/httpdocs/public/site/assets/cache/FileCompiler/site/modules/TracyDebugger/tracy-2.7.x/src/Tracy/Bar/Bar.php(150): RequestInfoPanel->getPanel()
#6 /var/www/vhosts/klforexpats.preview-server.dev/httpdocs/public/site/assets/cache/FileCompiler/site/modules/TracyDebugger/tracy-2.7.x/src/Tracy/Bar/Bar.php(122): Tracy\Bar->renderPanels()
#7 /var/www/vhosts/klforexpats.preview-server.dev/httpdocs/public/site/assets/cache/FileCompiler/site/modules/TracyDebugger/tracy-2.7.x/src/Tracy/Bar/Bar.php(98): Tracy\Bar->renderHtml()
#8 /var/www/vhosts/klforexpats.preview-server.dev/httpdocs/public/site/assets/cache/FileCompiler/site/modules/TracyDebugger/tracy-2.7.x/src/Tracy/Debugger/Debugger.php(293): Tracy\Bar->render()
#9 [internal function]: Tracy\Debugger::shutdownHandler()
#10 {main}

This happens in the module configuration (in this case the module is TrelloWire, but I get this with most custom modules). Is this indicative of some problem with my module? Or just some strange interaction between the module config and Tracy?

Share this post


Link to post
Share on other sites

@MoritzLost - from my initial investigation, it looks like a PW core bug. You are using this (https://processwire.com/blog/posts/new-module-configuration-options/#enter-the-new-moduleconfig-class) approach to defining module settings which I have never used, but it appears that when that approach is used, the getArray() method doesn't exist on the module, hence the error.

Do you know of another module that uses that approach that I could test to confirm?

 

  • Like 1

Share this post


Link to post
Share on other sites

@adrian I have tested my other modules; I think the error only occurs when the module does NOT extend WireData, since the getArray method comes from there.

  • TextformatterPageTitleLinks extends Textformatter which extends WireData -> RequestInfoPanel is working.
  • ProcessCacheControl extends Process which extends WireData -> RequestInfoPanel is working.
  • TrelloWire extends Wire (instead of WireData) -> RequestInfoPanel displays the error.
    • When I change the class definition to extend WireData instead of Wire, the error disappears.

I have tested & confirmed this behaviour with another module I'm working on (currently not publicly available, will probably publish this next week or so). So I think it comes down to modules that don't extend WireData at all, which isn't required (at least according to the docs). I guess it's mostly a cosmetic choice, but for the modules that don't really keep track of data I didn't want to extend WireData. Maybe the RequestInfoPage could check for that case and use getModuleConfig instead?

  • Like 1

Share this post


Link to post
Share on other sites

Hi @adrian,

I've been cleanin' up my latest project and noticed this warning:

Cookie “tracyClearDumpsRecorderItems” will be soon rejected because it has the “sameSite” attribute set to “none” or an invalid value, without the “secure” attribute. To know more about the “sameSite“ attribute, read https://developer.mozilla.org/docs/Web/HTTP/Cookies

I don't know if it means anything. If so, great. If not, please ignore this post. 🙂

  • Like 1

Share this post


Link to post
Share on other sites

Thanks @MoritzLost for figuring that out. I have added a check to prevent that error when a module doesn't extend WireData. Honestly, I think the getting of module settings in PW is a bit of a mess which is why I use 3 different approaches in Tracy because they all return different things for some modules. Let me know if you have any problems with the new version.

Thanks @rick for the heads up on that. I took a quick look, but I don't have time to fix things at the moment - I set a lot of cookies in various places in Tracy and I am not using a standard method so it's not easy to change them all and I sometimes set in JS and sometimes in PHP. Obviously I don't want to make them "secure" because I am sure many of us are running local dev setups without https, so I probably need to just set the sameSite rule to Lax, but maybe Strict is better? Not sure yet, but it's on my list to take care of soon.

  • Like 1

Share this post


Link to post
Share on other sites
32 minutes ago, adrian said:

Thanks @MoritzLost for figuring that out. I have added a check to prevent that error when a module doesn't extend WireData. Honestly, I think the getting of module settings in PW is a bit of a mess which is why I use 3 different approaches in Tracy because they all return different things for some modules. Let me know if you have any problems with the new version.

Thanks for the fix @adrian, I just tested it and it seems to be working! I'm not getting errors any more with both modules I tested before 🙂 

34 minutes ago, adrian said:

Thanks @rick for the heads up on that. I took a quick look, but I don't have time to fix things at the moment - I set a lot of cookies in various places in Tracy and I am not using a standard method so it's not easy to change them all and I sometimes set in JS and sometimes in PHP. Obviously I don't want to make them "secure" because I am sure many of us are running local dev setups without https, so I probably need to just set the sameSite rule to Lax, but maybe Strict is better? Not sure yet, but it's on my list to take care of soon.

Just butting in here: I don't believe you want to use Strict, this may break the debugger for if you visit the site by clicking on a link from somewhere else. Since you can't really use Secure cookies because of the local dev environments like you said, you'll probably be best of with SameSite=Lax to most cookies. This article on web.dev is a good resource for the SameSite changes.

  • Like 1

Share this post


Link to post
Share on other sites
1 minute ago, MoritzLost said:

Just butting in here: I don't believe you want to use Strict, this may break the debugger for if you visit the site by clicking on a link from somewhere else. Since you can't really use Secure cookies because of the local dev environments like you said, you'll probably be best of with SameSite=Lax to most cookies. This article on web.dev is a good resource for the SameSite changes.

Much appreciated - I'll admit to not knowing too much about these options yet, so great to get some more knowledgeable input. Thanks!

  • Like 1

Share this post


Link to post
Share on other sites

Hey @adrian,

would it somehow be possible to get the tracy console in a separate process module? I'm working on my RockFinder and there I have built a "RockFinderTester" process module that does basically the same thing like the tracy console, only a lot worse 😄 I have many modules where a console feature would be great for testing. At the moment I'm using the console for lots of things, but I wonder how complicated it would be to move the console to a separate page that we can modify to our needs.

So for example for testing a RockFinder it might be great to have the code input on the top and below that it would be great to have an area where I can not only dump variables but also show the result as paginated table (using tabulator.js). The tabulator part could totally be done by me - I'd only need to have the proper JS events I can listen for.

I know we have the console snippets at the moment, but I think the console is such a powerful tool, that it would be great if it could be used by other modules as well.

Do you understand my idea? Would that be very complicated to achieve? Thanks in advance for thinking about it 🙂 

Share this post


Link to post
Share on other sites
16 minutes ago, bernhard said:

I wonder how complicated it would be to move the console to a separate page that we can modify to our needs

I have thought about making it a separate Process module so it can be opened on it's own page in the PW admin, but I am not sure about making it modifiable - what would you need to modify for you needs? Based on your tabulator example, it sounds like you are talking about extending the output options? But how best to do that? Is it just a matter of being able to inject (in the background) some additional JS to process the code and format as a table?

I am happy to talk about this more, but I haven't enough time at the moment to do anything substantial on this unfortunately. If you could think through how it should work in some more detail, that might make make it easier for me to implement. Of course PRs are also welcome, but I am happy to help implement if you figure out a plan for how it should work.

 

Share this post


Link to post
Share on other sites

Thx adrian,

this is what I have currently in my RockFinder2 module:

lTFDooA.png

This is basically a sandbox where one can test finders, sees a dump and also sees the data listed as tabulator. When looking at the code of RockFinder2 today I was quite surprised that it has +1200 lines of code. I had in my mind that it is quite lightweight compared to RockFinder1 because it builds upon the pw core query classes. Then I realized that I actually have lots of stuff packed into RockFinder2 that imho does not belong there. The finder tester is one of those things! I want to remove that part from the module so that RockFinder3 will just do one thing: Finding PW data and returning it as array of objects.

Nevertheless the finder tester is useful! So I don't really want to drop it as a whole. I can use the tracy console and do this:

kuqEJZp.png

This is already great, but it would be even greater if I could see the data in a tabulator. That's what I have in my process module, BUT: What I do not have there is the dumping features of the tracy console. Look at the first screenshot: There is a dump, but I always dump the returned finder object. I cant to any other dumps, because it's a custom implementation of the console. I also don't have the same settings and shortcuts as in the console.

Vision: Ideally I'd like to build RockFinder3 with only the features that it needs and pack the tester in a separate module. This module would require tracy (but only the process module, not the finder module) and could use the tracy console process. This process would show an InputfieldForm that everybody could modify easily via hooks. So I could just add a new InputfieldMarkup to that form below the tracy console, add some lines of javascript that intercept the AJAX events sent by the console and then show the result as tabulator grid.

Hm. I see that the ajax response at the moment does only send the html of the dumps. Maybe it could instead send the response as JSON? One property being the dump: "<foo>bar</foo>" and the other property being the returned value:

3Uob1Z6.png

In this case the code would return a RockFinder2 instance, so we would need something on the backend that transforms the returned data (here the rockfinder) in something readable by the client. Maybe something like this:

// pseudo code
$wire->addHookAfter("Console::getPayload", function($event) {
  $rockfinder = $event->arguments(0);
  $array = $rockfinder->toPlainArrayReadyForJavaScript(); // ['foo', 'bar']
  $event->return = $array;
});

This would result in this ajax response:

{
	dump: "<foo>bar</foo>",
	return: ['foo', 'bar']
}

So the console could just dump the markup and I could intercept that response with JS:

$(document).on('tracyConsoleResponse', function() {
  // get the return value of the xhr
  // render tabulator
});

Maybe that kind of refactoring could also make sense for the console? Maybe this approach could also make sense in an even bigger context: What if all panels where process modules? I for example have no idea how to build a panel for tracy (I'd have to study my hello world module again 😉 ), but it would be piece of cake to build a process module. Maybe I'm requesting too much here. But again: Maybe refactoring could make sense - I leave that assessment to you 🙂 

---

Side note: Also I have this bug when I open the console on my process module: The code of my ACE field gets quirky.

6S0Xr7M.png

That's not a request how to fix it - just to let you know why it would be great to have one central solution that can be modified instead of building our own solution and fix bugs 🙂 

 

  • Like 1

Share this post


Link to post
Share on other sites

Hey @bernhard - thanks for all the details. I'll have to get back to you on most of them, but I can explain the reason for the quirky stuff in your module. It is due to the really old version of ACE included with the InputfieldAceExtended module that you are making use of. The same thing happens with Ryan's HannaCode module - there is an issue posted about that here: https://github.com/ryancramerdesign/ProcessHannaCode/issues/21

  • Like 1

Share this post


Link to post
Share on other sites

Just had another idea that might be even more powerful and simpler to implement: What if we could define custom dumping functions? For example:

$rf = new RockFinder2();
[...]
tabulator($rf);

// modify tabulator and dump another one
tabulator($rf);

instead of a regular dump() this would render the markup of a tabulator, eg:

<div id="1905terf8dvuid"></div>
<script>
var table = new Tabulator("#1905terf8dvuid", {
 	height:205,
 	data:[
 	{id:1, name:"Oli Bob", age:"12", col:"red", dob:""},
 	{id:2, name:"Mary May", age:"1", col:"blue", dob:"14/05/1982"},
 	{id:3, name:"Christine Lobowski", age:"42", col:"green", dob:"22/05/1982"},
 	{id:4, name:"Brendon Philips", age:"125", col:"orange", dob:"01/08/1980"},
 	{id:5, name:"Margret Marmajuke", age:"16", col:"yellow", dob:"31/01/1999"},
 	],
 	layout:"fitColumns", //fit columns to width of table (optional)
 	columns:[ //Define Table Columns
	 	{title:"Name", field:"name", width:150},
	 	{title:"Age", field:"age", hozAlign:"left", formatter:"progress"},
	 	{title:"Favourite Color", field:"col"},
	 	{title:"Date Of Birth", field:"dob", sorter:"date", hozAlign:"center"},
 	],
 	rowClick:function(e, row){ //trigger an alert message when the row is clicked
 		alert("Row " + row.getData().id + " Clicked!!!!");
 	},
});
</script>

So basically we'd only need a way to define custom functions like "tabulator()" that define the returned markup and that's it 🙂 

  • Like 1

Share this post


Link to post
Share on other sites

@bernhard

Just a little rough experimentation - I've added a new echo() method to the TD class which outputs exactly what is sent to it.

With this addition, I managed to do this:

image.png.43a3b4c134549a7238c5c1c0e19b12b4.png

Obviously in this case I am not passing any data to the tabulator() method, but you can make this happen easily by modifying your new tabulator() function.

In a process module I have a couple of things to make this all work:

1) Load the tabulator js and css files in the init() method:

        $this->wire('config')->scripts->add("https://unpkg.com/tabulator-tables@4.6.3/dist/js/tabulator.min.js");
        $this->wire('config')->styles->add("https://unpkg.com/tabulator-tables@4.6.3/dist/css/tabulator.min.css");

2) Define a new tabulator function - note that in this case this is a global function outside the process module class, but you could also make it a class function and call $rf->tabulator()

function tabulator($str, $title = NULL) {
    \TD::echo('<div id="tabletest"></div>
    <script>
    var table = new Tabulator("#tabletest", {
         height:205,
         data:[
         {id:1, name:"Oli Bob", age:"12", col:"red", dob:""},
         {id:2, name:"Mary May", age:"1", col:"blue", dob:"14/05/1982"},
         {id:3, name:"Christine Lobowski", age:"42", col:"green", dob:"22/05/1982"},
         {id:4, name:"Brendon Philips", age:"125", col:"orange", dob:"01/08/1980"},
         {id:5, name:"Margret Marmajuke", age:"16", col:"yellow", dob:"31/01/1999"},
         ],
         layout:"fitColumns", //fit columns to width of table (optional)
         columns:[ //Define Table Columns
             {title:"Name", field:"name", width:150},
             {title:"Age", field:"age", hozAlign:"left", formatter:"progress"},
             {title:"Favourite Color", field:"col"},
             {title:"Date Of Birth", field:"dob", sorter:"date", hozAlign:"center"},
         ],
         rowClick:function(e, row){ //trigger an alert message when the row is clicked
             alert("Row " + row.getData().id + " Clicked!!!!");
         },
    });
    </script>', $title);
}


You can try it out by replacing the attached TD.php for your Tracy install (in the includes subfolder).

Note that you can supply two arguments to the \TD::echo method: $str and $title, just like with d() and bd()

Does that work for you ok?

TD.php

  • Like 1
  • Thanks 1

Share this post


Link to post
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

  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By d'Hinnisdaël
      Format Datetime fields as Carbon instances.
      You can find the latest release and the complete readme on Github.
      Installation
      composer require daun/datetime-carbon-format Usage
      All Datetime fields will now be formatted as Carbon instances instead of strings. Some examples:
      // $page->date is a Datetime field // Output format: j/n/Y echo $page->date; // 20/10/2020 echo $page->date->add('7 days'); // 27/10/2020 echo $page->date->format('l, F j'); // Monday, October 20 echo $page->date->year; // 2020 echo $page->date->diffForHumans(); // 28 minutes ago Frontend only
      The ProcessWire admin seems to expect datetime fields to be strings. This module will only return Carbon instances on frontend page views.
      Date output format
      When casting a Carbon instance to a string (usually when outputting the field in a template), the field's date output format will be respected.
      Links
      GitHub • Readme • Carbon docs
       
       
      PS. I remember reading about a Carbon module in a recent newsletter, but couldn't find it anywhere. Was that you, @bernhard?
    • By MoritzLost
      TrelloWire
      This is a module that allows you to automatically create Trello cards for ProcessWire pages and update them when the pages are updated. This allows you to setup connected workflows. Card properties and change handling behaviour can be customized through the extensive module configuration. Every action the module performs is hookable, so you can modify when and how cards are created as much as you need to. The module also contains an API-component that makes it easy to make requests to the Trello API and build your own connected ProcessWire-Trello workflows.
      Warning: This module requires ProcessWire 3.0.167 which is above the current stable master release at the moment.
      Features
      All the things the module can do for you without any custom code: Create a new card on Trello whenever a page is added or published (you can select applicable templates). Configure the target board, target list, name and description for new cards. Add default labels and checklists to the card. Update the card whenever the page is updated (optional). When the status of the card changes (published / unpublished, hidden / unhidden, trashed / restored or deleted), move the card to a different list or archive or delete it (configurable). You can extend this through hooks in many ways: Modifiy when and how cards are created. Modify the card properties (Target board & list, title, description, et c.) before they are sent to Trello. Create your own workflows by utilizing an API helper class with many convenient utility methods to access the Trello API directly. Feedback & Future Plans
      Let me know what you think! In particular:
      If you find any bugs report them here or on Github, I'll try to fix them. This module was born out of a use-case for a client project where we manage new form submissions through Trello. I'm not sure how many use-cases there are for this module. If you do use it, tell me about it! The Trello API is pretty extensive, I'll try to add some more helper methods to the TrelloWireApi class (let me know if you need anything in particular). I'll think about how the module can support different workflows that include Twig – talk to me if you have a use-case! Next steps could be a dashboard to manage pages that are connected to a Trello card, or a new section in the settings tab to manage the Trello connection. But it depends on whether there is any interest in this 🙂 Links
      Repository on Github Complete module documentation (getting started, configuration & API documentation) TrelloWire in the modules directory Module configuration

    • By David Karich
      ProcessWire InputfieldRepeaterMatrixDuplicate
      Thanks to the great ProModule "RepeaterMatrix" I have the possibility to create complex repeater items. With it I have created a quite powerful page builder. Many different content modules, with many more possible design options. The RepeaterMatrix module supports the cloning of items, but only within the same page. Now I often have the case that very design-intensive pages and items are created. If you want to use a content module on a different page (e.g. in the same design), you have to rebuild each item manually every time.
      This module extends the commercial ProModule "RepeaterMatrix" by the function to duplicate repeater items from one page to another page. The condition is that the target field is the same matrix field from which the item is duplicated. This module is currently understood as proof of concept. There are a few limitations that need to be considered. The intention of the module is that this functionality is integrated into the core of RepeaterMatrix and does not require an extra module.
      Check out the screencast
      What the module can do
      Duplicate multible repeater items from one page to another No matter how complex the item is Full support for file and image fields Multilingual support Support of Min and Max settings Live synchronization of clipboard between multiple browser tabs. Copy an item and simply switch the browser tab to the target page and you will immediately see the past button Support of multiple RepeaterMatrix fields on one page Configurable which roles and fields are excluded Configurable dialogs for copy and paste Duplicated items are automatically pasted to the end of the target field and set to hidden status so that changes are not directly published Automatic clipboard update when other items are picked Automatically removes old clipboard data if it is not pasted within 6 hours Delete clipboard itself by clicking the selected item again Benefit: unbelievably fast workflow and content replication What the module can't do
      Before an item can be duplicated in its current version, the source page must be saved. This means that if you make changes to an item and copy this, the old saved state will be duplicated Dynamic loading is currently not possible. Means no AJAX. When pasting, the target page is saved completely No support for nested repeater items. Currently only first level items can be duplicated. Means a repeater field in a repeater field cannot be duplicated. Workaround: simply duplicate the parent item Dynamic reloading and adding of repeater items cannot be registered. Several interfaces and events from the core are missing. The initialization occurs only once after the page load event Attention, please note!
      Nested repeaters cannot be supported technically. Therefore a check is made to prevent this. However, a nested repeater can only be detected if the field name ends for example with "_repeater1234". For example, if your MatrixRepeater field is named like this: "content_repeater" or "content_repeater123", this field is identified as nested and the module does not load. In version 2.0.1 the identification has been changed so that a field ending with the name repeater is only detected as nested if at least a two-digit number sequence follows. But to avoid this problem completely, make sure that your repeater matrix field does NOT end with the name "repeater".
      Changelog
       
      2.0.1
      Bug fix: Thanks to @ngrmm I could discover a bug which causes that the module cannot be loaded if the MatrixRepeater field ends with the name "repeater". The code was adjusted and information about the problem was provided 2.0.0
      Feature: Copy multiple items at once! The fundament for copying multiple items was created by @Autofahrn - THX! Feature: Optionally you can disable the copy and/or paste dialog Bug fix: A fix suggestion when additional and normal repeater fields are present was contributed by @joshua - THX! 1.0.4
      Bug fix: Various bug fixes and improvements in live synchronization Bug fix: Items are no longer inserted when the normal save button is clicked. Only when the past button is explicitly clicked Feature: Support of multiple repeater fields in one page Feature: Support of repeater Min/Max settings Feature: Configurable roles and fields Enhancement: Improved clipboard management Enhancement: Documentation improvement Enhancement: Corrected few typos #1 1.0.3
      Feature: Live synchronization Enhancement: Load the module only in the backend Enhancement: Documentation improvement 1.0.2
      Bug fix: Various bug fixes and improvements in JS functions Enhancement: Documentation improvement Enhancement: Corrected few typos 1.0.1
      Bug fix: Various bug fixes and improvements in the duplication process 1.0.0
      Initial release Support this module
      If this module is useful for you, I am very thankful for your small donation: Donate 5,- Euro (via PayPal – or an amount of your choice. Thank you!)
      Download this module (Version 2.0.1)
      > Github: https://github.com/FlipZoomMedia/InputfieldRepeaterMatrixDuplicate
      > PW module directory: https://modules.processwire.com/modules/inputfield-repeater-matrix-duplicate/
      > Old stable version (1.0.4): https://github.com/FlipZoomMedia/InputfieldRepeaterMatrixDuplicate/releases/tag/1.0.4
    • By picarica
      so i am trying to put CustomHooksForVariations.module, a custom module, i am placing it into site/modules direcotry yet my modules page in admin panel gives me errors
      so this is the screen show when i refresh modules, i dont know why the shole hook is written on top of the page :||

      and this next image is when i try to install it, i saw that it is not defiuned modules.php but it shouldnt need to be ?, any ways i dont want to edit site's core just to make one moulde work there has to be a way

    • By Robin S
      A new module that hasn't had a lot of testing yet. Please do your own testing before deploying on any production website.
      Custom Paths
      Allows any page to have a custom path/URL.
      Note: Custom Paths is incompatible with the core LanguageSupportPageNames module. I have no experience working with LanguageSupportPageNames or multi-language sites in general so I'm not in a position to work out if a fix is possible. If anyone with multi-language experience can contribute a fix it would be much appreciated!
      Screenshot

      Usage
      The module creates a field named custom_path on install. Add the custom_path field to the template of any page you want to set a custom path for. Whatever path is entered into this field determines the path and URL of the page ($page->path and $page->url). Page numbers and URL segments are supported if these are enabled for the template, and previous custom paths are managed by PagePathHistory if that module is installed.
      The custom_path field appears on the Settings tab in Page Edit by default but there is an option in the module configuration to disable this if you want to position the field among the other template fields.
      If the custom_path field is populated for a page it should be a path that is relative to the site root and that starts with a forward slash. The module prevents the same custom path being set for more than one page.
      The custom_path value takes precedence over any ProcessWire path. You can even override the Home page by setting a custom path of "/" for a page.
      It is highly recommended to set access controls on the custom_path field so that only privileged roles can edit it: superuser-only is recommended.
      It is up to the user to set and maintain suitable custom paths for any pages where the module is in use. Make sure your custom paths are compatible with ProcessWire's $config and .htaccess settings, and if you are basing the custom path on the names of parent pages you will probably want to have a strategy for updating custom paths if parent pages are renamed or moved.
      Example hooks to Pages::saveReady
      You might want to use a Pages::saveReady hook to automatically set the custom path for some pages. Below are a couple of examples.
      1. In this example the start of the custom path is fixed but the end of the path will update dynamically according to the name of the page:
      $pages->addHookAfter('saveReady', function(HookEvent $event) { $page = $event->arguments(0); if($page->template == 'my_template') { $page->custom_path = "/some-custom/path-segments/$page->name/"; } }); 2. The Custom Paths module adds a new Page::realPath method/property that can be used to get the "real" ProcessWire path to a page that might have a custom path set. In this example the custom path for news items is derived from the real ProcessWire path but a parent named "news-items" is removed:
      $pages->addHookAfter('saveReady', function(HookEvent $event) { $page = $event->arguments(0); if($page->template == 'news_item') { $page->custom_path = str_replace('/news-items/', '/', $page->realPath); } }); Caveats
      The custom paths will be used automatically for links created in CKEditor fields, but if you have the "link abstraction" option enabled for CKEditor fields (Details > Markup/HTML (Content Type) > HTML Options) then you will see notices from MarkupQA warning you that it is unable to resolve the links.
      Installation
      Install the Custom Paths module.
      Uninstallation
      The custom_path field is not automatically deleted when the module is uninstalled. You can delete it manually if the field is no longer needed.
       
      https://github.com/Toutouwai/CustomPaths
      https://modules.processwire.com/modules/custom-paths/
×
×
  • Create New...