Jump to content

Robin S

Members
  • Posts

    4,791
  • Joined

  • Days Won

    303

Posts posted by Robin S

  1. 4 minutes ago, oma said:

    I have managed to manipulate /wire/modules/Process/ProcessPageEditLink/ProcessPageEditLink.module so should do the same for that too I guess! I realise it gets a little dodgy doing things like this but won't be updating the version once it's live.

    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/.

    • Like 1
  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.

    2 hours ago, oma said:

    Another question would be... is it possible to edit the 'wire/modules/Inputfield/InputfieldCKEditor/plugins/pwlink/plugin.js' file within '/site/templates/' as an extension so updates don't override any added/adapted code?

    Copy /wire/modules/Inputfield/InputfieldCKEditor/plugins/pwlink/ to /site/modules/InputfieldCKEditor/plugins/pwlink/ and make your changes there.

  3. 2 minutes ago, szabesz said:

    LostKobrakai did not mention MVC at all, probably he did not even referred to it , as far as I can see.

    He talks about the separation of concerns...

    9 hours ago, LostKobrakai said:

    I'd much rather would like to see a guide dedicated to examples of direct output -> delayed output -> separation business logic / view logic -> templating engine (twig/blade), what the benefits are and how to switch between them (e.g. same output in different strategies). Especially the third one is a kinda pet peeve of mine, because I went into the rabbit hole myself, where markup was so deeply coupled with processwire api stuff, that it was a nightmare to change anything.

    ...and MVC is a popular pattern that enforces that. But they're not exactly the same thing, for sure.

    • Like 2
  4. 7 hours ago, szabesz said:

    By Ryan: "What's described in this post is not a template engine, and not even related to a template engine.

    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.

    7 hours ago, LostKobrakai said:

    And as likely to misuse.

    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...

    On 14/01/2017 at 10:57 AM, ryan said:

    Yet it’s likely to be more accessible for front-end developers and newcomers to ProcessWire, without sacrifices.

    ...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.

    • Like 3
  5. 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.

    2017-01-16_110804.png

    • Like 1
  6. 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')
    )

     

     

     

    • Like 1
    • Thanks 1
  7. 2 hours ago, mangopo said:

    Makin a separate mobile version to (m.tld) is better in this case. How would it work with PW: two sets of templates using the same database for articles?

    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.

    • Like 3
  8. 15 minutes ago, adrian said:

    Can you find the actual repeater item, or just the page that has a repeater item that matches the find?

    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

    • Like 1
  9. 5 hours ago, wheelmaker24 said:

    So, bernhard, how did you hide the label and the "Add new" link? Or is this just a mockup?

    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".

    • Like 2
  10. 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.

    • Like 4
  11. @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"); 

     

    • Like 1
  12. 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!

    • Like 7
  13. 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

     

  14. 1 hour ago, OpenBayou said:

    One item I use is `add_image_size( 'link-image', 630, 330, true);` so that when a person uploads an image it crops it to 630px width and 330px height and calls it 'link-image' so you can call that image setting in your theme.

    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...

    2017-01-14_095657.png

    ...then call it by name in your template...

    $page->image->getCrop('link-image')->url;

     

    • Like 2
  15. 3 minutes ago, OpenBayou said:

    Keep in mind that I'm on a MacBook Pro retina

    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.

    • Like 1
  16. 50 minutes ago, horst said:

    add a custom name part (suffix) to the different sharpening variations:

    
    foreach(array('none', 'soft', 'medium', 'strong') as $sharpening) {
      echo "<img src='" . $child->post_image->first()->size(200, 0, [
        'upscaling' => false,
        'quality' => 90,
        'suffix' => $sharpening
      ])->url . "' title='{$sharpening}' />";
    }

     

    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}' />";
    }

     

    1 hour ago, OpenBayou said:

    sharpening is strong

    1 hour ago, OpenBayou said:

    The main problem I'm having is you can see wavy lines on images that are slanted.

    The jaggies are a consequence of the sharpening - you can't have it both ways. With sharpening off the edges are smooth.

    gaems_m155-front_right_facing_thumb_jpeg_cc5c678eeef90dc44c2c2c169a0ad9bc.200x0.jpeg

     

    • Like 2
  17. 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; ?>

     

    • Like 4
  18. 1 hour ago, ZGD said:

    I've tried creating a repeater in this matrix type which contains an image field (each supporting two images, as above), but this means that I can no longer drag and drop multiple images at once.

    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

    • Like 1
  19. 8 hours ago, godmok said:

    So the search for "tower located in chicago" has other results (two) than the results for "tower chicago" (two, but different). As I understand is: user will fill in any kind of random words into it and think the search for "tower chicago" has the searched pages for "tower located in chicago" too, because the two words are inside that text too, right?

    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);
    }

     

    • Like 2
  20. 28 minutes ago, abdus said:

    Also, the method utilizes other methods and fields from InputfieldPage class itself, so replacing it won't do any help either.

    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.

  21. 42 minutes ago, abdus said:

    I tried that as well. I can intercept and hook into InputfieldPage::processInputAddPages events, and change parent id to correct one, but PW ignores the change. 

    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.

    • Like 2
×
×
  • Create New...