Leaderboard
Popular Content
Showing content with the highest reputation on 09/05/2017 in all areas
-
Since I had nothing to do, I went ahead, and implemented a form as a proof of concept. This works with `jobs` and `currentJobs` setup. When you submit and check the person page Here's the code: <?php namespace ProcessWire; /* @var $input WireInput */ /* @var $sanitizer Sanitizer */ /* @var $pages Pages */ if(input()->requestMethod('POST')) { $jobs = []; foreach ($input->post->hasJob as $jobId) { $jobs[] = $sanitizer->int($jobId); } $currentJobs = []; foreach ($input->post->currentJobs as $currId) { // make sure person has the current job in his jobs if(!in_array($currId, $jobs)) continue; $currentJobs[] = $sanitizer->int($currId); } $p = new Page(); $p->template = 'person'; $p->parent = 1076; $p->name = 'name-lastname'; $p->jobs = $jobs; $p->currentJobs = $currentJobs; $p->save(); return $this->halt(); } $jobs = pages('template=profession'); ?> <form method="POST"> Pick your jobs: <table> <thead> <tr> <td></td> <td>Job Title</td> <td>Current?</td> </tr> </thead> <tbody> <?php foreach ($jobs as $job): ?> <tr class="job"> <td><input class="job__has" id="job<?= $job->id ?>" type="checkbox" name="hasJobs[]" value="<?= $job->id ?>"></td> <td><label class="job__title" for="job<?= $job->id ?>"><?= $job->title ?></label></td> <td><input class="job__current" disabled type="checkbox" name="currentJobs[]" value="<?= $job->id ?>"></td> </tr> <?php endforeach; ?> </tbody> </table> <button type="submit" name="submit" value="1">Submit</button> </form> <script> let jobs = document.querySelectorAll('.job'); [].slice.call(jobs).forEach(job => { job.addEventListener('click', function (e) { if(!e.target.classList.contains('job__has')) return; if (e.target.checked) { job.querySelector('.job__current').removeAttribute('disabled'); } else { let current = job.querySelector('.job__current'); current.checked = false; current.setAttribute('disabled', 'disabled'); } }); }); </script>2 points
-
@noelboss - have you tried using TracyDebugger yet? You could get that going and then troubleshoot the contents of the $page in the profile editor; you may also be able to see warnings and errors when using Tracy. Using it is pretty much required if you are doing any serious dev work in the backend.2 points
-
Here's how I did it. Searching, sorting, filtering, pagination all works <?php namespace ProcessWire; /* @var $config Config */ /* @var $pages Pages */ /* @var $input WireInput */ /* @var $sanitizer Sanitizer */ // fields to return $fields = ['id', 'name', 'publishedStr', 'createdStr']; if ($config->ajax) { // sanitize inputs $search = $sanitizer->selectorValue($input->get->queries['search']); $sorts = []; if ($input->get->sorts) { foreach ($input->get->sorts as $f => $direction) { $key = $sanitizer->fieldName($f); $direction = $sanitizer->int($direction, ['min' => -1, 'max' => 1]); if ((!$key) || (!$direction)) continue; $sorts[$key] = $direction > 0 ? '' : '-'; // sort=field or sort=-field } } $page = $sanitizer->int($input->get->page, ['min' => 0, 'blankValue' => 1]); $perPage = $sanitizer->int($input->get->perPage, ['min' => 10, 'max' => 100, 'blankValue' => 10]); $offset = $sanitizer->int($input->get->offset, ['min' => 0]); // base selector $selector = [ "id>0", "include=all", ]; $selectorFiltered = array_merge($selector, [ "name|title*=$search", // change fields to search ]); $selectorFilteredLimited = array_merge($selectorFiltered, [ "limit=$perPage", "start=$offset" ]); // include sorts as sort=(-)fieldName foreach ($sorts as $f => $d) { $selectorFilteredLimited[] = "sort={$d}{$f}"; } // perform database query $totalCount = $pages->count(join(', ', $selector)); // # of all pages $queryCount = $pages->count(join(', ', $selectorFiltered)); // # of filtered pages $pageData = $pages->find(join(', ', $selectorFilteredLimited))->explode($fields); // data to return // output json header("Content-type: application/json"); $data = [ 'records' => array_values($pageData), 'queryRecordCount' => $queryCount, 'totalRecordCount' => $totalCount ]; echo json_encode($data); // stop return $this->halt(); } ?> <?php if (!$config->ajax): ?> <table class="table"> <thead> <tr> <?php foreach ($fields as $field): ?> <td><?= $field ?></td> <?php endforeach; ?> </tr> </thead> <tbody></tbody> </table> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css"> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/Dynatable/0.3.1/jquery.dynatable.min.js"></script> <script> $('table').dynatable({ dataset: { ajax: true, ajaxUrl: '.', // current page ajaxOnLoad: true, records: [] } }); </script> <?php endif; ?> Here's a screenshot Although I think the code is clear, feel free to ask me if you have any questions. https://processwire.com/api/ref/wire-array/explode/ https://processwire.com/api/ref/sanitizer/ https://processwire.com/api/ref/pages/count/ https://processwire.com/blog/posts/processwire-2.6.8-brings-new-version-of-reno-admin-theme-and-more/#new-this-gt-halt-method-for-use-in-template-files2 points
-
This is the "Sticky CKE toolbar" feature located in the RenoTweaks. I'm also using it and most of the ime it works fine but sometimes there's a jump when the toolbar goes to fixed position and its height is changing. There's a "Fixed" CKEditor plugin that never worked well for me (even with the fix in their forums) so I revisited this again today and found a nice and easy solution using position:sticky. This works in latest browsers only but I think it's still better than the current one - no hacky JS/CSS, and works with multiple editors too. I'll upload this new version soon, until that you can uncheck this feature.2 points
-
Hmm, most lightboxes use <a> with an <img> inside. Href for <a> points to portrait image, and src of the image points to square image. For instance: baguetteBox uses following scheme for responsive images (for non-responsive, remove data-at-# attributes) <a href="img/2-1.jpg" data-at-450="img/thumbs/2-1.jpg" data-at-800="img/small/2-1.jpg" data-at-1366="img/medium/2-1.jpg" data-at-1920="img/big/2-1.jpg"> <img src="img/thumbs/2-1.jpg"> </a> This can be achieved with a code like this. You can modify hook to get rendered markup as well. <?php $image = $page->images->first; $square = $image->size(400, 400); // cropped around center $portrait = $image->width(600)->url; // non-cropped $portrait2x = $image->width(1200)->url; $markup = "<a href='$portrait' data-at-1200='$portrait2x'><img src='$square' /></a>"; echo $markup; You can specify different crop location as a third argument to size() method https://processwire.com/api/ref/pageimage/size/2 points
-
1 point
-
Hello @fisnik, have a look at the $session variable: https://processwire.com/api/variables/session/ https://processwire.com/api/ref/session/ It works similar to a cookie, but lasts only as long as the browser is opened, as far as I know. If you want to save the cookie for a longer duration, I can recommend using JavaScript Cookie. Regards, Andreas1 point
-
Amazing, but I would love to be able to select this to display in a tab without the label (but the label would be used as the tab title).1 point
-
1,2,3) There is a module called Hanna Code which can do most shortcode functionality you would need. Also the Oembed Textformatter can handle a lot of those things: http://modules.processwire.com/modules/textformatter-oembed/ http://essence.github.io/essence/ Spotify, Instagram, Youtube are listed. 4. In terms of building content as you linked to, that article is composed of stacked containers, so you'd most likely be building that type of content with a Repeater Matrix. 5. Gif insertion into the RTE should be no problem AFAIK. 6. I've never had any problem creating galleries; it comes down to writing code. 7. There is built in cropping and there is a Crop Image module; they both work differently. PW has the most advanced photo manipulation capabilities of any CMS, and thanks to @horst for all of his work in that area.1 point
-
Page table is basically a custom table in DB, so you can add any column you want. Instead of using pages like repeaters, with table field, every record is a row in DB with the columns you define. $page->of(false); // turn off output formatting, if necessary $award = $page->awards->makeBlankItem(); $award->title = "Tallest Building"; $award->date = "2014-05-01"; $award->category = "Engineering"; $award->url = "http://di.net/tallest/building/award/"; $page->awards->add($award); $page->save('awards'); As you see using Table field is very straightforward. But one glaring problem is to get 2-way relations for getting jobs a certain person have or people that have a certain job. For that you probably need a custom module that updates a job page with the person that added a job to its table field and vice versa. But now thinking of it you can still use page fields `jobs` and `currentJobs` and make it work. I'm not sure how you render your form on the front end, but you can render a list of jobs with a checkbox to mark as current. Then when you post your data with AJAX or HTTP request, you add all jobs to `jobs` field and filter current jobs (that user checked) and add those to `currentJobs` field. I'm not sure if that was clear, I can rephrase it better if you want.1 point
-
Maybe this is related https://github.com/processwire/processwire/commit/d427b7f563f3024c1030265463ecaf79ab92d0701 point
-
When building your markup, to decide whether a job is current you can use WireArray::has($item) method. <?php namespace ProcessWire; $persons = pages('template=person'); ?> <ul class="persons"> <?php foreach ($persons as $person): ?> <li class="person"> Name: <?= $person->title ?> <?php if ($person->jobs->count): ?> Jobs: <ul class="person__jobs"> <?php foreach ($person->jobs as $job): ?> <?php $isCurrent = $person->currentJobs->has($p); ?> <li class="job <?= $isCurrent ? 'job--current' : '' ?>"> <?= $job->title ?> </li> <?php endforeach; ?> </ul> <?php endif; ?> </li> <?php endforeach; ?> </ul>1 point
-
OK, I got it working. Using an extra `currentJobs` field works. Go to `jobs` field and clone it from Actions tab Disable `create new pages` option Change inputfield type to `checkboxes` Add field to `person` template Edit your /site/ready.php to include this hook wire()->addHookAfter('InputfieldPage::getSelectablePages', function (HookEvent $e) { /** @var Page $page */ $field = $e->object; if(!$field == 'currentJobs') return; $page = $e->arguments(0); $jobs = $page->jobs; $e->return = $jobs; }); Once you add jobs to a person and save the page, currentJobs field is populated with jobs, and you can pick current jobs.1 point
-
$jobs = $pages->find('template=profession, persons.count>0'); Find all professions that has at least one person referenced (i.e. where at least one person has this profession)1 point
-
Yes, that's what I meant You can use the same method for those as well.1 point
-
This looks like a job for Page fields instead of Repeaters, and the module ConnectPageFields by @Robin S which makes 2-way relations possible. This way you wont have to use 4 nested loops to build your markup. You need a set up templates and fields like this PAGES: collection/ Peter : person Maria : person Paul : person professions/ Doctor : profession Actor : profession FIELDS: professions Page field, limited to `profession` template, and professions under /professions Enable create new pages persons Page field, limited to `person` template, and persons under /collection Add `professions` field to `person` template, and `persons` field to `profession` template. Then set up a synced pair from ConnectPageFields module settings When you add a new profession to a person, it will be created under /professions Then in your templates you can just use: <ul class="jobs"> <?php foreach ($jobs as $j): ?> <li class="job"> <ul class="job__persons"> <?php foreach($j->persons as $p): ?> <li class="person"> <?= $p->title ?> </li> <?php endforeach; ?> </ul> </li> <?php endforeach; ?> </ul> and you're done. I'm not sure how Residency system works, but if range of its values is not too wide, Page field can be replace repeaters for that too. Also, instead of getting all pages then filtering, you can extend your selector to include the filter, so you wont overload DB and RAM for nothing. Also I've found using IDs for speed-critical operations to be more performant. Around 2ms for id based fetches, >6ms for non-id based fetches $persons = $pages->find("parent=$collectionId, lang=$user->language"); // $user->language is interpreted as page id for the user's language1 point
-
Thanks. It's its parent module.1 point
-
@Zeka As far as I can tell from your screencast, you are not saving again, after the params are loaded - in other words: 1) clear field 2) select preset 3) Save 4) optional, edit or view the loaded params 5) Save (again) I followed your exact steps, however as i said you are not saving 2x - that is essential to commit the settings to the database. It is not necessary to change the skin, in your step 5. In other news, the latest commit should fix the repeater problem, it was just a super simple matter of hooking into the renderReadyHook, instead of the plain render, because the repeater will actually run the renderReady on every inputfield within the repeater itself which forces the assets to load.1 point
-
After verifying the login, you can do $users->setCurrentUser($loginUser); Afterwards, $user->isLoggedin() etc. should behave as expected. Setting the user "guest" as the current user (that part hasn't been tested by me) should accomplish the same after a logout.1 point
-
1 point
-
You could also try something like that: $styles = array("class1", "class2", "class3"); $recipes = $pages->find('your-selector'); foreach($recipes as $key => $recipe){ $class = (isset($styles[$key])) ? $styles[$key] : "default-class"; echo "<div class='$class'><img src='{$recipe->images->first->url}'></div>"; }1 point
-
Hello, Yes maybe this could help you https://github.com/NinjasCL/pw-rest1 point
-
Hi! Is there a way to mix vuejs with server side rendering? I kind of get that Vue works with templates and components, but it all seems to be done on the client side and I would like to stick to templating in Processwire and pulling straight HTML from here and there just depending on the url and replacing a div's content. Or maybe I'm choosing the wrong approach/framework? Or maybe I am missing how to use Vue to accomplish this? A framework I found to be almost exactly what I was looking for is Senna.js but there are things I don't really like, like the way the routes have to be initialized either by the js object or through embedding <link> tags in the document, I'd rather have something like an attribute on the anchor tag (just like vue-router has v-link attribute!).1 point
-
$pages->find("parent.template=news-month-archive"); $page->rootParent->find("parent.template=news-month-archive");1 point