Jump to content

taotoo

Members
  • Posts

    85
  • Joined

  • Days Won

    1

Posts posted by taotoo

  1. This module is so handy.

    A minor thing, but I find myself not being able to differentiate between fields when selecting them:

    Untitled-1.jpg.fea9187b443abc8d506afa1a29f20d13.jpg

    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.

     

    • Like 1
  2. 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.

    • Like 2
  3. 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);
    			}
    		}
    	}

     

    • Like 2
  4. 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.

  5. 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]
  6. 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.

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

    • Like 1
  8. 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.

    • Like 1
  9. 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).

    image.thumb.png.f7b610a14f29e2aa8fdd8fbb47a3368b.png

    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();
  10. 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).

    image.thumb.png.f7b610a14f29e2aa8fdd8fbb47a3368b.png

    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!

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

     

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

×
×
  • Create New...