Leaderboard
Popular Content
Showing content with the highest reputation on 01/09/2024 in all areas
-
Hello everyone, Among other interesting projects listed in the December 2023 PhpStorm blog newsletter, I found these particularly interesting: human-readable regular expressions for PHP PHP Dictionary OrbStack (macOS only, free for non-commercial purposes only) Happy coding ;)5 points
-
Media Lister Lists images and files from across the site in a sortable and filterable table. For images you can choose between table, small thumbnails and large thumbnails view modes. The module retrieves the data using SQL queries so is able to efficiently list media information for all but the largest of sites. Possible use cases: Check that a nice variety of banner images is used for top-level pages. Find duplicate files/images by sorting by filesize or filename. Find images without descriptions if this is important for use in alt tags. Find large PDF files that would benefit from optimisation. Check for "inappropriate" images, or images that are not "on-brand". Images in small thumbnails view mode Files saved as a bookmark Controls Media type: Choose between Images and Files. View mode: When listing images you can choose between small thumbnails, large thumbnails and table view modes. When in one of the thumbnail view modes you can see information about the image in a tooltip by clicking the "i" icon, or edit the page containing the image by clicking the pencil icon. From pages matching: This field allows you to add filters to limit the pages that the media will be listed for. Add bookmark: Superusers can add bookmarks for the current settings that will be available from the flyout menu for all users. See the bookmarks section below for more information. Column visibility: Choose the columns that appear in the table and in the information tooltip (when in thumbnails mode). Search: Quickly filters the results to show only items that have the search text in any column, whether the column is visible or not. Custom search builder: For more advanced searches where you can combine conditions for specific columns with AND/OR logic. Pagination: You can navigate through the results and set the number of results per page. Reset: Click the "Reset" button at the top right to return to the default settings for Media Lister (or for the current bookmark if applicable). Editing the page that contains the media For any media result click the link in the "Page" column to open the page that contains the media item in Page Edit. When in thumbnail view mode you can click the pencil icon to achieve the same thing. The field that contains the media item will be focused. When a media item is contained within a Repeater field this is indicated by an asterisk at the start of the page title. When opening Page Edit for a media item within a Repeater field the Repeater item will be automatically expanded, including for nested Repeaters. Limitations for values that are merged in the database The module has limited support for multi-language values and custom fields for images/files. In order to be efficient enough to handle large sets of results the module retrieves raw values from the database, and in the case of multi-language values and custom field values ProcessWire stores these in JSON format in a single database column. The module improves the display of this JSON data by extracting the uploadName value into a separate column, substituting custom field labels for field IDs, adding language names where possible, and by transforming the data into a quasi-YAML format for better readability. Some limitation remain though – for example, if you use Page Reference fields in the custom fields then only the page IDs are displayed. Bookmarks Superusers are able to create a bookmark for the current Media Lister settings by expanding the "Add bookmark" field, entering a title for the bookmark, and clicking the "Add bookmark" button. Bookmarks will be visible to all users from the flyout menu. You can delete a bookmark from the module config screen. Module config In the module config screen you can define defaults for controls such as media type, view mode, pagination limit and column visibility. You can also delete bookmarks from the module config screen. https://github.com/Toutouwai/ProcessMediaLister https://processwire.com/modules/process-media-lister/1 point
-
In this tutorial I want to show you how to set up a simple ajax-driven auto-complete search within ProcessWire. Something that looks like this: Requirements: 1. Use the Fieldtype Cache to create a search index For fast and easy search queries we will create a search index field. You can read more on this here: https://processwire.recipes/recipes/set-up-search-index-with-fieldtypecache/ First of all, go to Modules and install a Core module called FieldtypeCache. Add a new field “search_cache” and select “Cache” as it’s type. Save the field. On the Details tab choose the fields you want to make searchable. Save again. Add “search_cache” to all templates you want to include in your search results. Optional but recommended: use the “Regenerate Cache” option found from the Details tab of the field to make existing content instantly searchable. In my case i only want to search inside body and title fields, so I included those fields in the settings of the search cache field: 2. Install the Pages2JSON module We want to make ajax requests to the search template and those results should be returned in JSON format so that our java script can process the results inside the auto-complete dropdown. Therefore we make use of this module here: https://processwire.com/modules/pages2-json/ In the module settings we define what data will be included in the JSON object that is returned. Remember that this is the data that we want to display in our auto-complete dropdown. So for my case I only want the title and the url field. Now let's start: 1. Setting up the search template Set up a template file called „search“. Then create a page using this template. On most ProcessWire installations this is already the case and this template exits in the file system. This template will handle the search queries and list all the results for us and that in two ways: - you can send a search query and the search result page will list all the results (as you would expect) - you can send an ajax search query and the result page will return the results as a json object to be processed within javascript and displayed in the frontend in real-time search.php: <?php if($config->ajax) { // Return search results in JSON format $q = $sanitizer->selectorValue($input->get->q); $results = $pages->find('search_cache%=' . $q);; // Find all pages and save as $results header("Content-type: application/json"); // Set header to JSON echo $results->toJSON(); // Output the results as JSON via the toJSON function return $this->halt(); } ?> <main> <div class="uk-container"> <?php // look for a GET variable named 'q' and sanitize it $q = $sanitizer->selectorValue($input->get->q); // did $q have anything in it? if($q) { // Find pages that match the selector $matches = $pages->find('search_cache%=' . $q); // did we find any matches? ... if($matches->count) { echo "<h2>We found $matches->count results:</h2>"; echo "<ul class='uk-list uk-list-square'>"; foreach($matches as $match) { echo "<li><a href='$match->url'>$match->title</a>"; echo "<div class='summary'>$match->summary</div></li>"; } echo "</ul>"; } else { ?> <h2>No results found.</h2> <div uk-grid class="uk-flex uk-flex-center"> <div class="uk-width-1-1 uk-width-1-2@m"> <?= $files->render('elements/_searchbox'); ?> </div> </div> <? } } else { ?> <h2>Search:</h2> <div uk-grid class="uk-flex uk-flex-center"> <div class="uk-width-1-1 uk-width-1-2@m"> <?= $files->render('elements/_searchbox'); ?> </div> </div> <? } ?> </div> </main> Explanation: This part here at the top of the template handles the requests that are send via ajax. This is the important part for later on. <?php if($config->ajax) { // Return search results in JSON format $q = $sanitizer->selectorValue($input->get->q); $results = $pages->find('search_cache%=' . $q);; // Find all pages and save as $results header("Content-type: application/json"); // Set header to JSON echo $results->toJSON(); // Output the results as JSON via the toJSON function return $this->halt(); } ?> What this does: check if the current request is an ajax request if so, search inside the search cache field return the results in JSON format then quit processing the rest of the template (we don’t want to render any markup in that case!) Everything below this part is the normal search template logic. If you send a search request via a form somewhere on the website you want to be redirected to the result page and all the results will be listed on the page just like you would expect. 2. Make the search „work“ Create a template file called "_searchbox.php" (this file is also included in the search template code above, so adjust your paths/names accordingly). To make search requests you want to include this search form anywhere on your page. _searchbox.php: <div class="search-wrapper uk-padding uk-text-center"> <h4>Searchbox</h4> <form class="searchform uk-position-relative uk-flex" method="get" action="<?= $pages->get("template=search")->url ?>"> <input class="uk-input" id="searchInput" name="q" type="search" aria-label="Suchen" autocomplete="off" placeholder="z.B. Bagger"> <button class="uk-button uk-button-primary search-button" type="submit"> <span class="uk-visible@s">Search</span> </button> <div id="suggestions" class="uk-box-shadow-medium"> </div> </form> </div> With this simple search form you should now be able to do a basic search that leads you to a search result page. 3. Make the ajax-search „work“ Now comes the interesting part. We will add in a java script snippet into our just created _searchbox.php that sends ajax requests to the search template page while we are typing into the search intput field and it will display the results in a nice little dropdown. Feel free to adjust the code to your needs! <script> document.addEventListener("DOMContentLoaded", () => { const searchForm = document.querySelector('.searchform'); const searchUrl = searchForm.getAttribute('action'); const searchInput = document.getElementById('searchInput'); const suggestionsDiv = document.getElementById('suggestions'); let selectedSuggestionIndex = -1; // close the auto-complete container when clicked outside the element document.addEventListener('click', function(event) { if (!suggestionsDiv.contains(event.target)) { suggestionsDiv.style.display = 'none'; } }); searchInput.addEventListener('input', () => { const searchText = searchInput.value.toLowerCase(); // Immediately Invoked Function Expression (IIFE) (async () => { try { const response = await fetch(searchUrl+"?q="+searchText, { headers: { 'X-Requested-With': 'XMLHttpRequest' } }); if (response.status === 200) { const data = await response.json(); showResults(data); } else { console.log(response.status); console.log(response.statusText); } } catch (error) { console.error(error); } })(); function showResults(data) { // Show suggestions only if the input has at least two characters if (searchText.length >= 2) { const suggestionHTML = data.map(item => { // Highlight the matching characters using a <span> element with a CSS class const highlightedTitle = item.title.replace( new RegExp(searchText, 'gi'), match => `<span class="highlight">${match}</span>` ); return `<li class="suggestion"><a href="${item.url}">${highlightedTitle}</a></li>`; }).join(''); // Array to string conversion suggestionsDiv.innerHTML = ''; // Clear the suggestions if input length is less than two characters // create list and append search results const suggestionList = document.createElement("ul"); suggestionList.classList.add('suggestion-list', 'uk-list'); suggestionList.innerHTML = suggestionHTML; suggestionsDiv.appendChild(suggestionList); selectedSuggestionIndex = -1; // show the results suggestionsDiv.style.display = "block"; } else { suggestionsDiv.innerHTML = ''; // Clear the suggestions if input length is less than two characters } } }); // Event listener for arrow key presses searchInput.addEventListener("keydown", function (event) { const suggestions = document.querySelectorAll(".suggestion"); if (event.key === "ArrowDown") { event.preventDefault(); selectedSuggestionIndex = Math.min( selectedSuggestionIndex + 1, suggestions.length - 1 ); } else if (event.key === "ArrowUp") { event.preventDefault(); selectedSuggestionIndex = Math.max(selectedSuggestionIndex - 1, -1); } else if (event.key === "Enter") { event.preventDefault(); if (selectedSuggestionIndex === -1) { searchForm.submit(); } else { window.location = suggestions[selectedSuggestionIndex].querySelector('a').href; } } // Highlight the selected suggestion suggestions.forEach((suggestion, index) => { suggestion.classList.toggle( "selected", index === selectedSuggestionIndex ); }); }); }); </script> Keep in mind that you need some CSS styes to make it look good and actually work. These are my styles(in LESS format) but feel free to write you own stylesheet for this. search.less: .search-wrapper { position: relative; background: @secondary-blue; h4 { color: @primary-blue; } .highlight { color: @primary-red; } } #suggestions { display: none; position: absolute; top: 100%; left: 0; right: 0; z-index: 10; background: @white; .suggestion-list { margin: 0; li { transition: background-color 150ms ease-in-out; a { padding: 10px; display: block; text-align: left; &:hover, &:focus, &:active { text-decoration: none; } } &:hover, &:focus, &:active, &.selected { background: @secondary-blue; } } li + li { border-top: 1px solid @secondary-blue; } } } That's it! Again feel free to adjust all of the code to your needs. If you have any suggestions how to achieve things a bit easier just let me know.1 point
-
If it's only an issue on Apple devices, then it's likely either (1)an update to Safari, or a (2)coincidence that both device's browsers got some sort of strange file corruption in their cache. Another options is that (3)it is just something kind of weird. Give it a day, turn the device(s) fully off and see what happens the next day. Sometimes hardware likes a nice rest, too. You could try hard-refreshing the pages on your Apple devices to see if that helps, or clear cookies and temporary cache (which may also delete saved passwords or logged-in accounts on websites for those devices).1 point
-
Ho, is it possible to config that (for example) the db:pull command will use a ssh-key file and the place would be configurable via the $config options? I mean, i know it can't use my ssh-agent on the host, but it would help in a team env, where you add the keys of the dev's in the authorization file on the server. Never mind, the answer is to load the .ssh in the ddev container... (from the ddev manual) If you use SSH inside the container and want to use your .ssh/config, consider mkdir -p ~/.ddev/homeadditions/.ssh && ln -s ~/.ssh/config ~/.ddev/homeadditions/.ssh/config. Some people will be able to symlink their entire .ssh directory, ln -s ~/.ssh ~/.ddev/homeadditions/.ssh. If you provide your own .ssh/config though, please make sure it includes these lines: UserKnownHostsFile=/home/.ssh-agent/known_hosts StrictHostKeyChecking=accept-new The option can set global, like above in ~/.ddev or per project projectFolder/.ddev1 point
-
Hello, If you want a free module for user registration you can use LoginRegister. There's features to validate emails, manage forgotten passwords and more. For the notifications you can add a checkbox on user template "registered to notifications", and check it when user wants notifications, so later you can find them with $users->find('registeredToNotifications=1'). To build forms for free you can use module InputfieldForm, for example for the form to register to notifications. To send mails you can use PHP mail function, if your server is well configured to send mails.1 point
-
A very nice module, thank you Bernhard! That was a missing function of the Processwire Core ? (even if you could do it via a page)1 point
-
Thanks @bernhard, only just got around to this, but all good now. ?1 point
-
@FireWire I'm still loving the convenience of this module, thanks! I've got a couple questions: When we add new languages to a site soon we're going to have empty language fields all over. If we use "translate to all languages" again to populate these blank language fields any manual edits to existing languages will be overwritten. How easily could the "translate from English" button be added back to co-exist alongside the "translate to all languages" button, so we could just pull individual translations without altering others when needed? Currently when a page is created and I translate the title, I'll have to add a space at the end of each translated title to prompt the page URL to reflect the translation. Would this be difficult to trigger automatically? If these are non-trivial changes, let me know what it would cost to sponsor the work. Thanks!1 point
-
GitHub has recently changed something that now makes it much more difficult to host readme images at GitHub without making them a part of the repo. There has long been a gotcha for previously private repos where if you if you added images before making the repo public then those image URLs wouldn't get the public subdomain. But now it seems that if a public repo has ever been private then GitHub forces the "private-user-images" subdomain, even retrospectively changing image URLs that previously had the public "user-images" sudomain. I can observe this in some of my recent modules where the PW forum post has the public URLs that were copy/pasted from the readme at the time the post was created but the readme at GitHub now has the "private-user-images" subdomain, which is going to make it a real drag to update the forum post when the readme is updated. And GitHub tricks you into thinking the image URLs are publicly accessible (I double-checked in an incognito window to make sure after the previous attempt to fix), but as this post describes the private URLs contain an encoded token that causes the images to expire after 5 minutes, although I don't know how any mere mortal is expected to know that. Presumably GitHub checks the referrer so the expiry doesn't occur when viewing the readme on GitHub itself. So the only solution I can see is manually changing all image URLs from the private to the public subdomain before using them in the readme - you can no longer conveniently use the GitHub image markdown directly from the "issue". I wrote a little Tracy Console script to make the process a bit less painful - might be useful to anyone else who changes repos from private to public and likes to host readme images at GitHub. // Require Simple HTML Dom: https://sourceforge.net/projects/simplehtmldom/ require_once $config->paths->templates . 'TracyDebugger/snippets/simple_html_dom.php'; // Get HTML from issue where images are embedded $html = file_get_html('https://github.com/Toutouwai/ProcessMediaLister/issues/1'); // Process images foreach($html->find('.markdown-body img') as $img) { $alt = $img->alt; $src = $img->src; // Remove query string $pos = strpos($src, '?'); $src = substr($src, 0, $pos); // Replace private subdomain with public subdomain $src = str_replace('private-user-images', 'user-images', $src); // Echo image Markdown for copy/paste into readme echo "![$alt]($src)<br>"; }1 point
-
I get that the gist of this thread is "WP bad", but to be fair I've ran relatively often into the opposite issue in ProcessWire: an image or file that should've been uploaded once and then reused is instead uploaded to a whole bunch of separate pages, using loads of unnecessary disk space. ProcessWire doesn't by itself create a lot of unnecessary variations, but it is not uncommon occurrence either: years of code changes combined with badly configured image fields (no limit for image dimensions) can lead to major disk bloat. Worse yet is when someone decides that a file/image that is separately uploaded all around the place now needs to be updated everywhere. Oh the joy! Long story short: there are cases for and against both central media/asset management and page based media/asset management, neither are perfect. Now what is indeed suboptimal is the way WordPress handles variations: they need to be globally registered, are created on upload (whether you need them or not), and won't be (re)created automatically if registered or changed later. This can absolutely lead to unnecessary disk usage, and on the other hand means that you may not have the variation you were looking for available, or it may not be what you expected it to be. But again, each approach/architecture has upsides and downsides ? -- By the way, I'm not generally against bashing [insert a CMS or any other product here] or venting frustrations about it, but I do think we should try to be fair. WP gets a lot of bad rep for a good reason, there are definitely issues and shortcomings, but it also gets blamed for legacy/aging custom (site/theme specific) code, overuse of third party plugins, outdated third party plugins, etc. None of these are core issues, and it's not really fair to blame them on WP ?1 point
-
Thanks, @ryan! Being here for so many years it feels like home. And everyone in the forums like relatives, even though I never seen them in person and only imagine them as their avatars living somewhere around the globe) So these "winter holidays" celebration posts are kind of like a family reunion, when everybody gathers at a holiday table after a not so easy year passed. Happy new year to everyone! Let it be a better one! С наступающим! Всего хорошего и доброго! ???1 point
-
Hello, ? I've solved the problem with my sitemap and am looking to adapt a script for recursion and here I am looking at code and learning PHP (and English) at the same time. I should have started sooner ? Then, while doing my research, I came across some very interesting contributions and was amazed at the possibilities offered by PW. What a job done! I'm delighted to have finally found what I've been looking for for years. A system that allows me to learn while I work, with enough resources at my fingertips to set up a site. The rest is done at the same time, and there's enough to last a lifetime. I've begun to tell the story in an article I started this morning about my adventure with this CMS-CMF. Visitors will be able to follow the day-by-day progress I've made with it. https://wire.reseauk.info/about/ Merry Christmas to all! ?1 point
-
Hi guys, I'm kinda stuck here. How do you set an InputfieldCheckbox to unchecked via API? I've tried setting it to false, 0, '' and nothing seems to work. Shouldn't be relevant, but I'm using this to control whether a user's password was auto or manually generated. So when a password recovery is requested, I'm doing: $user->setOutputFormatting(false); $user->pass = $randomGeneratedPassword; $user->passwordSet = false; $user->save(); passwordSet is the name of my field. This is generating and saving the random password correctly, but that checkbox stays checked.1 point
-
When working with Checkboxes ("Type: Page Reference - Input field type: Checkboxes - with Page field value type: Multiple pages PageArray" fields, that is), this works: $rs = $pages->find('template=foo, parent=/bar/'); foreach ($rs as $p) { $p->of(false); $p->myCheckboxes = null; // Unset all values first $p->myCheckboxes = 'baz'; // Then set the active checkbox with name (or, use Page ID) $p->save(); }1 point
-
First off I would recommend re-reading this part of the hooks documentation: https://processwire.com/docs/modules/hooks/#conditional-hooks. If we take a closer look at your second code example, here's what it's trying to do: Add hook after the saveField() method of the Pages class has been executed ... but only if the first argument to saveField() contains string value "snipcart_item_image" Now, if you look at the definition of Pages::saveField() ... * @param Page $page Page to save * @param string|Field $field Field object or name (string) ... you can see that the first argument is actually a Page, not a string. In other words your condition doesn't really make sense here — what you're probably looking for is the second argument, which is the name of the field as a string or Field object. The conditional hooks documentation explains how to access a specific argument: $wire->addHookAfter('Pages::saveField(1:snipcart_item_image)', function($event) use($item) { Note: as you can see from the second @param definition, saveField() can receive either a string or an object. If there's a way to target both with conditional hook format, it's something I'm not aware of. I'm afraid that you're making things a bit complicated for yourself by trying to use the conditional hook syntax; it's an advanced feature that has it's use cases, but it's often easier to just hook into some method and "return" if the arguments are not what you are looking for. But, alas — there's a potentially much bigger problem here: when you save a page, ProcessWire doesn't call saveField() for each field individually. I don't know in what context you're trying to make your hook work so I can't say right away how you should write this hook, but I'd be interested to know if you gave my earlier example a try... and if so, did it do anything? If you're trying to change the value right before the page gets saved in the admin, you most likely should be hooking into Pages::saveReady. Or you could hook into Pages::savePageOrFieldReady if you also want to catch single field saves ? Edit: keep in mind that even if you hook into Pages::savePageOrFieldReady, the field name (second argument for said method) is only populated if a single field was saved. The value is not going to be there if an entire page was saved. If you take a look at my previous reply and change it the code sample to use Pages::savePageOrFieldReady, it should actually be pretty close to catching both "full page saves" and single field saves.1 point
-
There are a few problems with that code: Switching $magazine to $page doesn't actually help at all. $page is not defined here either. As I mentioned in my previous post, you're in function context, and in that context you only have access to a) function arguments ($event), b) variables you've made accessible with "use" (currently there are none), and c) global functions. $page is none of those. Another issue is that there's no savedPageOrField method for Inputfield, so Inputfield(...)::savedPageOrField is never triggered — what you're looking for is Pages::savedPageOrField. From your post I assume that you've put this code in the template file, i.e. /site/templates/your_template_name.php? If so, the hook only applies to when you're viewing a page using that template, i.e. it has no effect in Admin. I'm not sure if that's what you really intended, but I'd assume not — more likely you'd want to put this hook somewhere it gets added in the admin as well, so perhaps /site/init.php or /site/ready.php. ... and, finally, even if your code did work, you would've likely ran into an infinite loop: if you hook into page save and save the page, that'll trigger the page save hook, which will then save the page and trigger the page save hook again, which... you know the drill. Pages::saveReady() is often better method to hook, as you can just modify the page values, and they'll get saved soon after (you don't have to call save in your hook) ? In this case something along these lines could work: // hook into Pages::saveReady $wire->addHookafter('Pages::saveReady', function($event) { // get current Page object — in this case this is the first argument for the $event object $page = $event->arguments[0]; // bail out early if current Page *doesn't* have the field we're interested in if (!$page->template->hasField('snipcart_item_image')) return; // ... and also bail out early if the snipcart_item_image field hasn't changed if (!$page->isChanged('snipcart_item_image')) return; // now that we know that snipcart_item_image has changed, set a custom value to another field $page->set('imagecolorat', 'YOUR_NEW_VALUE_HERE'); // finally, populate our modified $page object back to the event $event->arguments(0, $page); }); Note: written in browser and not properly tested.1 point
-
I know you mentioned docs being confusing, but I'd still suggest taking another look at them — specifically this part, as it explains this pretty clearly: https://processwire.com/docs/modules/hooks/#defining-hooks. To simplify things a bit... the key difference between the first two is that $wire->addHookAfter() works outside classes, while $this->addHookAfter() is how you'd usually attach the hook when you're in a method of a class (i.e. while you're working on a module of your own). $page->addHookAfter() attaches the hook to the current Page object (which $page typically refers to), not all Page objects in general. Important distinction in case you're working with multiple pages and don't want your hook to run for all of them. Not sure if that explains it any better than the docs, but again the biggest difference is just the context in which you're defining the hook (use $wire when in template files, /site/init.php, /site/ready.php, /site/admin.php, etc. and $this when you're within a method in a class) and whether you want your hook to apply to a single object ($page, $pages, or a specific item such as $mypage where $mypage = $pages->get('some_selector')) or all items of a specific type. Most commonly you'll need your own hookable methods when you're, say, developing a reusable module. Instead of tweaking the module on a per-site basis, you'll likely want to keep it as-is and rather make some minor modifications by hooking into it's methods. This way you can easily update the module without having to redo or work around your modifications every single time. On some edge cases you might have a utility function on the site, and then depending on some other event you may want to say that "at this specific instance the method should do something else", so you'd want to make it hookable. Can't think of many cases where that'd make sense, though. I'm not sure what you're getting at here. Is this is just an example of what you're doing at the moment? Either way your hook looks fine to me. Should've read this more carefully. You're accessing $magazine object here, but if this is your entire code, that won't work — you're not defining $magazine variable anywhere. Since you're in function scope, you only have access to the arguments passed to that function, variables you've passed in with "use" language construct, and global functions. Even if $magazine exists outside your function, you'd have to pass it in with function($event) use ($magazine) { ... } That being said, what you're probably looking for is something like Pages::savedPageOrField(). If you take a look at that docs page, there are code examples dealing with changes etc. Or, alternatively, Pages::savePageOrFieldReady(), which occurs right before the page/field is saved (which means that you can modify the values right before they are saved to the database). ... and please let me know if I missed your point here ?1 point
-
Once again I make an ass of myself For starters, I was testing the frontend part on the server and looking at the CMS locally. It was all downhill from there. This to say of course setting it to false unchecks the box. Sorry for wasting your time. Now excuse me while I go reflect on life.1 point
-
I just tried it and it works both with 0/1 and true/false. Have you tried the code as is without any conditions?1 point