Jump to content

abdus

Members
  • Posts

    743
  • Joined

  • Last visited

  • Days Won

    42

Everything posted by abdus

  1. It does run find() on every loop, but PW caches pages as it fetches them from the DB, so subsequent calls to the same page will be made in memory without touching the db again. From /wire/core/PagesLoaderCache.php /** * Cache the given page. * @param Page $page * @return void */ public function cache(Page $page) { if($page->id) $this->pageIdCache[$page->id] = $page; }
  2. I haven't used the module, but because it's not an autoload module, you can include autoloader before you call the module, or in your config file it doesn't matter, as long as it's before module instantiation. But, after PW 3.0, there's composer support, so if you have composer installed, you can: - cd into root directory of your pw setup - Run composer require google/apiclient:^2.0 PW will pick up the library and autoload it for you. Then, in your template file, say, events.php, you can use the module as it's documented in the blog post. $google = $modules->GoogleClientApi;
  3. Don't worry about it. At a rate of one post/day, it takes ~30 years to hit that point. Even at hundreds of post you won't have an issue. If you hit that point, there's $pages->findMany() method for you. One thing I've noticed is you're not limiting the amount of posts under a category. What happens when a category has tens of posts while another has only 1-2? With three column layout you'll get a very long column that will push others down quite a bit. (Unless you set up a masonry layout.)
  4. I understand. No need to overengineer a simple blog. But check out the module description. Maybe not with this project but @Robin S gives a few use cases, which I'm sure you'll find quite useful later on.
  5. I also recommend using built-in InputfieldPageAutoComplete, install it from Modules > Core and change categories field to use autocomplete. It's much easier to seach and pick categories with it. There's also selectize and chosen js alternatives as well https://modules.processwire.com/modules/inputfield-selectize/ https://modules.processwire.com/modules/inputfield-chosen-select/
  6. Also, for 2-way relations, like posts under a certain category vs. categories of a post you can use @Robin S's Connect Page Field module. It's really handy. I use it for ordering categories by number of posts under each category. https://modules.processwire.com/modules/connect-page-fields/
  7. I'd pluralize category -> categories and display a list of categories with 3-4 posts under each category. Then you can display a category under /categories/processwire or use urlSegments to rename that to /category/processwire. Or just render category list at /categories with urlSegments and redirect /category to /categories. What I normally do is keep categories under /blog/categories/. Everything works just fine with no need for urlSegments. One handy tool when using urlSegments is to hook into Page::path and modify $event->return, so you won't have to manually building urls everywhere you need. You still need to implement urlSegment logic though, changing Page::path is a passive operation, it doesnt change routing behavior
  8. Glad to help I'm intrigued, though. I thought Empty Cache and Hard Reload affected just the asset/file cache. Does chrome cache redirects too? Or how can file cache stop fields from being saved? Also, a useful hook to keep around. To refresh module cache on superuser login: $this->addHookAfter('Session::loginSuccess', function (HookEvent $e) { /** @var User $user */ $user = $e->arguments('user'); if ($user->isSuperuser()) { $e->modules->refresh(); } });
  9. Looking at ProcessField.module, this is where a field is saved // ProcessField.module public function ___executeAdd() { // unrelated shortcut feature: double check that all field tables actually exist // and re-create them in instances where they don't (like if a bunch of fields // were migrated over in an SQL dump of the "fields" table or something). $this->wire("fields")->checkFieldTables(); return $this->executeEdit(); } public function ___executeEdit() { // ... if($this->field->id) { $headline = sprintf($this->_x('Edit Field: %s', 'edit headline'), $this->field->name); // Headline when editing a field } else { $headline = $this->_x('Add New Field', 'add headline'); // Headline when adding a field } // ... return $out; } And this is the checkFieldTables() method protected function checkFieldTable(Field $field) { // if(!$this->wire('config')->debug) return; $database = $this->wire('database'); $table = $database->escapeTable($field->getTable()); if(empty($table)) return; $exists = $database->query("SHOW TABLES LIKE '$table'")->rowCount() > 0; if($exists) return; try { if($field->type && count($field->type->getDatabaseSchema($field))) { if($field->type->createField($field)) $this->message("Created table '$table'"); } } catch(\Exception $e) { $this->trackException($e, false, $e->getMessage() . " (checkFieldTable)"); } } Here I can deduce: There's something wrong with the field table, it already exists but PW cant associate the field with its id/table? $field->type is empty string or field does not return a schema. Having null fieldtype probably means something wrong with the Module cache, refreshing cache may help. Going forward, this is how field table is created public function ___createField(Field $field) { $database = $this->wire('database'); $schema = $this->getDatabaseSchema($field); if(!isset($schema['pages_id'])) throw new WireException("Field '$field' database schema must have a 'pages_id' field."); if(!isset($schema['data'])) throw new WireException("Field '$field' database schema must have a 'data' field."); $table = $database->escapeTable($field->table); $sql = "CREATE TABLE `$table` ("; foreach($schema as $f => $v) { if($f == 'keys' || $f == 'xtra') continue; $sql .= "`$f` $v, "; } foreach($schema['keys'] as $v) { $sql .= "$v, "; } $xtra = isset($schema['xtra']) ? $schema['xtra'] : array(); if(is_string($xtra)) $xtra = array('append' => $xtra); // backwards compat: xtra used to be a string, what 'append' is now. $append = isset($xtra['append']) ? $xtra['append'] : ''; $sql = rtrim($sql, ", ") . ') ' . $append; $query = $database->prepare($sql); $result = $query->execute(); if(!$result) $this->error("Error creating table '{$table}'"); return $result; } From here it seems you'd get an error if table couldnt be created, so no issues with table creation. Also you've mentioned that duplication works fine. These are somewhat obvious deductions from the source code. But, to me, everything points to fields table in the DB.
  10. For the last week or so, a number of accouts have started to post status updates with (mostly) unrelated content. I've checked out the submission histories of ~20 of them, and none of them has a recent post. They were registered long time ago and made several status updates over time. I started noticing them after the last week's forum update. Something about it allowed these status updates to surface, and now around ~10-15 updates are posted daily, which is enough to flood the activity stream. Is anyone else bothered by this? These are from the last 24 hours
  11. You're right, it should be like you said, I mixed those up. Glad you've solved your problem
  12. You need to set 755 660 for files and 660 755 for directories. This should help: https://processwire.com/docs/security/file-permissions/#how-to-change-permissions-of-existing-files
  13. I've found a cleaner way to modify prepend/append files depending on the current page. wire()->addHookBefore('PageRender::renderPage', function (HookEvent $e) { /** @var Page $page */ /** @var HookEvent $event */ /** @var Template $template */ $event = $e->arguments(0); $options = $event->arguments(0); $page = $event->object; $template = $page->template; $options['prependFiles'] = [ "{$template}.routes.php", "_common.php", ]; $options['appendFiles'] = [ "views/{$template}.php", "_after.php", "layouts/main.php", ]; $event->setArgument(0, $options); }); The older way felt too much like a hack to me. To early exit and skip including remaining files during render, use `return $this->halt();` anywhere in your templates.
  14. When adding link ProcessPageEditLink module checks for file fields on the page and repeater items. And does a recursion when it encounters a repeater field. Reading the core, it looks like getting the type of a field fails (field->type == null) and causes the error. Which version of PW are you using? Do you have a repeater field on the page? Uninstalled a fieldtype? Removed a field from repeater field or the page's template? Tried repairing the DB? protected function getFilesPage(Page $page, $prefix = '') { $files = array(); foreach($page->template->fieldgroup as $field) { /** @var Fieldtype $type */ $type = $field->type; if($type instanceof FieldtypeFile) { $value = $page->get($field->name); if($value) foreach($page->get($field->name) as $file) { $files[$file->url] = $prefix . $field->getLabel() . ': ' . $file->basename; } } else if(wireInstanceOf($type, 'FieldtypeRepeater')) { $value = $page->get($field->name); if($value) { if($value instanceof Page) $value = array($value); if(WireArray::iterable($value)) { foreach($value as $repeaterPage) { $files = array_merge($this->getFilesPage($repeaterPage, $field->getLabel() . ': '), $files); } } } } } return $files; }
  15. @kongondo You wont be creating these files manually of course, you extend logic for the signup form to create the files for you. Then in index.config.php, you parse, merge and return the array. Something like this function ProcessWireHostSiteConfig() { $configDir = __DIR__ . '/.config/'; $files = wire()->files; $siteConfigs = $files->find($configDir, [ 'extensions' => ['yaml'] ]); $sites = []; foreach ($siteConfigs as $cfg) { $config = yaml_parse_file($cfg); // needs better sanitization $isValidConfig = true; if (!$isValidConfig) continue; $sites[$config->domain] = $config->siteDir; } $sites['*'] = 'site'; return $sites; }
  16. Why not create a simple JSON/YAML config file (one for each domain) in a folder with strict permissions then in your index.config.php parse all files in the folder to build your array? Or from a small sqlite db if that's your thing. http://php.net/manual/en/book.sqlite3.php http://php.net/manual/en/yaml.examples.php
  17. Thread pagination in listings overlaps meta info. Pagination links probably need display: inline-block
  18. I have a template my-template that has a page reference field myUser. The field is set to a user with custom template (using $config->advanced). When I try to filter pages with my-template whose myUser.name or myUser.title includes a certain keyword, I get inconsistent results. Here's what I mean: // works because tom is an exact match $pages->find("template=my-template, myUser.name=tom"); // doesnt work even though myUser name is 'tom' $pages->find("template=my-template, myUser.name*=tom"); // doesnt work despite myUser's title being 'Your Mom' $pages->find("template=my-template, myUser.title*=tom"); // doesnt work $pages->find("template=my-template, myUser.title|myUser.name*=tom"); // doesnt work at all $pages->find("template=my-template, createdUser.name*=tom"); // works $pages->find("template=my-template, anotherPageField.title*=value"); // works $pages->find("template=my-template, anotherPageField.title|anotherPageField.body*=value");
  19. Some debugging ideas: // check which fields are added to the page dump($page->fields->explode('name')); dump($pages(1)->fields->explode('name')); // get the first page reference field of the page $pageFieldName = $page->fields->findOne('type=FieldtypePage')->name; dump($page->$pageFieldName);
  20. Both should work as long as they have a name=submit and a non-empty value <input type="submit" value="submit"> <button type="submit" value="1">Submit</button> When accessing a field with $input->post->myField, you get empty string if that field is not filled, or its value attribute does not exist. It should not return you false.
  21. It doesn't really matter, but high quality source gives you higher quality thumbnails. However, in both cases, unless _web is an very low quality version of _flat, the difference between the results wouldn't even be noticable. One thing to note, however, lower resolution images take less time & cpu to work on, so I guess you should go with _web version.
  22. I don't have that behavior. Can you post your code? If your inputs do not have name attribute, they wont be sent with POST requests This is my test setup: <?php namespace ProcessWire; ?> <style> form { max-width: 500px; margin: 5rem auto; } input { display: block; width: 100%; } </style> <form method="POST"> <div class="inputs"> <input name="myField[]" type="text"> </div> <hr> <button id="addMore" type="button">Add More Inputs</button> <hr> <button type="Submit" name="submit" value="submit">Submit Form</button> <hr> <?php if ($input->post->submit): // DUMP POST DATA ?> <pre><?= wireEncodeJSON($input->post->getArray(), true, true) ?></pre> <?php endif; ?> </form> <script> let addMore = document.getElementById('addMore'); let inputs = document.querySelector('.inputs'); addMore.addEventListener('click', function () { let newInput = document.createElement('input'); newInput.placeholder = Math.round(Math.random() * 1000); newInput.name = 'myField[]'; inputs.appendChild(newInput); }); </script> I add new text inputs with JS. When I post, I can get the values with no problem.
  23. Check out Pageimage::size() method https://processwire.com/api/ref/page-image/size/ <?php namespace ProcessWire; $img = $page->images->first; $img1x = $img->size(300, 400)->url; $img2x = $img->size(600, 800, ['quality' => 70])->url; $img3x = $img->size(1200, 1600, ['quality' => 60])->url; ?> <img src="<?= $img1x ?>" srcset="<?= $img1x ?> 1x, <?= $img2x ?> 2x, <?= $img3x ?> 3x" alt="">
  24. Here are my generic versions WireArray::map wire()->addHookMethod('WireArray::map', function (HookEvent $e) { $func = $e->arguments(0); if (!is_callable($func)) throw new WireException('first argument must be a callable function'); $mapped = array_map($func, $e->object->getArray()); $e->return = $mapped; }); WireArray::reduce wire()->addHookMethod('WireArray::reduce', function (HookEvent $e) { $func = $e->arguments(0); $initial = $e->arguments(1) ?? []; if (!is_callable($func)) throw new WireException('first argument must be a callable function'); $reduced = array_reduce($e->object->getArray(), $func, $initial); $e->return = $reduced; }); WireArray::forEach wire()->addHookMethod('WireArray::forEach', function (HookEvent $e) { $func = $e->arguments(0); if (!is_callable($func)) throw new WireException('first argument must be a callable function'); $foreached = []; foreach ($e->object as $i => $item) $foreached[] = $func($item, $i); $e->return = $foreached; }); Tests $mapped = $pages->find('id>0, parent=2')->map(function($page) { return [ 'title' => $page->title, 'id' => $page->id ]; }); $reduced = $pages->find('template=post')->reduce(function($carry, $item){ $carry[] = $item->id; return $carry; }, []); $foreached = $pages->find('template=post')->forEach(function($item){ echo $item->id . '<br>'; }); dump($mapped); dump($reduced); dump($foreached); Which outputs array (4) 0 => array (2) title => "Pages" (5) id => 3 1 => array (2) title => "Setup" (5) id => 22 2 => array (2) title => "Modules" (7) id => 21 3 => array (2) title => "Access" (6) id => 28 array (8) 0 => 1024 1 => 1026 2 => 1028 3 => 1031 4 => 1033 5 => 1058 6 => 1062 7 => 1065 1024 1026 1028 1031 1033 1058 1062 1065 array (8) 0 => null 1 => null 2 => null 3 => null 4 => null 5 => null 6 => null 7 => null 29.59ms, 0.06 MB
  25. When editing a comment font-size of editor contents are much larger than that of comments.
×
×
  • Create New...