Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 01/24/2016 in all areas

  1. Okay, so I've done it. Two sets of modules, one for the server side, the other for the client side. There are still a lot of ToDos, like adding dedicated endpoints on server and client (I'm currently hooking indiscriminately into ProcessPageView::execute, but I'd like to go the route of only loading the listeners for this template) or adding some kind of challenge-response mechanism to keep nosy third parties out. The modules are up on github: Server component Client component There's also a screen cap in the readmes. Both module sets have lots of hooks, so component modules should be easily able to extend the basic functionality. Currently, the online functions arealdy built-in are the setup of the management connection on both sides and getting basic client information. I haven't really looked at the upgrade or db backup modules, so I've got no idea how complicated remoting them would be. But the sky's the limit. Comments, critiques and pull requests welcome!
    10 points
  2. These are automagically called by ProcessController when an URL segment is appended to the path of an admin page. If an admin page url is http://server/processwire/adminpage/ and that page is called, the execute method is called. But if you open, for example, http://server/processwire/adminpage/edit, the first letter of the URL segement (edit) is uppercased and it is appended to the process method, resulting in executeEdit. Process methods with multiple uppercase letters (camel case) are called by passing URL segments with hyphens. The hyphens are stripped, but each letter after a hyphen is uppercased, so http://server/processwire/adminpage/point-me-to-crocodiles will look for a method executePointMeToCrocodiles in adminpage's process module. This way, one doesn't have to set up another process module for a subtasks and create a page for it or parse even more form values in execute. For a new subtask XXX, it's sufficient to add links/form targets with an URL segment of xxx and define a matching executeXxx method. A perfect starting point to learn more about creating process modules is the source code of Ryan's ProcessHello module, which can be found at github and in the module repository.
    6 points
  3. This is a website about a label I had in the past. After a long pause it was time to set the former label website up again (with a new look) by popular demand. The whole site was set up in less than 2 months in my spare time: setting up everything, creating templates and loading the data page by page. 2 languages (with a main emphasis on German) and everything's fully responsive. Thanks to Processwire and UIkit no problem. - Ryan, thank you for this wonderful CMS. This is only the beginning. If people are using it (and it looks like that) I will expand this thing with videos and more. https://www.chrom.de
    5 points
  4. Hmmm... I'm looking for a module that can clean my house and can make me coffee...
    3 points
  5. So, 48 hours or so after a question that initially got the standard "PW != WP" answer, there's been a reasoned discussion, people have come round to seeing some merit in the initial premise, and BitPoet has a couple of alpha modules on GitHub. That is an extraordinary testament to the quality of PW and this community.
    2 points
  6. I installed pw at another hosting cyon.ch. It worked like a charm! Finally I can have my hands on. Thanks for your help!
    2 points
  7. I think PHP Trends gets its data from github. So if we get some significant grow in likes in the latter, we will get to PHP Trends mainpage.
    2 points
  8. It is now working. After trying everything I could think of I started over. Re-installed pw. Previously I had exported a profile from my server and imported that, this time I used the blank site profile and manually added all the fields. Not sure what was wrong, but it is working now.
    2 points
  9. I am really glad this topic is brought up in the community discussion. I think we all can benefit from PW being more known and used all around the world. It does not pay off to be good at something nobody else around want to use. It is not like karate secret move you can win the fight with. Your customer has to agree and preferably desire that you use PW. More like Kamasutra than martial arts. But those are common words you all understand those thing better than me. I said about "known" and "used" in the same sentence, but those are quite different things although connected. I do not think that we can or should expect PW to be as commonly used as Wordpress or Joomla, as it is obviously targeting a narrower target audience. But we definetely wish and can expect almost everyone in the web-dev world to at least be familiar with the name. And we want it to have a positive connotation. This is a task, and if we want to achieve it, we need to know, when it is achieved. I think that we need to set goals for 2016 and track the porogress. Site visits might not be the best parameter to evaluate for this particular purpose. I am well aware of Symfony 2 framework and I entertain my thought that once I will learn it and use, but I do not visit their site anywhere near often. What other measurable metrics can we track? Backlinks? Google trends? Maybe even conduct some kind of sociological survey now and in the end of 2016? I also suggest we organize ourselves in our effort. What about conducting a number of marketing campaigns with defined goals, timeframe, and summing up in the end? I can propose a few right now: Get PW more stars on Github. So we can be rated closer to the top in the searches like "PHP CMS" and so. If we do it in condensed period of time, we can even make it to trending, which can bring us quite a number of newcommers. Get PW more reviews with stars on bitnami, which will position PW closer to the top of the apps list. Get PW atop of syn.in on alternativeto.net. I think we deserve at least No. 4 . It could be beneficial to make a dedicated forum thread for the campaign to encourage forum members to participate. We also probably want to investigate the target resource's anti-spam policies if any and organize against them. What do you think?
    2 points
  10. 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
  11. On GitHub: https://github.com/plauclair/AutodetectLanguage PW's Modules repo: http://modules.processwire.com/modules/autodetect-language/ This ProcessWire 2.x module tries finds a best match between HTTP_ACCEPT_LANGUAGE and currently installed languages. If a match is found, the user will be redirected from the requested page to the same page in his preferred language. This match occurs only on the first page load, and will work with default caching on. If no match is found, the website will revert back to the "default" language. Installation info and more details on GitHub. Please submit any bug on the bug tracker, as it is easier to track different issues.
    1 point
  12. Hey, The Form API has CSRF protection build in, but if you for some reason don't want to use the API you can however use the CSRF protection. Its very simple but it took some time for me to find out, so i figured i share my findings with the rest. What is CSRF? First you need to create a token and a token name you do that as following: $tokenName = $this->session->CSRF->getTokenName(); $tokenValue = $this->session->CSRF->getTokenValue(); Very simple. Now what you want to do is create a hidden input field like this: $html .= '<input type="hidden" id="_post_token" name="' . $tokenName . '" value="' . $tokenValue . '"/>'; Now this will generate something that will look like this: You are done on the form side. You can now go to the part where you are receiving the post. Then use: $session->CSRF->validate(); This will return true (1) on a valid request and an exception on a bad request. You can test this out to open up your Firebug/Chrome debug console and change the value of the textbox to something else. Basicly what this does is set a session variable with a name (getTokenName) and gives it a hashed value. If a request has a token in it it has to have the same value or it is not send from the correct form. Well I hope I helped someone.
    1 point
  13. I have to agree. As first impressions go, this is excellent. Having spent years at the helm of Joomla sites and having just moved to an agency that has a WP back catalogue and have been dabbling in PW, it looks like they picked the right platform and more importantly community!
    1 point
  14. Is the name of the module HappyClasses or DynamicCSSClasses? Congrats on your first module.
    1 point
  15. Maybe abstract different tasks to different (sub)modules? Something similar to the tools module by netCarver et al. (can't remember its name atm). Then one could add only the bits they need or use other third party tools for some tasks. As for the monitoring system itself, I would probably install it on a ProcessWire site with no frontend traffic, basically, only backend whose only work is to monitor, inform and issue commands to the sites being monitored. Oh, welcome to PW and the forums petejones
    1 point
  16. Yes, all these points would mean creating a monster. In terms of database backups or malware scans, those are highly platform specific and not something easily implemented in a module. A centralized overview actually makes sense to me. Showing.PW and module versions and outputting some statistical information is also quite doable. Displaying a momentary status can be done, but continuous monitoring is not something that you can build on top of PW - for this, you'd need to add some layers under or next to it. I've started tweaking together a set of modules that could serve as a base. I'll try to add the necessary hooks to allow extending it tomorrow and put an alpha release on github. If nothing else, it's an interesting conceptual challenge
    1 point
  17. Hmm, there are message boards and everything, and a small community. You might be able to get "direct support", but in case of bugs or feature request I suggest opening an issue on GitHub. This is the problem with new things, there is not a solution to every newly discovered problem yet
    1 point
  18. Real-Life Example Website: crms.sdtool.info Purpose: Collaborative Resource Management System (CRMS) Ok, this website uses Adrian's Protected Mode module to control access to the website. ProcessWire (PW) Roles are then used throughout to control access to selected pages. Fields within templates are also controlled via this method. These PW Roles are added at each PW template using the Access Tab. I use a concept I call a "Security Container" that sits at the top of the PW Page Tree (backend) on the website. This is how the "Security Container"is explained on the website: Each "Security Container" has a PW template that controls who has access to that particular page. Once again, access is gained via one or more PW Roles. You have to have access to the gateway "Security Container" page to get to any pages under it. My Client: (I will be using the name Axxxx, as I still need to respect confidentiality and privacy) is an Internet Marketing and Investment Company in the Washington DC Metropolitan Area. They provide selected SEO services to their clients. My role with this client is to provide back-end Internet-based infrastructure support for Axxxx and their clients. This comprises of: Manage/maintain existing web hosting user accounts (SSH/SFTP) and creating new ones (when required) Database creation and upkeep Domain and SSL/TLS registrations Wordpress website installations, day-to-day back-end management and upkeep Email domain/account creation, back-end management and upkeep (website, plug-ins and themes) Centralized database backups and restorals Analytics management using Google Tag Manager/Analytics, Piwik and Woopra Work with Wordpress developers, on behalf of the client, to integrate third-party plug-ins or capabilities Accessing Axxxx Client Data or Resources The Axxxx Client has three possible PW Roles that can be assigned: axxxx-client-access (Contractors or any outside Axxxx related entity) axxxx-manager-access (Axxxx Business Owner or Manager) axxxx-staff-access (Axxxx Staff who aren't at the manager level) The top-level Axxxx "Security Container" Page ensures that only the above three PW Roles have access to Axxxx data or resources. Whenever an Axxxx employee logs into the website, they only see Axxxx related information. Form-Based Page Submissions All newly created pages (by clients) make extensive use of Ryan's Form Builder module. Support request pages and emails are created using this handy tool. Each client has dedicated Form Builder forms that are applicable to their particular mission. Email-Based Page Submissions All my clients have the capability to submit updates or new submissions to me through email. I use the fantastic Email To Page module by Pete and Adrian to achieve this feat. I now make extensive use of Twilio based communications capabilities due this module being installed on this website. Axxxx Company Clients The Axxxx Client company has clients of their own and their data is stored within the website's "Client Portal" Security Container. They can all see the "Client Portal" page (but not any CStevensJr or Axxxx data) and each has an individual named page (which is a "Security Container" for their permissions) under it. PW Roles are used here also to segregate access to each client's own data. Whenever a Axxxx client logs into the CRMS, they only see the "Client Portal" PW Page and beneath that their own data/resources. Final Thoughts PW has an extensive Roles and Permissions system which has significantly improved over the last year. I previously made use of Ryan's Page Edit Field Permission module but now use the greatly expanded native permissions instead. My SDTool Project has progressed very nicely and is being expanded to make use of all the great new capabilities that PW provides. I hope this rather long explanation is helpful. This is just one way I work with PW. I will, in the next few months, provide some more promised updates on the SDTool Project (in the linked post) .
    1 point
  19. Ryan - you're the twinkly fairy atop our ProcessWire Christmas tree. But seriously, I wonder if you should include a screen grab from GoogleTrends too? It does a great job of showing the increase in Searches for ProcessWire on Google. BTW, your clarity and openness here just highlights the WTF-fest surrounding another platform I use. Nobody knows the number of the next version, they can't agree on the product name, there's no public (if any) roadmap and it's probably over a year since there was any type of public info. I wish them well but reading great posts like yours on how solid PW is and how bright it's future (and present) is, clarifies for me that banking on PW has been the right decision for my business and clients too. And that's not because the other CMS is headlining at Confusion-Palooza but because PW on its own merits has a bright, long road ahead. You've written too a post which I'll happily send clients to when they ask "well, what is ProcessWire"?
    1 point
  20. I think a central manager (ProcessWatch ?) is a great idea and something I've needed in the past. My collection of PW sites is growing rapidly and a birds eye view if all of them would be a real bonus as we manage more and more. Are there recent developments with PW3 which allows it to share data with other PW sites? Maybe the time has never been better to have a central PW install with the: 1. Ability to see which version is running and what latest Dev and Stable version is 2. Ability to upgrade , backup database etc 3. See a modules installed and their version. See if a new version is available 4. See the health of a site (some kind of ping or status - live or non responsive) 5. See who is logged in per site 6. See latest changes per site I think all of the above are already available within a PW install via native functions and Module so I wonder how they could be harnessed on a central console.
    1 point
  21. In some cases it doesn't matter, and in some cases it does It depends on the scope and class context as to whether $this->user->name will work or not, but seems to have been common practice in various modules. With PW 3.x ramping up I would suggest reading this: https://processwire.com/blog/posts/processwire-2.6.21-upgrades-comments-more-on-pw-3.x/#more-updates-on-processwire-3.0 - scroll down a little to the "Multi-instance with 3rd party modules and PW 3.x" section where it explains what works where. Actually this is a good reminder for me to update my modules to use $this->wire()
    1 point
  22. I have always seen processwire terminology like the OOP way Template = Class Field = Property Page = Instance Also everything is a page is a wonderful concept that saves me a lot of engineering efforts when creating websites
    1 point
  23. I actually think “page” is a stroke of genius. It keeps the learning curve low for beginners by giving them a word they can immediately understand and work with. You can either keep working under the assumption that a page represents an HTML document, or dig deeper little by little. You’ll install a module like Language Support, and notice that – what do you know – languages are pages, until you arrive at “everything is a page”.
    1 point
  24. ? $page->parent; http://cheatsheet.processwire.com/?filter=parent See also: $page->parentID; $p = $page->parent;// here, $page->parent will give you the parent page object of the current page or nullpage if it does not have one echo $p->title; if($p->id == $someOtherID)// do whatever....
    1 point
  25. There is this: http://modules.pw/ (Needs a little updating, however...)
    1 point
  26. I created a pull request. Cheers Oliver
    1 point
  27. Turn off session fingerprint in config.php.
    1 point
  28. I have thought a bit about newsletter integration and how an emailer setup would work from within ProcessWire, either by building something natively or integrating with Campaign Monitor / Mailchimp. I have a couple of sites for organisations with medium-sized memberships. These need to email their members from time to time so I built a dead simple module to do this which supports a single email template. You can take a look here. Please feel free to build upon this, or just take the basic idea and run with it. https://github.com/ffub/ProcessMailer These are the benefits I can see from building a complete web mailer in PW: Ease of use My clients already know how to use the PW backend All of them find Campaign Monitor and MailChimp very hard to understand and use, especially the latter Content management all in one place. They can manage their web presence all from the backend of their site [*]Tight integration with user database. You can easily create a mailing lists with PW’s awesome selector engine, eg: $users->find(“roles=5810, newsletters=news|offers”) [*]Create email templates based on the PW templating and field system Multiple email templates Familiar API Keep your templates alongside your front end templates Use templates for system messages [*]Because sent mails would be stored in the system as Pages and the templates would be on the server, These are the negatives Your server will get blacklisted! Preventing users from marking your email as spam is a pretty herculean task. If you use the web server the site is hosted on to send the email then a blacklisting will also affect the system messages send out by all the sites on that server. You can work around this somewhat by allowing the web mailer to use a separate SMTP host in its settings. Hiring an SMTP host for bulk mailing will typically cost you more than just using Campaign Monitor or MailChimp. Hosts such as Gmail will only let you send up to 500 messages and will frown upon sending bulk mailings through their service. Performance: Sending multiple HTML emails can be very slow. I’m not sure how much offsetting the sending to an SMTP server improves this, but it’s definitely a concern on a web server. Bounces: You would have to setup the mailer on your server to route these to ProcessWire. Even then, it’s quite a job working out which are actual bounces and which are Out of Office messages or genuine replies. Metrics: Email analytics is a task best suited to the big boys. How would you build an emailer in processwire? I think it would actually be pretty simple to build a pretty powerful Mailer. Lists would be created by choosing a role, or using a selector for more advanced ones. Templates would be stored alongside regular page templates and you’d use the familiar $page API within them. Eg $page->subject. The rich text editor field might need some trickery to make sure all links and image paths are absolute URLs including the hostname. Campaigns or Messages would be created as pages. You could have draft and sent statuses or parents. It would be possible to view them on the front end too. Your email templates could easily pull in data via the Page field type, allowing you to sent out emails for events and the like with ease. Text versions could either be based on an alternative template (multiple files per template may be tricky) that strips out any HTML or by running the HTML template through Lynx on the server, which makes for a unix/cygwin dependency. If you used Textile or Markdown for your body field rather than TinyMCE this would be less of an issue to work around. An analytics field in the settings would let you enter a Google Analytics ID. Links could then be tracked with Google's campaign tracking I’m certainly keen to look into the templating side of this over Spring as I’d like to use HTML templates to send some of my notification messages. thanks, Stephen
    1 point
  29. Looks like a great solution, thanks for posting Diogo. A couple of suggestions I'd have would be: 1. For all your $pages->get("title=$email"), I'd suggest making them as specific as possible since they can be initiated by a user. Specifically, I'd make it "title=$email, template=person, parent=/subscribers/". While not technically necessary, it just puts in another layer of security at very little expense. Who knows, maybe you'll use email addresses for titles somewhere else? 2. You may want to consider changing your $page->delete() to a $pages->trash($page), just to give you the opportunity to review who unsubscribed before emptying.
    1 point
  30. I want to share with you guys the final solution that I implemented for this newsletter. So, I decided not to use any system like Mailchimp or Campaign Monitor (thanks for these and other suggestions, anyway). I wanted an extremely simple system, and decided to built it with PW instead. Collecting the emails is done in a very simple way: when the user inputs the email, it is sanitized and, if it doesn't exist, a new page with the email as title is created under a parent called "people". Like this I get a nice list of emails in the page tree. After this, the user gets a success message, and is sent a welcome email. $email = $sanitizer->email($input->post->email); if(!$email) { echo $pages->get(1023)->not_email; } elseif($pages->get("title=$email") instanceof NullPage) { $p = new Page(); $p->template = $templates->get("person"); $p->parent = $pages->get(1015); $p->title = $email; $p->save(); echo $pages->get(1023)->confirm; //send the email $to = $email; $subject = 'Willkommen'; $message = <<<EOT ...(here goes the html of the welcome email)... This email (and also the future ones) has a link for an unsubscribing page that looks for the imputed email and deletes it: $pages->get("title=$email")->delete(); if($pages->get("title=$email") instanceof NullPage) { echo $page->byebye; } else { echo $page->error; } The newsletter itself is also very simple. In this case we decided that periodically, the administrator will choose some of the posts from the blog to build the emails. So, I created a page "messages" that accepts children pages with a template that has only a date field and a pages select field. To send a message, the administrator creates a new page under "messages", chooses the blog posts that wants to include, publishes it and presses view. Here she is presented with a sample of how the email looks like, and a button "send" on the bottom. The email is sent, and she is redirected to the PW admin with a success message. Again, I kept it very simple because we wanted limited functionality, and maybe it needs some adjustments. But It could be much more complete, with the alternative to write a text and put images instead of only choosing the blog posts, for instance. And maybe even turned into a module.
    1 point
  31. I use Mailchimp for newsletters. As Apeisa said, when using the API, confirmation mails are not necessary. I save the users in PW and sync them to Mailchimp. This is the piece of code I use: <?php /** This Example shows how to run a Batch Subscribe on a List using the MCAPI.php class and do some basic error checking or handle the return values. **/ require_once 'libs/mailchimp/MCAPI.class.php'; require_once 'libs/mailchimp/config.inc.php'; //contains apikey $api = new MCAPI($apikey); foreach ($page->children as $subscriber) { $name = $subscriber->title; $email = $subscriber->visitor_email; $batch[] = array('EMAIL'=>$email, 'NAME'=>$name); } $optin = false; //no, don't send optin emails $up_exist = true; // yes, update currently subscribed users $replace_int = false; // no, add interest, don't replace $vals = $api->listBatchSubscribe($listId,$batch,$optin, $up_exist, $replace_int); if ($api->errorCode){ echo "Batch Subscribe failed!\n"; echo "code:".$api->errorCode."\n"; echo "msg :".$api->errorMessage."\n"; } else { echo "added: ".$vals['add_count']."\n"; echo "updated: ".$vals['update_count']."\n"; echo "errors: ".$vals['error_count']."\n"; foreach($vals['errors'] as $val){ echo $val['email_address']. " failed\n"; echo "code:".$val['code']."\n"; echo "msg :".$val['message']."\n"; }} ?>
    1 point
×
×
  • Create New...