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 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 Changelog
      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.0)
      > 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 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/
    • By teppo
      Hey folks!
      I'm happy to finally introduce a project I've been working on for quite a while now: it's called Wireframe, and it is an output framework for ProcessWire.
      Note that I'm posting this in the module development area, maily because this project is still in rather early stage. I've built a couple of sites with it myself, and parts of the codebase have been powering some pretty big and complex sites for many years now, but this should still be considered a soft launch 🙂
      --
      Long story short, Wireframe is a module that provides the "backbone" for building sites (and apps) with ProcessWire using an MVC (or perhaps MVVM... one of those three or four letter acronyms anyway) inspired methodology. You could say that it's an output strategy, but I prefer the term "output framework", since in my mind the word "strategy" means something less tangible. A way of doing things, rather than a tool that actually does things.
      Wireframe (the module) provides a basic implementation for some familiar MVC concepts, such as Controllers and a View layer – the latter of which consists of layouts, partials, and template-specific views. There's no "model" layer, since in this context ProcessWire is the model. As a module Wireframe is actually quite simple – not even nearly the biggest one I've built – but there's still quite a bit of stuff to "get", so I've put together a demo & documentation site for it at https://wireframe-framework.com/.
      In addition to the core module, I'm also working on a couple of site profiles based on it. My current idea is actually to keep the module very light-weight, and implement most of the "opinionated" stuff in site profiles and/or companion modules. For an example MarkupMenu (which I released a while ago) was developed as one of those "companion modules" when I needed a menu module to use on the site profiles.
      Currently there are two public site profiles based on Wireframe:
      site-wireframe-docs is the demo&docs site mentioned above, just with placeholder content replaced with placeholder content. It's not a particularly complex site, but I believe it's still a pretty nice way to dig into the Wireframe module. site-wireframe-boilerplate is a boilerplate (or starter) site profile based on the docs site. This is still very much a work in progress, but essentially I'm trying to build a flexible yet full-featured starter profile you can just grab and start building upon. There will be a proper build process for resources, it will include most of the basic features one tends to need from site to site, etc. --
      Requirements and getting started:
      Wireframe can be installed just like any ProcessWire module. Just clone or download it to your site/modules/ directory and install. It doesn't, though, do a whole lot of stuff on itself – please check out the documentation site for a step-by-step guide on setting up the directory structure, adding the "bootstrap file", etc. You may find it easier to install one of the site profiles mentioned above, but note that this process involves the use of Composer. In the case of the site profiles you can install ProcessWire as usual and download or clone the site profile directory into your setup, but after that you should run "composer install" to get all the dependencies – including the Wireframe module – in place. Hard requirements for Wireframe are ProcessWire 3.0.112 and PHP 7.1+. The codebase is authored with current PHP versions in mind, and while running it on 7.0 may be possible, anything below that definitely won't work. A feature I added just today to the Wireframe module is that in case ProcessWire has write access to your site/templates/ directory, you can use the module settings screen to create the expected directories automatically. Currently that's all, and the module won't – for an example – create Controllers or layouts for you, so you should check out the site profiles for examples on these. (I'm probably going to include some additional helper features in the near future.)
      --
      This project is loosely based on an earlier project called pw-mvc, i.e. the main concepts (such as Controllers and the View layer) are very similar. That being said, Wireframe is a major upgrade in terms of both functionality and architecture: namespaces and autoloader support are now baked in, the codebase requires PHP 7, Controllers are classes extending \Wireframe\Controller (instead of regular "flat" PHP files), implementation based on a module instead of a collection of drop-in files, etc.
      While Wireframe is indeed still in a relatively early stage (0.3.0 was launched today, in case version numbers matter) for the most part I'm happy with the way it works, and likely won't change it too drastically anytime soon – so feel free to give it a try, and if you do, please let me know how it went. I will continue building upon this project, and I am also constantly working on various side projects, such as the site profiles and a few unannounced helper modules.
      I should probably add that while Wireframe is not hard to use, it is more geared towards those interested in "software development" type methodology. With future updates to the module, the site profiles, and the docs I hope to lower the learning curve, but certain level of "developer focus" will remain. Although of course the optimal outcome would be if I could use this project to lure more folks towards that end of the spectrum... 🙂
      --
      Please let me know what you think – and thanks in advance!
    • By tcnet
      PageViewStatistic for ProcessWire is a module to log page visits of the CMS. The records including some basic information like IP-address, browser, operating system, requested page and originate page. Please note that this module doesn't claim to be the best or most accurate.
      Advantages
      One of the biggest advantage is that this module doesn't require any external service like Google Analytics or similar. You don't have to modify your templates either. There is also no JavaScript or image required.
      Disadvantages
      There is only one disadvantage. This module doesn't record visits if the browser loads the page from its browser cache. To prevent the browser from loading the page from its cache, add the following meta tags to the header of your page:
      <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" /> <meta http-equiv="Pragma" content="no-cache" /> <meta http-equiv="Expires" content="0" /> How to use
      The records can be accessed via the Setup-menu of the CMS backend. The first dropdown control changes the view mode. There are 4 different view modes.
      View mode "Day" shows all visits of the selected day individually with IP-address, browser, operating system, requested page and originate page. Click the update button to see new added records. View mode "Month" shows the total of all visitors per day from the first to the last day of the selected month. View mode "Year" shows the total of all visitors per month from the first to the last month of the selected year. View mode "Total" shows the total of all visitors per year for all recorded years. Please note that multiple visits from the same IP address within the selected period are counted as a single visitor.
      Settings
      You can access the module settings by clicking the Configuration button at the bottom of the records page. The settings page is also available in the menu: Modules->Configure->ProcessPageViewStat.
      IP2Location
      This module uses the IP2Location database from: http://www.ip2location.com. This database is required to obtain the country from the IP address. IP2Location updates this database at the begin of every month. The settings of ProcessPageViewStat offers the ability to automatically download the database monthly. Please note, that automatically download will not work if your webspace doesn't allow allow_url_fopen.
      Dragscroll
      This module uses DragScroll. A JavaScript available from: http://github.com/asvd/dragscroll. Dragscroll adds the ability in view mode "Day" to drag the records horizontally with the mouse pointer.
      parseUserAgentStringClass
      This module uses the PHP class parseUserAgentStringClass available from: http://www.toms-world.org/blog/parseuseragentstring/. This class is required to filter out the browser type and operating system from the server request.
      Special Feature
      PageViewStatistic for ProcessWire can record the time a visitor viewed the page. This feature is deactivated by default. To activate open the module configuration page and activate "Record view time". If activated you will find a new column "S." in the records which means the time of view in seconds. With every page request, a Javascript code is inserted directly after the <body> tag. Every time the visitor switches to another tab or closes the tab, this script reports the number of seconds the tab was visible. The initial page request is recorded only as a hyphen (-).
       
    • By MoritzLost
      This module allows you to integrate hCaptcha bot / spam protection into ProcessWire forms. hCaptcha is a great alternative to Google ReCaptcha, especially if you are in the EU and need to comply with privacy regulations.

      The development of this module is sponsored by schwarzdesign.
      The module is built as an Inputfield, allowing you to integrate it into any ProcessWire form you want. It's primarily intended for frontend forms and can be added to Form Builder forms for automatic spam protection. There's a step-by-step guide for adding the hCaptcha widget to Form Builder forms in the README, as well as instructions for API usage.
      Features
      Inputfield that displays an hCaptcha widget in ProcessWire forms. The inputfield verifies the hCaptcha response upon submission, and adds a field error if it is invalid. All hCaptcha configuration options for the widget (theme, display size etc) can be changed through the inputfield configuration, as well as programmatically. hCaptcha script options can be changed through a hook. Error messages can be translated through ProcessWire's site translations. hCaptcha secret keys and site-keys can be set for each individual inputfield or globally in your config.php. Error codes and failures are logged to help you find configuration errors. Please check the README for setup instructions.
      Links
      Github Repository and documentation InputfieldHCaptcha in the module directory Screenshots (configuration)

      Screenshots (hCaptcha widget)

       
       

       
×
×
  • Create New...