Jump to content

Robin S

Members
  • Posts

    4,791
  • Joined

  • Days Won

    303

Everything posted by Robin S

  1. As a general rule, you can copy any PW module from /wire/modules/ to /site/modules/ if you want to customise it. When you do a Modules > Refresh you will see a notice... Session: Module "SomeModule" has multiple files (bold file is the one in use). Click here to change which file is used ...and you can enter the module settings to switch between the version in /wire/ and the version in /site/.
  2. You can certainly create your own plugin and toolbar button for CKEditor. PW doesn't get in the way of that, but it's something that you would learn about in the CKEditor docs rather than the PW docs. You can place your plugin in /site/modules/InputfieldCKEditor/plugins/ and then select it for CKEditor fields in the field settings on the Input tab. Or if you want to include your CKEditor plugin in a PW module you could have a look at how HannaCodeHelper does it. You will need to include the name of the toolbar button in the CKEditor Toolbar section of the field settings. Copy /wire/modules/Inputfield/InputfieldCKEditor/plugins/pwlink/ to /site/modules/InputfieldCKEditor/plugins/pwlink/ and make your changes there.
  3. He talks about the separation of concerns... ...and MVC is a popular pattern that enforces that. But they're not exactly the same thing, for sure.
  4. I think this new approach is similar to template engines in one respect: the idea of extending a named block. This feature is present in template languages like Smarty and Twig and I for one find that feature very useful. I don't see any other similarities to template engines though. What would be your idea of misuse of this new strategy? If you mean it allows (encourages?) developers to not follow the MVC pattern then I don't see this as a big issue. There is no cardinal rule: "Thou shalt use MVC in all projects" - it depends very much on the type of developer you are and the type of project you are working on. When Ryan says... ...I take this to mean people who are new to PHP development in general. People who have a design background, or those used to a drag-and-drop interface, or who have previously worked only with static HTML. If someone has a lot of PHP experience I doubt they would find anything about PW difficult to understand - more like a breath of fresh air. And people who are new to PHP development are not going to be: building large, complex web projects working on long-lived projects that will be handed over to future developers collaborating on a project with other developers in a team For any of these I totally see the value of MVC. But if you are a newbie working on <10 page brochure websites you do not need MVC.
  5. The error is visible if you install Tracy Debugger.
  6. Not sure how you got the rectangular thumbnails - mine are always square when rendered inside a PageTable, regardless of the the image field settings. Which isn't a bad thing in this case because the solution involves overriding the JS image sizing with CSS and you're not going to be able to preserve the aspect ratio for each image. These custom CSS settings (use AdminCustomFiles or AdminOnSteroids) gave the result that follows. .Inputfield_pt_thumbnails .InputfieldImage .gridImage__overflow img { height:100%; } .Inputfield_pt_thumbnails td:nth-child(2) .InputfieldImage .gridImage__overflow { height:260px !important; width:260px !important; } .Inputfield_pt_thumbnails td:nth-child(3) .InputfieldImage .gridImage__overflow { height:100px !important; width:100px !important; } There is no way to identify individual image fields from the markup so you have use nth-child() selectors to target table columns. Portrait-format images will not fill their frames.
  7. The inputfield value is not saved correctly because config you are trying creates an error: PHP Notice: Object of class ProcessWire\Page could not be converted to int in ...\modules\Process\ProcessModule\ProcessModule.module:1287 So it seems that the inputfield you have created is returning a page object when what is expected is a page id. One solution is to create the options you want to make available in the inputfield: class ProcessHelloConfig extends ModuleConfig { public function __construct() { $items = $this->pages->find("parent=1"); $page_options = []; foreach($items as $item) { $page_options[$item->id] = $item->title; } $this->add(array( // Text field: greeting array( 'name' => 'greeting', // name of field 'type' => 'text', // type of field (any Inputfield module name) 'label' => $this->_('Hello Greeting'), // field label 'description' => $this->_('What would you like to say to people using this module?'), 'required' => true, 'value' => $this->_('A very happy hello world to you.'), // default value ), // Radio buttons: greetingType array( 'name' => 'greetingType', 'type' => 'radios', 'label' => $this->_('Greeting Type'), 'options' => array( // options array of value => label 'message' => $this->_('Message'), 'warning' => $this->_('Warning'), 'error' => $this->_('Error'), ), 'value' => 'warning', // default value 'optionColumns' => 1, // make options display on one line 'notes' => $this->_('Choose wisely'), // like description but appears under field ), // My custom test field array( 'name' => 'myTest', 'type' => 'select', 'label' => $this->_('Test'), 'options' => $page_options, ), )); } } BTW, if you want to allow the user to select any page from the tree you can use the Page List Select inputfield: // My custom test field array( 'name' => 'myTest', 'type' => 'PageListSelect', 'label' => $this->_('Test') )
  8. I think a separate mobile website is an outdated approach and device sniffing will be both unreliable and require more maintenance. I would highly recommend a single responsive design, but if you're sure you want to pursue separate templates for mobile devices then you could select templates by domain as suggested here... ...or use the same approach but test for device using Mobile Detect.
  9. The actual repeater item. I also installed Language Support and set up a test Page field with template=language and that works too. $results = $page->test_repeater->find("test_page.name=german"); echo $results->each("<p>{name}</p>"); // echoes the repeater item name, e.g. 1484443861-212-1 Edit: fixed the above
  10. Maybe this issue is specific to language pages when used in a Page field, because I can successfully find repeater items with a Page field matching a given id, name, title, etc.
  11. The "Add New" link is automatically hidden when the max is reached. To hide the repeater item label for repeaters with min and max of 1 you can use a CSS rule like this in AdminCustomFiles or AdminOnSteroids: .InputfieldRepeater[data-min="1"][data-max="1"] .InputfieldRepeaterHeaderInit { display:none; } If you do this you would want to have your repeater set to "Items always open".
  12. This is just an idea... You could consider making the creation and maintenance of these articles easier for site editors by having a simpler structure in the page tree (just the categories as parent pages), entering the article date with a datetime field, and then creating the desired URL for the frontend using URL segments (enable this on the category template). So your category template would look for the following URL segments: segment 1: year - sanitize to integer, throw 404 if out of range segment 2: month - sanitize to integer, throw 404 if out of range segment 3: day - sanitize to integer, throw 404 if out of range segment 4: article page name - throw 404 if no match for article page name In terms of finding articles that match a given year, month or day you could convert to a timestamp range as Ryan shows here, but to make it easier (and considering you'll need the integers for building the article URLs) I would instead add 3 integer fields to your article template, set the field visibility to "Hidden (not shown in editor)" and then populate them with a saveReady hook. // in /site/ready.php $this->pages->addHookAfter('saveReady', function($event) { $page = $event->arguments('page'); if($page->template->name === 'article' && $page->article_date) { $page->day = date('d', $page->article_date); $page->month = date('m', $page->article_date); $page->year = date('Y', $page->article_date); } }); Now it's really easy to find articles, e.g. $matches = $pages->find("template=article, year=2016, month=11, sort=sort"); For the question in your original post you'd do something like this: $latest_article = $pages->get("template=article, parent=/politics/, sort=-article_date"); $recent_articles = $pages->find("template=article, parent=/politics/, article_date={$latest_article->article_date}, sort=sort, limit=5"); $day_link = "/politics/{$latest_article->year}/{$latest_article->month}/{$latest_article->day}"; // use this as the first link to the 'parent' page When you need to output the URL of an article you would build it like this: $url = "{$article->parent->url}{$article->year}/{$article->month}/{$article->day}/{$article->name}/"; For convenience you'd probably make a simple function that returns this URL string. In the backend, rather than browse through the page tree, if you want to list articles by day/month/year you can use the "Find" lister. Or better yet a dedicated Lister Pro instance for articles.
  13. @Tom., I think BitPoet's module is the way to go, but in case you can't use it (e.g. your MySQL doesn't have timezone support enabled) you could use a saveReady hook to populate a hidden field with the day of the week of the entered date. // in /site/ready.php $this->pages->addHookAfter('saveReady', function($event) { $page = $event->arguments('page'); if($page->template->name === 'act' && $page->date_field) { $page->day_of_week = date('l', $page->date_field); } }); // find pages $pages->find("template=act, day_of_week=Friday");
  14. A Snipcart integration case study, as mentioned in the Showcase forum... Les Ateliers Fromagers: Custom Shopping Cart Integration on a ProcessWire CMS Site https://snipcart.com/blog/case-study-ateliers-fromagers-processwire Also on the Snipcart site: https://snipcart.com/blog/processwire-ecommerce-tutorial
  15. This is freaking awesome - I love it! I've always disliked working with HTML markup inside PHP variables - the sacrificed readability of the HTML that comes with multiple variable concatenations, the single quotes/double quotes/escaped quotes hassle. I try to avoid it as much as possible using output buffering but this new feature suits me down to the ground and will definitely be my preferred way of managing markup in templates going forward. Simple and brilliant, like the rest of PW. Thanks!
  16. Do you mean that the PW htaccess is disallowing access to your PHP file (you are getting the 404 page)? PW blocks direct access to PHP files inside /site/ but you should be able to access it inside the root, e.g. /api.php ...or... /xapi/index.php
  17. I'm not sure about generating a new userAuthSalt, but in the future if you want to reuse an existing site as the starting point of a new site then check out the Site Profile Exporter module.
  18. That seems less flexible that the PW approach to image sizing. What is the advantage of it? If it's that you can type 'link-image' in your code rather than '630, 330' then you could achieve the same in PW: // in an init.php that is auto-prepended to template files $link_image = '630, 330'; // use this in your template files $page->image->size($link_image)->url; Or using Croppable Image, you define a crop... ...then call it by name in your template... $page->image->getCrop('link-image')->url;
  19. This may be stating the obvious, but for HiDPI displays you typically want to size your image to twice the dimensions you are displaying it at. The upscaling setting isn't relevant unless you are doing a resize operation to a size that is larger than the original uploaded image.
  20. This is missing the option for actually setting the sharpening amount. I think it should be: foreach(array('none', 'soft', 'medium', 'strong') as $sharpening) { echo "<img src='" . $child->post_image->first()->size(200, 0, [ 'upscaling' => false, 'quality' => 90, 'sharpening' => $sharpening, 'suffix' => $sharpening ])->url . "' title='{$sharpening}' />"; } The jaggies are a consequence of the sharpening - you can't have it both ways. With sharpening off the edges are smooth.
  21. As @Mike Rockett says, the quick and dirty way is to use CSS: .MarkupPagerNav li { display:none; } .MarkupPagerNav .MarkupPagerNavPrevious, .MarkupPagerNav .MarkupPagerNavNext { display:block; } For a PHP solution, here's what I use for prev/next pagination of news summaries. I think it's based on some code shared here in the forums but I can't remember where. In my case I wanted greyed-out prev/next links when on the first/last page. <?php $limit = 5; $news = $pages->find("template=news_item, post_date<=today, limit=$limit, sort=sort"); $total_pages = ceil($news->getTotal() / $limit); // output news summaries here // pagination if($total_pages > 1): $current_url = $page->url; if($input->urlSegmentsStr) $current_url .= $input->urlSegmentsStr . '/'; ?> <div class="pagination"> <div class="prev-page"> <?php if($input->pageNum > 2): ?> <a rel="prev" href="<?= $current_url . $config->pageNumUrlPrefix . ($input->pageNum - 1) ?>">Prev page</a> <?php elseif($input->pageNum === 2): ?> <a rel="prev" href="<?= $current_url ?>">Prev page</a> <?php else: ?> Prev page <?php endif; ?> </div> <div class="centre-text">Page <?= $input->pageNum ?> of <?= $total_pages ?></div> <div class="next-page"> <?php if($input->pageNum < $total_pages): ?> <a rel="next" href="<?= $current_url . $config->pageNumUrlPrefix . ($input->pageNum + 1) ?>">Next page</a> <?php else: ?> Next page <?php endif; ?> </div> </div> <?php endif; ?>
  22. Are you saying that an images field inside a repeater does not allow drag-and-drop uploading? I'm not aware of any such limitation and with a quick test it seems to be working for me, even inside nested repeaters. I think you should check out the Croppable Image 3 module for managing your different crops. https://github.com/horst-n/CroppableImage3
  23. The %= operator matches part words (which can be desirable) but all the characters in the search string must be in the given order in the searched fields. When I want to match part words I will usually explode() on the space character and then match against each word as a separate clause in the selector. $selector = ''; $search_terms = $sanitizer->selectorValue($input->get->search); if($search_terms) { $search_terms = preg_replace("/\s+/", " ", $search_terms); // replace multiple spaces with single space $terms = explode(" ", $search_terms); foreach($terms as $term) { $selector .= "title|body%=$term, "; } $matches = $pages->find($selector); }
  24. InputfieldPage is available in the hook function as $event->object - so in your hook code copied from InputfieldPage::processInputAddPages you can replace class methods called like $this->someClassMethod() with $event->object->someClassMethod(). But you will need to distinguish between class methods and other PW API variables accessed with $this. E.g. $this->getSetting() vs $this->pages() Edit: actually, that will only work for public methods and properties so it's probably not sufficient. Another alternative is to copy the entire InputfieldPage module to /site/modules/ and make changes there.
  25. As you found, you can't change the $parent_id variable inside the InputfieldPage::processInputAddPages method using this type of hook because $parent_id is neither an argument to the method nor a return value of the method. I think you would have to use a replace hook - copy the whole InputfieldPage::processInputAddPages into your hook function and change as needed. Bear in mind that doing this means that any future core changes in InputfieldPage::processInputAddPages will not take effect while your hook is in place.
×
×
  • Create New...