Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 12/04/2014 in all areas

  1. http://assessment.ifas.ufl.edu I've been working on this one a good while now. What's there now is essentially a phase one MVP (Minimum Viable Product). We start the next phase of the project soon, which migrates a lot more data, and takes all the paper processes and turns them into web forms and/or calculation tools. More on that another time. For those of you familiar with the pitfalls of infinite scroll — I'm still working out the kinks with history.js, but I wanted to go ahead and post the site here as it's now officially live. Some of the more crucial modules used: ListerPro AIOM ProFields: PageTable FormBuilder (not live yet, coming in phase 2) Homepage Search Page Filters Species Page
    12 points
  2. this is a work in progress... needs testing. in this module the edit links are added to the green boxes using 2 methods: jquery for the page list select and page auto complete, and the native asm select feature for asmSelects (thanks to Soma). Since the PageAutoComplete and PageListSelect are using the hover and icon from asmSelect, the asmSelect assets need to be loaded now on every page edit, in order to make the links look right. if you downloaded this before, please replace with the latest version, as there have been many changes, corrections/bugfixes and improvements. Please report any issues. Updated 12/6/14 at 10PM - please delete earlier versions due to issue with links being added on template editor. Updated 5/7/15: Module removed in anticipation of new official version release: https://processwire.com/talk/topic/9857-module-page-field-edit-links/?p=94599
    4 points
  3. Hey all, I launched this website a few weeks ago: http://www.archsf.com/ It was deceptively simple looking at a first glance of the mockups, however this project turned out to be very challenging and ProcessWire really shined, as it always does. The main template being used on the site is the Project Category template. Here's the "Residental" page, which is powered by that template: http://www.archsf.com/project-categories/residential/ As you can see, if you're on a large screen, there are 5 blocks across (1 callout + 4 projects). I'm using Zurb Foundation (the Grunt/Libsass version, which rocks), however like most CSS frameworks, there isn't an even 5 column structure, so I had to take care of that manually. Then, add in the fact that the website is full browser width, which presents a whole host of width/height manipulation that must be done. All the project thumbnails are the same size, but that first callout is text-based so it's height must calculated based of the height of one of the project thumbnails. But of course, the thumbnails themselves are dynamic in height depending on the browser width. And, you can only get the height of the images once they are loaded in (which is easy thanks to the imagesLoaded plugin). Now, if you look at the next row, it's not 5 easy blocks across, but rather 2 blocks, then a big block that takes up 2 block spaces, then another regular size block. I went through some different approaches to handle that situation, and what I ended up doing is hardcoding a the layout so that specific blocks would appear in specific places. It's not a masonry / nicely floated structure! Then, let's not forget this is a responsive site. So, for the phone-sized breakpoint, there's actually another repeated layout of all the project thumbnails, but it's set to hidden unless viewing that breakpoint (which will hide the other breakpoints). That breakpoint has 2 blocks across, with the occasional 1 block featured project. There is also the tablet-sized breakpoint, which has 4 blocks across. This approach, from a code point of view, is a bit ugly in that content is being repeated on a page, however this was a necessary decision I had to make in order for the complicated layout structure to work. It didn't seem to affect the search engine indexing of the site however. Also, each project thumbnail also has different image sizes based on the breakpoint being viewed. ProcessWire makes creating thumbnails on the fly so easy, which is a huge plus (especially compared to WordPress). Oh, while administrators have the ability to create projects, they sometimes wanted the ability to have a project assigned 2+ times for a page. Now, having them create a repeat project would be inefficient, so I created another template type called 'duplicate_project' which allows a custom title and thumbnail, but then has a dropdown field that makes the duplicate project act as the main project. As for the lightbox that appears when clicking on a project thumbnail. An ajax request is made to the project template file, which returns a JSON object containing the lightbox image data for Blueimp Gallery, which is the lightbox being used (not Foundation's Clearing Lightbox, which I find very annoying!). It works well, except aligning the bottom-left caption (and bottom-right "Project Information" toggle) was an huge exercise in manipulating the absolute positioning of that element, relative to the image itself, because Blueimp by default doesn't align captions relative to the image. I considered using other lightboxes, but Bluimp turned out to be the best one for my needs, and it's responsive out of the box. The projects themselves have their own individual pages/URLs, but not in the classic sense. If you go to a direct URL of the project, I wrote some code so that it will show the FIRST category it's been assigned to, and then automatically bring up the lightbox containing the projects images. It does this by detecting the the page being hit is either project-category.php or project.php and running the necessary code, which involves the same AJAX request to bring up the lightbox. Example: http://www.archsf.com/projects/aptos-street/ The firm page is whole other beast, but I won't get into that. Screenshots demonstrating some internals: Editing a Project Category: http://goo.gl/T30AEh Editing a Project: http://goo.gl/fekgqQ Editing a Duplicate Project: http://goo.gl/ppKfo5 Editing a Callout: http://goo.gl/gfEbPO Editing the Home Page: http://goo.gl/rbHlRQ Overall Page Structure: http://goo.gl/gfEbPO Enjoy. Jonathan
    4 points
  4. Have you looked at the After Save Actions module?
    4 points
  5. Introducing PVC PvcCore: https://github.com/oliverwehn/PvcCore/ PvcRendererTwig: https://github.com/oliverwehn/PvcRendererTwig/ (coming soon) PvcGenerator: https://github.com/oliverwehn/PvcGenerator/ (coming soon) Each time I’ve built a ProcessWire page I’ve struggled with organizing (and separating) code, markup and stuff. Playing around with frameworks (backend as well as frontend) like Rails, Ember and stuff I really liked having a given structure, knowing where to put what piece of code. Therefor I started working on a MVCish way to deal with templates in PW that considers the $page object kind of the data/model layer and adds View and Controller upon it. First by just catching everything via a small processor file added to all PW templates as altFilename. I’ve digged a bit deeper since then and hooked into the native rendering process, have been refactoring my code base more than a dozen times. Now I got a first version that seem to work and I’d love some of you guys to try it out! PVC (instead of MVC) stands for Page-View-Controller, as it considers PW’s $page var the model/data layer. I’m still working on the README.md on GitHub to document the basics. So have a look for more detailed infos there. I’ll give you a short overview here: Code separation: PVC introduces views and controllers to your PW templates as well as multiple action templates. Controllers, as most of you already know, keep all the business logic. Controllers execute actions wired to routes (urlSegment patterns). Even routes with dynamic segements (e.g. /edit/:id/) can be defined and assigned to an action, providing input through $this->input->route. Values can be set on the controller to be accessable in your templates later on. It’s also possible to set dynamic values as closures to be calculated (e.g. using field values of the current page) on render. Also controllers allow you to set layouts, styles and scripts to be available in your layout or template. Logic can be shared through inheritance between controllers. Views introduce view helpers. Helpers are functions that are made available to you (only) within your template context. There are predefined ones like embed(), snippet(), styles() or scripts(). But you can implement your own helpers easily and share them among your view classes through inheritance. Action templates contain the actual markup. Every action defined in a controller uses its own template. So the same page can display content accordingly to the action that was addressed via urlSegments/route. Within templates you can access all field values and values set on your controller like globals (e.g. <?=$title?>). Modular renderers: PVC implements rendering through separate renderer modules. PvcCore comes with PvcRendererNative that gives you template syntax the good ol’ PW/PHP way. A Twig renderer is in the making. And maybe you want to build your own renderer for the template syntax of your choice? I consider the module an early Beta version. So make sure to try it within a save environment! Would love to get some feedback (and error reports). I’m no professional developer, so code quality may suck here and there. So I’m glad for inputs on that, too. Also there is some old stuff in there yet, I still have to get rid of.
    3 points
  6. so thanks to Soma, there will be a new version of this that doesn't require all of the jquery stuff; currently using soma's code and have it working for asm selects, so now just need to do the same for page list select and autocomplete...
    3 points
  7. Not really sure what you are trying to do, since you don't have to check if a parent exists. A parent always exists in ProcessWire. This is how you can check the number of parents. Maybe that will help you out. $parentCount = count($page->parents); if ($parentCount == 2) echo "do something";
    3 points
  8. Dzień dobry girlz n boize! One thing just came to my mind, when reading Marcrura's new Module post: https://processwire.com/talk/topic/8477-processpageselectlinks/ There are many little helper modules out there that enhance the admin in neat little ways. Perhaps there should be ONE Module (say ProcessWireAdminHelpers.module), which provides hookable methods, so that helper modules can hook into them to be shown on the ProcessWireAdminHelpers.module settings page. There you could enable/disable or apply settings for each. Then there would be a single entry point for stuff like this. I don't want to manage the settings for 20 different modules on 20 different module setting pages. One person should take charge and design such a module, and module devs should then use it's hooks when creating little helpers schmelpers. Any thought's on that?
    2 points
  9. Unless I'm not fully understanding (entirely possible), you can just have them all saved under the same parent. The pageTable field handles the association.
    2 points
  10. About renaming the module...(it isn't a process module ) https://processwire.com/talk/topic/741-a-guideline-for-module-naming/?p=6267 https://processwire.com/talk/topic/1313-modules-process-and-the-difference/
    2 points
  11. <spam>Lot's of things can be done with AdminCustomFiles. Admin custom files has a lot of info in the JS var config.AdminCustomFiles which can be used to be build upon.</spam> Recently I've ported FontawesomePageListLabel to a standalone JS file and included it with the module.
    2 points
  12. You know Asm select plugin has this functionality just disabled?
    2 points
  13. https://processwire.com/talk/topic/2187-module-fieldtypepoll/#entry20484
    2 points
  14. Hello, PageTable is described as a leaner way to enter large amount of repeatable data into the admin backend, possibly with different sets of fields (think different templates). The main advantages compared to the Repeater are: 1. PageTable can save new pages where you tell it to. Repeaters are saved deep down the Admin pages and are given cryptic names. 2. One PageTable field can make use of several different templates. Repeaters play according to the "One repeater = one template" rule (roughly put). PageTable is a PageArray, so relevant methods are applicable. For example, here is how to add and remove items from a PageTable field using the PW API: // create a new page // IMPORTANT: your PageTable field must be configured to use template 'basic-page' in the field Setup tab $newpage = $pages->add('basic-page', '/about/', 'address', array('title' => 'Write to us')); $page->of(false); // add the newly created page to 'pt' which is a PageTable field $page->pt->add($newpage); $page->save(); Here is how to remove the first item from a PageTable field: $page->of(false); // 'pt' is a field of type PageTable $page->pt->get(0)->delete(); $page->save(); That's a quick overview of this new field type. Give it a bit of your attention, it's quite promising. Cheers, Valery.
    2 points
  15. This module adds CSV import and export functionality to Profields Table fields on both the admin and front-end. http://modules.processwire.com/modules/table-csv-import-export/ https://github.com/adrianbj/TableCsvImportExport Access to the admin import/export for non-superusers is controlled by two automatically created permissions: table-csv-import and table-csv-export Another permission (table-csv-import-overwrite) allows you to control access to the overwrite option when importing. The overwrite option is also controlled at the field level. Go to the table field's Input tab and check the new "Allow overwrite option" if you want this enabled at all for the specific field. Please consider limiting import overwrite option to trusted roles as you could do a lot of damage very quickly with the overwrite option Front-end export of a table field to CSV can be achieved with the exportCsv() method: // export as CSV if csv_export=1 is in url if($input->get->csv_export==1){ $modules->get('ProcessTableCsvExport'); // load module // delimiter, enclosure, file extension, multiple fields separator, names in first row $page->fields->tablefield->exportCsv('tab', '"', 'tsv', '|', true); } // display content of template with link to same page with appended csv_export=1 else{ include("./head.inc"); echo $page->tablefield->render(); //render table - not necessary for export - just displaying the table echo "<a href='./?csv_export=1'>Export Table as CSV</a>"; //link to initiate export include("./foot.inc"); } Front-end import can be achieved with the importCsv() method: $modules->get('TableCsvImportExport'); // load module // data, delimiter, enclosure, convert decimals, ignore first row, multiple fields separator, append or overwrite $page->fields->tablefield->importCsv($csvData, ';', '"', true, false, '|', 'append'); Please let me know if you have any problems, or suggestions for improvements. Enjoy!
    1 point
  16. Beautiful work. If you have time, can you explain how the assessments filtering works?
    1 point
  17. You can save all your pageTable pages to a hidden page (same as repeaters do). I put mine under /admin/. Think of it as a closet in the basement that you will never look in.
    1 point
  18. It's already fairly fast with template and markup cache, but up next is a little ProCache. The images are served a 2x resolution for everyone, but at 20% quality. $images->first()->size(556,416,array('quality' => 20)) The file sizes are decent, but I also want to add a lazy loading so that only images that make it to the viewport get loaded.
    1 point
  19. Thanks Adrian, That's part of the minimum viability. There is a proper contact form already built (as well as several other forms via FormBuilder), but the contact form has other options that we weren't ready to introduce, so we decided to go with the simplest option for now.
    1 point
  20. Love it Tom - really nice design and functionality - very sharp! One comment at the moment - maybe it's just me, but I find the Contact Us straight to mailto a little annoying
    1 point
  21. I do love plants and the website. Great work Tom.
    1 point
  22. @mr fan - also there is something that needs to be fixed in the module: // attach js+css to the page only on edit page public function loadAssets($event) { if($this->process == 'ProcessPageEdit') { //load jQueryMagnific $this->modules->get('JqueryMagnific'); //load module scripts and styles for the list links $this->config->scripts->add($this->config->urls->ProcessPageSelectLinks . "ProcessPageSelectLinks.js"); $this->config->styles->add($this->config->urls->ProcessPageSelectLinks . "ProcessPageSelectLinks.css"); } } forgot the brackets after the conditional (copied original code from a module that only had 1 script after the conditional).. without this it will break the admin
    1 point
  23. @Deltanic, It sounds like you are doing after-the-fact debugging using the call-stack shown in the browser. I try not to do that as I don't find it as helpful as using breakpoints or single-stepping new code in my IDE of choice (chrome + xdebug helper & vim + vdebug.) In an IDE you get the full call-stack, variables, code, execution location and can use breakpoints etc. Regarding cleaning up the format of the xdebug callstack output - have you tried the xdebug stack-trace documentation? (There's plenty of good documentation for xdebug.) Like I said, I don't use xdebug the way you seem to want to so I can't help any more than that. I would recommend giving some kind of IDE a go - as I find it so much more convenient for debugging than in-browser stack traces.
    1 point
  24. Well look at the source https://github.com/ryancramerdesign/ProcessWire/blob/master/wire/modules/Inputfield/InputfieldAsmSelect/asmselect/jquery.asmselect.js#L51 I don't know why it isn't used in PW (ASM was a standalone jquery plugin by Ryan, also used quite lot in drupal) But why not ask him I used it (tried) on my proof of concept block content module https://github.com/somatonic/BlocksContent/blob/master/BlocksContent.module#L106 Golden treasure not?
    1 point
  25. This module has intentionally been kept very simple, hence the login box appears on it's own. I actually prefer this for sites in development so that users can't see anything about the site until the protection has been disabled. However, what you are looking for is available in the Page Protector module. Just use the Login Template option in the module config settings. If you have any questions about it, please continue this discussion over in that thread.
    1 point
  26. @Deltanic, I use xdebug with PW almost daily. It works great and I don't need to disable any PW exceptions to get it working. In my case, I use xdebug along with the vdebug plugin for vim and the xdebug helper extension for chrome (similar ones exist for FF) and they do take some configuration to get right - but none of it in PW. Could you explain exactly what problem it is you are having with using xdebug?
    1 point
  27. For my part I can say that I have hired a developer to extend the existing ShoppingCart. Haven’t started yet, but it feels a bit silly to develop something that would quite possibly be included in the new shopping cart system. The developer I’ve taken on is very capable, so if you want to have his eyes on your new system let me know .
    1 point
  28. A starting point module to use angularjs in our templates in an easy manner.
    1 point
  29. PW is not 'failing' for a dumb reason and it tell you what has gone wrong. You can do a try & catch to handle it.
    1 point
  30. I saw this topic yesterday but pwired was quicker . I often use XCloner Standalone as Akeeba Solos didn't already exist at the moment I had to choose for a standalone version, between Akeeba Backup standalone and XCloner standalone. (I usually have to adjust some "paths" and after that it works well.) You can exclude chosen directories and files from the backup, and also "Store you backups on the Amazon S3 cloud", for example. I don't know if Akeeba Solos (which seems to be the new name for the standalone version) can exclude directories and files...
    1 point
  31. Hi Macrura. In the example below you´ll get a list of all children of the actual page. <script> app.controller('myCtrl', function ($scope) { $scope.children = []; $scope.children = <?=$page->getChildren()?>; }); </script> <div ng-controller="myCtrl"> <ul> <li ng-repeat="child in children">{{child.title}}</li> </ul> </div> The code is really clean and is not only that but you can make use of thousands of modules already available and a huge community. As mr-fan said you get lots of videos, docs, books.
    1 point
  32. here it is... https://processwire.com/talk/topic/8477-processpageselectlinks/?p=82020
    1 point
  33. Hello Michael, In response to your earlier post: I've tried storing PageTable pages directly under the parent but it didn't work (for me, at least). However, the idea behind trying to use existing pages in a PageTable field escapes me. Why not use Page fields with PageListSelect+ instead? For instance, here is a screenshot of mock-up of a color chooser for a webshop item.
    1 point
  34. Hey..! Thank you..! I successful login as admin..! Be blessed..! netcarver..!
    1 point
  35. You could use PageTable for that. So at least your overview is narrower. Customize the columns and you're done.
    1 point
  36. @Michael Murphy - i know it sounds sort of Yoda, but perhaps don't delete the pages except with the pagetable? that would prevent that issue; don't give trash/delete permission to those roles that might see the error?
    1 point
  37. pretty sure that this only works for children of the page (showing new pages that can be added)... but will need to test it to confirm... @Michael Murphy - this would basically be equivalent to my module in progress (currently an admin custom pages drop in), which would allow you to use regular page selects, but have the ability to access/edit them in a modal by clicking on the title.. you wouldn't be able to mix and match these with pagetables; i think of page table pages as pages that have to directly relate to to the page and can't be altered by any other page. https://processwire.com/talk/topic/7588-admin-custom-files/?p=81866 there are other ways you could achieve various functionality - for example write a module that clones the pages in a page select to new page table pages where you could then have contextual access to those new pages without the risk of affecting some other place that page is being used;
    1 point
  38. I'm also using this German hoster for some sites. In a nutshell, they are using rsnapshot for their backups. Their backup server is pulling data from the live server. The backups are mounted via NFS to the live server. I came from the Joomla universe to PW. Thus I'm familiar with Akeeba backup which is a great product. Using their free and well maintained standalone version makes backing up PW and other PHP applications a breeze.
    1 point
  39. Don't know why it is not working, can't test right now. You could to it manually, though: $desc = $image->description; echo $modules->get('TextformatterMarkdownExtra')->format($desc); Edit: just tested it, can confirm the Textformatter is not applied automatically. Still don't know why Edit 2: Just tested further, the Texformatter is there, checking via $fields->get('image')->textformatters but the format method is NOT called. Probably a bug.
    1 point
  40. Ha! I didn't notice that . Well I hope I said something useful
    1 point
  41. Yesterday I looked at the HTML output of a PW website of mine and thought it looked kind of messed up. It wasn't because the code was bad or I used the wrong tags. It also wasn't because I somehow forgot to close open tags (w3c validation went fine). No, it only was because the HTML output wasn't well formatted. I think this is a pretty common "problem" when using PHP to generate your HTML code instead of creating static HTML pages. To solve my "problem" I searched a bit and stumbled upon https://github.com/gajus/dindent. The idea behind this remarkable little piece of software is imho great: In opposite to HTML purifier or tidy Dindent doesn't manipulate your HTML code in a sense that it will behave differently. It doesn't close unclosed HTML tags or something like that. No, Dindent only changes the format of the HTML output to make it more readable and appear cleaner. So, as a developer, you are still responsible for creating proper HTML code! So I decided to create a simple little ProcessWire module that hooks into the render-method and applies the magic provided by Dindent. That's all! But I really think it can make a difference in the presentation of your website for everyone that looks a bit deeper into your project and therefore looks at the HTML code your website provides. Beware: Of course the whole beautifying process is not free. It costs some time, so it works best together with a caching mechanisms (favourably the fantastic ProcessWire ProCache)! What do you think? DIndent_v1.0.0.zip
    1 point
  42. Some of you may be aware of Google Trends and the ability to search for a keywords trend over time. Here's one for PW. There's a very encouraging (and well deserved) climb north. Some crazy dudes from Germany obviously like the CMS too
    1 point
  43. No worries guys, sorry I haven't keep you updated. It's been busy here with other things, so no new progress on this. I think it will take winter (or next summer...) holidays for me to get back to this. Maybe I release early bird release of what I have now... I have been hesitating with that because I know I can't provide any real support.
    1 point
  44. <now you are already half way social engineered>Hah!</now you are already half way social engineered> read more ... (blog.fox-it.com) OMG! When it comes to the combination of these two human characteristics the world is uncertain: greed and stupidity.
    1 point
  45. Greetings, This is one of my primary reasons for getting away from Joomla and discovering and falling in love with ProcessWire. I wish this problem were more known. I work with a number of Drupal/WordPress/Joomla people, and I am amazed at how many just assume that what you install in these systems is safe. I'm talking about developers, by the way, not "regular" users! It's not only malicious plugins -- innocent ones can be an issue too. They all open security holes. A well-intentioned developer can compromise your application (I witnessed it first hand). I think another part of the problem that we don't hear about is hosting dishonesty. A lot of hosts specifically market to the Joomla audience (for example), and they spread a bit of false security. I've had conversations with two developers in recent weeks who host at a particular cloud service, and they both believed that the host protected their sites from malicious plugins. (I actually went so far as to write to this host and ask them to guarantee this, at which point, of course, they admitted it was not true). On a related note: happy two-year mark Joss! I'll try to round up the old Seblod and Molajo team for a celebration. Amy Stephen might come too. Matthew
    1 point
  46. 1 point
  47. Hi everyone, I'd like to announce a complete overhaul of this module - problem is that I am not sure whether to release it as an update to this module, or perhaps as something completely new, perhaps called PageProtector. UPDATE: The functionality described in this post is available as a separate module: PageProtector This new version (not on github just yet) makes it very easy for site editors to set up various password protected areas on their site, or to simply protect a new page or section while they are still working on it. New functionality Ability for your site editors to control the user access to pages directly from Settings tab of each page Includes whether to protect all children of this page or not Optionally allows access to only specified roles Ability to change the message on the login page to make it specific to this page Option to have login form and prohibited message injected into a custom template Access to the above "Protect this Page" settings panel is controlled by the "page-edit-protected" permission Table in the module config settings that lists the details all of the protected pages Shortcut to protect entire site with one click What do you all think - replace the existing module, or release this functionality as a separate version? Module Config Settings Page Protection Settings
    1 point
  48. What you can also use, where PW does its validation is the processInput() of inputfields. You can hook into it and do you validation and add errors as needed. $form->addHookAfter("processInput", null, "formValidation"); function formValidation($event){ $form = $event->object; $email_inputfield = $form->get("email"); if($email_inputfield->value == "spam@hotmail.com"){ $email_inputfield->error("We got you!"); } } // direct on the inputfield type wire()->addHookAfter("InputfieldText::processInput", null, "validatText"); function validateText($event){ $inputfield = $event->object; if($inputfield->name == "username"){ ... } } And there's also the HTML5 regex pattern that can be used.
    1 point
  49. I'm not sure what's the issue you're talking about, nor if you want to or use admin to delete pages, as it will trash them and not delete them. So my example is just working for all hooks either trash or delete, just a question if you want the user page to be deleted if the page gets trashed or deleted. Looks ok, you could also use Pages::saved or Pages::saveReady (look at core/Pages.php to read the docs what they're doing), the problem seems more that you're doing a save() in your hook so it will trigger you save hook also. SO it will create user, save user, call save hook, update user. I'm wondering why you don't get a endless recursion (?) That's is simply to prevent recursion or in case the hook get's called multiple times. We could also avoid this differently, but it gets the job done. You could also write: if($page->thispageisalreadyudpated) return; // do nothing $page->thispageisalreadyupdated = true; edit: updated code
    1 point
  50. I'm embarrassed to admit that I send them myself, using a script I wrote more than a decade ago. It's always worked fine, so I've just stuck with it. But I agree with the guys that say it's better to use a service. Someday I will take that advice myself too. But if you want to use what I'm using, here you go… First you'll need a text file with your subscribers in it. 1 email address per line. It can be only a few, or it can be thousands. subscribers.txt bob@email.com jim@bigcompany.com mike@little-org.com Now you'll need the email content. You'll want 1 HTML file and 1 text file. Both should have the same content: template.html <html> <head> <title>test email</title> </head> <body> <h1>Test</h1> <p>This is a test email</p> </body> </html> template.txt TEST This is a test email email.php Place this PHP file in the same directory as the above files. Edit the DEFINEs at the top as necessary. I apologize in advance for this rather awful email solution, but hey it works, and that's why I haven't bothered to rewrite it in 10 years. To run, place the files on a web server and then load in your browser. It should start emailing immediately, once every 3 seconds. If you are sending thousands, then it might take several hours. But because it sends slow, it never seems to caught up in any filters. <?php /** * GhettoMailer v1.0 * * © 1994 by Ryan Cramer * */ define("NAME_FROM", '"Your Name Here"'); define("EMAIL_FROM", "you@domain.com"); define("REPLY_TO", "you@domain.com"); define("ERRORS_TO", "you@domain.com"); define("SUBJECT", "ProcessWire News & Updates - April/May 2013"); define("SECONDS", 3); // seconds delay between each email sent define("TEXT_ONLY", false); // set to true if not sending HTML email define("TEST_MODE", false); // set to true if just testing a send define("TEST_MODE_EMAIL", "you@domain.com"); // email to send to when testing define("SUBSCRIBERS_FILE", "subscribers.txt"); // file containing subscribers, 1 email per line define("TEMPLATE", "template"); // file containing email to send: template.html and template.txt define("X_MAILER", "GhettoMailer 1.0"); /**************************************************************************************/ ini_set("auto_detect_line_endings", true); function mailTextHtml($to, $subject, $message_text, $message_html, $headers) { // exactly like regular mail function except sends both text and html versions $semi_rand = md5(time()); $mime_boundary = "==Multipart_Boundary_x{$semi_rand}x"; $headers = trim($headers); // in case there is a trailing newline $headers .= "\nX-Mailer: " . X_MAILER . "\n" . "MIME-Version: 1.0\n" . "Content-Type: multipart/alternative;\n boundary=\"$mime_boundary\""; $message = "This is a multi-part message in MIME format.\n\n" . "--{$mime_boundary}\n" . "Content-Type: text/plain; charset=\"utf-8\"\n" . "Content-Transfer-Encoding: 7bit\n\n" . "$message_text\n\n" . "--{$mime_boundary}\n" . "Content-Type: text/html; charset=\"utf-8\"\n" . "Content-Transfer-Encoding: 7bit\n\n" . "$message_html\n\n" . "--{$mime_boundary}--\n"; $success = @mail($to, $subject, $message, $headers, "-f" . ERRORS_TO); return $success; } /**************************************************************************************/ $start = 0; if(!empty($_GET['start'])) $start = (int) $_GET['start']; $subscribers = file(SUBSCRIBERS_FILE); if(isset($subscribers[$start])) { $line = trim($subscribers[$start]); $total = count($subscribers)-1; $email = trim($line); $subject = SUBJECT; if(isset($_GET['pause'])) { $meta = ''; $content = "[$start/$total] Paused. <a href=\"email.php?start=$start\">Resume</a><br />"; } else { $meta = '<META HTTP-EQUIV=Refresh CONTENT="' . SECONDS . '; URL=./email.php?start=' . ($start+1) . '">'; $content = "[$start/$total] Emailing <u>$email</u><br />" . '<a href="email.php?pause=1&start=' . ($start+1) . '">Pause</a><br />'; if(TEST_MODE) $email = TEST_MODE_EMAIL; $headers = "From: " . NAME_FROM . " <" . EMAIL_FROM . ">\n" . "Reply-To: " . REPLY_TO . "\n" . "Errors-To: " . ERRORS_TO; $content .= "Subject: <b>$subject</b><br />"; $bodyText = file_get_contents(TEMPLATE . ".txt"); if(TEXT_ONLY) { mail($email, $subject, $bodyText, $headers, "-f" . ERRORS_TO); } else { $bodyHtml = file_get_contents(TEMPLATE . '.html'); mailTextHtml($email, $subject, $bodyText, $bodyHtml, $headers); } $handle = fopen("email.log", "a"); if($handle) { fwrite($handle, "[$start/$total]: $email\n"); fclose($handle); } } } else { $meta = ''; $content = "Subscriber emailing finished. $start emails sent."; } ?> <html> <head> <?=$meta; ?> </head> <body> <?=$content; ?> </body> email.php
    1 point
×
×
  • Create New...