Leaderboard
Popular Content
Showing content with the highest reputation on 02/08/2019 in all areas
-
The view permission controls viewing on the front-end, it doesn't relate to pages being listed in Page List. For more advanced control over page permissions try hooking after the following Page methods, returning true/false as needed. $page->listable() is the one related to which pages appear in Page List. $page->listable() bool Returns true if the page is listable by the current user, false if not. Can also be used as property: $page->listable $page->moveable() bool Returns true if the current user can move this page. Optionally specify the new parent to check if the page is moveable to that parent. Can also be used as property: $page->moveable $page->publishable() bool Returns true if the page is publishable by the current user, false if not. Can also be used as property: $page->publishable $page->restorable() bool Returns true if page is in the trash and is capable of being restored to its original location. @since 3.0.107 $page->sortable() bool Returns true if the current user can change the sort order of the current page (within the same parent). Can also be used as property: $page->sortable $page->trashable() bool Returns true if the page is trashable by the current user, false if not. Can also be used as property: $page->trashable $page->viewable() bool Returns true if the page (and optionally field) is viewable by the current user, false if not. Can also be used as property: $page->viewable An example of a Page::listable hook - note that such hooks do not restrict the superuser role: $wire->addHookAfter('Page::listable', function(HookEvent $event) { $page = $event->object; if($this->wire()->user->hasRole('editor') && $page->template == 'basic_page') $event->return = false; });4 points
-
Ok, I understand ? But even then I'd say it's easier to build in the backend than in the frontend: And that's all the code that is needed: public function ___execute() { /** @var InputfieldForm $form */ $form = $this->modules->get('InputfieldForm'); $form->add([ 'credit' => [ 'type' => 'markup', 'label' => 'Guthaben', 'value' => $this->files->render(__DIR__ . '/markup/credit'), 'columnWidth' => 25, ], 'trainings' => [ 'type' => 'markup', 'label' => 'Trainings', 'value' => $this->files->render(__DIR__ . '/markup/trainings'), 'columnWidth' => 25, ], 'shop' => [ 'type' => 'markup', 'label' => 'Buchung', 'value' => $this->files->render(__DIR__ . '/markup/shop'), 'columnWidth' => 50, ], 'dashboard_history' => [ 'type' => 'RockGrid', 'label' => 'Verlauf', 'ajax' => false, ], ]); return $form->render(); }4 points
-
A module helping you to manage SEO related tasks like a boss! Automatically generates and maintains a XML sitemap from your pages. Includes a Fieldtype and Inputfield to manage sitemap settings and meta data for pages (Title, Description, Canonical URL, Opengraph, Twitter, Structured Data etc.) Multi language support for the sitemap and meta data. Configure default values for meta data on template level and let pages inherit or overwrite them individually. Map existing fields to meta data, reducing the need to duplicate content. Live preview for content editors how the entered meta data appears on Google. Live preview for content editors how the entered Opengraph data looks like when sharing a page with Facebook. Check out the README on GitHub for more details, including usage instructions. The module is currently released as beta and needs testing! Please report any issues on GitHub or in this forum thread, if you find time to give it a try ? Examples Here is an example of rendered meta data you will get from a single SeoMaestro field: <title>Sed dictum eros quis massa semper rutrum. | acme.com</title> <meta name="description" content="Si lobortis singularis genitus ibidem saluto. Dolore ad nunc, mos accumsan paratus duis suscipit luptatum facilisis macto uxor iaceo quadrum. Demoveo, appellatio elit neque ad commodo ea. Wisi, iaceo, tincidunt at commoveo rusticus et, ludus."> <meta name="keywords" content="Foo,Bar"> <link rel="canonical" href="https://acme.com/en/about/"> <meta property="og:title" content="Sed dictum eros quis massa semper rutrum."> <meta property="og:description" content="Si lobortis singularis genitus ibidem saluto. Dolore ad nunc, mos accumsan paratus duis suscipit luptatum facilisis macto uxor iaceo quadrum. Demoveo, appellatio elit neque ad commodo ea. Wisi, iaceo, tincidunt at commoveo rusticus et, ludus."> <meta property="og:image" content="https://acme.com/site/assets/files/1001/og-image.jpg"> <meta property="og:image:type" content="image/jpg"> <meta property="og:image:width" content="1600"> <meta property="og:image:height" content="1200"> <meta property="og:image:alt" content="Lorem Ipsum"> <meta property="og:type" content="website"> <meta property="og:url" content="https://acme.com/en/about/"> <meta property="og:locale" content="en_EN"> <meta name="twitter:card" content="summary"> <meta name="twitter:creator" content="@schtifu"> <meta name="twitter:site" content="@schtifu"> <script type="application/ld+json"> { "@context": "https://schema.org", "@type": "BreadcrumbList", "itemListElement": [ { "@type": "ListItem", "position": 1, "name": "About", "item": "https://acme.com/en/about/" } ] } </script> <meta name="generator" content="ProcessWire"> <link rel="alternate" href="https://acme.com/en/about/" hreflang="en"> <link rel="alternate" href="https://acme.com/en/about/" hreflang="x-default"> <link rel="alternate" href="https://acme.com/de/ueber/" hreflang="de"> <link rel="alternate" href="https://acme.com/fi/tietoja/" hreflang="fi"> And some screenshots of the UI:3 points
-
Thanks @B3ta I think that the decision where the Seo Maestro field is rendered should be left to the user. And it should be done in the same way it works for all fields: By editing the template and placing the field. Display it in a new tab? Create an InputfieldFieldsetOpen and wrap the field. But maybe the content editor only needs to see meta title and description - then it's not worth to create a new tab. I understand that it requires some manual work to add the field to all templates, but I don't think it is the responsibility of the module to do this. There are other solutions like the Migrations module, which can do this task in a few milliseconds. For the project I built this module, it took me 10 minutes to write a migration that creates and configures the field, adds it to all templates, tweaks the settings per template and also wraps it in a tab. No need to do this by hand if I deploy to production. Cheers3 points
-
Enable debug mode to get more informative error messages. Open file /site/config.php via FTP or hosting file manager and edit the line below to set debug mode true, or add the line if none exists. $config->debug = true; It's possible if the original superuser was deleted, but that's not a common scenario. You could try adding a new superuser account by adding and loading the following "add_user.php" file in the site root. <?php require './index.php'; $u = new User(); $u->name = 'new_user'; $u->pass = '123456'; $u->addRole('superuser'); $u->save(); Edit: by the way, you can also find the names and ids of the existing users by looking in the pages table of the database. In phpMyAdmin or similar, sort the table by the templates_id column, and look at the names and ids of rows where templates_id is 3 (3 is the id of the user template).3 points
-
Works for me (tried to keep it as compact as possible): <?php namespace ProcessWire; /* Quick test to capture out of band ECHO messages from PHP */ class WontNameItFoo { public function Quote() { return('The best is yet to come...'); } public function Einstein() { return('E = mc²'); } } $PhpErrors = ''; // This will be filled from our error handler global $PhpErrors; function php_error_handler($errno, $errstr, $errfile, $errline) { global $PhpErrors; // Add an LI element to our error string $PhpErrors .= "<li><b>RUNTIME ERROR #{$errno}:</b> $errstr in ".basename($errfile)."({$errline}):<br>"; $PhpErrors .= '<pre>'.file($errfile)[$errline-1].'</pre></li>'; } if($this->config->ajax) // Handling an AJAX request? { header('Content-type: application/json; charset=utf-8'); // Define response header set_error_handler('ProcessWire\php_error_handler'); // Register Error Handler try { // Perform some PHP processing without any kind of sanitation for testing only // In a productive environment proper parameter verification should be implented! $ajaxDate = 'Date: ' . date('l jS \of F Y h:i:s A', $input->post('timestamp')); $ajaxDiv = $input->post('dividend') . ' / ' . $input->post('divisor') . ' = ' . (string)($input->post('dividend') / $input->post('divisor')); $wnif = new WontNameItFoo(); $func = $input->post('function'); $ajaxFunc = $wnif->$func(); // This is brute force catching of fatal PHP errors... } catch(\Throwable $t) { php_error_handler($t->getCode(), $t->getMessage(), $t->getFile(), $t->getLine()); // $PhpErrors .= '<li><pre>'.$t->getTraceAsString().'</pre></li>'; // in case you like to see the stack trace } if($PhpErrors != '') // Errors captured from our error handler? $TheData = [ 'errors' => $PhpErrors ]; // Only return errors else $TheData = [ // No error, return proper result 'ajax-result' => $ajaxResult, 'ajax-division' => $ajaxDiv, 'ajax-date' => $ajaxDate, 'ajax-func' => $ajaxFunc, ]; if($input->get->callback) // JSONP? (not used here, would require GET request, useful for cross-domain query) echo $input->get->callback."(".json_encode($TheData).")"; else echo json_encode( $TheData ); // Regular AJAX response die(); } // Setup regular HTML content including script // You may replace "$content =" with echo, depending on your output scenario $content = "<div><h1>{$page->title}</h1> <form id='the-form' action='#'> Timestamp: <input id='timestamp' name='timestamp' type='text' value='SomeBogusData'><button type='button' onclick='setNow(\"#timestamp\");'>Now</button><br/> Divide <input name='dividend' type='text' value='1234'> by <input name='divisor' type='text' value='0'><br/> Function <select name='function'><option value='Einstein'>The Einstein</option><option value='Quote'>Personal Quote</option><option value='FourtyTwo'>The answer to life, the universe and everything</option></select></br> <button type='submit'>Execute</button> </form> <div id='ajax-status'></div> <div id='ajax-division'></div> <div id='ajax-date'></div> <div id='ajax-func'></div> </div> <script> function setNow(target) { $(target).val(Math.round((new Date()).getTime() / 1000)); } $(document).ready(function() { $('#ajax-status').html('Ready...'); $('#the-form').submit(function(event) { event.preventDefault(); // No default action $.ajax({ url: '.', type: 'post', data: $( '#the-form' ).serialize() }) .done(function( jsonData ) { if(jsonData['errors']) { $( '#ajax-status' ).html( 'ERROR: <ul>' + jsonData['errors'] + '</ul>' ); } else { $( '#ajax-status' ).html( 'SUCCESS!' ); // console.log(jsonData); for (var key in jsonData) { $('#'+key).html(jsonData[key]); } // Distribute result into DIVs } }) .fail(function() { $( '#ajax-status' ).append( 'FAILED' ); }); }); }); </script> "; See it live: https://www.team-tofahrn.de/ajax-test/3 points
-
For anyone interested, I solved this by setting the "User navigation label format" in the AdminThemeUikit module config to an empty string... ...and changed the icon and link href with the following custom JS: // Modify tools menu var $tools_link = $('#tools-toggle'); $tools_link.find('.fa-user-circle').removeClass('fa-user-circle').addClass('fa-wrench'); $tools_link.attr('href', ProcessWire.config.urls.root).attr('target', '_blank');2 points
-
The "hookable" icon in the API methods listing is almost invisible - I think it's missing a width rule: Besides the size glitch, I think it would be helpful to make the meaning of this icon a bit more obvious - the single note at the top about it's meaning probably is not enough. Some ideas: Add a label for the column in the table header Add a title tooltip that explains the meaning of the icon on hover Use a different icon than the thunderbolt - didn't the old site have a "hook" icon in this place?2 points
-
@modifiedcontent Thanks for the post. Circular answer: It assumes it will be used for postal mailings because that's exactly what it was developed for. It was something I wrote for myself and a charity I'm involved with. Ironically, we use it for postal addresses that appear in other places, not just printed matter, including emails. Works just fine. If you need to prevent the address-label-like format preview, you can simply turn it off in the field settings. Not sure I understand. As all address subfields are accessible via the api, you can easily pull any, and format them as needed for whatever purposes within your own templates or hook functions. As I pointed out earlier in the thread, this was written as a compromise between straight textarea input and a form based approach. I've never come across an address input field that I actually liked - until I wrote this one. I am open to considering a PR that allows different skins for the module, if you're interested in helping. Otherwise I can only suggest customising the CSS file that appears inside the module if you'd like to revert to the default fonts/inputfield look. You could also try switching the input of the field over to the "Fixed data table" option under the Select Input Format section of the settings, to see if that suits your requirements better.2 points
-
2 points
-
I strongly disagree. The admin is built exactly for such tasks. It's a content MANAGEMENT SYSTEM. So why should it not be capable of managing projects? You have all you need in the admin: Access control, forms, hooks, fields, conditional fields, several listing tools (*hint* RockGrid *hint*), etc. That would be a LOT of work to rebuild on the frontend! I know it feels hard in the beginning, but it just makes a lot of sense to use the tools we already have instead of rebuilding it from scratch. You'll learn a lot of useful stuff for other PW projects and you'll build modules that you can reuse (or share).2 points
-
This is an infinite loop you're causing. You hook after the render of a field named a specific name and in the hook you render another field of the same name, which again triggers your hook to replace and so on. You'd either need to find a hook, which won't be triggered again by what you're doing inside the hook execution (like @Martijn Geerts tried) or you need to find a way to differenciate the first call to your hook from the ones triggered by your code within the hook.2 points
-
Conditionally 2, provided the collapsible option is available. One of the things I like about Processwire is that it plays nice with mobile screens. Some other CMSs are clearly designed for desktops or large tablets only, but Processwire will work even on a smartphone. I can't say how often I'd actually use it on a phone, but it would be nice to have the option. I actually can think of a case where having the backend mobile friendly would be handy. I was at a market last year, and someone didn't have any cash, but did have a credit card. Of course the front end of my site is mobile friendly anyway, but it could be handy to have the backend mobile friendly too.2 points
-
2 points
-
Alternatively you can hook after ProcessPageSearch::findReady to make it a bit more specific to autocomplete:2 points
-
I think there is still a big issue for the Functions API and variable API. As my understanding we are pushing the Functions API, however, the blog posts are still using the variable API in it's examples. I'm getting really mixed messages, are we pushing the functions API or not? I can see this starting to get really confusing for new people coming in to ProcessWire. I can see them building websites with a mix of Functions API and variable API with little understanding of the difference. For example, they may believe that to get page data you do <?= page('title') ?> but to sanatize the data you use <?= $sanitizer->text( page('title') ) ?> Honestly, I think we should just push one or the other. Sometimes using one and sometimes using the other is causing a lot of confusion. We run the risk of moving into WordPress territory where there are multiple ways of achieving the same thing. We will have people asking the questions, which one or which way is best. I just believe a decision needs to be made and run with it. At the moment, I have no idea which approach to use for my next project. I was edging towards the Functions API but I just want to use what is seen as the standard.2 points
-
A module for managing files and folders. Supports creating, opening (e.g. viewing, playing, editing), renaming, moving, copying, deleting and searching for files. You can also view and change (not supported on Windows) file and directory permissions. https://github.com/matjazpotocnik/ProcessFileManager The author of FileManager component is (c) 2006 - 2018 Gerd Tentler, http://www.gerd-tentler.de/tools/filemanager/. I modified it to work with ProcessWire as a module. Please see license files on usage in commercial projects!1 point
-
We're finally launching a redesign of our website! Doesn't feel like it to us, but our previous design was already from 2013 ? https://ed-works.com/ We like to keep things simple, so the only third-party modules that we installed were Tracy debugger, Admin on steroids and Admin Theme Boss, which we tweaked a little bit to our taste. All in all, there's not much going on inside PW. Our main concern was to serve the frontend with responsive images with a close quality to the originals, and for this, it's important that PW allows us to use ImageMagick for resizing them. We also love to use PW's image tags to add classes to the images. In this case, we use them to display the images with three different sizes. We also had to change the templates to serve the projects to the homepage via Ajax. We hope you guys like our new baby ? Edit: I forgot to refer that we also changed our logo and tweaked our name to ED works.1 point
-
ProcessWire 3.0.125 has several useful new $sanitizer methods and options, as well as new ways to access them directly from the $input API variable. This makes dealing with user input even easier than it was before. This version also brings updates to our translation functions and improvements to our API documentation: https://processwire.com/blog/posts/pw-3.0.125/1 point
-
1 point
-
That's a really good point, and a situation I haven't considered before. But I don't think there is any syntax that does what you want. And if you look at how the values of multiple page reference fields are stored in the database (with each selected page being a separate row in the database) I can't see a way to find exact matches, either with an API selector or an SQL query, without explicitly stating all the values that you don't want to match. So I'm thinking that one approach to make it easier to do these kinds of searches would be to create a function that: 1. Takes the field name and pages you want to match as arguments 2. Gets all the pages that have been selected in the field 3. Subtracts the pages to match from the pool of selected pages 4. Returns a selector string component for the pages not to match Then you include that exclusion string in your selector. I might have a play around with this later if you don't beat me to it or you come up with a smarter solution. ?1 point
-
Yeah, I can understand that, but I was going for a pretty opinionated input look - in part to try and provide a slick (fast) keyboard entry method for users at the charity - that really mimics an address label. Please feel free to share your "vanilla" CSS and whatever your findings are regarding getting it working with map marker modules - I know there will be some others in here who are interested in such an integration.1 point
-
To me the beauty of Processwire is that it makes no assumptions how you use it. This module breaks with that logic a bit, probably unnecessarily. I have started editing the css. That is no big deal. I'll look into how to use this field as input for the map marker modules, make them work together. btw, I hope your health problems are under control. Either way, take care.1 point
-
Aaahhhh!! A name! That's it, I didn'nt gave one! Thanks so much, Adrian!!!1 point
-
Version 0.4.0 renders some common meta tags not managed by the fieldtype, and fixes a couple of issues reported. Thanks! See https://github.com/wanze/SeoMaestro/releases/tag/v0.4.0 for more information. Cheers1 point
-
1 point
-
I agree with you @bernhard, but I said so because it seems the specs are for a simple page (more like a read-only executive report), as far as I understand it. But for the case you mentioned, the admin page is the way to go! And thank you for the article, I'll be using its lessons to build a dashboard in the near future. ?1 point
-
A different approach that has already been discussed would be an image reference field: https://www.google.com/search?q=site:processwire.com+image+reference+field1 point
-
I agree with Autofahrn, it seems that the logic should stay in the frontend as it will be easier to control and maintain.1 point
-
OK, I'll remember that, and any Admin here please delete that info for me, guess I cann't do that on my own. And I find it hard to amend my post, only get a short window of one minute or so. And, yes, I DID the hello world tuts. Also I'm watching some youtube tuts by Ryan. Hope I could learn fast. Thanks.1 point
-
I think this is okay - maybe to put some documentation note about that in the readme for user's who used MarkupSEO and will migrate zu SeoMaestro.1 point
-
Thanks @Robin S - you just reminded me to update to that version - cheers!1 point
-
Thanks for resolving the issue! I don't get the bit about only used in admin; do you mean use a condition to check whether in admin? If you tested and it works find in the frontend as well with your mod, that's great! If the mod affects the frontend, then we can do the condition check for admin. It's been a while since I looked at the module and the master branch is beginning to really lag behind the dev branch. If you can write some code for me here rather than a PR, I'll appreciate it, thanks.1 point
-
1 point
-
Techniques to use in order to cut down on new field creation: Free: https://processwire.com/blog/posts/making-efficient-use-of-fields-in-processwire/ https://processwire.com/blog/posts/processwire-3.0.73-and-new-fieldset-types/ https://processwire.com/blog/posts/pw-3.0.87/#new-field-template-context-settings https://processwire.com/blog/posts/processwire-3.0.14-updates-file-compiler-fields-and-more/#best-practices-with-fields-and-values https://processwire.com/blog/posts/pw-3.0.106/#a-new-way-to-search-with-upgraded-tags-for-fields Paid but this money supports the project ? https://processwire.com/store/pro-fields/ https://processwire.com/blog/posts/functional-fields/1 point
-
Hi @ryan, could you please add some more detailed documentation for the $page->render() method to the API docs? Currently the details are quite minimal (the method doesn't have it's own page but just a short entry on the $page documentation) and doesn't cover all the options that you describe in this post: I guess the docs for $page->render() need to somehow pull in the PhpDoc comments from PageRender::renderPage().1 point
-
Same feelings also. I think Teppo really said well how I felt also when read the latest post (and discussion about api examples). That kind of optimization is nice per project, but it is really confusing for a platform that we use to maintain and build hundreds of websites and applications with multiple developers. I'm all in for introducing breaking changes for 4.0. That would get rid of compiler also.1 point
-
I must agree as well with all those alternatives and multiple ways for the same thing.... should really stop. I lost track long time ago and 99.99% never use any of them and really don't care at all. It's utterly confusing and I completely don't understand the reason behind it. It makes it harder than it should be. So many things goes against it...1 point
-
<div id="result">Ajax</div> <script type="text/javascript"> $('#result').click(function () { var ajaxUrl = "https://example.com/ajax-page-name"; //not template path $.ajax({ type: "GET", url: ajaxUrl, success : function(data){ var markup = $(data).find('#result'); $('#result').html(markup); } }); }); </script> You need to call the URL of the page itself, not its template path. ?1 point
-
It's been some time since I read the blog-post, but I really need to ask if we need the magic functions for the sanitizer, especially the grouped ones. They're hard to document, harder to be used for automated setups – where used sanitizers are aggregated by some coded means – compared to having them as parameters and I would say they're hardly simpler for manual usage over proper parameters. Personally I'd really vote for one clear way instead of having even more ways to do the same. For me there's also the reason that I find it way cleaner to work with data a.k.a. an array of sanitizer names vs. some magic naming, but that may just be me, but I think we really need to be aware of the backdraws of having to many options to do a thing in general.1 point
-
You have to make the ajax call with the url .. not the template file. Make sure you have created a page with that template. $.post('ajax.inc', function(e) {}); $.post('/path-to-ajax-page', function(e) {}); Example Ajax Template from different db: $mydb = new Database('host', 'username', 'password', 'db'); $result = $mydb->query("SELECT * FROM example"); from pw db: $query = $database->prepare("SELECT id, name FROM pages LIMIT 10"); $result = $database->execute($query); Your js $.ajax({ type: "GET", url: "/path-to-ajax-template", success : function(data){ var markup = $(data).find('#result'); $('#result').html(markup); } });1 point
-
Sounds interesting. Here's one way you can do it: $table = $fields->get('your_page_field')->getTable(); $query = $database->query("SELECT data FROM $table GROUP BY data"); $ids = $query->fetchAll(PDO::FETCH_COLUMN); $items = $pages->getById($ids); // $items is a PageArray echo $items->implode("\n", "<a href='{url}'>{title}</a>"); If we were to add this to the API, I think I'd want to make it accessible from a regular find() selector, rather than as a separate findSelectedPages method. That way it could be used with things like InputfieldSelector. Perhaps something like this: $pages->find("your_page_field=:selected"); ...where ":selected" is a keyword is would recognize to execute this behavior.1 point