taotoo
-
Posts
85 -
Joined
-
Days Won
1
Posts posted by taotoo
-
-
This module is so handy.
A minor thing, but I find myself not being able to differentiate between fields when selecting them:
It would be great if there was an option to show field Names instead of Labels (or show both).
Obviously I can rename my fields, but I like to keep them short for the client, and want to avoid the complication of using template overrides.
-
1
-
-
On 8/11/2025 at 10:26 PM, ryan said:
@taotoo Thanks, fixed the animation in Firefox. It turns out Firefox needs the SVG filter to be visible, so had to remove the "hidden" attribute and move it off screen with absolute position. I don't know what's up with the MS Edge appearance (I don't have that environment to test in) but if you find what it is, please let me know.
On Windows 11, Chrome/Firefox/Edge all looking good to me now - consistent animations and the aliasing has gone too.
-
2
-
-
-
+1 🙂
-
1
-
-
I'm currently looking at Grav/Kirby/Statamic etc. for certain simple sites where MySql doesn't make sense, but I'd much rather use PW with SQLite.
-
3
-
-
While I've never encountered that particular error, I have solved other ones by removing empty lines from beneath the closing php tag in my ready.php file.
-
Thanks for another great module Robin. Just a thought - I wonder if the icons might be inverted, e.g. so that an eye means the page is visible, and an eye with a strike through means it's hidden.
-
1
-
-
You can use FieldtypeConcat, or do it with a hook.
https://processwire.com/modules/fieldtype-concat/
// Merge First and Surname for Title and Name if($page->template == 'some-template') { // Don't change name field if page is going to trash if(!$page->isTrash) { // If the fields that make up the title are populated if($page->first_name && $page->surname) { // Set the title $page->title = "{$page->first_name} {$page->surname}"; // Sanitize the title as a page name $name = $event->wire()->sanitizer->pageName($page->title, true); // Set the page name while making sure it auto-increments if there is a sibling page with the same title $page->name = $pages->names()->uniquePageName($name, $page); } } }-
2
-
-
2 hours ago, ngrmm said:
@taotoo just a guess, try these:
or template=category >> parent=/blog/posts, categories=page.parent.id
This is the one, thank you!
-
1
-
-
Not sure if anyone has used this module yet.
Example code from the module page (https://processwire.com/blog/posts/page-list-custom-children-module/):
template=category >> parent=/blog/posts, categories=page.idI want to insert 'parent', as below, but it doesn't work. I'm hoping someone might know how to do it.
template=category >> parent=/blog/posts, categories=parent.page.id -
You could try the Limit Repeater module to set a max number of rows. Alternatively, I have a feeling you may also be able to set a min and max number of rows within the field setup, if so you could set them to the same number. Or maybe use the Admin On Steroids module, enable the setting for it to add CSS classes for each admin page, then add CSS via the same module to hide the add new button.
-
Dpi normally shouldn't matter. Are the problem images' px dimensions larger than the limits you have set?
If using server side resize you could try client side.
-
2
-
-
On 2/16/2023 at 11:19 PM, OHP22 said:
but our htaccess doesnt rewrite the url from png,jpg to webp?
With method 2 htaccess should rewrite it from webp to jpg shouldn't it?
Assuming that is what you're expecting it to do, I found the example htaccess code didn't work for me. But I found that the code below did work (of course YMMV).
RewriteCond %{HTTP_ACCEPT} !image/webp RewriteRule (.+)\.webp$ $1.jpg [T=image/jpeg,E=REQUEST_image] -
FYI it works fine for me on my Android phone in both Chrome and Stargon (not sure which engine the latter uses).
-
Maybe you could see if the control panel also displays the output of php.ini somewhere, and see if it matches those values. You could also create a php.ini file, and see if those values match. I might also try uploading files of various sizes around 75mb, have the browser inspector open to see if there's any indication of when it fails, and time the failure point to see if it's something like 30s, or perhaps a multiple of 5 or 7.5 in case it's related to CPU time and the server has a multicore CPU.
I have a similar issue when creating variations - I get the endless spinner if the creation takes longer than 15s on a dual core server.
-
I think "n" is simply an instruction to type the number of results that you would like to have per page in place of it.
-
1
-
-
I had something similar when using the Title field in a repeater. I'm not sure if it's the same issue or not, but I think I solved it by going to the field's Access tab, turning on access control, and assigning the view permission to guests.
-
50 minutes ago, 7Studio said:
@taotoo thanks for a notice! I'm also on Win10 (integrated GPU, FHD display) but I can't replicate this issue on Chrome/Firefox. Could you please let me know what kind of GPU is that and what display are you using (hdpi with windows scalling)? will try to debug this further ? Thanks!
Annoyingly I've just revisited the website and it's no-longer doing it! I'll check it again later. The GPU is a GTX750, and the display is low pixel density, with no scaling involved.
-
1
-
-
On 11/12/2022 at 8:26 PM, 7Studio said:
continuous transitions like mouse cursor are triggered with requestAnimationFrame to avoid drops in frame rate
On Chrome (and Firefox) on Win10 I do notice that with the browser window wider than about 1,000 pixels my mouse cursor slows down. The wider the window, the slower it gets. At 2560px wide, the mouse is at about half speed. This is with a modern CPU and also a GPU.
-
1
-
-
1 hour ago, dragan said:
Basically, you could clone the clone function (ha!) from the core and alter it slightly:
https://github.com/ryancramerdesign/ProcessWire/blob/master/wire/core/Pages.php#L1733
function cloneWithoutFiles(Page $page, Page $parent = null, $recursive = true, $options = array()) { $defaults = array( 'forceID' => 0, 'set' => array(), 'recursionLevel' => 0, // recursion level (internal use only) ); if (is_string($options)) $options = Selectors::keyValueStringToArray($options); $options = array_merge($defaults, $options); if ($parent === null) $parent = $page->parent; if (count($options['set']) && !empty($options['set']['name'])) { $name = $options['set']['name']; } else { $name = wire()->pages->names()->uniquePageName(array( 'name' => $page->name, 'parent' => $parent )); } $of = $page->of(); $page->of(false); // Ensure all data is loaded for the page foreach ($page->fieldgroup as $field) { // changed: if ($field->type !== "FieldtypeImage") { if ($page->hasField($field->name)) $page->get($field->name); } } /** @var User $user */ $user = wire()->wire('user'); // clone in memory $copy = clone $page; $copy->setIsNew(true); $copy->of(false); $copy->setQuietly('_cloning', $page); $copy->setQuietly('id', $options['forceID'] > 1 ? (int)$options['forceID'] : 0); $copy->setQuietly('numChildren', 0); $copy->setQuietly('created', time()); $copy->setQuietly('modified', time()); $copy->name = $name; $copy->parent = $parent; if (!isset($options['quiet']) || $options['quiet']) { $options['quiet'] = true; $copy->setQuietly('created_users_id', $user->id); $copy->setQuietly('modified_users_id', $user->id); } // set any properties indicated in options if (count($options['set'])) { foreach ($options['set'] as $key => $value) { $copy->set($key, $value); // quiet option required for setting modified time or user if ($key === 'modified' || $key === 'modified_users_id') $options['quiet'] = true; } } // tell PW that all the data needs to be saved foreach ($copy->fieldgroup as $field) { // changed: if ($field->type !== "FieldtypeImage") { if ($copy->hasField($field)) $copy->trackChange($field->name); } } wire()->pages->cloneReady($page, $copy); wire()->cloning++; $options['ignoreFamily'] = true; // skip family checks during clone try { wire()->pages->save($copy, $options); } catch (\Exception $e) { wire()->cloning--; $copy->setQuietly('_cloning', null); $page->of($of); throw $e; } wire()->cloning--; // check to make sure the clone has worked so far if (!$copy->id || $copy->id == $page->id) { $copy->setQuietly('_cloning', null); $page->of($of); return wire()->pages->newNullPage(); } // copy $page's files over to new page // changed: // basically, you could delete this block altogether if (PagefilesManager::hasFiles($page)) { // $copy->filesManager->init($copy); // $page->filesManager->copyFiles($copy->filesManager->path()); } // if there are children, then recursively clone them too if ($page->numChildren && $recursive) { $start = 0; $limit = 200; $numChildrenCopied = 0; do { $children = $page->children("include=all, start=$start, limit=$limit"); $numChildren = $children->count(); foreach ($children as $child) { /** @var Page $child */ $childCopy = wire()->pages->clone($child, $copy, true, array( 'recursionLevel' => $options['recursionLevel'] + 1, )); if ($childCopy->id) $numChildrenCopied++; } $start += $limit; wire()->pages->uncacheAll(); } while ($numChildren); $copy->setQuietly('numChildren', $numChildrenCopied); } $copy->parentPrevious = null; $copy->setQuietly('_cloning', null); if ($options['recursionLevel'] === 0) { // update pages_parents table, only when at recursionLevel 0 since parents()->rebuild() already descends if ($copy->numChildren) { $copy->setIsNew(true); wire()->pages->parents()->rebuild($copy); $copy->setIsNew(false); } // update sort if ($copy->parent()->sortfield() == 'sort') { wire()->sortPage($copy, $copy->sort, true); } } $copy->of($of); $page->of($of); $page->meta()->copyTo($copy->id); $copy->resetTrackChanges(); wire()->pages->cloned($page, $copy); wire()->pages->debugLog('clone', "page=$page, parent=$parent", $copy); return $copy; } // basic usage just as with original function: $pg = $pages->get(23506); cloneWithoutFiles($pg);
Besides the three places marked with // changed, I also had to replace $this-> with wire()-> to use it in a template file.
Images (files) are not copied to the new page, however, the fields are. It wouldn't be too hard to delete these after you've created the clone (after initial clone-save).
This works great, thank you so much!
I noticed that your code is based on a a PW v2.7 Pages.php file. My existing PW v3 Pages.php file had in it only this cloning code:
public function ___clone(Page $page, Page $parent = null, $recursive = true, $options = array()) { return $this->editor()->_clone($page, $parent, $recursive, $options); }I just pasted your code in below this, and it works. Not sure if that's what I'm meant to be doing or not.
Where does PW v3 keep all its cloning code?
1 hour ago, dragan said:I guess this should do the trick (delete orphaned images)
// before the function definition: $imageFields = array(); // hold all image field-names // replace/insert in my above function this: // tell PW that all the data needs to be saved foreach ($copy->fieldgroup as $field) { if ($field->type !== "FieldtypeImage") { if ($copy->hasField($field)) $copy->trackChange($field->name); } else { $imageFields[] = $field->name; // here } } // test it: $pg = $pages->get(23506); // clone a page $newClone = cloneWithoutFiles($pg); $id = $newClone->id; // echo "new page id = $id <br>"; $pg = $pages->get($id); $pg->of(false); foreach($imageFields as $f) { $pg->$f->deleteAll(); $pg->save($f); }
Perhaps there's a cleaner way to do all this... it would be nice to have this as an option built into the core function!
I found that I could just add the code below to the hook - it seems to prevent the contents of the field being copied over to the new page:
$clone->image = null; $clone->save(); -
14 minutes ago, dragan said:
Basically, you could clone the clone function (ha!) from the core and alter it slightly:
https://github.com/ryancramerdesign/ProcessWire/blob/master/wire/core/Pages.php#L1733
function cloneWithoutFiles(Page $page, Page $parent = null, $recursive = true, $options = array()) { $defaults = array( 'forceID' => 0, 'set' => array(), 'recursionLevel' => 0, // recursion level (internal use only) ); if (is_string($options)) $options = Selectors::keyValueStringToArray($options); $options = array_merge($defaults, $options); if ($parent === null) $parent = $page->parent; if (count($options['set']) && !empty($options['set']['name'])) { $name = $options['set']['name']; } else { $name = wire()->pages->names()->uniquePageName(array( 'name' => $page->name, 'parent' => $parent )); } $of = $page->of(); $page->of(false); // Ensure all data is loaded for the page foreach ($page->fieldgroup as $field) { // changed: if ($field->type !== "FieldtypeImage") { if ($page->hasField($field->name)) $page->get($field->name); } } /** @var User $user */ $user = wire()->wire('user'); // clone in memory $copy = clone $page; $copy->setIsNew(true); $copy->of(false); $copy->setQuietly('_cloning', $page); $copy->setQuietly('id', $options['forceID'] > 1 ? (int)$options['forceID'] : 0); $copy->setQuietly('numChildren', 0); $copy->setQuietly('created', time()); $copy->setQuietly('modified', time()); $copy->name = $name; $copy->parent = $parent; if (!isset($options['quiet']) || $options['quiet']) { $options['quiet'] = true; $copy->setQuietly('created_users_id', $user->id); $copy->setQuietly('modified_users_id', $user->id); } // set any properties indicated in options if (count($options['set'])) { foreach ($options['set'] as $key => $value) { $copy->set($key, $value); // quiet option required for setting modified time or user if ($key === 'modified' || $key === 'modified_users_id') $options['quiet'] = true; } } // tell PW that all the data needs to be saved foreach ($copy->fieldgroup as $field) { // changed: if ($field->type !== "FieldtypeImage") { if ($copy->hasField($field)) $copy->trackChange($field->name); } } wire()->pages->cloneReady($page, $copy); wire()->cloning++; $options['ignoreFamily'] = true; // skip family checks during clone try { wire()->pages->save($copy, $options); } catch (\Exception $e) { wire()->cloning--; $copy->setQuietly('_cloning', null); $page->of($of); throw $e; } wire()->cloning--; // check to make sure the clone has worked so far if (!$copy->id || $copy->id == $page->id) { $copy->setQuietly('_cloning', null); $page->of($of); return wire()->pages->newNullPage(); } // copy $page's files over to new page // changed: // basically, you could delete this block altogether if (PagefilesManager::hasFiles($page)) { // $copy->filesManager->init($copy); // $page->filesManager->copyFiles($copy->filesManager->path()); } // if there are children, then recursively clone them too if ($page->numChildren && $recursive) { $start = 0; $limit = 200; $numChildrenCopied = 0; do { $children = $page->children("include=all, start=$start, limit=$limit"); $numChildren = $children->count(); foreach ($children as $child) { /** @var Page $child */ $childCopy = wire()->pages->clone($child, $copy, true, array( 'recursionLevel' => $options['recursionLevel'] + 1, )); if ($childCopy->id) $numChildrenCopied++; } $start += $limit; wire()->pages->uncacheAll(); } while ($numChildren); $copy->setQuietly('numChildren', $numChildrenCopied); } $copy->parentPrevious = null; $copy->setQuietly('_cloning', null); if ($options['recursionLevel'] === 0) { // update pages_parents table, only when at recursionLevel 0 since parents()->rebuild() already descends if ($copy->numChildren) { $copy->setIsNew(true); wire()->pages->parents()->rebuild($copy); $copy->setIsNew(false); } // update sort if ($copy->parent()->sortfield() == 'sort') { wire()->sortPage($copy, $copy->sort, true); } } $copy->of($of); $page->of($of); $page->meta()->copyTo($copy->id); $copy->resetTrackChanges(); wire()->pages->cloned($page, $copy); wire()->pages->debugLog('clone', "page=$page, parent=$parent", $copy); return $copy; } // basic usage just as with original function: $pg = $pages->get(23506); cloneWithoutFiles($pg);
Besides the three places marked with // changed, I also had to replace $this-> with wire()-> to use it in a template file.
Images (files) are not copied to the new page, however, the fields are. It wouldn't be too hard to delete these after you've created the clone (after initial clone-save).
Ah - that's how to do it! I was looking in ProcessPageClone.module and couldn't figure out how the files were being copied...
Thank you very much for the comprehensive answer, I'll try it out!
-
I'm using a hook (similar to @bernhard's below) to add a Clone button when editing pages.
Is it possible to clone the page, but without also copying over the image files?
I tried adding this code towards the end of the hook:
$clone->image = null; $clone->save();This successfully prevents the contents of the image field being cloned, but PW still copies the image files themselves into the new page's directory.
I also looked at the API documentation, but it doesn't seem to provide an option for this.
I want to avoid copying the images as there are typically about 20 files that get copied, which takes about 10 seconds on the shared server. Additionally, the first thing the client will do after cloning the page is delete the images as they will be unneeded.
-
On 4/30/2019 at 2:38 AM, Noboru said:
Hi @horst,
My ImageSizerEngineVips is based on your ImageSizerEngineIMagickCLI with code from other sizers. The module works fine, but at the moment only for my needs, because I optimized for speed and left some options like sharpening. But if I have the time and interest, I can polish it.Might you make your module available @Noboru? I'd love to give it a try.
-
Is it trying to display thousands of pages and timing out? If so maybe an input type such as Page Auto Complete, which doesn't load all of the pages at once might work.
-
5
-
Connect Page Fields
in Modules/Plugins
Posted
Thank you Robin, as ever you're a star!