Jump to content

ryan

Administrators
  • Posts

    16,467
  • Joined

  • Last visited

  • Days Won

    1,461

Everything posted by ryan

  1. I want to make sure I understand how to duplicate. So create a new page, and set the name is "0" or something different? Thanks, Ryan
  2. Very cool Adam. I just installed and tested it out on one of my existing textarea fields and it works great! This opens up some cool new possibilities, like having pages as CSS or JS files. Tell me more about the way you are using it in your own projects? Nice work. Thanks, Ryan
  3. ProcessWire works in both of the ways that you described for Wordpress and Wolf CMS. By default, each page has a parent, but that is just one of many ways you can retrieve them from the API. For example, you could retrieve all pages using the "news" template, regardless of where it was in the site, by using this API command: $items = $pages->find("template=news"); 20-100 articles on the back end is not going to get bulky. ProcessWire is designed to deal with tens of thousands of pages (or more) on the back end. I think you will find it can scale better than WordPress in that respect. Though I don't have enough experience with Wolf CMS to make any comparisons with that product.
  4. Definitely not a reserved-word problem with a name like "latest-news". I think we must be running into some kind of incompatibility with your server or it's version of PHP. Do you know what version of PHP is running on the server? One thing you can do is upload a file called phpinfo.php with nothing in it but this: <?php phpinfo(); Then load the URL you uploaded that file to in your browser, and PM me the link or send a PDF/screenshot of the result to me.
  5. Changing the password is as simple as: $user->pass = "new_password"; $user->save(); But this a security problem from the front-end because we don't have any way to confirm that the user is who they say they are... without them actually being logged in. In the new user system, an email address will be part of the default user profile. That's one way to confirm a user's identity, and means you'll have the option of sending them an email with a password reset URL. You could implement that approach now by saving account email addresses in some other place. But if you don't need it to happen right away, you might just want to wait for the new user system, which will have this capability built-in.
  6. You can make a template (and it's corresponding page or pages) do just about anything. But I think we need more technical details about what you are working with, because I'm not sure that I totally understand your question? Thanks, Ryan
  7. Take a look at this post from awhile back that documents one way to approach it: http://processwire.com/talk/index.php/topic,17.0.html There are also some changes in progress for the user system that may be worthwhile for your need as well. The only concern I have in your instance is the "clients can register" part. That means that you'll have to implement some extra security measures to ensure you don't get millions of automated spammer accounts. But I can help you through that. Whereas if you are creating the account and password, you don't have to worry about that aspect.
  8. Are you doing this from the admin or from the API? If from the API, what it's telling you is that you need to populate $page->name before saving it. But it sounds like you are in the admin, so it is a strange error to see when adding a page in the admin. What is the name you trying to give the page? The only instance I can think of where you might get this error is if the page name you are trying to use is a reserved word. Also you mentioned some other problems - Can you describe them further? If there is something environment specific, the more we know, the better chance we can track down what's going in in this environment. Since the installer couldn't detect the server type or mod_rewrite, that indicates potential incompatibility. A link to phpinfo may be helpful too (feel free to PM it to me if you prefer). Thanks, Ryan
  9. Not yet positive about the actual format of the file, but the two you mentioned are likely candidates. Though the files may end up being used just for importing/exporting, and DB used for storage. Regardless of the file format, we're going to make them editable in the admin so that the format won't matter too much.
  10. The structure is designed to support an auto update, so that this module can be written at some point in the future. The way it would work is that it would grab the latest zip (like from GitHub), then it would rename your /wire/ dir to /.wire.[version]/, and move the /wire/ dir from the zip into the location of the old one. At the same time, it would also replace the /index.php and /.htaccess files (unless you wanted to do that part manually). Lastly, it would run an update.php file from the zip to perform any necessary DB updates (if there were any). On most servers, we can't assume that the /wire/ dir is writable, so it would likely unzip the latest PW version into a writable dir in /site/assets/, and then FTP into itself to rename and replace the /wire/ dir with the new one. I believe this is the same method that the Wordpress automatic update uses.
  11. The way we solve it currently is to not actually have a /site/ dir in the repo, but instead have a /site-default/ dir. That way when you do a "git pull" to update your installation, it should leave your /site/ dir alone (which is in the .gitignore). That's the intention anyway. (I'm also new to git). Granted, PW will create a new /site-default/ dir, which you would then want to remove after an upgrade (or add it to your .gitignore so that it doesn't get pulled). We could certainly have a /wire/ only repo too, but the /index.php and /htaccess.txt files are an important part of each version, even though they can't be in /wire/. I'm not sure how to handle that... though maybe that would just be a disclaimer for using the /wire/ repo.
  12. Great update! Thanks for your work on this. I did run into one minor issue, and that's if the site is installed in a subdirectory, the redirect doesn't work. The reason is that it attempts to do the redirect to page's path without the subdirectory it's installed in. I just submitted a pull request to you with a possible solution. It converts PW urls to their page ID for storage purposes. This solution also ensures that redirects aren't broken if the redirect_to page is moved in PW. It only does this with redirect_to URLs that resolve to pages... it leaves all the others alone.
  13. Apeisa's example is correct. Thanks, Ryan
  14. Here's how to implement the page picker in your Redirects module. First, give your redirect_to field an id attribute in addition to the name attribute it already has. So replace this: $field->name = "redirect_to"; with this: $field->name = "redirect_to"; $field->id = "redirect_to"; Now add a new field to your form, right after the redirect_to field: <?php $field = $this->modules->get("InputfieldPageListSelect"); $field->label = 'Select Page to Redirect to'; $field->attr('id+name', 'select_page'); $field->startLabel = "Select Page"; $field->parent_id = 0; // tell it to start from homepage if(strpos($to, '/') === 0) { // if a value is already set, determine if it's a page // if it's a page, then populate the input with the page_id $page = $this->pages->get($to); if($page->id) $field->value = $page->id; } $form->add($field); // now add a script that makes it automatically populate the redirect_to field // with the URL of the selected page. $script = <<< _END <script type="text/javascript"> $("#select_page").bind('pageSelected', function(event, data) { if(data.url.length) $("#redirect_to").val(data.url); }); </script> _END; Lastly, at the bottom of your function, we want to include the $script in the output, so replace this: return $form->render(); with this: return $form->render() . $script; Let me know how that works? Thanks, Ryan
  15. Thanks Marcin! That's great -- I'll be glad to take you up on that. In about a month or so I hope to have a separate dev branch that includes the multi language support (at least the basics).
  16. Just tried it out and it works great! I will definitely use this, thanks for putting it together. Nice work! Two minor CSS suggestions (see attached screenshots showing before and after): /* adds padding at bottom so floated buttons don't touch footer */ #redirects_form { margin-bottom: 3em; } /* the margin-right addition ensures the button floats all the way right */ #submit_delete { float: right; margin-right: 0; } This is such a useful module, it makes me start thinking of what more could be added... any thoughts on future additions? A couple ideas are: ability to upload (or paste into a textarea) a CSV file with the "from, to" urls. A counter for each redirect that keeps track of how many times it's been used. Thanks, Ryan
  17. To uninstall something you want to do it through admin>modules. If the dir/files were removed without uninstalling, it's best to put them back where they were. It sounds like you may have already tried this? If so double check that the dirname and filenames are the same as before. If that still doesn't work, you can always remove the entry from the modules table manually, if you are sure it's not actively being used on any fields. Better yet, try deleting the modules cache file in site/assets/. I dont recall what the filename is (I'm not at computer) but I think the name is recognizable as being for modules. Please let me know how this works out.
  18. I'm not sure how I missed this before, but turns out we already have a hook that looks like it'll work. It's ProcessPageView::pageNotFound Here's one approach that could be used to handle the hook and redirect. This is coded in the browser/forum, so not tested and probably has parse errors, etc., but hopefully the general idea works. <?php public function init() { $this->addHook('ProcessPageView::pageNotFound', $this, 'checkRedirects'); } public function checkRedirects($event) { // determine the URL that wasn't found $url = $_SERVER['REQUEST_URI']; // if installed in a subdirectory, make $url relative to the directory ProcessWire is installed in if($this->config->urls->root != '/') { // you might need to double check that below results in a path with a slash still at beginning $url = substr($url, strlen($this->config->urls->root)-1); } // we'll check the DB against trailing slash version and non-trailing slash version // and escape them for the DB select while we are at it $url = $this->db->escape_string(rtrim($url, '/')); $url2 = $this->db->escape_string($url . '/'); // now see if it's in the DB $sql = "SELECT redirect_to FROM {$this->className} WHERE redirect_from='$url' OR redirect_from='$url2'"; $result = $this->db->query($sql); // if there is a match, then redirect to it if($result->num_rows) { list($redirect_to) = $result->fetch_array(); $this->session->redirect($redirect_to); } }
  19. Sorry I forgot something. Add this right after you get the $table from $modules: $table->setEncodeEntities(false); I recommend having ProcessRedirects live in it's own directory, like: /site/modules/ProcessRedirects/ProcessRedirects.module Then create another file in there called ProcessRedirects.css Use that CSS file to place the button element where you want. In your module file, you can give the button an id attribute so that it's easier to target in the css file: $button = $this->modules->get("InputfieldButton"); $button->id = 'submit_delete'; // assign an ID attribute $button->type = 'submit'; $button->value = 'Remove selected redirects'; Note that id attribute may actually be assigned to a containing element of the button (not positive). If it is, then you'd want to target in your CSS as "#submit_delete button" rather than just "#submit_delete". In your executeSave function, I recommend escaping the $from and $to vars before insertion into the DB. The reason is that there are some chars allowed in URLs that would need to be escaped for the database (at last I think there are). To do that, you'd just use PHP's mysqli escape_string function: $from = $this->db->escape_string($from); $to = $this->db->escape_string($to); I'm working on adding the hook and should have that this morning! Edit: One last thing is to add is "$count = 0;" at the top of your executeDelete function. Otherwise PHP will throw notice errors about an uninitialized variable when ProcessWire is in debug mode. Thanks, Ryan
  20. ProcessWire wasn't built to be a full-on MVC framework like CodeIgniter, and so most of what is used in developing the admin modules is fairly basic. Though I've never actually built anything in CodeIgniter, so I don't know all that it does specifically. I know CI maps URL segments to functions (like a Process module), but it also maps URL segments to function arguments (unlike a Process module). I didn't do that because I preferred to keep dynamic arguments as GET or POST vars. PW1 enforced MVC for processes, and enforced keeping everything in separate files. It had it's benefits, but in my case it was a net loss to time and maintenance compared to PW2's system. PW2 leaves it more up to you how much you want to enforce a pattern. I usually keep my views in the class, but under a function called "render()" ... that's stylistic only. You'll find that most Process modules call upon other modules to provide views, like the Markup and Inputfield modules. (i.e. MarkupAdminDataTable, InputfieldForm, InputfieldText, etc.). If you want to maintain a view in a separate file, use the TemplateFile class. It works much the same way that a view in CodeIgniter would work, and it's the same class that ProcessWire uses to render template files throughout the site. Though I don't actually do this in any of the Process modules, but here's how you would: public function ___execute() { $view = new TemplateFile($this->config->paths->MyModuleName . "view.php"); $view->set('videos', $this->getVideos()); return $view->render(); } ProcessWire assumes that all "execute" functions return the output that will ultimately be populated in the main part of the template. It includes a couple of helpers in the "fuel" for populating the headline (processHeadline) or breadcrumbs. These are optional -- if you omit these, the breadcrumb trail will be to the current page, and the headline will be the title field from the current page. Very often, this is what you want, so I don't bother with the headline or breadcrumbs until my Process module is up and running and I find it makes sense to add them. Any function that begins with 3 underscores, like "___execute()" is hookable. If you don't want it to be hookable, then just use the same function name, but without the 3 underscores, i.e. "execute()". ProcessWire doesn't care which version you use. When in doubt, make them hookable. For functions that you make hookable (by preceding with 3 underscores), any other module can add a hook either before or after it. Hooks that run 'before' can modify the function arguments sent to the hooked function. Hooks that run 'after' can modify the return values of the function. Beyond that, hooks can do whatever they want. See the /wire/modules/Helloworld.module for an example of a couple hooks. For more insight on Process modules, I would first look at the Module interface, defined in the /wire/core/Module.php file. This basically just lists the functions that all modules are required to have. Most are optional, so you'll see them documented, but commented out. As a result, this Module.php file is more for documentation purposes than anything else. Next look at the definition of a Process module in /wire/core/Process.php. You'll see it's pretty simple and short. It enforces an execute() function, which gets called on a request of /path/to/page/. Any others you create, i.e. executeEdit(), executeSave(), etc., it only calls if it finds "edit" or "save" in the URL. There are no predefined names after the "execute" part, so it could just as easily be "executeHello()" and that function would get called when the URL was "/path/to/page/hello/". The only other significant thing that Process module does for you is that it looks for a css and js file that follow the same name format (and are in the same dir) as your .module file: /site/modules/Process/ProcessVideos/ProcessVideos.module /site/modules/Process/ProcessVideos/ProcessVideos.css /site/modules/Process/ProcessVideos/ProcessVideos.js If it finds them, they get automatically included in the admin template's <head> section.
  21. I'd like to build a ready-to-go blog site profile in PW at some point. I think PW would lend itself very well to building a blog. But the need comes up so rarely in my own work, that I haven't done much other than experiment ... my site (ryancramer.com, in PW1) is loosely in a blog format, though I built that several years go and it's long past time for a redesign and redevelopment. On sites where the client has asked for a blog, I've used WordPress. ProcessWire and WordPress run alongside each other quite well. Then I'll use WordPress RSS feeds to pull blog entry headlines into ProcessWire so that they can be output anywhere on the site, so make it seem like it's all running together...
  22. Since it looks like you have some cached pages, another thing you might want to do when moving a site is to clear the cache. You can do it before or after, but probably do it before just so you are transferring fewer files. Go to Admin > Modules > Page Render > and click on the "clear cache" checkbox, and submit. This can be especially useful when moving a site from one path to another (like subdirectory to root), because cached pages might temporarily be looking for external assets like CSS and JS files in the wrong directory. So if you ever transfer a site and see your homepage show up with no stylesheets or images, go in and clear that cache and you'll be set. Another way to clear the cache is: rm -rf ./site/assets/cache/Page/* But I always get a little nervous with anything involving an "rm -rf" (one stray character could wipe out everything) so I usually do it from the admin.
  23. Technically modules are just a class that implements an interface. It doesn't have to extend any other class in order to implement that interface, but it does make life a little easier ... especially in the case of Process modules, because they have some flow control built in and know to look for specific CSS/JS files, etc. There isn't any requirement that you have to use Process modules in the admin. You can just as easily use any template of your own if you prefer. But if Process modules save work for what you need to do, then I think they are a good way to go. The ProcessPage modules are probably the broadest in scope of all of them. For most other instances, I'll usually integrate the List, Edit, Add, Delete all into a single Process module. In the case of ProcessPageEdit/Add/List, it was a lot of code so I split them up. But for your own needs, you may find you prefer keeping it to a single module, or splitting them up.. it doesn't matter. The main advantage of keeping them in a single module is that they are attached to a single page, so you don't have to worry about a multi-page dependency (not that it matters that much though). Now that I know people are going in and using these as examples to create others, it makes me think I need to go in there and make sure all my code is clean. That was fast! Glad that it worked out well. Though I think your previous approach was a good one too. But I also think that using pages will hopefully save you time and be more fun to work with. I'm in the process of doing the same thing that you did, but with the user system rather than videos. I'm converting the user/role/permissions system to use pages rather than WireSaveableItems, along with multi language support. From the user side, I'm doing it so that the system can accommodate any number of users (more scalable), and let you add custom fields to users, roles and permissions just like any other page template (more flexible), as well as reduce some redundancies on the multi language system. Sounds good, I look forward to seeing what you are doing. And of course, please let me know anytime I can be of any help with questions. You and a couple of other people are getting deeper into the code than what is currently in the documentation, and I'm here to help with any questions you have. Thanks, Ryan
  24. That's great to hear! Thanks for your message, this makes my day. That's impressive! Sounds like a great site, and that you've done a lot of great things with it. I'm always wanting to add new sites to this page, if you ever have any you want me to post there just let me know: http://processwire.com/about/sites/ There really isn't much in the way of a form builder right now, but it's something we've been talking about. I expect we'll be making progress on this in the summer (soon!), assuming someone else doesn't do it first. But multi-language support and a redesign of the user/role/permissions system are in progress now, and a form builder comes after that. This is relatively straightforward because pages in the Admin are just like any other pages on your site. You can add a page to the admin, and make it use any one of your templates. Internally, ProcessWire uses what are called "Process" modules to serve as a very basic framework for managing flow control on a given page (very loosely like CodeIgniter in terms of calling a function based on a URL segment). But it's not a requirement to use them. I've found that my clients relate well to the tree structure too. Or when they don't, I tell them to think of a family tree, and then they get it. Thanks for using ProcessWire and being part of the community here! I look forward to talking more. Ryan
  25. Looks like you've got a good start here! To create the table, I would do it in your install function. The only part of PW that creates tables are the fieldtypes, and those aren't useful here, so you'll want to issue the create table yourself. Something like this: <?php public function ___install() { parent::___install(); $p = new Page(); $p->template = $this->templates->get("admin"); $p->parent = $this->pages->get($this->config->adminRootPageID); $p->title = 'Redirects'; $p->name = 'redirects'; $p->process = $this; $p->save(); // hold off on the permissions if you can because this system is being redesigned. // $this->installPermission('Edit'); $sql = <<< _END CREATE TABLE {$this->className} ( id int unsigned NOT NULL auto_increment, redirect_from varchar(512) NOT NULL DEFAULT '', redirect_to varchar(512) NOT NULL DEFAULT '', UNIQUE KEY(redirect_from) ); _END; $this->db->query($sql); } public function ___uninstall() { $p = $this->pages->get('template=admin, name=redirects'); $p->delete(); $this->db->query("DROP TABLE {$this->className}"); } For your CRUD, I would make your default function (execute) the one that lists the redirects, and then create functions to edit, save and delete. Here's an example of how you might do some of it as a starting point (written in the browser, so not tested!): <?php /** * List Redirects - Called when the URL is: ./ * */ public function ___execute() { $this->setFuel('processHeadline', 'List Redirects'); // example here uses a PW module to output this table, but that's not required. $table = $this->modules->get("MarkupAdminDataTable"); $table->headerRow(array('Redirect From', 'Redirect To', 'Delete')); $result = $this->db->query("SELECT * FROM {$this->className} ORDER BY created"); while($row = $result->fetch_assoc()) { // output in table rows with edit link and delete checkbox? $table->row(array( $row['redirect_from'] => "edit/?id=$row[id]", $row['redirect_to'] => "edit/?id=$row[id]", "<input type='checkbox' name='delete[]' value='$row[id]' />" )); } $table->action(array('Add Redirect' => 'edit/?id=0')); return "<form action='./delete/' method='post'>" . $table->render() . "</form>"; } /** * Edit/Add Redirect - Called when the URL is: ./edit/ * */ public function ___executeEdit() { $this->fuel->breadcrumbs->add(new Breadcrumb('./', 'Redirects')); $id = (int) $this->input->get->id; if($id > 0) { // edit existing record $result = $this->db->query("SELECT id, redirect_from, redirect_to FROM {$this->className} WHERE id=$id"); list($id, $from, $to) = $result->fetch_array(); $this->setFuel('processHeadline', "Edit Redirect"); } else { // add new record $id = 0; $from = ''; $to = ''; $this->setFuel('processHeadline', "Add Redirect"); } $form = $this->modules->get("InputfieldForm"); $form->method = 'post'; $form->action = './save/'; $field = $this->modules->get("InputfieldHidden"); $field->name = 'id'; $field->value = $id; $form->add($field); // maybe use InputfieldURL for the 'redirect_from' and 'redirect_to' inputs return $form->render(); } /** * Save Redirect - Called when the URL is ./save/ * */ public function ___executeSave() { // perform save of existing record if id>0, or add new if id=0 $this->message("Saved Redirect"); $this->session->redirect("./"); // back to list } /** * Delete Redirect - Called when URL is ./delete/ * */ public function ___executeDelete() { if(!is_array($input->post->delete) || empty($input->post->delete)) { $this->message("Nothing to delete"); $this->session->redirect("./"); // back to list } foreach($input->post->delete as $id) { $id = (int) $id; $this->db->query("DELETE FROM {$this->className} WHERE id=$id"); } $this->message("Deleted " . count($input->post->delete) . " redirect(s)"); $this->session->redirect("./"); // back to list } I will work on setting up an appropriate hook in the ProcessPageView module. thanks, Ryan
×
×
  • Create New...