Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 06/11/2020 in all areas

  1. This is a module I made as an experiment a while ago and never got around to releasing publicly. At the time it was prompted by discussions around using Repeater fields for "page builder" purposes, where the depth feature could possibly be used for elements that would be nested inside other elements. I thought it would be useful to enforce some depth rules and translate the depth data into a multi-dimensional array structure. I'm not using this module anywhere myself but maybe it's useful to somebody. Repeater Depth Helper This module does two things relating to Repeater fields that have the "Item depth" option enabled: It enforces some depth rules for Repeater fields on save. Those rules are: The first item must have a depth of zero. Each item depth must not be more than one greater than previous item depth. It provides a RepeaterPageArray::getDepthStructure helper method that returns a nested depth structure for a Repeater field value. Helper method The module adds a RepeaterPageArray::getDepthStructure method that returns a multi-dimensional array where the key is the page ID and the value is an array of nested "child" items, or null if there are no nested children. Example The module doesn't make any assumptions about how you might want to use the depth structure array, but here is a way you might use it to output a nested unordered list. // Output a nested unordered list from a depth structure array function outputNestedList($depth_structure, $repeater_items) { $out = "<ul>"; foreach($depth_structure as $page_id => $nested_children) { $out .= "<li>" . $repeater_items->get("id=$page_id")->title; // Go recursive if there are nested children if(is_array($nested_children)) $out .= outputNestedList($nested_children, $repeater_items); $out .= "</li>"; } $out .= "</ul>"; return $out; } $repeater_items = $page->my_repeater; $depth_structure = $repeater_items->getDepthStructure(); echo outputNestedList($depth_structure, $repeater_items); https://github.com/Toutouwai/RepeaterDepthHelper https://modules.processwire.com/modules/repeater-depth-helper/
    13 points
  2. I just noticed that the topic title mentions field type. The jqTree library you linked to can read/write to/from JSON format, so that data can be stored in a FieldtypeTextarea. For the inputfield you could create a custom inputfield module that extends InputfieldTextarea - in the renderReady() and render() methods you would make use of jqTree. If you are not up for coding that another idea is to use the depth option available for Repeater fields. If you go this route you might also find my Repeater Depth Helper module useful.
    4 points
  3. We have created a module to create BlurHash strings for images while uploading in ProcessWire. This blurry images will be saved in the database because they are very small (20-30 characters) and can be used for Data-URL's as placeholders for image-lazy loading. https://github.com/blue-tomato/ImageBlurhash E.g. where we use this in production: https://www.blue-tomato.com/en-INT/blue-world/ https://www.blue-tomato.com/en-INT/blue-world/products/girls-are-awesome/ https://www.blue-tomato.com/en-INT/buyers-guides/skateboard/skateboard-decks/ https://www.blue-tomato.com/en-INT/team/anna-gasser/
    3 points
  4. If you want to make sure there are no duplicates, excluding them by ID is the way to go. There shouldn't be any performance issues - excluding one ID or a hundred shouldn't make any noticable difference for the generated database query. You can save the first result to the session as a string, and then include it in your selector. // first result $randomPages = $pages->find("template=gallery-detail, sort=random, limit=100"); $session->set('current-random-pages', (string) $randomPages); // later, in an ajax call $previous = $session->get('current-random-pages'); $randomPagesWithoutPrevious = $pages->find("template=gallery-detail, sort=random, limit=100, id!={$previous}"); // add the new pages to the list so you can load more multiple times $session->set('current-random-pages', $previous . '|' . $randomPagesWithoutPrevious); Quick and untested, might need some adjustments and context, but you get the idea ? If you want to go stateless, you can also include the ID-list in the ajax call. By the way, casting a PageArray to string creates a pipe-seperated list of IDs (e.g. 2|5|28|278), this can go right into the query and is a good format to save the IDs to the session or include them in the ajax call.
    3 points
  5. It's not a Processwire problem but a error in CSS. Your CSS class .owl-carousel is set to display:none; which makes the slider disappear. The culprit is in owl.min.css. Someone must have changed it...
    2 points
  6. Not yet, when the website used to promote the module will be ready, the release date will posted here. Same here, and what I can say/confirm, is that once you get your hand into the editor, you will want to use it ? Thanks you for your interest. PS: If you think onto something that should be indispensable and that need to be implemented, please do not hesitate to ask/discuss the feature here.
    2 points
  7. That's me. Memory's gone!
    2 points
  8. Ryan introduced it at the end of 2016. In my mind it doesn't seem like that long ago. I must be getting old. ? https://processwire.com/blog/posts/pw-3.0.44-repeaters/
    2 points
  9. Mystique Module for ProcessWire CMS/CMF Github repo : https://github.com/trk/Mystique Mystique module allow you to create dynamic fields and store dynamic fields data on database by using a config file. Requirements ProcessWire 3.0 or newer PHP 7.0 or newer FieldtypeMystique InputfieldMystique Installation Install the module from the modules directory: Via Composer: composer require trk/mystique Via git clone: cd your-processwire-project-folder/ cd site/modules/ git clone https://github.com/trk/Mystique.git Module in live reaction with your Mystique config file This mean if you remove a field from your config file, field will be removed from edit screen. As you see on youtube video. Using Mystique with your module or use different configs path, autoload need to be true for modules Default configs path is site/templates/configs/, and your config file name need to start with Mystique. and need to end with .php extension. Adding custom path not supporting anymore ! // Add your custom path inside your module class`init` function, didn't tested outside public function init() { $path = __DIR__ . DIRECTORY_SEPARATOR . 'configs' . DIRECTORY_SEPARATOR; Mystique::add($path); } Mystique module will search site/modules/**/configs/Mystique.*.php and site/templates/Mystique.*.php paths for Mystique config files. All config files need to return a PHP ARRAY like examples. Usage almost same with ProcessWire Inputfield Api, only difference is set and showIf usage like on example. <?php namespace ProcessWire; /** * Resource : testing-mystique */ return [ 'title' => __('Testing Mystique'), 'fields' => [ 'text_field' => [ 'label' => __('You can use short named types'), 'description' => __('In file showIf working like example'), 'notes' => __('Also you can use $input->set() method'), 'type' => 'text', 'showIf' => [ 'another_text' => "=''" ], 'set' => [ 'showCount' => InputfieldText::showCountChars, 'maxlength' => 255 ], 'attr' => [ 'attr-foo' => 'bar', 'attr-bar' => 'foo' ] ], 'another_text' => [ 'label' => __('Another text field (default type is text)') ] ] ]; Example: site/templates/configs/Mystique.seo-fields.php <?php namespace ProcessWire; /** * Resource : seo-fields */ return [ 'title' => __('Seo fields'), 'fields' => [ 'window_title' => [ 'label' => __('Window title'), 'type' => Mystique::TEXT, // or InputfieldText 'useLanguages' => true, 'attr' => [ 'placeholder' => __('Enter a window title') ] ], 'navigation_title' => [ 'label' => __('Navigation title'), 'type' => Mystique::TEXT, // or InputfieldText 'useLanguages' => true, 'showIf' => [ 'window_title' => "!=''" ], 'attr' => [ 'placeholder' => __('Enter a navigation title') ] ], 'description' => [ 'label' => __('Description for search engines'), 'type' => Mystique::TEXTAREA, 'useLanguages' => true ], 'page_tpye' => [ 'label' => __('Type'), 'type' => Mystique::SELECT, 'options' => [ 'basic' => __('Basic page'), 'gallery' => __('Gallery'), 'blog' => __('Blog') ] ], 'show_on_nav' => [ 'label' => __('Display this page on navigation'), 'type' => Mystique::CHECKBOX ] ] ]; Searching data on Mystique field is limited. Because, Mystique saving data to database in json format. When you make search for Mystique field, operator not important. Operator will be changed with %= operator. Search example $navigationPages = pages()->find('my_mystique_field.show_on_nav=1'); $navigationPages = pages()->find('my_mystique_field.page_tpye=gallery');
    1 point
  10. No, I uploaded the zip file by using the modules installation uploader. just upload, install, didn't work. hope that helps.
    1 point
  11. The issue of paginating results when sort=random has come up before. Ryan suggested finding all the IDs with a random sort, then loading pages from slices of that array. His example assumes normal pagination but could be adapted for ajax loading. $limit = 10; $start = $limit * ($input->pageNum()-1); $ids = $session->get('ids'); if(!$ids) $ids = $pages->findIDs("template=project, sort=random"); $session->set('ids', $ids); $a = array_slice($ids, $start, $limit); if(!empty($a)) { $items = $pages->getByID($a)->setStart($start)->setLimit($limit)->setTotal(count($ids)); echo $items->implode("<li>{title}</li>") . $items->renderPager(); }
    1 point
  12. Are you sure the $input->get variable is set? Is this code executing on form submission? Otherwise, it won't work because the $input->get->tag variable won't be filled. Second on this loop: foreach($found as $image){ ... } $image is not an image object, it's a page object, $found is an array (more precisely, a PageArray) of pages. Check again this code: foreach($found as $p){ $imagesWithTag = $p->images->findTag($tag); foreach($imagesWithTag as $image){ //this is now possible $image->size(100,100); } }
    1 point
  13. It is fine to ask here. If it it is not directly related to ProcessWire, you can post in the dev forum. https://processwire.com/talk/forum/25-dev-talk/ I noted that you posted two different links. To get accurate help and as quickly as possible, it is best to post as much descriptive information as possible. These include: What ProcessWire version are you using? Did you change something in the code just before the banner stopped working? Etc Please repost the link to your site.
    1 point
  14. you should ? will do that right away, thanks!
    1 point
  15. You could use a masonry-like component, f.e. Filter from UI-Kit (https://getuikit.com/docs/filter). Place the tags from the images in the filter-tags. For creating the filter elements, you could create an array of unique tags and then loop over the array for creating the selectors.
    1 point
  16. OK. Won't they get confused by the interface though? Also check out Tabulator Yes, in a sense, though it depends on whether you want automatic (i.e. no user interaction, like an auto module or cron thing) versus manual (press a button and it gets synchronized. The latter can be done, easily in Media Manager. The former would need a bit of coding, essentially calling Media Manager API via some automated process. Media Manager has a 'Scan' uploads mode. How it works is you upload files to a set folder in /site/MediaManager. You can upload files to that folder via FTP, or other method. Inside Media Manager. The files can be loose or zipped. If zipped, Media Manager would unzip them. The files are then presented in a list. You can then select the ones you wish to upload to the Media Manager library. Those added to the library are then deleted from the folder where they were uploaded. There are settings for what to do when Media Manager encounters duplicates: rename/replace/skip. In your case, you would go for replace (synchronization). In Media Manager? Yes, but post upload (not during). Each media is a page. Say you uploaded a file called My End of Year Report.xlsx. Media Manager would create a page with that file name (sanitized) as the title. That will end up as My End of Year Report. The file name itself would be sanitized as my-end-of-year-report.xlsx. Post-upload, you can manually add keywords, e.g. via tags, or a custom field or fields (e.g. options, page reference fields, etc). If you want automatic indexation, that would require some custom code. If this is something you want to pursue alongside a Media Manager option, we can discuss further via PM (as a custom paid option). I meant tools like rsync ?
    1 point
  17. Please start a new topic and show us some code ? Your question does not seem to be related to the current thread.
    1 point
  18. @MoritzLost Thank you ! works like expected
    1 point
  19. Outstanding Robin, this looks amazing, I am definitely going to try this out.
    1 point
  20. This is awesome. Have to test it in production. Thank you
    1 point
  21. Not exactly a module, but the page tree emulates a tree, allows drag and drop organisation of elements, and returns results as a (Page)Array. ? You could also use exactly that example. If you are talking about the frontend then PW doesn't place any limitations on what JS libraries you can use. And you could use it in the backend too if needed, via RuntimeMarkup for example.
    1 point
  22. I see your point. However, imagine if the two were separate sites. This: Would be this: What is the difference between the two except for the fact that they are not directly sharing a parent folder? i.e. web/parentofsites/site-1 and web/parentofsites/site-2 versus web/somesite1/site (for 1) and web/somesite2/site. It is almost just an issue of semantics. They are in the same web server and there are no security issues at all. Not even SEO issues to the best of my knowledge. The sites are not talking to each other (although you can make them talk if you want) and are not accessing each other's resources. The only common thing they have is wire. No worries ? Feel free to ask away! ?
    1 point
  23. You'll have to look through the $_COOKIE superglobal to find the cookie name that matches your format. You can do that with regular array functions. For example: // just for testing $_COOKIE['name_xyz'] = 'Test value'; $_COOKIE['name_foo'] = 'Bar'; $cookieNames = array_filter(array_keys($_COOKIE), function ($key) { // check if the cookie name starts with "name_" return preg_match('/^name_/', $key) === 1; })); print_r($cookieNames); // -> Array ( [6] => name_xyz [7] => name_foo ) print_r($_COOKIE[current($cookieNames)]); // -> Test value Adjust the preg_match pattern to match the pattern you're looking for. The result will be an array of keys that match your format. Note that this array is NOT zero-indexed, because array_filter doesn't change the keys, hence the use of current to get the first value. Alternatively, use array_values to zero-index the array, or foreach to loop through all matching cookies. If you dislike the raw use of $_COOKIE, you can also use $input->cookie()->getArray() (docs).
    1 point
  24. I took the liberty of opening a GitHub issue for this problem: https://github.com/processwire/processwire-issues/issues/1192 As a workaround for now you could use this hook in /site/ready.php: $pages->addHookBefore('added', function(HookEvent $event) { /** @var Page $page */ $page = $event->arguments(0); /** @var Pages $pages */ $pages = $event->object; // Only for a particular template if($page->template != 'your_template') return; // Check if there is a name clash with an existing sibling page $default_name = $this->wire('sanitizer')->pageName($page->title, true); if($pages->count("parent=$page->parent, id!=$page->id, name=$default_name, include=all")) { // Manually create a proposed name $name = $default_name . '-1'; // Auto-adjust the name when needed $name = $pages->names()->uniquePageName($name, $page); // Set the name $page->setAndSave('name', $name); } });
    1 point
  25. This looks great - I don't personally care for these types of editors because I'm an older user, but many clients have asked for this type of builder. I'd probably get used to it and enjoy it once I got into the habit.
    1 point
  26. Shut up and take my money. I also thought a long time about making a fieldtype with editor.js, because it is just awesome to store contents as structured data. Prosemirror is an alternative, which works similar and is used in Statamic for its Bard field (which is also awesome). Is there any release date yet?
    1 point
  27. Hey @Sebi have you thought of registering $twack as API variable? // in your module $this->wire('twack', $this); // in any template // no need for $twack = $modules->get('Twack'); $general = $twack->getNewComponent('General');
    1 point
  28. Inspired by a recent question. Image Crop Ratios Allows preset aspect ratios to be defined per image field for the ProcessWire image crop tool. The module adds a select dropdown to the crop tool. Choose an aspect ratio and the crop area will be fixed to that ratio. Screencast Installation Install the Image Crop Ratios module. Configuration Default aspect ratios for all image fields can be defined in the module config. Aspect ratios for specific image fields can be defined on the Input tab of the field settings. You can override the ratio settings in template context if needed. Insert a hyphen as the first item in the ratio settings unless you want to force a ratio to be applied to the crop tool. The hyphen represents a blank option that allows a free crop area to be drawn. Usage Click the "Crop" link on the details view of an image thumbnail. Click the "Crop" icon at the top of the editor window. Choose an option from the "Ratio" select dropdown. https://github.com/Toutouwai/ImageCropRatios https://modules.processwire.com/modules/image-crop-ratios/
    1 point
  29. You need to set additional data attributes on your button data-buttons='button#submit_dashboard_status_action' data-autoclose $field->attr('data-buttons', 'button#submit_dashboard_status_action'); $field->attr('data-autoclose', ''); and your submit button needs an id, too $submit->attr('id+name', 'submit_dashboard_status_action'); // set id and name in one go This is documented at the top of file wire/modules/Jquery/JqueryUI/modal.js.
    1 point
  30. thank you both. neither check_access=0 nor include_all=1 works here (even in the field settings, the access-toggle for api usage is set true for both, content_blocks repeater and downloads) . instead i got it working (for both, suberadmin and guest) by doing it like that (similar to Cengiz' solution from the post below): wire('pages')->find("template=basic-page, content_blocks=content_blocks.downloads.tags!='', check_access=0"); maybe this has some impact on further usage of the including function, but for this case it works. Any tips are welcome for a more certain syntax.
    1 point
  31. I solved finally. check_access=0 must be in '[ ]' brackets. $kisiler= $pages->find("template=kisi,sort=title,repeater_ozlusoz=[ozlusoz_konusu=$page->id,check_access=0]");
    1 point
×
×
  • Create New...