adrian

Tracy Debugger

Recommended Posts

For some reason, no. But clicking the "clear compiled files" did the trick (at the very bottom - I often overlook it).

  • Like 1

Share this post


Link to post
Share on other sites
2 minutes ago, dragan said:

For some reason, no. But clicking the "clear compiled files" did the trick (at the very bottom - I often overlook it).

Glad you got it sorted - I guess this is a side effect of adding .php to the end of the module filename. I guess this will be a bit of a pain for some users upgrading, but I think the php extension does make more sense so probably worth it in the long term.

  • Like 1

Share this post


Link to post
Share on other sites

Minor, but useful update just committed. I noticed that the Console panel didn't have access to custom properties/methods added via hooks in other modules if they were added in ready() vs init().  

For example, in the MarkupSEO module when trying to do this, I got null returned.

d($page->seo);

Anyway, this now works as expected and returns the "seo" property object. 

Hopefully you guys will find it useful also.

If you grab the latest fork of the MarkupSEO module (https://github.com/adrianbj/MarkupSEO/tree/various-fixes-enhancements) you'll also be able to make that call in the Console panel when editing a page in the backend as well as the frontend page view.

  • Like 4

Share this post


Link to post
Share on other sites

Finally 🙂😉 

ymnU75r.png

 

Thank you adrian for this awesome tool and your great support in the forum!

  • Like 5

Share this post


Link to post
Share on other sites

Thanks @bernhard for pointing out the Donate button and a big thanks to everyone who has donated already 🙂

I have just committed a new panel that hopefully you will all find useful.

The Page Files panel shows (and links) to all the files that belong to the current page (including those in repeater items and even nested repeaters).

It highlights (orange) files that are orphans - these are files that are in the /site/assets/files/xxxx folder for the page, but which don't belong to any of the file/image fields on the page.

It also highlights (red) files which are missing from the /site/assets/files/xxxx folder but are referenced by one of the file/image fields on the page. Obviously missing files are more important and critical than orphans, so they are red as an alert, rather than a warning.

The icon on the debug bar tells you how many files there are and how many are orphans and how many are missing.

There is a "Delete Orphans" button to make it easy to cleanup these unneeded files.

Note that the results are divided up into page IDs, starting with the ID of the page you are currently viewing/editing and followed by pages for any repeater field items. In parentheses it shows the name of the field that each file belongs to (except the orange orphans because obviously these don't belong to a field).

image.png.bf36241981a6d51f94c314d389798d9a.png

You might wonder how you can end up with orphans or missing files? I find this mostly happens if I am building an API import script to bring in data from a site I am migrating and I mess something up. I also have this issue quite often when developing image related modules (especially my Custom Upload Names module). It may also potentially happen if there is a network glitch during an upload or delete call.

Even if you don't have any orphans or missing files, you might still find it useful just as a way to quickly see the contents of the page's assets/files folder without needing to navigate via your file manager / FTP program etc.

Let me know if you find it useful or if you have ideas for improving it.

PS - this is obviously page based so it's not useful for doing a cleanup of your entire site - if you need that, then take a look at https://processwire.com/talk/topic/4437-delete-orphaned-filesimages-from-siteassetsfiles/?tab=comments#comment-43687 or other similar scripts in the forum.

  • Like 3

Share this post


Link to post
Share on other sites

There seems to be a small issue with the new Page Files panel when there are no files on the page. The panel overflows showing a scrollbar. Looks like the panel footer markup isn't nested correctly so maybe an unclosed div tag?

2018-12-21_212317.png.3d283a88ff6da21a932e68cb6fdce975.png

  • Like 1

Share this post


Link to post
Share on other sites

Thanks @Robin S it's fixed in the latest version. I have also added a message to note that there are no files associated with the page.

Also fixed a few other bugs so please update.

  • Like 1

Share this post


Link to post
Share on other sites

I've committed a new version of the Page Files panel.

  • It is now about twice as fast as v1, so I think it will now be a panel I leave open all the time as a reference.
  • It has a new "Delete missing pagefiles button" which deletes the pagefile references to the files which are missing from the filesystem.

image.png.610ff4a4e8ccddb7100111981b927617.png

  • Like 1

Share this post


Link to post
Share on other sites

Wish: is it possible to have a checkbox (unchecked by default) in the console panel, that would clear the results automatically before run? 

Share this post


Link to post
Share on other sites
2 minutes ago, matjazp said:

Wish: is it possible to have a checkbox (unchecked by default) in the console panel, that would clear the results automatically before run? 

Hey @matjazp - I don't really want to add another checkbox to the interface if we can avoid it, but I value your opinion, so I am curious why you would like this. I never use the "Run" button, or the "Clear Results" either. I just use the keyboard shortcuts - almost always the ALT/OPT + Enter combination (which automatically clears old results before running), and occasionally the CTRL/CMD + Enter combination if I do actually want to keep the previous results for comparison.

Is there a reason you don't like the keyboard shortcuts, or is there some other reason I am missing that makes this new checkbox a useful addition?

Share this post


Link to post
Share on other sites

Oh, didn't know about shortcuts! That's enough for me, I don't mind using the shortcuts, thanks.

Share this post


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

I don't really want to add another checkbox to the interface if we can avoid

You mean the console panel or the module config? You could add a checkbox which behaviour should be the default in the config page if you meant the console panel.

The module config page in aos have become a bit large and it takes some time to load, just like in tracy debugger (at least on my not so new notebook). I'm not sure what could be done about that, perhaps simplifying some settings to a textarea key-value pairs? Or using ajax loaded tabs or else to break down settings to smaller parts?

Share this post


Link to post
Share on other sites
5 hours ago, matjazp said:

Oh, didn't know about shortcuts! That's enough for me, I don't mind using the shortcuts, thanks.

There are lots of shortcuts 🙂

Njp77AyhoS.gif.ca8f6e26a39485e47be284b16b5cb7a1.gif

 

5 hours ago, tpr said:

You mean the console panel or the module config? You could add a checkbox which behaviour should be the default in the config page if you meant the console panel.

I think @matjazp was looking to have one in the Console panel. Yes I could make it a module config setting but if you make it the default then the "Clear Results" link it irrelevant (I guess it could be removed in this case), but then you'd have to use shortcuts to not automatically clear the results. Some time ago IIRC there were two buttons, "Run" and "Clear & Run" and no separate "Clear Results". I actually think that you had something to do with this change but I don't really remember why we went this way?

 

5 hours ago, tpr said:

The module config page in aos have become a bit large and it takes some time to load, just like in tracy debugger (at least on my not so new notebook). I'm not sure what could be done about that, perhaps simplifying some settings to a textarea key-value pairs? Or using ajax loaded tabs or else to break down settings to smaller parts?

Yeah, I agree the Tracy settings can be slow to load. Turns out the biggest issue is actually populating the DOM. If I simply collapse all the fieldsets it loads reasonably quickly. I used to have all (except the first couple of key ones) fieldsets collapsed, but I was convinced to change this, but that was some time ago and there were a lot less settings then. I wonder if I should revisit this? Perhaps I should collapse by default, but when following the cog/settings links at the bottom of a panel, then this would open up the requested fieldset. Maybe it also needs a toggle all at the top of the settings page for those who actually want to browse?

Any thoughts?

  • Like 1

Share this post


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

Is there a reason you don't like the keyboard shortcuts, or is there some other reason I am missing that makes this new checkbox a useful addition?

If you don't RTFM you don't know there are shortcuts available. I understand why you don't want more checkboxes. I wanted to suggest text info about shortcuts, but then I discovered that you already have alt text on Run button. The problem is that I never hoovered long enough to see that. 

6 hours ago, tpr said:

The module config page in aos have become a bit large and it takes some time to load, just like in tracy debugger (at least on my not so new notebook).

Yeah, both modules have a plethora of options, so it's expected to take some time to load. There's a lot of javascript things going on behind the scenes. I'm not a js guru, but I'm sure there is room for improvement in PW admin theme/inputfields itself. 

When I tried Page Files panel, I get this error:

Error: Call to a member function filesManager() on integer in C:\inetpub\wwwroot\site\assets\cache\FileCompiler\site\modules\TracyDebugger\panels\PageFilesPanel.php:171

Edit: support for fieldtype FieldtypeFieldsetPage is missing, it looks lik this is working in getPageFiles and getDiskFiles...

           if($item && $f && $f->type instanceof FieldtypeRepeater) {
                $repeaterValue = $p->get($f->name); 
                if($repeaterValue instanceof Page) $repeaterValue = array($repeaterValue); 
                foreach($repeaterValue as $subpage) {
                //foreach($p->$f as $subpage) {
                    $files += $this->getPageFiles($subpage);
                }
            }

 

Edited by matjazp
  • Like 1

Share this post


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

Any thoughts?

Never had any problems loading the tracy settings.

  • Like 2

Share this post


Link to post
Share on other sites
4 minutes ago, matjazp said:

When I tried Page Files panel, I get this error:

Error: Call to a member function filesManager() on integer in C:\inetpub\wwwroot\site\assets\cache\FileCompiler\site\modules\TracyDebugger\panels\PageFilesPanel.php:171

I can't see why that $p would ever be an integer - would you mind checking to see if it's returning a $page id or something else for me? It should be a page object. Thanks!

Share this post


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

There are lots of shortcuts

Cool! It never crossed my mind I could clik/hoover on that icon. Form usability point of view it would make more sense to have the underlined text: "Keybord Shorcuts". Of course, that's just my opinion, not a request for you to implement it...

Quote

I can't see why that $p would ever be an integer - would you mind checking to see if it's returning a $page id or something else for me? It should be a page object.

I edited my post providing possible solution ...

  • Like 1

Share this post


Link to post
Share on other sites
4 hours ago, matjazp said:

Edit: support for fieldtype FieldtypeFieldsetPage is missing, it looks lik this is working in getPageFiles and getDiskFiles...

Thanks, the fix you provided looks to be working well. I have just committed it.

Share this post


Link to post
Share on other sites

Happy holidays everyone!

Here's a little present for the new year 🙂

The API Explorer, Console, and File Editor panels now have access to the PW API data via a cache, rather than generating on-the-fly so those panels are now all much quicker after the first load after a core or module version update/install. This also means that we can now provide a "New Since" section in the API Explorer panel, which I first suggested over here.

This shows you all the additions to the API compared with the previous installed version. In the screenshot you can see what's new since 3.0.117.

image.png.ec3afb1f38fd05ad0f695e893dc3f110.png

If you want to get details about the changes from earlier versions, use the Process Version panel to change back to an old version (to build the cache of the old version), and then change back to the newer one. The Console and File Editor panels only cache the variables sections, so the list would be incomplete if you only had those loaded.

I just ran this on the old PW master (3.0.98) and then switched to the current master (3.0.123) and this is what was returned - quite the changelog!

Spoiler

 

Variables

$config->phpVersion()
$config->version()
$config->logIP
$config->noHTTPS
$config->pageNameUntitled
$config->pagerHeadTags
$config->wireInputLazy
$database->supportsTransaction()
$fields->findByTag()
$fields->getTags()
$files->allowPath()
$files->fileInPath()
$files->filePutContents()
$files->rename()
$files->unixDirName()
$files->unixFileName()
$files->unlink()
$input->__debugInfo()
$input->httpHostUrl()
$input->httpsUrl()
$input->pageNumStr()
$input->setLazy()
$mail->from()
$mail->mail()
$mail->mailHTML()
$mail->sendHTML()
$mail->subject()
$mail->to()
$modules->findByInfo()
$modules->getModuleEditUrl()
$modules->getModuleInfoProperty()
$page->addUrl()
$page->descendant()
$page->descendants()
$page->findOne()
$page->___links()
$page->numDescendants()
$page->numParents()
$page->___references()
$page->removeUrl()
$page->restorable()
$page->traversalPages()
$page->urls()
$page->hasLinks
$page->hasReferences
$page->numDescendants
$page->numLinks
$page->numParents
$page->numReferences
$page->numReferencing
$page->urls
$pages->names()
$permissions->getReducerPermissions()
$process->getProcessPage()
$sanitizer->camelCase()
$sanitizer->getTextTools()
$sanitizer->getWhitespaceArray()
$sanitizer->hyphenCase()
$sanitizer->kebabCase()
$sanitizer->normalizeWhitespace()
$sanitizer->pascalCase()
$sanitizer->reduceWhitespace()
$sanitizer->removeWhitespace()
$sanitizer->snakeCase()
$sanitizer->truncate()
$session->___allowLoginAttempt()
$session->removeAllFor()
$user->___changed()
$user->findOne()
$user->___links()
$user->numDescendants()
$user->numParents()
$user->___references()
$user->traversalPages()
$user->urls()

Core classes

AdminTheme->addClass()
AdminTheme->getClass()
AdminTheme->setClasses()
AdminThemeFramework->addClass()
AdminThemeFramework->getClass()
AdminThemeFramework->setClasses()
DatabaseQuery->bindIndex
Field->addTag()
Field->getTags()
Field->hasTag()
Field->removeTag()
Field->setTags()
Field->tagList
Field->tags
Fieldtype->getLastAccessField()
Fieldtype->setLastAccessField()
FieldtypeMulti->getLastAccessField()
FieldtypeMulti->setLastAccessField()
Inputfield->appendMarkup()
Inputfield->class()
Inputfield->collapsed()
Inputfield->columnWidth()
Inputfield->contentClass()
Inputfield->description()
Inputfield->getForm()
Inputfield->getRootParent()
Inputfield->head()
Inputfield->headerClass()
Inputfield->icon()
Inputfield->id()
Inputfield->label()
Inputfield->name()
Inputfield->notes()
Inputfield->parent()
Inputfield->parents()
Inputfield->prependMarkup()
Inputfield->required()
Inputfield->requiredIf()
Inputfield->requiredLabel()
Inputfield->showIf()
Inputfield->skipLabel()
Inputfield->unsetParent()
Inputfield->wrapClass()
InputfieldWrapper->child()
InputfieldWrapper->getEmpty()
InputfieldWrapper->getForm()
InputfieldWrapper->getRootParent()
InputfieldWrapper->___new()
InputfieldWrapper->parent()
InputfieldWrapper->parents()
InputfieldWrapper->unsetParent()
MarkupQA->findLinks()
NullField->addTag()
NullField->getTags()
NullField->hasTag()
NullField->removeTag()
NullField->setTags()
NullPage->findOne()
NullPage->___links()
NullPage->numDescendants()
NullPage->numParents()
NullPage->___references()
NullPage->traversalPages()
NullPage->urls()
PageArray->hasNextPagination()
PageArray->hasPagination()
PageArray->hasPrevPagination()
PageFinder->count()
PageTraversal->hasLinks()
PageTraversal->hasReferences()
PageTraversal->links()
PageTraversal->numDescendants()
PageTraversal->numLinks()
PageTraversal->numParents()
PageTraversal->numReferences()
PageTraversal->numReferencing()
PageTraversal->references()
PageTraversal->referencing()
PageTraversal->urls()
Pagefile->__debugInfo()
Pagefile->createdStr
Pagefile->modifiedStr
Pagefile->mtimeStr
Pagefiles->__debugInfo()
PagefilesManager->importFiles()
PagefilesManager->replaceFiles()
Pageimage->__debugInfo()
Pageimage->focusStr
Pageimage->suffix
Pageimage->suffixStr
Pageimages->__debugInfo()
PagesNames->adjustNameLength()
PagesNames->__construct()
PagesNames->defaultPageNameFormat()
PagesNames->hasAutogenName()
PagesNames->hasNumberSuffix()
PagesNames->incrementName()
PagesNames->isUntitledPageName()
PagesNames->nameAndNumber()
PagesNames->pageNameExists()
PagesNames->pageNameFromFormat()
PagesNames->setupNewPageName()
PagesNames->uniquePageName()
PagesNames->uniqueRandomPageName()
PagesNames->untitledPageName()
PagesTrash->getRestoreInfo()
PagesTrash->getTrashPage()
PagesTrash->getTrashTotal()
PagesTrash->parseTrashPageName()
PaginatedArray->hasNextPagination()
PaginatedArray->hasPagination()
PaginatedArray->hasPrevPagination()
PaginatedArray->renderPager()
Password->randomAlnum()
Password->randomAlpha()
Password->randomDigits()
Password->randomLetters()
Permission->findOne()
Permission->___links()
Permission->numDescendants()
Permission->numParents()
Permission->___references()
Permission->traversalPages()
Permission->urls()
Role->findOne()
Role->___links()
Role->numDescendants()
Role->numParents()
Role->___references()
Role->traversalPages()
Role->urls()
Selectors->getOperatorType()
Selectors->isOperator()
Template->icon
Tfa->active()
Tfa->___buildAuthCodeForm()
Tfa->__construct()
Tfa->enabledForUser()
Tfa->getModule()
Tfa->getModuleConfigInputfields()
Tfa->getUser()
Tfa->getUserSettings()
Tfa->___getUserSettingsInputfields()
Tfa->hookAfterInputfieldFormProcess()
Tfa->hookBeforeInputfieldFormProcess()
Tfa->hookInputfieldFormRender()
Tfa->___install()
Tfa->isValidUserCode()
Tfa->___process()
Tfa->___processUserSettingsInputfields()
Tfa->___render()
Tfa->saveUserSettings()
Tfa->___start()
Tfa->startUser()
Tfa->success()
Tfa->___uninstall()
Tfa->codeExpire
Tfa->codeLength
Tfa->codeType
WireArray->__callStatic()
WireArray->__construct()
WireArray->new()
WireArray->newInstance()
WireArray->slices()
WireDatabasePDO->supportsTransaction()
WireFileTools->allowPath()
WireFileTools->fileInPath()
WireFileTools->filePutContents()
WireFileTools->rename()
WireFileTools->unixDirName()
WireFileTools->unixFileName()
WireFileTools->unlink()
WireHttp->getHttpCodes()
WireHttp->getSuccessCodes()
WireHttp->setValidateURLOptions()
WireInput->__debugInfo()
WireInput->httpHostUrl()
WireInput->httpsUrl()
WireInput->pageNumStr()
WireInput->setLazy()
WireMail->htmlToText()
WireMail->newline
WireMailTools->from()
WireMailTools->mail()
WireMailTools->mailHTML()
WireMailTools->sendHTML()
WireMailTools->subject()
WireMailTools->to()
WireMarkupRegions->stripOptional()
WireRandom->alpha()
WireRandom->alphanumeric()
WireRandom->arrayKey()
WireRandom->arrayKeys()
WireRandom->arrayValue()
WireRandom->arrayValues()
WireRandom->base64()
WireRandom->cryptoSecure()
WireRandom->integer()
WireRandom->numeric()
WireRandom->pass()
WireRandom->shuffle()
WireShutdown->shutdownExternal()
WireTextTools->collapse()
WireTextTools->fixUnclosedTags()
WireTextTools->getPunctuationChars()
WireTextTools->getVisibleLength()
WireTextTools->markupToText()
WireTextTools->truncate()

CoreModules classes

PagePathHistory->addPathHistory()
PagePathHistory->deletePathHistory()
PagePathHistory->hookPageAddUrl()
PagePathHistory->hookPageRemoveUrl()
PagePermissions->restorable()
PagePermissions->trashListable()
PagePermissions->userViewable()

 

 

A lot of refactoring went into this so that I could cache the API data in a way that I could compare so please let me know if you notice any problems.

  • Like 4
  • Thanks 3

Share this post


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

This shows you all the additions to the API compared with the previous installed version.

This is really cool @adrian!

It got me thinking... could something be built upon what you've done here to make it easy for @ryan to update the core PHPDoc comments (and therefore the core documentation) with @since tags? I was imagining something like:

Ryan downloads all the PW3 versions from 3.0.0 to current (or maybe he already has them archived somewhere), and then some script runs across all these versions to identify the PW version numbers where new class methods were added. The information is then written back as @since tags to the latest PW version and Ryan pushes this to GitHub to update the documentation.

Not sure if this is something that could be built into Tracy as a hidden feature (mainly just for Ryan's use) or if it would be better separated off into a standalone script. Do you think it would it be difficult to code?

  • Like 2

Share this post


Link to post
Share on other sites
7 hours ago, Robin S said:

This is really cool @adrian!

Glad you like it 🙂

7 hours ago, Robin S said:

Not sure if this is something that could be built into Tracy as a hidden feature (mainly just for Ryan's use) or if it would be better separated off into a standalone script. Do you think it would it be difficult to code?

While I like your thinking here, I think it might actually be a better fit inside Ryan's API Explorer Pro module. My understanding is that he uses that to build the documentation on the website as well as being a module that users can install on their systems. I think because of the way I have written this for Tracy, working off an array of classes/methods/properties cached from the last version, I don't think I have much of a leg up towards what you are suggesting. I definitely think it's a good idea though and maybe worth a suggestion to Ryan here: https://github.com/processwire/processwire-issues/issues/759

Perhaps someone out there with Ryan's module might like to tackle adding this functionality?

 

  • Like 2

Share this post


Link to post
Share on other sites

Small update to the "New Since" section this morning.

It now automatically generates a full API data cache before any PW core system updates so there is no longer a need to have the API Explorer panel open before changing the core version.

I also fixed a bug generating this when in the PW admin - it was working fine on the frontend of a site, but not the backend.

  • Like 1

Share this post


Link to post
Share on other sites

Hello all, hope everyone has a happy new year 🎆

I'm using the newest version of Tracy ( 4.16.8 ) and after enabling Tracy this is showing at the bottom of all pages, front and back end:

Fatal error: Uncaught Exception: Serialization of 'Closure' is not allowed in [no active file] on line 0

Googling the message tells me this is something to do with unit testing? Is this Tracy or something in my code?

PW: 30118

Apache Version: 2.4.23  - Documentation

PHP Version: 7.0.10  - Documentation

Server Software: Apache/2.4.23 (Win64) PHP/7.0.10 - Port defined for Apache: 80

Edited by breezer
added environment

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 anderson
      Hi all,
      I'm a new to website building. Learned some CRASH course of js,jquery,php. Then I found CMS. Still learning around forum, youtube....
      Anyway, please help me with some beginer questions:
      1, About template - please correct me if I understand wrong : every page should be (or recommended) built on a template. So if in total I'll have 10 pages, 2 of them have same layout, I'll need 9 templates.  And, what fields a page includes, is not defined in page, but defined in the template that page uses. 
      2,  Where to see what modules I've installed? is it in "Modules - Site"? 
      3, I installed "PageTable Extended", then what?  As in a youtube tutorial, it should appear in Setup tab, but it doesn't.  What's in there: templates,fields,logs,comments. (I installed "Uikit 3 site_blog profile".)
      4, I did a search in Processwire website for the famous "repeater matrix" module, and can not find it, there's a Repeater, as well as a Matrix. Is it not a module?
      5, I watched this youtube tuts: https://www.youtube.com/watch?v=IHqnLQy9R1A
      Anybody familiar with this tuts please help: 
      After he analysed a target webpage layout he wanted to mimic, he created some fields, some template, then based on those he created a page and input some "content" in there, then clicked "view", it's just some text. So, here comes my question, he copied a folder "assets" (subfolders are: css,fonts,js,img) over, then the page have the appearance/layout he wanted to mimic. Where does that assets folder come from?
      Appreciate any help.
    • By mtwebit
      I've created a set of modules for importing (manipulating and displaying) data from external resources. A key requirement was to handle large (100k+) number of pages easily.
      Main features
      import data from CSV and XML sources in the background (using Tasker) purge, update or overwrite existing pages using selectors user configurable input <-> field mappings on-the-fly data conversion and composition (e.g. joining CSV columns into a single field) download external resources (files, images) during import handle page references by any (even numeric) fields How it works
      You can upload CSV or XML files to DataSet pages and specify import rules in their description.
      The module imports the content of the file and creates/updates child pages automatically.
      How to use it
      Create a DataSet page that stores the source file. The file's description field specifies how the import should be done:
      After saving the DataSet page an import button should appear below the file description.

      When you start the import the DataSet module creates a task (executed by Tasker) that will import the data in the background.
      You can monitor its execution and check its logs for errors.

      See the module's wiki for more details.
      The module was already used in three projects to import and handle large XML and CSV datasets. It has some rough edges and I'm sure it needs improvement so comments are welcome.
    • By dreerr
      TemplateEnginePug (formally TemplateEngineJade)
       
      This module adds Pug templates to the TemplateEngineFactory. It uses https://github.com/pug-php/pug to render templates.
      doctype html html(lang='en') head meta(http-equiv='content-type', content='text/html; charset=utf-8') title= $page->title link(rel='stylesheet', type='text/css', href=$config->urls->templates . 'styles/main.css') body include header.pug h1= $page->title if $page->editable() p: a(href=$page->editURL) Edit Project on GitHub: github.com/dreerr/TemplateEnginePug
      Project in modules directory: modules.processwire.com/modules/template-engine-pug/
       
      For common problems/features/questions about the Factory, use the TemplateEngineFactory thread.
       
    • By Robin S
      Pages At Bottom
      Keeps selected pages at the bottom of their siblings.
      A "bottom page" will stay at the bottom even if it is drag-sorted to a different location or another page is drag-sorted below it (after Page List is refreshed the bottom page will still be at the bottom).
      Newly added sibling pages will not appear below a bottom page.
      The module also prevents the API methods $pages->sort() and $pages->insertAfter() from affecting the position of bottom pages.
      Note: the module only works when the sort setting for children on the parent page/template is "Manual drag-n-drop".
      Why?
      Because you want some pages to always be at the bottom of their siblings for one reason or another. And someone requested it. 🙂
      Usage
      Install the Pages At Bottom module.
      Select one or more pages to keep at the bottom of their siblings. If you select more than one bottom page per parent then their sort order in the page list will be the same as the sort order in the module config.

       
      https://github.com/Toutouwai/PagesAtBottom
      https://modules.processwire.com/modules/pages-at-bottom/
    • By Robin S
      Another little admin helper module...
      Template Field Widths
      Adds a "Field widths" field to Edit Template that allows you to quickly set the widths of inputfields in the template.

      Why?
      When setting up a new template or trying out different field layouts I find it a bit slow and tedious to have to open each field individually in a modal just to set the width. This module speeds up the process.
      Installation
      Install the Template Field Widths module.
      Config options
      You can set the default presentation of the "Field widths" field to collapsed or open. You can choose Name or Label as the primary identifier shown for the field. The unchosen alternative will become the title attribute shown on hover. You can choose to show the original field width next to the template context field width.  
      https://github.com/Toutouwai/TemplateFieldWidths
      https://modules.processwire.com/modules/template-field-widths/