Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 07/01/2013 in all areas

  1. Guide to installing ProcessWire on the OpenShift PaaS. Create an account at http://www.openshift.com.'>http://www.openshift.com. Next, select Create Application at the top of the screen and PHP 5.3. Once that is done, add a MySQL 5.1 cartridge to the PHP application. You'll get the following info from creating the PHP app and MySQL cartridge. Setup local Git repository Clone the application's Git repository to your local machine with following command. git clone ssh://51d12b59500446e0df000118@processwire-example.rhcloud.com/~/git/processwire.git/ Fetch the ProcessWire source and code and add them to the php on the local repository with these commands cd processwire git clone https://github.com/ryancramerdesign/ProcessWire'>https://github.com/ryancramerdesign/ProcessWire mv ProcessWire/* php/ mv php/htaccess.txt php/.htaccess rm -rf ProcessWire Push to the Openshift server Commit and push to the Openshift server with following commands: git add . git commit -m 'Setup ProcessWire' git push Complete the ProcessWire setup Acesss and complete the ProcessWire setup at your application's URL: http://processwire-example.rhcloud.com Use the IP address for the MySQL DB, in this case, 127.7.170.2 instead of the environment variable, $OPENSHIFT_MYSQL_DB_HOST
    5 points
  2. Module: MarkupCSScompress 0.8.5 (beta) convert $config->styles array to a single gzipped & cached CSS file and give <link rel="stylesheet" src="/processwire/styles.min.css/"> tag back. I love using the $config->styles array on the front-end. One disadvantage is, I like it that much that I end up with a multitude of styles with their corresponding links. To much requests for the browser if you asked me. So my thought was: I wish I could combine all styles, compress the css and serve 1 link back to the browser. But I don't like struggling to find CSS selectors in a compressed file. So I add the setting: Caching & concatenating disabled for superusers. For caching I used Ryan's beautiful MarkupCache module. Cons: Doesn't work with external CSS files ( All CSS files have to exist in processwire )How to use: ( important ) Put the MarkupCSScompress.php into the template folder. Place <?php echo $modules->get('MarkupCSScompress')->render(); ?> in the head where normally the CSS <link> would be. Install this module. Totally open for changes & improvements. download from github view on github modules on PW Todo: Change al relative urls to absolute urls in the CSS cache files. ( done ) Check PW version compatibility
    5 points
  3. Sorry, am rushing somewhere...the following will answer your question http://processwire.com/talk/topic/2786-request-seems-to-be-forged/ http://processwire.com/talk/topic/1563-this-request-was-aborted-because-it-appears-to-be-forged/ http://processwire.com/talk/topic/2102-using-previous-pw-installation-as-template-for-the-next-one/ http://processwire.com/talk/topic/2763-500-error-when-visiting-the-backend/ http://processwire.com/talk/topic/3668-internal-server-error-in-admin-page/
    4 points
  4. If you can wait, I'm currently working on a booking module for ProcessWire Currently it has specific needs for a specific job, so allows bookings on non-consecutive days, but will have consecutive days as an option by the time I'm finished (more useful for accommodation then). One thing I would say is that a restaurant booking system and a room booking system have very different needs. Both have been at the back of my mind when developing this module, but I need to look into the options required for a restaurant booking system when I get further along with this - the links in the first post here are helpful for that. There are some other nice features I don't want to give away just yet, but it might be worth waiting if you can for a few weeks.
    3 points
  5. Some fun stuff just pushed to the dev branch: the core now includes a Modules Manager "Lite". The screenshots below best describe how it works. But it lets you install modules from the directory just by typing (or pasting) in the module's class name. It also provides a 1-click capability to check for a given module's updates and upgrade it when necessary. Beyond that, the modules screen is now split into tabs: Site, Core and New. Site shows just your /site/modules/, and Core shows just your /wire/modules/. The New tab is where you can install modules. I really wanted a solution that kept the actual browsing for modules out of the CMS. Not because I think it's a bad idea (it's a great idea) but because I wanted the modules directory (modules.processwire.com) to serve that purpose as much as possible, at least as a default. That way I don't have to worry about scalability as the size of the modules directory increases. Plus less automation might make the newbies be a little more careful about what they are installing and where it's coming from. The power of the automation in ModulesManager here is so powerful it scares me, so think it's better for the users that know what they are doing. Lastly, ModulesManager is one of the best modules out there and Soma does an amazing job with it. Bringing a little taste of ModulesManager into the core I thought would help both projects. Most credit for the new core "Modules Manager Lite" goes to Soma (though he doesn't yet know that). It's all built around his code lifted directly from Modules Manager. Hope that's okay Soma? Your code now powers not just the new stuff in ProcessModule, but also the new WireHttp::download function, and the new wireUnzipFile() function, all added this week. People who want the most power will still want to use Soma's Modules Manager. That does a whole lot more than the built-in one does, including installation of themes, checking for updates en-masse, and browsing and filtering through the modules directory. But now you can install ModulesManager or other modules without having to manually FTP things to your server (so long as your /site/modules/ is writable). Please let me know if you guys run into any issues with it.
    3 points
  6. .. and in case that you actually want to alter values of previously created repeaters, not just create new ones, seems that this related thread holds an answer for you. You'll have to save the repeater items individually, not just page that contains them. Try something like this instead: $faqQA = $page->faqQA->get(0); $faqQA->of(false); $faqQA->title = '1'; $faqQA->body = '1'; $faqQA->save(); Completely untested and not something I've ever done, but looks like it should work (and kind of makes sense since repeaters are, under the hood, actually pages.) Edit: fixed broken example. Probably
    2 points
  7. Hi davydhaeyer, welcome! One solution is to create every ingredient as page too and link as many as you want to your recipes. Your page tree would look something like this: - recipes -- recipe1 -- recipe2 ... - ingredients -- ingredient1 -- ingredient2 ... In your recipe template, you can create a Page field (autocomplete) to add ingredients. This way you can add as many ingredients as you want and create them on the fly, if they don't exist: http://processwire.com/videos/selecting-and-adding-pages-with-autocomplete/ (suppose the tags in the video are your ingredients) However, if you need additional data to an ingredient e.g. the number or weight, things get a bit more complex -> Repeater Cheers
    2 points
  8. Since you guys asked for it, I'll take a stab at a case study on the development process. Most of the development was done in about a week and a half. I started with the basic profile, but it ended up being something somewhat similar to the Blog profile in terms of how it's structured. Below I'll cover some details on the biggest parts of the project, which included data conversion, the template structure, the front-end development and anything else I can think of. Data Conversion from WordPress to ProcessWire One of the larger parts of the project was converting all of the data over from WordPress to ProcessWire. I wrote a conversion script so that we could re-import as many times as needed since new stories get added to cmscritic.com almost daily. In order to get the data out of WordPress, I queried the WordPress database directly (my local copy of it anyway) to extract what we needed from the tables wp_posts for the blog posts and pages, and then wp_terms, wp_term_relationships, and wp_term_taxonomy for the topics and tags. WordPress stores its TinyMCE text in a state that is something in between text and HTML, with the most obvious thing being that there are no <p> tags present in the wp_posts database. Rather than trying to figure out the full methodology behind that, I just included WP's wp-formatting.php file and ran the wpautop() function on the body text before inserting into ProcessWire. I know a lot of people have bad things to say about WordPress's architecture, but I must admit that the fact that I can just include a single file from WordPress's core without worrying about any other dependencies was a nice situation, at least in this case. In order to keep track of the WordPress pages imported into ProcessWire through repeat imports, I kept a "wpid" field in ProcessWire. That just held the WordPress post ID from the wp_posts table. That way, when importing, I could very easily tell if we needed to create a new page or modify an existing one. Another factor that had to be considered during import was that the site used a lot of "Hana code", which looked like [hana-code-insert name="something" /]. I solved this by making our own version of the Hanna code module, which was posted earlier this week. Here's an abbreviated look at how to import posts from WordPress to ProcessWire: $wpdb = new PDO("mysql:dbname=wp_cmscritic;host=localhost", "root", "root", array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'UTF8'")); $posts = wire('pages')->get('/posts/'); $sql = " SELECT * FROM wp_posts WHERE post_type='post' AND post_status='publish' ORDER BY post_date "; $query = $wpdb->prepare($sql); $query->execute(); while($row = $query->fetch(PDO::FETCH_ASSOC)) { $post = $posts->child("wpid=$row[ID]"); // do we already have this post? if(!$post->id) { // create a new post $post = new Page(); $post->template = 'post'; $post->parent = $posts; echo "Creating new post...\n"; } $post->of(false); $post->name = wire('sanitizer')->pageName($row['post_name']); $post->title = $row['post_title']; $post->date = $row['post_date']; $post->summary = $row['post_excerpt']; $post->wpid = $row['ID']; // assign the bodycopy after adding <p> tags // the wpautop() function is from WordPress /wp-includes/wp-formatting.php $post->body = wpautop($row['post_content']); $post->save(); echo "Saved post: $post->path\n"; } What I've left out here is the importing of images, topics, tags, and setting the correct authors for each post. If anyone is interested, I'll be happy to go more in depth on that, but didn't want to overwhelm this message with code. Template File Structure This site makes use of the $config->prependTemplateFile to automatically include the file _init.php before rendering a template file, and $config->appendTemplateFile to automatically include the file _main.php after. So the /site/config.php has this: $config->prependTemplateFile = '_init.php'; $config->appendTemplateFile = '_main.php'; You may recognize this as being the same setup from the Skyscrapers profile. The _init.php includes files containing functions we want to be available to all of our templates, and set default values for the regions we populate: /site/templates/_init.php /** * Include function and hook definition files * */ require_once("./includes/render.php"); require_once("./includes/hooks.php"); /** * Initialize variables populated by templates that get output in _main.php * */ $browserTitle = $page->get('browser_title|title'); $body = "<h1>" . $page->get('headline|title') . "</h1>" . $page->body; $side = ''; $renderMain = true; // whether to include the _main.php file The includes/render.php file that is included above includes several functions for generating markup of navigation and post summaries, or any other shared markup generation functions. Examples are renderPost(), renderNav(), renderTags(). This is similar to the blog.inc file from the Blog profile except that I'm letting these functions generate and return their own markup rather than splitting them into separate view files. I personally find this easier to maintain even if it's not as MVC. The includes/hooks.php sets up any hooks I want to be present for all of my templates. I could have also done this with an autoload module, but found this to just be a little simpler since my hooks were only needed on the front-end. The main hook of interest is one that makes all posts look like they live off the root "/" level rather than "/posts/" (where they actually live). This was in order to keep consistency with the URLs as they were in WordPress, so that the new site would have all the same URL as the old site, without the need for 301 redirects. /site/templates/includes/hooks.php /** * This hook modifies the default behavior of the Page::path function (and thereby Page::url) * * The primary purpose is to redefine blog posts to be accessed at a URL off the root level * rather than under /posts/ (where they actually live). * */ wire()->addHookBefore('Page::path', function($event) { $page = $event->object; if($page->template == 'post') { // ensure that pages with template 'post' live off the root rather than '/posts/' $event->replace = true; $event->return = "/$page->name/"; } }); Our /site/templates/_main.php contains the entire markup for the overall template used site wide, from <html> to </html>. It outputs those variables we defined in _init.php in the right places. For example, $body gets output in the <div id='bodycopy'>, $side gets output in the right <aside>, and $browserTitle gets output in the <title> tag. /site/templates/_main.php <?php if($renderMain): ?> <html> <head> <title><?=$browserTitle?></title> </head> <body> <div id='masthead'> // ... </div> <div id='content'> <div id='bodycopy'><?=$body?></div> <aside id='sidebar'><?=$side?></aside> </div> <footer> // ... </footer> </body> </html> <?php endif; ?> We use the rest of the site's template files to simply populate those $body, $side and $browserTitle variables with the contents of the page. As an example, this is an abbreviated version of the /site/templates/post.php template: /site/templates/post.php // functions from /site/templates/includes/render.php $meta = renderMeta($page); $tags = renderTags($page); $authorBox = renderAuthor($page->createdUser); $comments = renderComments($page); $body = " <article class='post post-full'> <header> <h1>$page->title</h1> $meta </header> $page->body $tags $authorBox $comments </article> "; if(count($page->related)) { $side = "<h4>Related Stories</h4>" . renderNav($page->related); } What might also be of interest is the homepage template, as it handles the other part of routing of post URLs since they are living off the root rather than in /posts/. That means the homepage is what is triggering the render of each post: /site/templates/home.php if(strlen($input->urlSegment2)) { // we only accept 1 URL segment here, so 404 if there are any more throw new Wire404Exception(); } else if(strlen($input->urlSegment1)) { // render the blog post named in urlSegment1 $name = $sanitizer->pageName($input->urlSegment1); $post = $pages->get("/posts/")->child("name=$name"); if($post->id) echo $post->render(); else throw new Wire404Exception(); // tell _main.php not to include itself after this $renderMain = false; } else { // regular homepage output $limit = 7; // number of posts to render per page $posts = $pages->find("parent=/posts/, limit=$limit, sort=-date"); $body = renderPosts($posts); } The rest of the site's template files were handled in the same way. Though most were a little simpler than this. Several were simply blank, since the default values populated in _init.php were all that some needed. Front-end development using Foundation 4 The front-end was developed with the Foundation 4 CSS framework. I started with the Foundation blog template and then tweaked the markup and css till I had something that I thought was workable. Then Mike and I sent the _main.php template file back and forth a few times, tweaking and changing it further. There was no formal design process here. It was kind of a photoshop tennis (but in markup and CSS) where we collaborated on it equally, but all under Mike's direction. After a day or two of collaboration, I think we both felt like we had something that was very good for the reader, even if it didn't originate from a design in Photoshop or some other tool like that. I think it helps a lot that Foundation provides a great starting point and lends itself well to fine tuning it the way you want it. I also felt that the mobile-first methodology worked particularly well here. Comments System using Disqus We converted the comments system over to Disqus while the site was still running WordPress. This was done for a few reasons: Disqus comments provide one of the best experiences for the user, in my opinion. They also are platform agnostic, in that we could convert the whole site from WP to PW and not have to change a thing about the comments… no data conversion or importing necessary. Lastly, ProcessWire's built-in comments system is not quite as powerful as WordPress's yet, so I wanted cmscritic.com to get an upgrade in that area rather than anything else, and Disqus is definitely an upgrade from WP's comments. In order to ensure that Disqus could recognize the relations of comment threads to posts, we again made use of that $page->wpid variable that keeps the original WordPress ID, and also relates to the ID used by the Disqus comments. This is only for posts that originated in WordPress, as new posts use a ProcessWire-specific ID.
    1 point
  9. You don't get anything because the pages are hidden. Add this to your selector include=hidden Please read this page: http://processwire.com/api/selectors/ and specifically this section in relation to access control in selectors.
    1 point
  10. Hi Valery, See this page about using the API to add or remove repeater items There is a sample code on that page. As you can see, it can really be more simple compared to your code
    1 point
  11. Using phpmyadmin: 1. mywebsite.com 2. go to mywebsite.com/phpmyadmin and select database and click export and click GO. DONE! Using php script: 1. mywebsite.com/securebackup DONE! NOTE: I've actually been using adminer (http://www.adminer.org/) instead of phpmyadmin. Super tiny script. Fast. Easy
    1 point
  12. I think the problems inherent with a table booking system are as follows (and this is with no real research by the way): Do restaurants have a good grasp of how long a table will be occupied for? If so, give them an option (maybe default to 2 hours per table) Different table sizes will affect the booking. You need to enter your party size ideally to see what is available. That or the restaurant may be able to push tables together in many cases - how do you deal with that? If you're using a web booking system for a restaurant and it needs to be up to date, the system needs updating whenever walk-in customers come into the restaurant. Either that or you can only book online X hour in advance (4 hours default maybe?). Basically, what I'm getting at is that there are far more variables in play than other booking systems. Booking a holiday cottage is easy - it's got a fixed number of beds - no problem. Booking a hotel room is slightly trickier - you have more options, not just with how many beds per room, but type of room. The more I think about it, the less likely every eventuality will be covered just by the module I'm creating. I think it far more likely that each scenario needs to be tailored and that they might be best as site profiles since there will be a lot of templates with them. As such, the module I'm working on may help as a starting point for accommodation/asset-based booking, but won't be much help for table bookings and other time-of-day based scenarios. At least, not in version 1.
    1 point
  13. Take all my code and money too. Well the latter comes in form of code. Serious, I'm very proud to have played a role. I agree with what you said and will first go check it out and come back later...
    1 point
  14. Thank you! Unfortunately my work ended with the implementation of the website. The copywriting and managing are beyond me.. and terrible Also, why is the "facebook" link pointing to the homepage? We will never know.
    1 point
  15. Thanks Wanze, I managed to get it sorted out. $n = 1; $type = "expense$n"; $desc = "desc$n"; $amount = "amount$n"; $pm = "method$n"; $expenses = $p->travel_expense; // the repeaters foreach ($expenses as $expense){ $rp = $pages->get("id=$expense->id"); // the repeater page we want to update $rp->of(false); // update repeater fields $rp->expense_type = $input->post->$type; $rp->expense_description = $sanitizer->text($input->post->$desc); $rp->expense_amount = filter_var($input->post->$amount,FILTER_SANITIZE_NUMBER_FLOAT,FILTER_FLAG_ALLOW_FRACTION); $rp->payment_method = $input->post->$pm; // save the repeater page $rp->save(); // update counter etc $n++; $type = "expense$n"; $desc = "desc$n"; $amount = "amount$n"; $pm = "method$n"; }
    1 point
  16. 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
×
×
  • Create New...