Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 09/06/2017 in all areas

  1. I'd still keep the Page fields, and use two fields to determine all jobs and current jobs a person has. What you should do is to pull up your sleeves and get down to build a select field, maybe extend @ryan's asmSelect, or more modern alternatives (chosen.js select2.js etc) that have tagging support. In fact, I had some free time and went ahead and created a signup form that does this. I used selectize.js for selecting/creating jobs on the frontend. Options load with AJAX at page load Once you submit the form, you get this On the backend, I get the input, sanitize it and filter values, if a new job name is specified, I create the page, and add it to `jobs` or `currentJobs`. Here's the code in all its glory: <?php namespace ProcessWire; /* @var $input WireInput */ /* @var $sanitizer Sanitizer */ /* @var $pages Pages */ if (input()->requestMethod('GET') && input()->urlSegment1 === 'jobs.json') { // serve json for input fields $jobs = pages('template=profession, sort=title'); echo wireEncodeJSON($jobs->explode(['id', 'title'])); return $this->halt(); } elseif (input()->urlSegment1) { // don't allow other url segments throw new Wire404Exception(); } elseif (input()->requestMethod('POST')) { $jobs = $input->post->jobs; $currentJobs = $input->post->currentJobs; // sanitize inputs $saneJobs = []; foreach ($jobs as $j) { $jobId = $sanitizer->int($j); $jobTitle = $sanitizer->text($j); if ($jobId) $saneJobs[$jobId] = false; // not current job elseif ($jobTitle) $saneJobs[$jobTitle] = false; // not current job } // check if a job is one of current jobs foreach ($currentJobs as $cj) { $currId = $sanitizer->int($cj); $currTitle = $sanitizer->text($cj); // if person has the job, set it to current if (isset($saneJobs[$currId])) $saneJobs[$currId] = true; // set to current elseif (isset($saneJobs[$currTitle])) $saneJobs[$currTitle] = true; // set to current } // save info $person = $pages->get(1228); $person->of(false); $addableJobs = []; $addableCurrents = []; foreach ($saneJobs as $j => $isCurrent) { // $j is job id or new job title $job = null; // does job already exist? if (is_int($j)) { $job = $pages->get($j); } else { // create a new job and add it $job = new Page(); $job->template = 'profession'; $job->parent = 1027; $job->name = $sanitizer->pageName($j); $job->title = ucwords($j); // already sanitized, but capitalize it $job->save(); } if (!$job) continue; $addableJobs[] = $job; if ($isCurrent) $addableCurrents[] = $job; } $person->jobs->add($addableJobs); $person->currentJobs->add($addableCurrents); $person->save(); } ?> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/selectize.js/0.12.4/js/standalone/selectize.js"></script> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"> <link rel="stylesheet" href="https://rawgit.com/selectize/selectize.js/master/dist/css/selectize.bootstrap3.css"> <div class="flex"> <form method="POST" class="signup-form"> <div class="form-group"> <label for="name">Name</label> <input name="name" required type="text" class="form-control" id="name" placeholder="Name Lastname"> </div> <div class="form-group"> <label for="jobs">Your Jobs</label> <select name="jobs[]" required id="jobs" multiple class="form-control"> <option>Loading...</option> </select> </div> <button class="btn" type="submit">Save</button> </form> </div> <script> $jobs = $('#jobs'); // fetch all jobs $.getJSON('./jobs.json', function (data) { initSelect(data); }); function initSelect(data) { const makeOption = (it) => ({text: it.title, value: it.id}); let selected = data.splice(0, 5).map(makeOption); window.jobs = data; $jobs.selectize({ create: true, render: { item: function (data, escape) { return `<div class='option'> <span class="option__label">${escape(data.text)}</span> <input class="option__current" type="checkbox" name="currentJobs[]" value="${escape(data.value)}"> </div>`; } }, options: data.map(makeOption), // populate the field with the jobs person already has // items: data.splice(1,4).map(i => i.id) }); } </script> <style> .flex { display: flex; justify-content: center; margin-top: 10rem; } .signup-form { width: 500px; margin: auto; } .option { width: 100%; } .option:after { content: ''; display: table; } .option__label { float: left; } .option__current { float: right; } </style>
    4 points
  2. It's certainly better than putting plain <img> tags on the page. How many images you have on the page doesnt really matter. Images either have a 1x1px transparent GIF or a low quality placeholder. As visitor scrolls down the page JS swaps placeholders with a real/HQ image and browser starts loading the high quality version. If user doesnt scroll down to an image, it doesnt load. Pages load much quicker and you get save bandwidth in the process.
    3 points
  3. Enable $config->debug = true to load non-minified version of ProcessPageList.js, maybe it can give you more clues
    2 points
  4. I think it's important to sync `jobs` `currentJobs` fields such that `currentJobs` doesnt have more jobs than `jobs` field has. You can use the following hook to update `currentJobs`. wire()->addHookBefore('Pages::saveReady', function (HookEvent $event) { $page = $event->arguments('page'); if ($page->template != 'person') return; // make sure currentJobs items <= jobs items if ($page->isChanged('jobs')) { foreach ($page->currentJobs as $cj) { if (!$page->jobs->has($cj)) $page->currentJobs->remove($cj); } } });
    2 points
  5. I don't think it would resolve the issue. SHDB just saves to DB instead of the file-system. But PHP will still do one session request after another and probably uses db table locks instead of file locks (at least that's my guess). Are you using PW session functions or native PHP? Towards the bottom of this article there is PHP 7 option: session_start([ 'read_and_close' => true, ]); https://ma.ttias.be/php-session-locking-prevent-sessions-blocking-in-requests/ The author also mentions Redis (there's also a redis session handler db module for PW), but if you're not using it it won't be of much use...
    2 points
  6. Sorry guys. Buried with work currently, but it is getting better. Padloper is alive and kicking!
    2 points
  7. No. After you make a crop and close the modal (Accept), no 0x48 image is generated (perhaps the module should do this?). That's why I load the original thumb instead (this is fast because it's cached by the browser). On next crops I toggle the "?v=1" "?v=2" params, in my tests it was enough to bypass the browser cache. It's hard to tell what goes wrong for you until I can duplicate the issue. Could you share your settings and workflow exactly? (PM is ok too)
    1 point
  8. You can use a selector like this to seach among children and siblings: (use has_parent=$page to search in deeper children) $myPages = $pages->find("(parent=$page->parent, template=X), (parent=$page, template=X)"); https://processwire.com/api/selectors/#or-groups
    1 point
  9. @horst Could you add this JS fix too?
    1 point
  10. I added the timestamp to the url. So I wasn't able to reproduce this issue, but cannot see any harm by adding the timestamp to the url. If you think this should be added to the core Variations Page, please make an issue at Github.
    1 point
  11. There's always good old pagination you could use... https://processwire.com/api/modules/markup-pager-nav/ Maybe in 2017 that's not considered "sexy", but hey - if it works, it works
    1 point
  12. Did you consider using lazy loading instead? http://afarkas.github.io/lazysizes/ https://github.com/conclurer/TextformatterSrcset
    1 point
  13. It's strange. I guess this has nothing to do with jumplinks. https://mydomain.com/de/existing-page/non-existing -> 404 -> I get the jumplink debug page https://mydomain.com/de/non-existing -> I just get the root page @edit: aahhh I found it! URL Segements was turned on but not handled. So everything not existing was just redirected to frontpage.
    1 point
  14. v1.5.4 is available with the fixed sticky CKE toolbar and some other fixes.
    1 point
  15. Best not to use the Redirect directive. Rather use RewriteRule ^page-one/?$ /page-two/ [R=301,L] just after RewriteEngine On. Alternatively, use Jumplinks.
    1 point
  16. The link to the forum itself won't help you much. Access to that forum is what you need. If you have access, you will see the support forum when you log into the ProcessWire forums. Try sending Antti a PM. I know he's had a busy summer so he might have missed an email or two. He'll add you to the list of members who can access the Padloper support forum.
    1 point
  17. 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
  18. The code is to show how to add new records to a Table field Unless you develop your own module, there's not a native way to handle 2-way relations from Table <--> Page Reference field. This means you'll still have to use a code similar to the one in the first post. Can you show the whole form? Also, one thing to note is that the pages you create from Page field input aren't created instantaneously. They're created once you submit (to perform permission checks, sanitizations etc). This would mean page has to reload to add new jobs in the first place, and you wont be able to dynamically render/populate currentJobs field using JS. So it seems you will have to either instruct user to save the page, or replace repeaters with Table field, or find other ways to shave time off of your process
    1 point
  19. 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>
    1 point
  20. 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
  21. In your first post, there's this line <?php $langname = $user->language->title; //get current user language?> What type of field is it? (You can use Page field for that too ) Is it a basic text field or what?
    1 point
  22. 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
  23. 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
  24. I guess it's possible, but of course not optimal. Maybe try this? https://www.drupal.org/docs/8/modules/json-api/json-api i.e. fetch JSON feeds from Drupal, and import to PW with file_get_contents() + json_decode()
    1 point
  25. Then I'd add another page field called `currentJobs` just like `jobs` field, and when outputting you can combine both to get the markup you want. A better way would be hooking into Page::saved to copy `jobs` field value to `currentJobs` and changing `currentJobs` input field to checkboxes. After you save the page, you can use checkboxes to mark the current jobs. I can try to see if this would even work, but I need to eat my lunch first. Also, this is where Page reference field falls short. It just references and nothing more. If you have ProFields, you can use Table field to get a very lean and performant repeater-like experience
    1 point
  26. To mark the current job, you need a different approach, Page field only references other pages. For this situation, I'd pick the first job as the current one, (or the last) because it makes sense if you're ordering jobs chronologically. Oh by the way, install Autocomplete input from Code modules (it's not installed by default) and change input type of the page fields to `Multiple page selection (sortable)` > `Autocomplete`. This way you can order job entries and simulate a chronological order. Then in your templates you can do something like this <ul class="persons"> <?php foreach ($persons as $p): ?> <li class="person"> Name: <?= $p->title ?> <?php $jobs = $p->jobs; $lastJob = $jobs->pop(); ?> <ul class="person__jobs"> <li class="job job--current"> Current Job: <?= $lastJob->title ?> </li> <?php foreach ($jobs as $j): ?> <li class="job"> <?= $j->title ?> </li> <?php endforeach; ?> </ul> </li> <?php endforeach; ?> </ul> On my multi language setup there's no `lang` field, I'm not sure it it's a native field. Is it a field that you've created yourself?
    1 point
  27. $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
  28. @helmut2509 Just go to the home page of the settings tab and change the name field
    1 point
  29. Since I read about the new fieldsets I'm thinking if it would make sense to have some kind of fieldset library. Maybe export jsons in github gists? Or maybe collect them just in a forum thread here... This could make it more easy and more efficient to share common fieldsets, like SEO, person details or the like. What do you guys think?
    1 point
  30. You can download and test from this address: GITHUB-SITE-BS4 and this MODULES - SITE-BS4 And I add a screenshot:
    1 point
  31. finally: https://processwire.com/blog/posts/processwire-3.0.73-and-new-fieldset-types/
    1 point
  32. @ryan, could you please add an option to include setlocale() in the exported config.php if it is defined. Now that PW is giving warnings if setlocale() is missing it would be nice not to have to remember to manually add this each time a profile is installed.
    1 point
  33. Usually it works if you just set the "$entryPage->titel" to the value, but think it only works with the ID. Depends if you use the "ID" or the additional "value" options (id=value|title) If using value: foreach ($options as $option) { $field->addOption($option->value, $option->title); } foreach ($entryPage->titel as $value) { $valArray[] = $value->value; // array of values selected, not key=>title } $field->attr("value", $valArray); Using ID foreach ($options as $option) { $field->addOption($option->id, $option->title); } $field->attr("value", $entryPage->titel); // just passing the field (only when outputformatting off) If that doesn't work just make an array using id. foreach ($entryPage->titel as $value) { $valArray[] = $value->id; }
    1 point
  34. If the users are all editors, it's true that you won't want to use any automatic caching (and may not be able to). But you can always use MarkupCache to cache elements that you know are ok to do so. In your case, I would try to isolate the bottleneck. Wrap statements like this around your significant sections of code, until you track down what is causing the slowdown: $timer = Debug::timer(); // .. a block of code you want to measure $this->message(Debug::timer($timer)); It'll tell you how many seconds the block took to execute. If this is outside of admin context, you can replace the $this->message() with an echo or something else, anywhere that you can see the results. Once you find the source of the bottleneck(s), you may be able to optimize them to improve the speed. Often times there is just an inefficient block of code that can be fixed. But if that's not the case, you may want to then look at MarkupCache'ing them. $cache = $modules->get('MarkupCache'); $out = $cache->get('your-unique-name', 86400); // 86400=num seconds age if(!$out) { $out = SomethingThatTakesAwhile(); $cache->save($out); } echo $out; I don't know about that context, but an opcode cache can be very helpful. If you can't use an opcode cache, I would make whatever changes are necessary so that you can. No PHP 5.4+ should not break anything. In fact, I think you'll find that just switching to PHP 5.4 provides a nice speed boost in itself (at least it seemed like it to me). I am running PHP 5.4+ on all of my own PW installs now.
    1 point
×
×
  • Create New...