Leaderboard
Popular Content
Showing content with the highest reputation on 06/28/2016 in all areas
-
Sounds like a job for the API Delete fields by name: <?php $field_names = ['field1', 'field2', 'etc']; foreach($field_names as $field_name) { $field = $fields->get($field_name); $fields->delete($field); echo "Deleted field '{$field->name}'<br>"; } Or maybe delete all unused fields: <?php foreach($fields as $field) { if( count($field->getFieldgroups()) === 0 ) { $fields->delete($field); echo "Deleted field '{$field->name}'<br>"; } } Or you could make a form displaying checkboxes for each unused field and select which to delete, similar to what @diogo does here for templates.5 points
-
Hi @kixe, first just want to say thanks for this useful module (if I don't have already)! And I want to share a usage that propably wasn't intended with your module, but I find it useful for small sites where content changes slightly in a weekly manner or less. I use a hook into Session::logout in the ready.php file that invokes a DB-Backup. Currently the simplyfied code looks like: /* Autobackups */ $wire->addHookBefore("Session::logout", function(HookEvent $event) { if(!wire('user')->hasPermission('db-backup')) return; if(wire('modules')->isInstalled('CronjobDatabaseBackup')) { // execute a cronBackup ignore_user_abort(true); set_time_limit(120); $cdb = wire('modules')->get('CronjobDatabaseBackup'); $e = new HookEvent(); $cdb->cronBackup($e); } return; }); This is a bit hacky. What do you think about to embedd a public method to do this more transparent. Also it would be good if the description ($fileinfo) could be set dynamically with this method or as separate method or option. Currently I have hacked this into the module to be able to set it like: "logout horst (CronjobDatabaseBackup)". Anyway, also without that, it is a big, big helper!4 points
-
Updated to v025, here are the latest changes: 0.2.5 (2016-06-28) new RenoTweak: miniScrollbar for main content and sidebar (using perfect-scrollbar.js) added Language Translator page to the supported hotkey save pages 0.2.4 (2016-06-26) remove ctrl+click feature to activate all language tabs of the same language (core feature from ProcessWire 3.023) FireFox fix for clearing filterbox miniScrollbar in action:3 points
-
Thanks for this @Beluga I had to use $modules->get('EmailNewUser'); in my register.php instead. But it works with the FrontendUser now. Very useful module @adrian!3 points
-
Jumplinks is your friend http://modules.processwire.com/modules/process-jumplinks/ use wildcards to define the redirect: SOURCE: /home/business-directory/* DESTINATION: /home/business-directory/3 points
-
Newline characters are the de facto correct way of handling newlines in text. It's just that html does not care about them, which is why you need <br> tags instead.2 points
-
If your image field is named 'image' use the following api: // single image field $page->image->url $page->image->description //multi image field $page->image->first()->url $page->image->last()->url $page->image->eq(5)->url // your example $content = "<p><img src='{$page->image->url}' alt='{$page->image->description}' ></p>"; 1 ARROW: use curled brackets OR paste as is between double quotes 2 ARROWS and more: you need to use curled brackets, as I did in the example with the image $content = "<article><h2>$page->body</h2>"; Please read some tutorials and informations in the docs, before going further https://processwire.com/api/templates/ https://processwire.com/docs/tutorials/default-site-profile/ https://processwire.com/docs/tutorials/simple-website-tutorials/2 points
-
1.) "<article> <h2>{$page->title}</h2> <header class='news-meta'><strong>Date : </strong>{$page->publish_date}</header> <div class='news-content-text'> <p>{$page->summary}</p> </div> <div class='article'>{$page->body}</div> <p><img src='{$image->url}' alt='{$image->description}'></p> </article>"; _main.php should be the global layout; the templates just populate the content variable which is within the content area of the '_main' layout. $page->body is the "body" field (the one with the Rich Text Editor) Closing brackets are not needed and should always be left out when the file ends with php code: https://processwire.com/api/coding-style-guide/#2-general2 points
-
.htaccess to the rescue? Redirect 301 /home/business-directory/business-categories/ http://www.yourdomain.ext/business-directory/2 points
-
you could do a hook that rewrites the URL for those child pages to the parent.. doing it 'all the time' in site/ready.php /** * This hook modifies the default behavior of the Page::path function (and thereby Page::url) * this will rewrite the path to children that should not have their own page * any automatic links to the page, e.g. in the admin, will direct to the parent page. * */ wire()->addHookBefore('Page::path', function($event) { $page = $event->object; if($page->template == 'sometemplate') { $event->replace = true; $event->return = $page->parent->path; } });2 points
-
What does autojoin do? Using the 'autojoin' optimization can increase performance on fields that get used a lot. Not using it can reduce the page's memory footprint. What is more desirable in each instance depends on your situation. What sites should use autojoin? Autojoin is most applicable with larger sites. On smaller sites, there may be no benefit to using it or not using it. But it's good to know what it's for regardless. Where do you control autojoin? Autojoin is controlled per-field. You can turn it on by editing each field under Setup > Fields > [your field], and you'll see it under the 'Advanced' heading. When should you use autojoin? Autojoin causes the field's data to be loaded automatically with the page, whether you use it or not. This is an optimization for fields that you know will be used most of the time. Fields having their data loaded with the page can increase performance because ProcessWire grabs that data in the same query that it grabs the Page. Autojoin is a benefit for fields that are always used with the Page. This is best explained by an example. Lets say that you have a template for individual news stories called news_story. The news_story template has these fields: title date summary body sidebar We'll assume that when you view a page using the news_story template, all of the fields above are displayed. Fields that should have autojoin ON: Now consider a separate news_index template that displays ALL of the news stories together and links to them. But it only displays these fields from each news story: title* date summary In this case, the 3 fields above would be good to autojoin since they are used on both the news_index and news_story templates. If your title, date and summary fields didn't have autojoin turned on, then ProcessWire wouldn't go retrieve the value from the database until you asked for it it (via $page->summary, for example). Because the news_index template displays all the stories at once, and always uses the title, date and summary fields, it will perform better with title, date and summary having autojoin ON than with it OFF. In this case, it reduces the query load of the news_index template by 3 for each news story. To take that further, if it were displaying 20 news stories, that would mean 60 fewer queries, which could be significant. Fields that should have autojoin OFF: Now lets consider the body and sidebar fields, which are only used on the news_story template: body sidebar It would be desirable to leave autojoin OFF on those fields because there is no reason for the body and sidebar to be taking up space in memory when they are never used on the news_index template. While it might mean 2 fewer queries to view a news story, that is not significant and certainly not a worthwhile tradeoff for the increased memory footprint on the news_index template. Keeping autojoin OFF reduces a page's memory footprint. Conclusion Using the 'autojoin' optimization can increase performance on fields that get used a lot. Not using it can reduce the page's memory footprint. What is more desirable in each instance depends on your situation. But if your situation doesn't involve lots of pages or data, then you don't need to consider autojoin at all (and can generally just leave it off). Additional Notes Not all fields have autojoin capability. You won't see the option listed on fields that don't have the capability. *The title field has autojoin on by default, so you don't need to consider that one. It was included in the examples above because I thought it's omission might cause more confusion than it's inclusion. Be careful with multi-value fields that offer autojoin capability (page references and images, for example). Because MySQL limits the combined length of multiple values returned from a group in 1 query, autojoin will fail on multi-value fields that contain lots of values (combined length exceeding 1024 characters). If you experience strange behavior from a multi-value field that has autojoin ON, turn it OFF. If you want to play it safe, then don't use autojoin on multi-value fields like page references and images.1 point
-
I'm writing this to give back something to the community that has given so much up front over the past year. I noticed there's hardly any discussion about testing in these forums so I decided to write this quick primer to get some discussion going. I'm by no means an expert on phpunit or selenium but I had to jump through a few hoops to get it working (especially with PHPStorm), so I thought I figured I should share my experiences with the community. Also, I'm hoping non Phpstorm users can still pick something up useful in this post. Prerequisites : It is assumed Phpunit (https://phpunit.de/) is installed via Composer, Selenium (http://www.seleniumhq.org/) and Php-webdriver for Selenium (https://github.com/facebook/php-webdriver) is preinstalled. For Phpstorm users, there's a fairly detailed installation and unit testing instructions here (https://www.jetbrains.com/help/phpstorm/2016.1/testing.html) I found some parts of it leaving me with unanswered questions, so I'm hoping this post will supplement any questions that you might encounter. Rather than writing a single monolithic post, I will write several posts covering different topics.1 point
-
Nope, sort is only evaluated for the main selector part, but not for/inside or-groups.1 point
-
Glad you got it working. The sub-selector docs are here but I'm sure you found them by now.1 point
-
@krisj, You may want to post this information in the support forum for that Module.1 point
-
I do not know why do you need it? Why not have 404 on something you don't want to show anyway? Why not have a php file to do what you need if you need it? You can build a separate page tree branch just for categories (for business-categories template pages) and connect them to end-level pages like ABC Fence with page field. In this case your end-level pages should have different template and can live under business-directory, while categories themselves are elsewhere as noted above.1 point
-
Updated to PW 3.0.23 and the same problem exists. Had to downgrade back down to 3.0.20 to properly use PageTable fields. Updated the Github issue with this status.1 point
-
In MySQL NULLs are considered lower than any non-NULL value. So if you order ASC then NULLS come first. To change this you would use maybe something like this in MySQL: ORDER BY ISNULL(yourfield) ASC, yourfield ASC; But i don't think ISNULL is somehow implemented in PW's selector engine sorting. I've never needed this myself but maybe it's worthwhile to add this. A very ugly workaround could be to set the 'no date' items to a date of let's say 31-12-9999. I think a second find for empty items and appending them to the original PageArray wouldn't hurt too much either. You could compare performance against solutions like Wanze's.1 point
-
Does using dedicated module files help a lazy programmer? For a private helper module I wanted to built, I decided to use the possibilities of dedicated files (implemented in PW 2.5.5) and not to write all into a single module file. Until now, I totally missed or forgot about this possibility. To my excuse: on introduction I may have thought not to use it early in my modules to keep backward compatibility. And then totally forgot about it. I allready use a tool for postprocessing in my sites. And I'm not familiar with all those popular node/grunt/gulp/npm/bower/and-what-else stuff out there. It looks to me a bit oversized for small to medium websites. But I also wanted not miss a comfortable, easy to use config for less and sass files, especially for those from frameworks like Bootstrap 3 / 4 or UIKit. So, what my toolbox should get added was a preprocessor (compiler) for sass (.scss) files first. I choosed the UIKit for the first shot. The created files for a configurable module called PreAndPostProcessor and a process module called ProcessPreProcessor were: PreAndPostProcessor.module PreAndPostProcessor.info.json PreAndPostProcessorConfig.php ProcessPreProcessor.module ProcessPreProcessor.info.json ProcessPreProcessor.css ProcessPreProcessor.js As you can read about the differences to the old-schooled style in Ryans blog post, I focus on what I found out to be most useful for me. Starting with the Config file, I decided to use the $this->add() method in the __constructor(). It is the way what needs less code to define your inputfields for a configpage: just a collection of arrays with field or fieldset definitions. Mandatory definitions are: type, name, label. Others are optional: description, notes, required, columnWidth, collapsed, showIf, ... And, of course, you need the definitions specific to your fieldtypes (value, options, ...). To group some fields into a fieldset, add a key called "children" to the fieldset array and add all field definitions to it as collection. Simple! Another nice thing I discovered, is the use of the *.info.json files. So, this I have used before, but not like here. The behave is like with the *Config.php files, - you write really less code, just arrays with key - value pairs and PW does the rest for you! Only difference here is, that you have to write it in JSON notation. The ProcessPreProcessor.info.json file contains the neccessary and common parts: title, version, requires. And some others: permission, permissions, page and nav. Page and nav are specific to Process modules. With page {name, parent, title} you define where PW should create you a page in the admin, and with nav, you can define a complete submenu for this page. For those who are yet not familiar with the internal structure of Processmodules: you can navigate to a submenu entry by calling it: {pw-admin-url}/{main-module-url}/{submenu-url}/. Calling the main menu url invokes the ___execute() method of the module. Calling a submenu url invoke the ___executeSubmenu() method. This all is really simple and straight forward. And it is really really helpful in cases like with the new toy for my toolbox. The nav is a collection of arrays, each holding at least an url and a label. Thats enough for PW to implement the menu and submenu for you in the admin. But you also may define an icon too. Aaaand, you also can add your own custom key / value pairs to it. PW does not complain on it. I have added a description. The nav was generated by parsing all core distribution scss files from the UIKit. They have a name and description in their first two lines. I programatically read this out and generated this nav notation for the info.json file: The (main) ___execute() method of the ProcessPreProcessor.module should present a submenu list with file infos. This now could be done by parsing the info.json file: public function ___execute() { // generate a navigation $dump = json_decode(file_get_contents(dirname(__FILE__) . '/' . basename(__FILE__, '.module') . '.info.json')); $nav = $dump->nav; $out = "\t\t\t<dl class='nav hnpp'>\n"; foreach($nav as $obj) { $out .= "\t\t\t\t<dt><a href='./{$obj->url}'>{$obj->label}</a> ></dt>\n"; $out .= "\t\t\t\t<dd>{$obj->description}</dd>\n"; } $out .= "\t\t\t</dl>\n"; return $out; } To make it even more friendly for lazy devs, , I created one method that is called from all sub-execute methods by simply passing their own name over into this function that loads and parse the scss file and displays its config page: The first version work out nicely. Here is a screenshot of it: ... and to answer the initial question: Yes, it does!1 point
-
Hi Xonox, You could create a new PageArray and append the pages without the training start time at the end: $today = time(); $parent = $pages->get('/formacao/'); $trainings = $pages->find("parent=$parent, template=training, limit=6, !training_start<$today, sort=training_start"); $_trainings = new PageArray(); $empty = new PageArray(); foreach ($trainings as $training) { if ($training->training_start) { $_trainings->add($training); } else { $empty->add($training); } } $_trainings->import($empty); I'm sure there are more elegant solutions1 point
-
Doesn't for me; I got two error messages (which doesn't break the map) and then a forced error which returns this: https://www.latecnosfera.com/2016/06/google-maps-api-error-missing-keymap-error-solved.html1 point
-
There are probably various examples of the plain pw api usage around in the forums. I've also started this one, to allow for a user-contributed migration "snippets" directory: https://github.com/LostKobrakai/MigrationSnippets Examples on how to use the specific helper migration classes of the module can be found here: https://github.com/LostKobrakai/Migrations/tree/master/migrations1 point
-
In the ideal case you're not keeping log, but rather you make the local changes only via migration files in the first place. The actual number of those does not really matter as long as it's in logical steps. It might seem like a lot of extra work, but it really is – after creating a few of those – more a case of copy&pasting and adjusting a few key points. And the time saved when actually deploying changes is a lot. It makes the whole update process a lot more transparent and less error prone. I'd strongly suggest you to not hardcode/rely on any page IDs in your app (besides maybe ID 1 and 2). They'll get out of sync faster then you can keep track of it. The idea of separating tables might seems like a nice solution, but it would probably need a lot lot of core hacking to make that happen. Also it's not just the 'pages' table, but you'd need to split any field's table as well. It might work somehow, but I imagine it to be not worth the hassle and the inflexibility. I'm not really recommending anythings. Migrations work great for me, but every use-case is different.1 point
-
I've just gone ahead and added such a repo to GitHub: https://github.com/LostKobrakai/MigrationSnippets. Maybe this can also serve as a resource for people, who are not sure they understand what this module does provide. I've already added 2 example cases. I think over time I'll add some more, but everyone is welcome to add their files as well.1 point
-
My module does not really do anything on it's own. It's more a managing helper for handling/running those migration files. Any actual changes you'd write on your own using the processwire api (in those files). It's like you would have done these changes in the backend, but it's done by code. There are some helpers included to reduce the amount of verbose code, but that's about it. With the processwire api at hand you'll probably not even need to think about the db, which is probably the biggest difference between something like phinx or other frameworks' migration files to the ones my module does handle. You'll not manually add any new tables or columns. You'll just add a field to a template or create a new page or something. If you've handled all local changes using those migration files you can just put those on the production server and run them there as well. If everything went well all your changes should be applied as they were locally. Just keep in mind the module is not making any backups of sorts. This is the users responsibility. Your points about db dumps are certainly valid, but it just is the case, that almost everything in pw is a page, even users. There's no point in working against this. E.g. how should pw know which users where created by you locally and which one online in the production system? Same for normal pages. How should pw devide between a list of countries you added as pages for a select field and some other pages, which represent dummy user content you work with locally, but are not to be migrated. Especially in a dynamic structure like the pagetree where things can be moved around super easily and templates can also be changed as fast there's no point in even trying to separate out anything.1 point
-
The problem – as you're describing it – is trying to separate user-content from otherwise bootstrapped content. That's just not how it works. It's all content in pages and processwire does not care where it came from. You might set templates up to be only single use or other things, but in the end it's all pages. So you probably should not try to work/hack around that. Also db backups and dumps are almost never a sane way to update a production site as soon as any content is independently created on it, be it user or only client/editor changes. It's hardly a processwire specific problem. If you need things to not be manual updates you've probably not many more options than these. The common way for other web frameworks out there to have is to use migration files, which are files handling any "bootstrap" changes in the db and as they're files they simply are tracked by any used VCS and just run on each deployment. I've created a module to use this strategy with processwire: There's also a migrator module from adrian, which tries to solve the "migrating pages / templates / fields" issue, but I'm not sure if it can handle e.g. changes of module settings or installing new modules and such things: You could also look in non pw-specific migration tools like https://phinx.org/, but hand writing pw changes in mysql queries might not be fun. There's also this tool, which claims to track db changes, but I'm not sure how well it does work: http://dbv.vizuina.com/.1 point
-
The old wiki was still useful when one wanted to learn about the general concepts behind ProcessWire, but module development has evolved since then, so probably a good starting point is this: https://processwire.com/blog/posts/new-module-configuration-options/ BTW, as far as I know, there are no plans about saving the old wiki. If someone needs it, I have a version of it that was saved by a "web grabber". Just pm me, if you need it.1 point
-
Thanks! Setting autoload to true actually didn't work, but it is simply enough for me to put this in my register.php: $modules->get('EmailAdminNewUser'); Now I will get admin emails for users that have registered!1 point
-
Why did Ruby needed the Rails framework to become very popular? Why do Google developers love PHP. Does NodeJS stays popular in the future, say 4 or 5 years? Why is facebook coded in PHP? What's wrong with PHP?1 point
-
1 point
-
Quick and dirty interface to batch delete unused templates by selecting them with checkboxes: if ($input->post->submit) { foreach ($input->post as $t) { // proceed only if the input is an integer different from 0 if (!(int)$t) return; $t = $templates->get($t); $templates->delete($t); $name = $t->name; // delete the fieldgroup associated with this template. more info in the next post $fg = $fieldgroups->get($name); $fieldgroups->delete($fg); // verify that the template is not there and print the confirmation if (!$templates->get($t)) echo "<p>template {$name} was deleted.</p>"; } } else { // print the form echo "<form method='post'>"; echo "<ul>"; foreach ($templates as $t) { // name of the temlate and number of pages it uses echo "<li>" . $t->name . " (" . $t->getNumPages() . " pages)"; // include checkbox if the template is not used by pages, and set it's id as value if (!$t->getNumPages()) echo " <input type='checkbox' value='{$t->id}' name='{$t->name}'>"; echo "</li>"; } echo "</ul>"; echo "<input type='submit' value='delete these' name='submit'>"; echo "</form>"; } Edit: Added "if ($templates->get($t)))" to the "template was deleted" line. Now we are sure that it was really deleted Edit2: Edited the code based on the problem explained in the next post1 point