-
Posts
1,331 -
Joined
-
Last visited
-
Days Won
61
Everything posted by BitPoet
-
I live on the countryside too, but I had to travel to another town to restock toilet paper on Friday because every single one of our eight supermarkets and drug stores was out of stock. I finally got a pack (one out of the last three) in a neighbor town. People are hoarding like crazy. I saw a few customers with trolleys heaped with paper towels and pasta. Stupid. But if you look at the run for toilet paper, you know what's in their minds... But yes, most people around here are both realistic and calm, thankfully. At work, we have a revolving home office schedule now in most departments to make sure that we can have staff on site in case those present at the office have to quarantine. Business is slowing down because negotiation meetings can't happen in person. But all that (as always in changing circumstances) means more work for our department for now to get as many colleagues as possible set up to work from home, i.e. additional VPN lines, laptops, remote desktops, e-learning, conferencing software etc. All things which we were already rolling out to everyone, but what was planned over the course of a year now has to happen within days and on top of ongoing major projects. So the weekends are going to get even shorter, and instead of implementing planned features in software, it's now more about tying things together to get everybody's remote work experience to lift off flawlessly. For me personally, things got turned on the head because I was about to start the last four weeks of work before my half year sabbatical. After years of planning, I was about to thru-hike the Pacific Crest Trail from Mexico to Canada. I had my visa approved, gear bought, flight booked, the first stays before the trail arranged, my post re-routed and thousands of other little things taken care of. It's simply not feasible now. 5/6 of the trail go through what are now deemed high risk states California and Washington, and people there are going to have their own problems without me adding to it. Even if I found a way to hike there, I couldn't do so with a good conscience and leave family and friends here in such uncertain times. I thankfully can postpone my sabbatical to next year, but there's always an uncertainty about such massive undertakings. But such things suddenly became far less important. It's about keeping people safe and being there for those who do or might need me right now. Here in Germany, we're hitting exponential growth in numbers (from 157 new infections on Wednesday, to 271 on Thursday, then 802 on Friday and about 1800 yesterday). There will be no way around more restrictions similar to those in the countries around us.
-
WireCache question about storing JSON strings
BitPoet replied to baronmunchowsen's topic in API & Templates
There's already a github issue about this. Perhaps give it an upvote? -
WireCache question about storing JSON strings
BitPoet replied to baronmunchowsen's topic in API & Templates
WireCache tries to be smart (too smart) when it finds a valid json string because it uses json to serialize array data for storing. So any string that look like json gets json_decode()ed into an array. It's kind of a known bug because there is currently only a part of a fix implemented in WireCache. A workaround can be to prefix your string to break WireCache's json recognition and strip it after retrieval, like this: $response = substr($this->cache->get('mycache', 60, function() { return 'JSON{ "glossary": { "title": "example glossary", "GlossDiv": { "title": "S", "GlossList": { "GlossEntry": { "ID": "SGML", "SortAs": "SGML", "GlossTerm": "Standard Generalized Markup Language", "Acronym": "SGML", "Abbrev": "ISO 8879:1986", "GlossDef": { "para": "A meta-markup language, used to create markup languages such as DocBook.", "GlossSeeAlso": ["GML", "XML"] }, "GlossSee": "markup" } } } } }'; }), 4); -
Adding a custom Page Reference field to ProcessPageEditLink
BitPoet replied to a-ok's topic in General Support
Not with the built-in anchor select. If you don't mind a bit of regex ugliness: wire()->addHookAfter("ProcessPageEditLink::execute", function(HookEvent $event) { $page = wire('pages')->get((int)wire('input')->get('id')); if(wire('input')->get('href')) { $currentValue = wire('sanitizer')->url(wire('input')->get('href'), array( 'stripQuotes' => false, 'allowIDN' => true, )); } else { $currentValue = ''; } $inp = wire('modules')->get('InputfieldSelect'); $inp->attr('id+name', 'select_anchor'); $inp->label = wire()->_('Select Repeater Anchor'); $inp->icon = 'anchor'; $inp->collapsed = $currentValue ? Inputfield::collapsedNo : Inputfield::collapsedYes; // Instead of addOptions here, fill your select however you want $inp->addOptions([ "" => "", "#some_anchor" => "some_anchor_text", "#other_anchor" => "other_anchor_text", "#third_anchor" => "third_anchor_text" ]); if($currentValue) $inp->attr('value', $currentValue); $wrap = new InputfieldWrapper(); $wrap->append($inp); // It's a bit ugly, but to get our InputfieldSelect to render correctly, we need // it rendered by an InputfieldWrapper. We do that, then strip out the wrapping // parts afterwards (i.e. everything before the first <li> and after the last </li>). $html = $wrap->render(); $html = preg_replace('~^.*?(?=<li\b)~is', '', $html); $html = preg_replace('~</li>.*?$~is', '', $html); $js = '<script> $("#select_anchor").bind("change", function(evt) { $("#link_page_url_input").val($(evt.target).val()).change(); }); </script> '; $html .= $js . "</li>"; $event->return = preg_replace("~(?=<li[^>]+id='wrap_link_page_file')~", $html, $event->return); }); -
Adding a custom Page Reference field to ProcessPageEditLink
BitPoet replied to a-ok's topic in General Support
It looks at the HTML in the CKEditor field you're triggering PWLink from, but that shouldn't matter anyway. This is how it should look: The anchor select only appears if there are anchors in the array. What does bd($anchors) say before it's assigned to the input var? -
Adding a custom Page Reference field to ProcessPageEditLink
BitPoet replied to a-ok's topic in General Support
The builtin feature means that PW parses the HTML for named anchors, and if found, adds a "Select Anchor" select box at the top right. Did you remove the if($page->template...) line in my example? This was just meant for demonstration of limiting the functionality to a certain template. -
@ryan, I just fiddled with custom Page classes and hit the same issue as @rafaoski. I can access every Page property from methods in my custom class but not createdUser and modifiedUser. <?php namespace ProcessWire; class BasicPagePage extends Page { public function myMethod() { $creator = $this->createdUser; var_dump($creator); // Outputs: // NULL $creator = $this->get('createdUser'); var_dump($creator); // Outputs: // object(ProcessWire\User)#214 (7) { // ["id"]=> // int(41) // ["name"]=> // string(5) "admin" // ["parent"]=> // string(26) "/processwire/access/users/" // ["template"]=> // string(4) "user" // ["email"]=> // string(15) "nobody@invalid" // ["roles"]=> // string(17) "(PageArray) 37|38" // ["data"]=> // array(2) { // ["email"]=> // string(15) "nobody@invalid" // ["roles"]=> // object(ProcessWire\PageArray)#189 (3) { // ... // } } } Calling $page->createdUser->name from outside works, though. Inside the class, $this->createdUser never hits Page::__get().
-
Not without a hook, but this should work: // Hook for site/ready.php that makes $page->render($fieldname) look for // its template in site/templates/$templatename/fields/$fieldname.php. // Specifying alternative files still works. // Pass a path with a leading slash as $file to go directory from the templates dir. $storedFieldTemplates = []; $this->addHookBefore("Page::renderField", function(HookEvent $event) use($storedFieldTemplates) { $page = $event->object; $file = $event->arguments(1); $storedFieldTemplates[] = $this->config->paths->fieldTemplates; $this->config->paths->fieldTemplates = substr($file, 0, 1) == '/' ? $this->config->paths->templates : $this->config->paths->templates . $page->template->name . "/fields/"; }); $this->addHookAfter("Page::renderField", function(HookEvent $event) use($storedFieldTemplates) { $this->config->paths->fieldTemplates = array_pop($storedFieldTemplates); }); Shortens it down to $article->render('article_lead', 'lead')
-
Adding a custom Page Reference field to ProcessPageEditLink
BitPoet replied to a-ok's topic in General Support
Here's a quick and dirty demo how to add your own anchors to the builtin anchor feature of ProcessPageEditLink. No form manipulation shenanigans and no JS either. ? wire()->addHookBefore("ProcessPageEditLink::execute", function(HookEvent $event) { $page = wire('pages')->get((int)wire('input')->get('id')); // Limit to a certain template type: if($page->template->name !== 'home') return; $anchors = is_array(wire('input')->get->anchors) ? wire('input')->get->anchors : []; // This is the spot to add your own annotation anchors: $myAnchors = [ "some_anchor", "other_anchor", "third_anchor" ]; $anchors = array_merge($anchors, $myAnchors); wire('input')->get->anchors = $anchors; }); -
Have you also installed the FieldtypeToggle module?
-
Not sure if you need to change open_basedir at all. The line in question chdir()s back into the directoy PHP was in when TemplateFile::render was invoked, so it is a bit strange that it would go into the root directory at all. Perhaps a chdir("/home/runcloud/webapps/app-sitename"); inside site/ready.php already cures the problem.
-
@astock, you don't have the lists you mention anywhere in your code. $abgestimmt = []; foreach ($datenbank->query($sql) as $row) { $teilnehmer = $users->get($row['user_id']); $antwort = $pages->get($row['vote_id']); echo "<tr>"; echo "<td>".$teilnehmer->nachname.", ".$teilnehmer->vorname."</td>"; echo "<td>".$antwort->title."</td>"; echo "</tr>"; // This first part works nice! // And here we fill the list of users who have already voted $abgestimmt[] = $teilnehmer; } $alleUser = $users->find("start=0"); // Now we remove the users who have voted and iterate // over the rest foreach($alleUser->removeItems($abgestimmt) as $nutzer) { $nu = $nutzer->nachname.$nutzer->vorname; $tn = $teilnehmer->nachname.$teilnehmer->vorname; echo $nu; }
-
Get admin page used for module setup
BitPoet replied to J_Szwarga's topic in Module/Plugin Development
You can get the page directly by calling $module->getProcessPage() -
A little hack like this for site/ready.php might be enough for that (only tested on desktop and not perfect when it comes to alignment): $this->addHookAfter('ProcessPageEdit::execute', function($event) { $event->return .= "<script> $('#pw-content-head-buttons').css('position', 'fixed'); $('#pw-content-head-buttons').css('right', '5%'); </script> "; });
-
Here's a small new module that started as a spinoff of a memcache proof-of-concept. Cache your strings and partials in-memory using Redis as a backend. CacheRedis All you need is a running Redis database. The module supports connection through regular TCP, over TLS and via unix domain sockets. Host and port are configurable, and authentication is supported too. Here's a screenshot of the module configuration options: I'll not go into too many details about the usage, you can see everything explained in the README on GitHub, and just highlight the most important points. When the module is active, you'll have a wired $redis variable, which means you can reach the module as $redis, wire("redis") or within Wire classes / modules as $this->redis. CacheRedis is strongly influenced by WireCache, and its usage is (hopefully) straight forward. // Store an entry in the cache under the given key name with the given value: $redis->store("cached_value_number_one", $expire, $value); // Retrieve a value from the cache $value = $redis->fetch($key); // Delete a cache entry $redis->delete("my_other_cached_value"); // Clear the whole cache $redis->flush(); // Retrieve a value from the cache, and if not found, create it through the given function // and store it with a lifetime of 5 minutes (300 seconds) $value = $redis->fetch($key, 300, function() use($page) { return "Page last changed on " . strftime('%m/%d/%Y %H:%M', $page->modified | $page->created); }); // Render a file using wireRenderFile and store it in the cache. // We'll pass a selector as the expiry value so this cache gets // emptied every time a page matching the selector is saved. $news = $redis->renderFile("partials/news.php", 'template=blog-post', ["page" => $page]); The module is still very crude work in progress, but I hope some of you feel daring, try it out and let me know in case anything breaks. Have fun!
- 11 replies
-
- 20
-
-
-
That can be a major factor, but you can speed that up a lot by using opcode caching, i.e. OPcache on *nix operating systems or WinCache on windows.
-
Why not just mount the volume as site/assets/files and copy the existing folders there?
-
Almost every time I find one of these interesting ML/AI/Science based Python projects I want to include in my own work, I run in major compatibility issues. Either a bound C library has changed its signature too much, or the Python lib never got adapted to version 3 (or 3.7 and another lib needs native types). To me it seems like Python is partly a graveyard of university projects nobody cared to continue. Not that Python is bad in general. When Google app engine support for Python came out I implemented a service together with two other devs (extending in-game functionality of a virtual world) that took up to a few million hits per day and was lots of fun to build. But developing in Python can easily become a package version nightmare, and most tutorials out there just ignore that, which adds a steep learning curve if you want to do complex projects in Python. pyenv and pipenv, which came out last year, only address parts of that. This xkcd is quite fitting I think ? I for one also have a (subjective) aversion to languages where whitespace has too much meaning. If you ever learned Cobol, you probably know what I mean...
-
@astock: I just checked the code. While the hasVoted method is called before renderPoll(), it doesn't get the current user. I have added a github branch with a fix if you want to give it a spin.
-
I've kept hearing that one for the last twenty years, yet here we are. I think that's enough said ?
-
It's been a while since I did that, but I'm pretty sure it worked. Can you share the relevant code for the poll from your template?
-
I've dabbled a bit and adapted my cache module to work with Redis (working mostly on Windows, this was a bit of an adventure, but Windows Subsystem For Linux saved the day). CacheRedis - a simple Redis cache interface for ProcessWire There should be enough documentation to get started in the README. In short, it has the following methods: $redis->fetch($key[, $expire, $func]) $redis->store($key, $expire, $value) $redis->delete($key) $redis->flush() $redis->renderFile($file[, $expire[, $options]])
-
Do you have a namespace declaration in your template?
-
What I know has been pieced together from official docs and discovered through trial and error, so I can't provide a good link there. However, I've pushed a few pieces into a small module based on Memache that can be a (partial) stand in for WireCache as an example. You can find it on github as PwMemcache. It has just a few methods to set/get/delete cache entries and doesn't allow saving and restoring of full pages like WireCache does, but it does have a renderFile method similar to WireCache. Maybe that could be a starting point. Most of the magic in using memory caches is using well thought out cache keys to avoid conflicting names (you're likely to use them more intensively than database caching) using reasonable expiry values (same as with database caches) preventing outdated data (e.g. by deleting entries when pages are changed, there's little 'automatic magic' there) taking care of special considerations when data is serialized and later unserialized, since behavior differs between solutions How exactly that best goes depends on the features of the caching solution. Unlike WireCache, many in-memory solutions have no wildcard deletion operators, so you sometimes have to build workarounds. My module for example does this when you pass PwMemcache::expireSave to the renderFile method. The cache contains an extra array where all the entries are stored that have to be cleared when a page is saved. In a Pages::saved hook, this entry is read, all cache entries listed in the array are deleted and the entry is emptied.