-
Posts
680 -
Joined
-
Last visited
-
Days Won
18
Everything posted by Jan Romero
-
Am I the only one who got turned into a spice girl by the upgrade? Somehow it didn’t migrate my latest pic but the one I had up until a couple of weeks ago?
-
Sweet site! From https://processwire.com/api/selectors/: ProcessWire 3 contains a workaround for this, but you should be able to build it into your search code by checking for such short words and handling them with a the %= operator.
-
Why don’t you do the three database finds after building the selector? I would imagine that to speed things up, because you won’t be loading as many pages just to throw them out later. Instead of slicing the PageArray you can also put limit and start into the selector like so "start={$start}, limit={$limit}". Edit: Actually, maybe I’m missing something, but it looks like you’re getting ALL horse-notes in $notes_other. I’m also pretty sure that PageArrays automatically filter out duplicates, so when you prepend the other two PageArrays, you’re not really doing anything.
-
ProcessWire trims and escapes selector values, so this doesn’t seem possible with pure PW selectors. You may try something like this… $query = wire('database')->prepare('SELECT pages_id FROM field_postcode WHERE data like concat(:areacode, " %")'); $query->bindValue(':areacode', 'A1', PDO::PARAM_STR); $pages->executeQuery($query); $results = $query->fetchAll(PDO::FETCH_COLUMN); $pages_matching_ = $pages->getById($results);
-
Admin Search - no unplubished Pages can be searched
Jan Romero replied to Erik Richter's topic in General Support
I’m not on 3.0, but I figured I’d just swap out the function and it’s working fine. Users still won’t show up even if you’re allowed to edit them, but that seems to be a separate issue I opened on GitHub. -
The redirection is probably the most problematic part of this plan, because the new page load will interrupt the visitor’s typing. What you would want to do is keep the search box and simply change the rest of the page using javascript. If the browser supports it, you can use history.pushState() to do manipulate the address bar, so visitors can have bookmarkable links to their search results. Here is a crude solution using jQuery. As you can see, JavaScript does most of the work: Normal page looks somewhat like this. There is a search box and some unrelated content. <body> <form id="searchform" method="GET"> <input type="text" name="s" value="purple unicorns" /> </form> <div id="content"> <!-- Your regular content stuff goes here. If the user starts typing, we replace all of this with a placeholder, do the search, then replace it with the results. Of course you would want to do something a bit more sophisticated and pretty in real life. --> </div> </body> Some JavaScript that runs on the above page and requires jQuery. $(document).ready(function() { $('#searchform :input').on('input', function() { $("#content").html('<h2>Loading…</h2>'); loadSearchResults(function(result) { if (result === false){ result = '<h2>An error occurred.</h2>'; } if (result == '') result = '<h2>No results found.</h2>'; $("#content").html(result); }); }); function loadSearchResults(callback) { var form = $('#searchform :input[value!=""]'); var serialized_form = form.serialize(); //if your search field is named “s” this will be “s=search words” if (serialized_form !== '') { var new_url = '/search/?'+serialized_form; //consequently, this will be „/search/?s=search words“ if (/* IE9 needs this check */ history.pushState) history.pushState({}, '', new_url); //your address bar now shows www.example.com/search/?s=search words $.ajax({ type: form.attr('method'), url: '/search/', data: serialized_form, success: function(result) { if (callback && typeof(callback) === 'function') { callback(result); } }, error: function() { if (callback && typeof(callback) === 'function') { callback(false); } } }); } } } The search page /search/ handles a GET parameter called s and either serves a full results page, or just the markup necessary to inject it into existing pages. <?php $s = $input->get->text('s'); $results = $pages->find("title%={$s}, limit=100"); $results_markup = "<h2>{$results->count} results found for “{$s}”:</h2>"; $results_markup .= "<ul>"; foreach($results as $r) { $results_markup .= "<li><a href='{$r->url}'>{$r->title}</a></li>"; } $results_markup .= "</ul>"; //if we’re live-searching, output only the results markup, //without <html>, <body> etc. if($config->ajax) { echo results_markup; return $this->halt(); } //now do your regular markup include('head.inc'); echo $results_markup; include('foot.inc'); ?> IRL you would probably serve JSON instead of full markup, but this keeps the JavaScript part short. You would also want to handle cases where users use the live search and then hit their browser’s back button.
-
I don’t see why not, although I have no experience with the Custom Files module. You could just hook into ProcessPageEdit from your admin.php. Here is a more complete example: $wire->addHookAfter('ProcessPageEdit::execute', function(HookEvent $event) { $tableField = 'product_features'; $changeColumn = 'feature_value'; $disableColumn = 'custom_value'; $event->return .= ("<script> $(document).ready(function() { $('#wrap_Inputfield_{$tableField} input[name$=_{$changeColumn}]').on('change', disable_my_field); function disable_my_field() { //probably not the best way of finding our target field… var disableThis = $(this).parent().parent().find(':input[name$=_{$disableColumn}]'); if ($(this).val() == '') { disableThis.prop('disabled', false); disableThis.parent().css('background', '#f0a'); //color just for better visibility } else { disableThis.prop('disabled', true); disableThis.val(''); //clear field disableThis.parent().css('background', '#ff0'); } }; //call the function once to affect existing rows //can’t get this to work for some reason disable_my_field.call($('#wrap_Inputfield_{$tableField} input[name$=_{$changeColumn}]')); }); </script>"); }); It’s not quite there yet, but it works pretty well. Seems quite useful actually. I might use this myself sometime. You can of course use the same principle to pre-select options based on another column. You may want to look into this thread: https://processwire.com/talk/topic/2331-doing-additional-logic-after-saving-a-new-page/. It’s a bit old, though.
-
I think Profield Table is still your best bet for this functionality. In order to conditionally disable the third row you would inject a bit of jQuery into the edit page. Per ejemplo: $('#wrap_Inputfield_features input').on("change", function() { if ($(this).val() == '') { $(this).parent().next().css('background', '#f0a'); $(this).parent().next().children('input').prop('disabled', false); } else { $(this).parent().next().css('background', '#ff0'); $(this).parent().next().children('input').prop('disabled', true); } });
-
Admin Search - no unplubished Pages can be searched
Jan Romero replied to Erik Richter's topic in General Support
I would like to take issue with this as well. It’s awkward for non-superusers not to find pages (or other users) they can otherwise reach, and I don’t really see why this restriction is in place by default. It is also not easy to implement a hook to change this behavior, which would be trivial to do the other way around. I.e. if the “include” parameter weren’t overridden by the Process function, that feature could be retrofitted like so: wire()->addHookBefore('ProcessPageSearch::executeFor', function($event) { if(!$this->user->isSuperuser()) wire()->input->get->include = 'hidden'; }); As well as any other custom restrictions one might need to respect custom roles and permissions. However, as it is now the restriction is hardcoded into the function and I’m not sure how to modify it in a non-destructive manner. Are there security reasons for the way it’s currently done? -
Related pages: How to enforce uniqueness and minimum/maximum count?
Jan Romero replied to wet's topic in API & Templates
That UI is fricken genius. I love it. Very convenient that I can like it twice now lol -
For your autoload scenario I’ve been doing something similar, but I execute the job via Ajax. That way it doesn’t impact the page load. It’s an extra request, but should go unnoticed by your visitors since you don’t need to wait for a response. Sorry this doesn’t answer your question specifically, but I thought it might be applicable to your scenario. With regards to caching, ProcessWire will always execute even if it only serves a cached page. That is unless you use ProCache, which allows you to serve cached HTML without invoking PW.
-
You don’t need to call size() at all if you don’t want to resize the image. Also you don’t seem to be entirely familiar with PHP’s control flow syntax. Try this inside your foreach: if ($image->width <= 800) { //width is simply a property of type integer, in pixels $imgurl = $image->url; //use url of source image } else { $imgurl = $image->size(800)->url; //create a variation 800px wide and use its url } $images .= "<img src='{$imgurl}' />"; You may also be interested to know that there is a config option that prevents images from being upscaled. Have a look around in config.php’s image options. I don’t know if it’s some kind of special syntax you’re using for your if-condition, but here is the PHP manual just in case: http://php.net/manual/en/control-structures.if.php Sorry, I would format more nicely, but I’m on mobile :/
-
Quick question: Show Markdown code in field notes
Jan Romero replied to wheelmaker24's topic in General Support
I use a zero-width space word joiner character to destroy the markdown: [Link-Beschreibung](http://www.beispiel.de) This will prevent users from copying it from the field description, though… -
I agree it's not optimal either, but the best way to do this is to click on "Jo" to highlight it before dragging "Dateityp" under it. Think of it as expanding the tree below "Jo". Even though it has no children yet, you have to "open" them before you can put one in. It makes a lot of sense but I agree it's not the most intuitive experience. With Ryan adding long-click actions now, I think this would be a use case worth considering. I. e., dragging and holding a page on top of another page for one second could make it expand.
-
Grandpa looking down his family tree
Jan Romero replied to heldercervantes's topic in General Support
You can do it from $pages as well, using the has_parent selector. It will match up the whole tree, not just the direct parent. I can't believe I actually didn't know $page->find(). Nice one! -
If you want to avoid converting the selector to SQL you can let ProcessWire do it for you as teppo has shown in this post: $selectors = new Selectors("template=blog-post, limit=1000000"); $pagefinder = new PageFinder(); $sql = $pagefinder->getQuery($selectors->getArray(), array())->getQuery(); Then you can modify that or wrap your own select around it: select sum(data) as sum_amount from field_amount where pages_id in ($sql)
-
$timerkey = Debug::timer(); //do lots of things echo "Lots of things took " . Debug::timer($timerkey) . " seconds to do."; Note Ryan’s benchmarking tips here: https://processwire.com/blog/posts/processwire-3.0.6-brings-pages-upgrades-and-link-abstraction/#how-to-benchmark-pages
-
Try clearing your browser cache or force-refresh the page using CMD+SHIFT+R (I think).
-
You don’t actually need to load the page at /url-one/, since you already know its url, and that’s all you need for your switch logic. Also, your variable $styleSwitcher refers to a Page object, but you’re comparing it to a string (the current page’s url). I would suggest simply comparing $page->url to "/url-one/".
-
PW 3.0.8: Smarter+faster page tree and a ProDrafts update
Jan Romero replied to ryan's topic in News & Announcements
I love fridays. -
Load page via AJAX and redirect to parent
Jan Romero replied to alejandro's topic in API & Templates
Existing pages always take precedence over urlSegments. You have several options: Use urlSegments that don’t exist as children of /site/teachers/, for example by adding a string, or by using 2 urlSegments. E.g. /site/teachers/selection/teacher1/. Use GET parameters instead: /site/teachers/?teacher=teacher1. You could either process the parameter with PHP or catch it with JavaScript and use your existing AJAX solution. Which would probably be the simplest option. Just add one or two lines of JS. Or, if you don't want the actual page under /site/teachers/teacher1/ to be reachable at all, just display /site/teachers/ in that template. Example below: template of /site/teachers/teacher1/: $options['teacher'] = $page; //pass the teacher to the parent page using options array echo $page->parent->render($options); //render the parent page (/site/teachers/) template of /site/teachers/: if(isset($options['teacher'] && $options['teacher'] instanceof Page) { $aside_teacher = $options['teacher']; } //Now render the page as you normally would, and you can use $aside_teacher to put its contents where you need them This also has the added bonus that you can use standard page caching for the child pages. -
How to get the title from a page field in a repeater
Jan Romero replied to joe_ma's topic in General Support
I'm confused. What @kongondo says is undoubtedly true: a page field will return a Page object, even from within a repeater. I just tested it myself. But knowing that, @joe_ma's code from the OP should have worked: echo "<div class='" . $s->color->title . "'>"; Here, $s is the repeater item, color is its page field, and title is the title property of that page field's page. Seems fine to me? Edit: Oh, I get it. The page field "color" is multi-page, so it returns a PageArray which silently fails to return a title property. @joe_ma, try changing color to a single page field, unless you need to define multiple colors per repeater item. Then your original code should work. It's a good idea to name your fields according to what they return, i.e. this one is called "color" as opposed to "colors", so when you access it, you're likely to expect a single item -
Dynamically create .ics file for existing pages
Jan Romero replied to gmclelland's topic in General Support
Great introduction to urlSegments. This is a textbook use case. However, some pointers for beginners who might want to copy and paste the code. You can probably skip the whole $allowedSegs array, imo. I would sanitize the segment like you did, then cut off the extension afterwards (not sure if anything can go wrong doing that string operation on unsanitized input, but it works the same). Then I’d just get a child page of that name. Most importantly, get the child page using $page->child('name=' . $sanitizedSegment), because with $pages->get() you might get an unexpected page of the same name from a different branch of the page tree. If it returns a NullPage, you can still 404. Also, I would refrain from overwriting $page, just to rule out any potential headaches that might cause -
Button on dashboard that creates new page with a specific template
Jan Romero replied to Jon's topic in API & Templates
You can set a default template by supplying the GET parameter “template_id”, or the POST parameter “template”: http://example.com/processwire/page/add/?parent_id=1024&template_id=46 I’m not sure about forcing the template. You could probably specify a default name format in order to bypass the page-add screen directly, or hook into ProcessPageAdd to manipulate the form. -
This line is executed regardless of whether $item has children: $out .= "<li$class><a href='{$item->url}'><i class='fa fa-file-text-o'></i> {$item->title}</a>\n"; You’re going to want to attach it to the condition if($numChildren) { below, so the link is only appended to your output if it doesn’t have children. Perhaps like so: if(!$numChildren) { //No children, so append the standard top-tier link $out .= "<li$class><a href='{$item->url}'><i class='fa fa-file-text-o'></i> {$item->title}</a>\n"; } else { //We have children here, so append the parent-style link and do the recursion //... }