-
Posts
695 -
Joined
-
Last visited
-
Days Won
20
Everything posted by Jan Romero
-
It’s actually really easy: $brands = $pages->find('template=brand'); echo $brands->sort('-numReferences')->each("<li>{title}: {numReferences}"); Whether it’s very efficient is a different story. I wouldn’t know. Be aware that you have to sort the PageArray. Putting it in the find() selector won’t work. Edit: actually, you probably want hasReferences, as per the documentation: $numReferences Total number of pages referencing this page with Page reference fields. $hasReferences Number of visible pages (to current user) referencing this page with page reference fields.
-
To take the last element of a WireArray and put it at the beginning, you can do this: $products->prepend($products->pop()); To get only pages after the current product, you can do this: $products = $pages->find("sort>{$page->sort}") Maybe post some of your code?
-
Your code as well as eelkenet’s should work if you set output formatting to false at the top instead of at the bottom. AFAIK, without output formatting, File fields always return a WireArray, or rather, a Pagefiles array, which inherits from WireArray. In general the reason you disable output formatting is that you can work with the “raw” data before saving. Changing the formatted data and then only disabling output formatting before the save() should be pointless and/or introduce errors. For example, if you have a field with Markdown formatting and you modify its contents without disabling output formatting, you’re modifying and saving the rendered HTML, destroying your original Markdown markup.
-
$session->redirect with arbitrary 30x status code
Jan Romero replied to schwarzdesign's topic in Wishlist & Roadmap
An easier way to set the status code: http_response_code(303); Available since PHP 5.4. -
Suppressing “command line API” error messages (AJAX/XHR)
Jan Romero replied to Jan Romero's topic in API & Templates
@Robin S Thanks for confirming that! I submitted an issue and a PR I’m not too sure about. https://github.com/processwire/processwire-issues/issues/1143 -
Suppressing “command line API” error messages (AJAX/XHR)
Jan Romero replied to Jan Romero's topic in API & Templates
But ProcessWire’s WireShutdown class considers everything hitting it with X-Requested-With: XMLHttpRequest to be CLI use. The way I see it, from a security perspective that makes the differentiation between public and detailed error messages completely useless: if you’re shown the public error, you can just resend the request with the header and any PW installation will gladly tell all. It kinda didn’t occur to me to even look through the source, because I figured something like this would have a prominent setting somewhere, but now I think it just might be a bug? WireShutdown does this: $useHTML = isset($_SERVER['HTTP_HOST']); // is this an HTTP request where we can output HTML? […] // use text-only output if an http request that is ajax if($useHTML && $config->ajax) $useHTML = false; […] if($config->debug) { $why = $this->labels['debug-mode'] . " (\$config->debug = true; => /site/config.php)."; } else if(!$useHTML) { $why = $this->labels['cli-mode']; } […] if($why) { $why = $this->labels['shown-because'] . " $why $who"; $message = $this->amendErrorMessage($message); $this->sendErrorMessage($message, $why, $useHTML); } else { $this->sendFatalError($who, $useHTML); } So for this purpose, sending two headers in your request is essentially equivalent to the site being in debug mode. That can’t be right? -
Interesting reads from around the web [collection]
Jan Romero replied to wbmnfktr's topic in Dev Talk
In case anyone else hates it when websites do that, set these to false in Firefox about:config: layout.css.scrollbar-color.enabled layout.css.scrollbar-width.enabled And perhaps this one to true: widget.disable-dark-scrollbar- 1 reply
-
- 3
-
-
-
Hi. This is kind of a dumb question, but I’ve been searching for days and couldn’t find an answer. I’m using an XMLHttpRequest to fetch some JSON from a page. This works as expected as long as I don’t send the header X-Requested-With: XMLHttpRequest. With the header, ProcessWire decides that I’m using the command line API and if something goes wrong, it shows detailed error messages to guest users (“This error message was shown because: you are using the command line API”). I appreciate that when debugging, but it would be nice if I could limit it to just superusers. Is there a setting for this? Thanks
-
PW 3.0.142 – Core updates + FormBuilder v40
Jan Romero replied to ryan's topic in News & Announcements
Tbh, I find this whole “virtual field” business somewhat unfortunate… The announcement of custom image fields filled me with joy, and I thought the idea of using templates seemed pretty ingenious (although I don’t like how it introduces magic strings into template names, and generally restricts their naming, and doesn’t allow multiple image fields to share a template. Feels icky to me. Why not have a template selector in the field settings?). However, I was disappointed to find that values are just serialized and dumped into the image-field table. Seems like this data is treated as some kind of second-class citizen. If the custom fields were stored in their own database columns, as suggested by using templates and fields, it would have been a trivial INSERT to migrate from the ImageExtra module. Now I needed to use the PW API to move values from one field to the next, which involves all kinds of voodoo behind the scenes. Wouldn’t it be much less work to just store a page reference with each image and have the custom image fields stored in their respective field-tables? Surely that way it would be easier to make everything play nicely with selectors and everything? Of course, I have to admit I don’t have a lot of MySQL experience. Maybe there are easy and performant and reliable ways to query serialized fields like this and I just need to read up a little ? -
@webhoes yeah, your javascript wants to put the search results into the element #content, and you don’t have one. If you add id="content" to your container div, it works. The search is doing something weird though. It will only find whole words, so if I look for guitars, the “g” gives me “Marshall MG 10 G Combo”, then everything disappears until I finish “guitar”.
-
Art Project Idea - Looking for Preliminary Advice and Developer
Jan Romero replied to montero4's topic in General Support
In accordance with the gist identified by Kongondo, I’ll comment that I figure most of the complexity will probably lie in your envisioned front-end. I’m certain that PW will work just fine as far as it is concerned, but it won’t help you any displaying a zoomable map and all that. This is an ambitious project if you’re really going to involve native mobile apps and payment processing. I would probably suggest keeping it simple for now, and just worry about getting your data from the user to your database and back. Working with data and users is pretty much a breeze with PW. While there may be more suitable products for your particular use case (you’d have to ask someone more broadly versed), I wouldn’t worry about the ProcessWire side of things too much. It’ll probably the part you’ll need the least help with. My tip would be to look into front-end people if you really are looking to hire. I should mention that my personal MO online is Hemingway-inspired, i.e. post drunk, browse sober, and right now I’m, like, really posting. -
Indeed. I just upgraded an old site from 2.7.2, *cough*, and MySQL complained about some query on the edit page. Turns out this module failed to get the name of the path history table, and then it just goes “from where pages_id”. The problem appears to be that it uses constant() to get PagePathHistory::dbTableName, but that has long since moved into the namespace ProcessWire. It seems to work fine once you remove line 74 here and replace it with: $this->dbTableName = $this->wire('modules')->getModule($moduleName)::dbTableName; At least, that’s the quickest fix. Sorry for unearthing this old thread…
-
Is there a way to combine hooks to reduce the code
Jan Romero replied to Juergen's topic in API & Templates
I don’t know your site, but wouldn’t you want to count only the siblings whose templates are also in $preventTpls? -
Well, uh, FWIW I’ve encountered a problem today that may or may not be similar. My backend sessions were working as fine as ever, but users on the frontend would get logged out immediately after logging in. Basically, they would get their welcome page but their next request would fail. After disabling Session Handler Database sessions would persist nicely. Now when I saw you mention the Multilanguage setup, I had a look at my prepend file, where for some reason I can’t really remember I had put this: $session->language = $user->language; I’m sure once upon a time this fixed something about Language settings getting lost in between requests or something, but apparently it doesn’t play nice with the Session Handler Database module. So after removing that line everything is back to normal, DB sessions enabled and all. I have no idea about the mechanics behind the effects I’m observing here, unfortunately, but I thought I’d throw it out there, I guess.
- 1 reply
-
- 1
-
-
Actually, I just experienced this “problem” where I’m saving an image field using $page->save('images') and even in non-quiet mode it didn’t invalidate the one-week template cache. That’s on a 2.7.2 installation. So the answer to your question seems to be Yes, it does prevent the cache from being cleared. I’m putting “problem” in quotes because I don’t really care one way or the other in this particular instance, but my user got confused (as always with caching).
-
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