Leaderboard
Popular Content
Showing content with the highest reputation on 08/05/2016 in all areas
-
Like mentioned in last week's post, this week was focused on covering remaining GitHub issue reports and pull requests in preparation for the 3.0 and 2.8 master version releases. In total we covered close to a dozen issues and around ten pull requests this week, so you'll find lots of updates in today's versions (3.0.29 and 2.8.29). In addition, we've also got a section in this post for those that have inquired about ProcessWire site development help. https://processwire.com/blog/posts/pw-3.0.29/5 points
-
@all: Was kind of out of business for a while. Will come back and check everything in September! Also some new ideas for this module ;-)4 points
-
Rather than put the "hidden" class on a containing div I would put it on the thumbnail links that you don't want to show. $album_iteration = 1; foreach($page->album_repeater as $album) { $image_iteration = 1; foreach($album->album_images as $image) { $class = $image_iteration == 1 ? '' : ' hidden'; echo " <a class='fancybox{$class}' rel='gallery{$album_iteration}' title='Gallery {$album_iteration} - {$image_iteration}' href='{$image->size(800,800,array('cropping'=>false))->url}'> <img src='{$image->size(200,200)->url}' alt=''/> </a> "; $image_iteration++; } $album_iteration++; }3 points
-
Until your question, it wasn't ....I have made some minor changes to version 005 which now enables this. I'll try and commit this today, if not, then over the weekend. Thanks for your interest in Media Manager...3 points
-
3 points
-
This module allows the default admin - and other users you specify - to login as any other user as defined in the module config. This could be useful for reproducing errors your users can see on websites or during testing, but I would suggest it is used wisely as there are some obvious snooping abilities in using this. Once installed, you can configure the module to be usable by various members of staff other than the default admin account, as well as define which roles or individual users you will be able to login as. After saving the config settings, you will find a page under the Setup menu in the admin called "Switch User". Selecting a user from the list checks via AJAX whether the user has admin access (this is a basic check for the page-edit permission as by default the admin homepage requires page-edit to load the page tree) and will either allow you to redirect to the homepage or back to the admin depending on that check. Download Here Version History 0.0.6 - Initial release2 points
-
flydev is right for the basic usage of the function with echo but additionally you define $pages but you did'nt that with $page: //you have this in your code... echo $page->title; so what is $page in this function? I think the whole idea is to build a function for the output of the basic page template...so i think this is the wrong way... I use in my templates the delayed output with a _main.php file (and _init.php and _func.php) and the interesting part different layouts on the equal templates...this idea is from @horst and the basic concept could read there: so you can split the template logic from the HTML output without to build a custom function for every template....since PW rendering the templates this is just unnecessary. You could build functions for special rendering that is needed in different templates or all over the place for example: /** * Show last Posts in several templates * @var $limit (Int) set the limit of displayed posts * @var $headline (string)set the headline of the postlist */ function renderArticles($limit = 3, $headline = 'New Articles') { //get articles $articles = wire('pages')->find("template=article,limit=$limit,sort=-publish_from"); if (count($articles)) { //get the rootpage of the articles $article_root = wire('pages')->get(1068); //open article list $out = '<h4 class="subtitle">'.$headline.' - <a href="'.$article_root->url.'">Overview</a><h4><div class="side-list"><ul>'; //get list items foreach ($articles as $a) { // get the image instance of the cropped version 70px x 70px $thumb = $a->artikel_bild->size(70); $out .= '<li>'; $out .= '<a href="'.$a->url.'"><img alt="'.$a->headline.'" src="'.$thumb->url.'"></a>'; $out .= '<h5><a href="'.$a->url.'">'.$a->title.'</a></h5>'; $out .= '<p>'.$a->article_cat->title.'</p>'; $out .= '</li>'; } //close list $out .= '</ul></div>'; return $out; } } Best regards mr-fan2 points
-
2 points
-
http://venturebeat.com/2016/08/03/microsoft-launches-excel-api-out-of-preview/2 points
-
A minor enhancement to the PW Info panel - it now shows the content of UrlSegments. This is what you see for this URL: http://pw3.dev/cms/processwire/?rated=one&star=five It's only the UrlSegments in the Summary section of the PW Info panel that is new, but I wanted to also point out that in the Tempate Info section is lets you know if URL Segments are enabled for the template. Also, you'll see that the URL has a couple of additional GET parameters - these are listed in the Debug mode panel - they possibly belong better in the PW Info Panel, but the debug mode tools in the PW admin list them here so I kept them this way for consistency. Note that POST variables are also shown if they are present - this can be very handy when debugging form submissions.2 points
-
Why no prefix? I would rather use the Pager with a blank PageArray and trick it a little. Configure your prefix to use something unique like "toreplaceprefix". Set your template to allow page numbers AND url segments. Then do something like this: $limit = 2; $start = $input->urlSegment1 ? ($input->urlSegment1 - 1) * $limit : 0; $pageNum = $input->urlSegment1 ? : 1; // page number for pager $pa = $pages->find("template=basic-page, start=$start, limit=$limit"); foreach($pa as $p){ $content .= "<p>$p->title</p>"; } $pagination = new PageArray(); $pagination->setTotal($pa->getTotal()); $pagination->setLimit($limit); $pagination->setStart($pageNum); $pagerHTML = $pagination->renderPager(array( "baseUrl" => $page->url, )); $pagerHTML = str_replace("toreplaceprefix", "", $pagerHTML); $content .= $pagerHTML;2 points
-
Metadata Exif Version 0.9.0 (currently a WIP) for PW 2.8.+ / 3.0+ This is a new attempt to add easy EXIF reading support to ProcessWire. It should be an easy and less error prone API task. Thats why the module internally uses lowercase key names for all EXIF keys and all of your requested key names. But you are not forced to use lowercase key names, you can use any mixed chars for it as you like. You will get back an array or object with keynames / properties named the same (casesensitive) way as you have passed them in with your request. API The module adds one hook to the Pageimage: getExif($options = null) Without any $options passed to the method, it returns all EXIF data in a RAW multidim array. Passing a simple list with requested key names as array to it returns an array with only the values of those requested keynames. If you want change the output from array to object, you can use the a boolean "toObject" set to true. Additionally to this and / or any other option, you need to put your requested keynames list to the option "keys". $rawArray = $image->getExif(); $options = array('Whitebalance', 'Flash', 'ISOSpeedRatings', 'FNumber', 'UserComment'); $array = $image->getExif($options); $options = array('toObject' => true, 'keys' => array('whitebalance', 'flash', 'isospeedratings', 'fnumber', 'usercomment')); $object = $image->getExif($options); Possible options are A working example $options = array( 'keys' => array('ISOSpeedRatings', 'FNumber', 'Flash') ); echo "<table><tr>"; foreach($options['keys'] as $key) echo "<th>{$key}</th>"; echo "</tr>"; foreach($page->images as $image) { $exif = $image->getExif($options); echo "<tr>"; foreach($exif as $value) echo "<td>$value</td>"; echo "</tr>"; } echo "</table>"; This will output something like: With the boolean option "unformatted" passed as true, the output would look like: For some keys, that only store something like integer values, what are not very meaningful to most of us, the module contain xyzFormatted methods. This way, it is easy to enhance and maintain the module in the future. Help wanted It would be nice if some of you test the module and report back if the intended API suites your needs. And you are very welcome to post suggestions for which keys you want to have a ...Formatted method. Thank you! https://github.com/horst-n/MetadataExif1 point
-
A quick tutorial how to create file downloads using pages You will be able to create a new page using template "PDF" (or any you setup), upload a pdf file. You then can select this page using page fields, or links in Wysiwyg. The url will be to the page and NOT the file itself. This will allow to keep a readable permanent unique url (as you define it), unlike /site/assets/files/1239/download-1.pdf, and you'll be able to update/replace the uploaded file without worring about its filename. Further more the file will also have an id, the one of the page where it lives. Clicking those links will download or open the file (when target="_blank") like it would be a real file on server with a path like /downloads/project/yourfile.pdf. You'll be also able to use the "view" action directly in the page list tree to view the file. Further more you'll be able to esaily track downloads simply by adding a counter integer field to the template and increase it every time the page is viewed. Since the file is basicly a page. This all works very well and requires only minimal setup, no modules and best of it it works in the same way for multi-language fields: Just create the language alternative fields like "pdf, pdf_de, pdf_es" and it will work without modifying any code! Still with me? ok PW setup Download folder: Create a template "folder" or "download-folder" with only a title needed. Create pages in the root like /downloads/project/ using this template. Setup the template for the pdf files 1. Create a new template in PW. Name it pdf 2. Goto template -> URLs tab and set the URL end with slash to no. (So we can have /path/myfile.pdf as the URL) 3. Create a new custom file field, name it pdf. Set its maximal count to 1 under -> Details tab. 4. Add the pdf field created to the pdf template. Easy. 5. Create a new "pdf" page using the pdf template under a download folder you created earlier. 6. Give it the title and in the name field add ".pdf" to the end (could also leave as is) Template PHP file for the pdf files 1. Create the template file pdf.php in your /site/templates folder 2. add the following code: <?php // pdf.php if($page->pdf){ wireSendFile($page->pdf->filename); } Done. To see the options you have with PW's wireSendFile() you can also overwrite defaults <?php // pdf.php if($page->pdf){ $options = array( // boolean: halt program execution after file send 'exit' => true, // boolean|null: whether file should force download (null=let content-type header decide) 'forceDownload' => false, // string: filename you want the download to show on the user's computer, or blank to use existing. 'downloadFilename' => '', ); wireSendFile($page->pdf->filename, $options); } Simple and powerful isn't it? Try it out. Some thoughts advanced Create as many file types as you like. It might also be possible to use one "filedownload" template that isn't restricted to one field type but evaluate it when being output using $page->file->ext, or save the file extension to the page name after uploading using a hook. One last thing. You can add other meta fields or preview images to the template and use those to create lists or detail pages. It's all open to goodness. Again all without "coding" and third-party modules. Further more you can use the excellent TemplateDecorator to add icons per template and have a nice pdf icon for those pages. This as a base one could also easily create a simple admin page for mass uploading files in a simple manner, and create the pages for the files automaticly. ImagesManager work in the same way. Cheers1 point
-
TL;DR How to change a paginated URL so it reads "example.com/foo/2/" instead of "example.com/foo/page2/"? Excuse me if this is the wrong place to post this (in which case please move this to the right forum), or this has been asked before... but how do you remove the "page" prefix in a paginated url so that it reads something like "example.com/foo/1/" instead of the default of "example.com/foo/page1/"? I know that for any other type of prefix, I can just override $config->pageNumUrlPrefix in site/config.php, but I can't figure out how you'd do it if you simply want an effectively "blank" prefix. I've tried setting $config->pageNumUrlPrefix = '' but that ends up breaking pagination altogether or the page prefix ends up in the URL instead. The only way I can think of doing this is actually changing the line: if(!$pageNumUrlPrefix) $pageNumUrlPrefix = 'page'; to if(!$pageNumUrlPrefix) $pageNumUrlPrefix = ''; but tampering a module file seems bad practice and so I am looking for a better way to achieve this. Help a ProcessWire noob out!1 point
-
@flydev most grateful for this ZF6/PW profile. I found your examples in _func.php to be tremendously helpful and enlightening. Thanks too for your introduction to the slick.js carousle/slider. I use the scss version of Foundation and was delighted to find the slick.js scss files in its distro. I chose to slug it out with the ZF6 top nav using @soma's MarkupSimpleNavigation rather than meanmenu.js but glad to learn about that too.1 point
-
1 point
-
1 point
-
1 point
-
@Sérgio - No problem. 1.5.3 will be the last of the 1.x range - hotfixes will increment the revision by one: 1.5.31, 1.5.32, etc. I'm going to put more focus on multi-lang in v2. Edit: Seems I didn't make a note of this somewhere, and have proceed to bump to 1.5.4. Will continue on 1.5.41, etc.1 point
-
I'm subscribed to Carl Alexander's newsletter, a developer how knows quite a lot about WordPress development. Today's topic is pretty interesting, quote: Wow! That's quite an invention No more comment. Should anybody be interested in the details: https://carlalexander.ca/designing-class-simple-wordpress-queries/1 point
-
$pages->trash($pages->find('cms!=processwire')); ps: no, i don't want to blame other great software products. but we are in the pub and i just want to make fun (and of course praise our great API)1 point
-
1 point
-
Thanks for the interest guys. I'll have to consider a few potential security issues first then make a decision. No ETA for now...1 point
-
You could try out my rest api helper https://github.com/NinjasCL/pw-rest Alamo Fire as AFNetworking its format agnostic, so it could easily adapt to your api design I recommend you to follow http://jsonapi.org principles. also reading this book https://leanpub.com/build-apis-you-wont-hate and this book https://leanpub.com/iosappswithrest could help you start out. If you need something done quick maybe using Parse Server SDK its more appropriate for a middleware (you can call PW later with that) https://parseplatform.github.io1 point
-
@Marcel Epp You could add a new parameter to the function. Assuming you are using the code shown in the first post, the following code should work (not tested) : function renderChildrenOf($pa, $maxDepth = 1, $output = '', $level = 0) // MODIFIED_CODE { $output = ''; $level++; foreach ($pa as $child) { $atoggle = ''; $class = ''; if ($child->numChildren(true) && count($child->parents) == 1) { $class .= 'dropdown'; $atoggle .= ' class="dropdown-toggle" data-toggle="dropdown"'; } else if ($child->numChildren(true) && count($child->parents) > 1 ) { $class .= ($maxDepth > 0) ? 'dropdown-submenu' : ''; // MODIFIED_CODE $atoggle .= ($maxDepth > 0) ? ' class="dropdown-toggle"' : ' '; // MODIFIED_CODE } else if ($child->numChildren(true) && $child->id != 1) { $class .= 'dropdown-menu'; } // Makes the current page and it's top level parent add an active class $class .= ($child === wire("page") || $child === wire("page")->rootParent) ? " active" : ''; $class = strlen($class) ? " class='" . trim($class) . "'" : ''; if ($child->numChildren(true) && count($child->parents) == 1) { // Add Caret if have children $output .= "<li$class><a href='$child->url'$atoggle>$child->title <b class='caret'></b></a>"; } else if ($child->numChildren(true) && count($child->parents) > 1) { $output .= "<li$class><a tabindex='-1' href='$child->url'$atoggle>$child->title</a>"; } else { $output .= "<li$class><a href='$child->url'$atoggle>$child->title</a>"; } // If this child is itself a parent and not the root page, then render it's children in their own menu too... if ($child->numChildren(true) && $child->id != 1 && $maxDepth > 0) { // MODIFIED_CODE $maxDepth--; // MODIFIED_CODE $output .= renderChildrenOf($child->children, $maxDepth, $output, $level); // MODIFIED_CODE } $output .= '</li>'; } $outerclass = ($level == 1) ? "nav navbar-nav" : 'dropdown-menu'; return "<ul class='$outerclass'>$output</ul>"; } // bundle up the first level pages and prepend the root home page $homepage = $pages->get(1); $pa = $homepage->children; $pa = $pa->prepend($homepage); // Set the ball rolling... echo renderChildrenOf($pa); Search the comments MODIFIED_CODE to see whats going on in the function.1 point
-
hi mike, just wanted to say a big thank you! installed it today on a relaunched site and it works great! awesome module, awesome docs!1 point
-
hi @ottogal that would be quite easy achievable via javascript. see this post of how i implemented this on a pagefield:1 point
-
Hi PWers. Im builing some kind of menu system for my current multilanguage project. $menu - is main menus page $menu->menu_groups - is PageTable field that hold menus groups $menu->menu_groups->menu_items - is repeater field that hold menu items Here is the code of it: <div class="sidebar-right"> <nav class="sidebar-nav"> <ul class="sidebar-nav__groups"> <?php $currentLang = $user->language; $currentPageId = $page->id; foreach ($menus->menu_groups as $menu_group) { $groupLanguages = $menu_group->getLanguages(); bd($groupLanguages); if ($menu_group->menu_group_position == 2 ) { echo "<li class='sidebar-nav__group-title'>". $menu_group->title ."</li>"; echo "<ul class='sidebar-nav__list'>"; foreach ($menu_group->menu_items as $menu_item) { $out = ""; // If user enter custom link if ($menu_item->menu_item_custom_link) { $out .= "<li class='sidebar-nav__list-item'>"; $out .= "<a class='sidebar-nav__list-item-link' target='_blank' href='". $menu_item->menu_item_custom_link ."'>"; $out .= $menu_item->menu_item_title; $out .= "</a>"; $out .= "</li>"; } else { // Get list of active languages for this page if ($menu_item->menu_item_page) { $pageLanguages = $menu_item->menu_item_page->getLanguages(); bd($pageLanguages); $children = $menu_item->menu_item_page->children(); $isChild = $children->has($page); $active_item = ($currentPageId == $menu_item->menu_item_page->id || $isChild ? "sidebar-nav__list-item--active" : ""); $active_link = ($currentPageId == $menu_item->menu_item_page->id || $isChild ? "sidebar-nav__list-item-link--active" : ""); // Menu item markup if current language is active for current page if ($pageLanguages->has($currentLang)) { $out .= "<li class='sidebar-nav__list-item ". $active_item ."'>"; $out .= "<a class='sidebar-nav__list-item-link ". $active_link ."' href='". $menu_item->menu_item_page->url ."'>"; $out .= $menu_item->menu_item_title; $out .= "</a>"; $out .= "</li>"; } } } echo $out; } echo "</ul>"; } } ?> </ul> </nav> </div> Im using Tracy Debuger module, so i will show outputs of it. When i get languages of a page of menu item, getLanguages returns expected data $pageLanguages = $menu_item->menu_item_page->getLanguages(); bd($pageLanguages); But when i try to get languages of a pages of menu groups getLanguages() returns: $groupLanguages = $menu_group->getLanguages(); bd($groupLanguages); Also i had tried to get languages by this code: $groupId = $menu_group->id; bd($pages->get($groupId)->getLanguages()); But got the same result. All languages are active on all pages. PW 3.0.25 Am i doing something wrong or missing something?1 point
-
Oh, they're in there are they? Okay so I should have: $ grep -R page-edit-created * Thanks for pointing me in the right direction. For pedantry's sake I've gone with: if(!wire('permissions')->has('page-edit-created')) { $permission = wire('permissions')->add('page-edit-created'); $permission->title = 'Edit only pages user has created'; $permission->save(); }1 point
-
Hi All - I've merged the previous 1.5.3-dev to master. Please let me know if you encounter any problems, and I'll patch them up as soon as I can. Development on JL2 is going quite well - busy organising a good OOP structure for the module.1 point
-
1 point
-
Thanks @Juergen (or z-index-man :)) Version 0.3.6 is uploaded which should fix it. The problem is that the leaflet field sets a z-index of 1000 so I decided to use much larger values. @szabesz is also covered with the new "Set narrow pagelist items" to reduce row height for the main pagelist. It's Reno theme only so it can be found under the RenoTweaks submodule. This update contains the "Pagelist thumbnails" feature. I'm sure this will have some iterations but I really like the "fieldname: selector" syntax to add thumbs, it's really flexible.1 point
-
You should never rely on client side validation on its own. Server side is a must! Not to say you shouldn't use client-side, but it should only be for a faster/nicer UX, not the ultimate check.1 point
-
Maybe you can create your own pagination $pageNumber = $sanitizer->selectorValue($input->urlSegment(2)); // wil get 2 from example.com/foo/2/ if(empty($pageNumber) || !is_numeric($pageNumber) || $pageNumber < 0) { $pageNumber = 0; } $limit = 10; $base = "template=post"; $query = $base . ", start=" . (($pageNumber > 0) ? $pageNumber + $limit : $pageNumber); $query = $query . ", limit=$limit"; // template=post, start=0, limit=10 $results = $pages->find($query); $total = $pages->count($base); $current = $pageNumber; $next = $pageNumber++; if($next > $total){ $next = $total; } $prev = $pageNumber--; if($prev < 0) { $prev = ''; }1 point
-
I have skim-read it. Best sentence I found somewhere in the middle: Keeping things simple for now Very good resolution.1 point
-
To follow up on this, it would be very much appreciated if the render functions were hookable. I need microdata in the markup for the comment lists ratings. I know I could loop through the comments and output my own markup. But it would be much better if I could place this in a module and hook from there as I (and maybe others) sure could use this on other projects, too. EDIT: I added an issue and a pull request on github.1 point
-
Media Manager version 004 (released (01/08/2016)) Happy to announce the latest release of Media Manager. Changelog FieldtypeMediaManager/InputfieldMediaManager: Configurable setting to insert media in inputfield and close modal. Set in the Details tab of your FieldtypeMediaManager field Fixed bug where non-allowed media types (for those limiting media types available to InputfieldMediaManager) would still show up in the results in the selection modal. Fixed bug where the menu item 'All' would not appear in the InptufieldMediaManager media selection modal even if allowed media types was limited to at least 2 types By popular demand, a CKEditor image plugin! mmimage (cloned and adapted from pwimage thanks @ryan) lets you insert images in your Media Manager Image Library directly into the rich text editor. See a video demo + instructions here @TODO: Multi-tagging of media Documentation (thanks for being patient with me guys...)1 point
-
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!1 point
-
This worked really great for me in a site with thousands of pages $selector = "template=pages_template"; // as an example while (1) { $p = wire('pages')->get("{$selector}, id>$id"); // get page with id bigger than previous if(!$id = $p->id) break; // assign current page's id to $id or break the loop if it doesn't exist // do stuff using $p as the current page wire('pages')->uncacheAll(); }; Like this you never have an array in memory, only one page at each time, and you can do all the operation in one go. Of course you would probably have to constantly write to the csv file (like, open,write,close,open,write,close,open,write,close edit: this doesn't make any sense you can open, write, write, write,... close), but I don't think that would be a problem. Edit: Ideally you would do this from the terminal by bootstrapping PW, to prevent overloading apache.1 point
-
Here is something I hacked together quickly for automatically adding new child pages to the pagetable field. This is only if you are using the page as the parent. It also handles deletion of items if they are trashed externally. I also disabled the internal check for orphans - because they have been automatically added already, there is no need for the "Children were found that may be added to this table. Check the box next to any you would like to add." option. I seems to be working great here, but please test carefully!! Add this to your admin.php file: wire()->addHookBefore('InputfieldPageTable::render', function($event) { $pp = wire('pages')->get(wire('input')->get->id); $ptf = $event->object; //remove pages from pagetable field if they were externally trashed foreach($pp->{$ptf->name} as $item) { if($item->is(Page::statusTrash)) $pp->{$ptf->name}->remove($item); } //add pages to pagetable field if they were created externally foreach($pp->children as $child) { if(!$ptf->has($child->id)) { $pp->{$ptf->name}->add($child); $pp->of(false); $pp->save($ptf->name); } } //reset orphans property so that we don't get a message asking to add new pages that are now already automatically added $ptf->setOrphans(new pageArray()); });1 point
-
And last some code when children would have their own template: $allChildren = $pages->get("/locations/")->find("template=child_tpl"); or even checking for parent template $allChildren = $pages->get("/locations/")->find("parent.template=parent_tpl"); or $allChild = new PageArray(); foreach($pages->get("/locations/")->children() as $parent) { foreach($parent->children() as $child) $allChildren->add($child); } and there's even more variations depending on who writes it.1 point
-
Great solution, thanks for posting this Pete. I figure I should follow-up and post the route that I use too, though this one depends on the server running unix. It creates rotating backups off your non-web-accessible home directory with a cron job, and then a cron job on your machine (or another server) copies the backups over every day. 1. Login to your unix-based web account (SSH or FTPS/SFTP) and create a directory off your non-web-accessible home directory where the backups will be stored. I call mine /db-backups/: mkdir /home/your-account/db-backups 2. Create a file in your home directory called .my.cnf (starting with a period). This holds your DB connection information. Place the following into that file, replacing "mysql_username" with your database username, and "mysql_password" with your database password: /home/your-account/.my.cnf [client] user=mysql_username pass=mysql_password If working on a shared server or some environment where other accounts can get into your files, make sure that .my.cnf file isn't readable by anyone else. i.e. type "chmod og-rwx .my.cnf" to remove (o)ther and (g)roup read/write/execute access to it. 3. Create another file in your non-web-accessible home directory called db-backup and paste the following in there. Update the first two lines in the script to point to the directory you created in step 1 (DB_BACKUP) and the name of the database you want to backup (DB_NAME). /home/your-account/db-backup #!/bin/bash # modify the following to suit your environment DB_BACKUP="/home/your-account/db-backups" DB_NAME="your-db-name" # title and version echo "" echo $DB_NAME echo "----------------------" echo "* Rotating backups..." rm $DB_BACKUP/$DB_NAME.5.sql mv $DB_BACKUP/$DB_NAME.4.sql $DB_BACKUP/$DB_NAME.5.sql mv $DB_BACKUP/$DB_NAME.3.sql $DB_BACKUP/$DB_NAME.4.sql mv $DB_BACKUP/$DB_NAME.2.sql $DB_BACKUP/$DB_NAME.3.sql mv $DB_BACKUP/$DB_NAME.1.sql $DB_BACKUP/$DB_NAME.2.sql echo "* Creating new backup..." mysqldump $DB_NAME > $DB_BACKUP/$DB_NAME.1.sql echo "----------------------" echo "Done" Note: I found this code somewhere else online a couple years ago and don't remember where to properly credit it. 4. Save the above and make it executable: chmod u+x db-backup If you are connected via SSH, test it out to make sure it's working by typing: ./db-backup It should create the first backup in your ./db-backups/ directory. 5. Setup a daily cron job to execute that file: /home/your-account/db-backup … most web hosting accounts have some ability to setup cron jobs in the control panel. 6. Now your server is keeping rotating backups in your account. Next I'd recommend going further and copying them to another machine, automatically every day. How you do this depends on whether you are going to use SFTP/FTPS or SSH (with rsync). Its preferable not to use regular FTP since it's not secure. In my case, I've setup a cron job on my OS X desktop to copy over the files to my computer every day. It executes a file that looks like this: #!/bin/bash /usr/bin/rsync --archive --rsh=/usr/bin/ssh --verbose user@domain.com:db-backups/* /Users/ryan/Backups/db/ That copies those rotating backups to a /Users/ryan/Backups/db/ directory on my computer. In order for the above to work, you'd have to already be using SSH with your account and have your SSH keys assigned so that you can connect without typing your login/password. If anyone is running a similar setup, I'll be glad to tell you how to do that. But I know there are other ways to automate this task and the approach you use here kind of depends on the platform and whether you have SSH access on the server. This setup is pretty bulletproof, but I'd like to have some module in PW in the future that will let it do all of this for you – Automatic backups from one server to another.1 point