Jump to content

BitPoet

Members
  • Posts

    1,331
  • Joined

  • Last visited

  • Days Won

    61

Everything posted by BitPoet

  1. You need to pass the page id of the event in question (probably as a GET parameter or URL segment) when you open the ICS page, then in your ICS template retrieve the corresponding page (remember to use sanitizer or (int) casting to make sure you're really getting a valid page id) and fill in the page's field values.
  2. While this is a reasonable way of structuring things, it's not a case I'll cover with the module. But that's why I made getPageMediaLibraries hookable. You don't need to modify the original module code, just add a hook in site/ready.php and change the return value there. wire()->addHookAfter("MediaLibrary::getPageMediaLibraries", null, "myCustomGetLibraries"); function myCustomGetLibraries(HookEvent $event) { $event->return = wire('pages')->find("template=MediaLibrary"); }
  3. Yes. A simple way would be hooking into ProcessPageListActions::getActions in your site/ready.php: wire()->addHookAfter("ProcessPageListActions::getActions", null, "removeNewAction"); function removeNewAction(HookEvent $event) { $page = $event->arguments(0); if($page->template == "blog") { $actions = $event->return; unset($actions['new']); $event->return = $actions; } }
  4. What $page->get returns depends on the field type, but you'll hardly ever get back a plain array. Btw., $page->get("planos") is the same as $page->planos. For image and file fields, the return value (unless null/empty or set to "Single item") is a PageImages object, which, while it inherits from WireArray and thus implements an iterator so you can run a foreach loop over it, isn't the same as a plain array. If you do need a plain array for some reason (in most cases you won't), you can call getArray() or getValues() on classes inheriting from WireArray.
  5. I see, that's of course different, and - since there's no direct relationship between two image fields - doable but dangerous in case one of the images is missing, and keeping then in sync isn't easy once the list gets long. $precioschico = $page->get("planos"); $preciosgrande = $page->get("mapas"); for($i = 0; $i < $precioschico->count(); $i++) { $chicoimg = $precioschico->eq($i); $grandeimg = $preciosgrande->eq($i); echo " <div class='col-md-6 col-lg-4'> <a href='{$grandeimg->url}' class='thumbnail' rel='prettyPhoto[galeriaplanos2]'> <img class='img-responsive' src='{$chicoimg->url}' /> </a> </div> "; } To make the code a little simpler and avoid errors by images not matching up, you might consider creating a repeater field with two image fields (one named "grande" and one "chico", each set to "Single item"). Then you could run a simple loop over your repeater field. foreach($page->repeaterimages as $img) { echo " <div class='col-md-6 col-lg-4'> <a href='{$img->grande->url}' class='thumbnail' rel='prettyPhoto[galeriaplanos2]'> <img class='img-responsive' src='{$img->chico->url}' /> </a> </div> "; } If you set the column width for both image fields to 50%, you can show and edit them side by side in the repeater list on the page. The page editor would look like this:
  6. Another approach using WireArray::and() which implicitly creates a copy of the Wire(or Page)Array: $precioschico = $page->get("planos"); $preciosgrande = $page->get("mapas"); $precios = $precioschico->and($preciosgrande); // Or all in one step: $precios = $page->get("planos")->and($page->get("mapas")); foreach( $precios as $precio ) { echo $precio . '<br/>'; }
  7. Merry Christmas from me to you and your family too Ryan, and to everybody else in the fabulous PW community. The updates over this year were really brilliant and I find myself using a lot of them already. The ProDrafts workflow feature is just the thing I was looking for and it's coming at the perfect time.
  8. I've seen that too, hand in hand with a near doubling of new sessions in GA with arbitrary pages/view rate for last month, so this really messes up the stats. I've found some reports saying that these entries all come from Accept-Language headers (not Measurement Protocol) so it should be possible to block these requests at server level with a regex on Accept-Language that throws away anything that doesn't match the required format given in rfc7231. I'm going to take a look after Christmas hols if Akamai lets me add that such a filter in DSA. It should be relatively easy to do in Apache and NGINX, something like RewriteCond %{HTTP:Accept-Language} !^$|\*$|([a-z]{2,3}(-[a-z]{2,3})?)(\s*,\s*[a-z]{2,3}(-[a-z]{2,3})?)*($|;) [NC] RewriteRule ^.*$ "-" [F] The regex isn't a complete validity check and untested yet, but it should get the job done. Might even work for a GA filter too.
  9. Depending on whether the last row needs to have a complete set of elements (not sure if bootstrap's css requires that), you could also use PHP's builtin array_chunk function to make the logic clearer. $out = ""; foreach(array_chunk($page->children->getArray(), 3) as $row) { $out .= "<div class='col-xs-4'>"; foreach($row as $p) { $out .= "<img src='{$p->images->first->url}' class='img-responsive'>"; $out .= $p->title; } $out .= "</div>"; }
  10. The only way I could see this working would be by adding a custom piece of javascript (using AdminCustomFiles) that adds the CSS class "on" for your entry, as PW's built-in logic tries to match the id of /admin/appearance/ in the link against the id of the current page (that of /settings-appearance/). You'd have to check the URL for your settings page in that custom code, something like (untested): $(document).ready(function() { // Page id of /admin/settings/ var pageid = 28; var regex = new RegExp("^http://[^/]+/admin/appearance/"); if(regex.text(window.location.href)) { $("#topnav-page-" + pageid).addClass("on"); } }); If you have PW in a subdirectory, you'll have to insert the path in the RegExp pattern and adapt it if you move your installation. In the long run, using AdminCustomPages might be a better approach. Create your settings-appearance page just as before, and create a /admin/appearance/ page with a custom admin template that displays the current settings and outputs an edit link for settings-appearance with the CSS class pw-modal. Also output a short JS snippet that listens for the pw-modal-closed event on that link and calls window.location.reload when triggered, to make sure you're not displaying stale settings. This way, the navbar highlighting will work without hassles.
  11. There are possibilities to prevent that, e.g. by excluding all physically existing files and directories using a rewrite condition: RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^(.*)$ /pw/$1 You could also add specific subdirectories from being redirected, for example if you want to have another PW installation in a sub directory named "pw3", you'd add a condition before the rule: RewriteCond %{REQUEST_URI} !^/pw3/
  12. This discussion might be worth a look:
  13. You could use my FieldtypeDropdownDynamic in conjunction with a snippet of code that iterates the gcb directory for php files like the following (untested): return array_map( function($file) { return array("label" => $file, "name" => $file); }, array_filter( scandir($config->paths->templates . "gcb"), function($found) { return substr($found, -4) == ".php"; } ) );
  14. WireArray's unique method is not what you're looking for, it removes duplicate entries from a WireArray like your images field, and the image list is already unique. But you could shorten the filling of your tags array (the internal steps are basically the same as what your code does): $tagsarray = array_unique($page->images->explode("tag"));
  15. <?php /** * Add "Siblings" tab to page editor. * */ class PageEditSiblings extends WireData implements Module { public static function getModuleInfo() { return array( "title" => "Page Edit Siblings", "summary" => _("Add siblings tab to page edtior"), "version" => "0.0.1", "autoload" => true ); } public function init() { $this->addHookAfter("ProcessPageEdit::buildForm", $this, "addSiblingsTab"); } public function addSiblingsTab(HookEvent $event) { $edit = $event->object; $form = $event->return; $master = $edit->getMasterPage(); $page = $master ? $master : $edit->getPage(); $wrap = $this->buildFormSiblings($edit, $form, $master, $page); $form->insertAfter($wrap, $form->get("ProcessPageEditChildren")); } public function ___buildFormSiblings($edit, $form, $master, $page) { $wrapper = $this->wire(new InputfieldWrapper()); $id = $this->className(); $wrapper->attr('id+name', $id); if(!empty($settings['ajaxChildren'])) $wrapper->collapsed = Inputfield::collapsedYesAjax; $defaultTitle = $this->_('Siblings'); // Tab Label: Siblings $title = $this->page->template->getTabLabel('siblings'); if(!$title) $title = $defaultTitle; if($page->parent->numChildren > 1) $wrapper->attr('title', "<em>$title</em>"); else $wrapper->attr('title', $title); $this->addTab($edit, $id, $title); if(!$edit->isPost) { $pageListParent = $page->parent; /** @var InputfieldMarkup $field */ $field = $this->modules->get("InputfieldMarkup"); $field->label = $title == $defaultTitle ? $this->_("Sibling Pages") : $title; // Siblings field label if($pageListParent->numChildren > 1) { $field->value = $this->renderPages($pageListParent->children(), $page); } else { $field->description = $this->_("There are currently no siblings of this page."); } if($page->addable()) { /** @var InputfieldButton $button */ $button = $this->modules->get("InputfieldButton"); $button->attr('id+name', 'AddPageBtn'); $button->attr('value', $this->_('Add New Page Under Parent')); // Button: add new child page $button->icon = 'plus-circle'; $button->attr('href', "../add/?parent_id={$page->parent->id}" . ($this->input->get('modal') ? "&modal=1" : '')); $field->append($button); } $wrapper->append($field); } return $wrapper; } public function ___renderPages($list, $cur) { $out = '<div class="PageList" style="display: block;">' . "\n"; foreach($list as $p) { $out .= ($p == $cur) ? "<div class='PageListItem'>{$p->title}</div>\n" : "<div class='PageListItem'><a href='{$this->page->url}?id={$p->id}' title='{$p->name}' class='PageListPage label'>{$p->title}</a></div>\n" ; } $out .= "</div>"; return $out; } protected function addTab($edit, $siblingid, $siblingtitle) { $tabs = $edit->getTabs(); $removed = array(); foreach(array_reverse($tabs) as $id => $title) { if($id == "ProcessPageEditChildren") { break; } $removed[$id] = $title; $edit->removeTab($id); } $edit->addTab($siblingid, $siblingtitle); foreach(array_reverse($removed) as $id => $title) { $edit->addTab($id, $title); } } } Only tested on PW 3.0.34 but should (I hope) work on any 2.7.x / 2.8.x / 3.0.x install. Large parts stolen from ProcessPageEdit::___buildFormChildren.
  16. Definitely an issue with the loop (a typo, to be precise). This: foreach(array($usrpache, $sprache, $dsprache) as $lang) { should contain $usprache instead of $usrpache.
  17. It might be that MySQL and PHP differ in the opinion what localhost should resolve to. If MySQL treats localhost as ::1 (ipv6) and PHP thinks of localhost as 127.0.0.1, that would explain this behavior. Though it's also possible that the user is defined as user@% instead of user@localhost and ipv6 loopback access is treated like a remote access. It's hard to say without taking a peek into the system.
  18. @LostKobrakai's question is a good one. You shouldn't run any logic inside getModuleInfo() since it is executed by the module cache update routine long before the system is ready and things like permissions, roles, users and session have been wire()d. I guess one cou could say it used to work accidentally. I don't think there's a way around moving your logic into __construct(), init() or ready() in recent PW versions.
  19. Shouldn't that read 'piece' instead of 'child', since you're using $piece in piece.php?
  20. Here's an announcement for the magazine in their news ticker.
  21. If you search using ~=, you're performing a fulltext search (aka natural language search) that only looks for words. If you need to be able to search for non-word characters too, you'll have to use %= (LIKE). For fulltext, you'll likely need to clear out any non-word, non-digit, non-whitespace and non-connecting characters, e.g. with '/[^\p{N}\p{L}\p{Pc}\p{Zs}]/u'.
  22. Welcome to the PW world @dg234! Your site reads like the perfect task for ProcessWire. While you don't need to move your data from its external tables, chances are high that you will want to do that and create a page for every hike that holds its data, track(s) and images. PW's template files are (unless you install a template engine module like smarty) just PHP files outputting your HTML, so you have every freedom regular PHP scripts give you. PW also provides you with a PDO wrapper to its database in the $database variable, or you can use the underlying WireDatabasePDO class to access an external database. Or use PHP's native database layers. Or use a third-party ORM layer. Whatever you fancy. You don't have to upload your images one by one. You can either drag and drop a number of files at once in the backend (though POST limits may hit you there depending on the server settings) or FTP them to the server and create a short bootstrap script that adds them to their pages. Since you control the HTML, you can include whatever scripts and styles you want, either generically (in such cases I like to put them into an extra include for the header, like _header.php, to keep them organized) or on a per-template basis. If you have a generic page layout but want to add different includes and styles depending on the template, you can use the (popular) strategy of automatically appending one "master" PHP template that produces the HTML and fill the variables used there (like e.g. $content and $headers variables) in every individual template's file as explained here. PW lets you override that setting on a per-template basis, so, like with most things in PW, you have every freedom. Just keep in mind that PW's pages first and foremost are equivalents for tables to store your data. The fields you assign in the backend template are their columns. Page fields, Repeaters and the implicit parent-child relationship are links between these "tables". Not every page needs to have a PHP template, in that case it can't be viewed directly but still used to hold and render data in other pages, but once you have your data in pages, it's easy to display it as well as search for it using PW's extremely powerful selector API. To wrap it up, you'll be able to do most if not all things you need with PW's default functionality and a handful of already available modules. I don't see a need to develop your own module yet, but there is a getting started documentation for module development in the online docs and, if you find that you do in fact need to, just ask here and you'll find a wonderfully helpful community.
  23. The quote above reminded me of something I tried a while ago: <?php /** * Keep track of module config versions in ProcessWire. * Allows smooth upgrading of module versions when configuration * options change. */ class ModuleConfigVersion extends WireData implements Module { public static function getModuleInfo() { return array( "title" => _("Module Config Verisons"), "summary" => _("Store module version in config to allow smooth upgrading."), "version" => "0.0.1", "autoload" => true, ); } public function init() { $this->addHookBefore("Modules::saveConfig", $this, "hookSaveConfig_SetVersionProperty"); } public function hookSaveConfig_SetVersionProperty(HookEvent $event) { $module = $event->arguments(0); $data = $event->arguments(1); $moduleInfo = $this->modules->getModuleInfo($module); $version = $moduleInfo["version"]; $data["version"] = $version; $event->arguments(1, $data); } } This automatically adds the version each time a module's configuration is saved.
  24. One thing I'd definitely never do is mix values of different languages in one language's field. It's bound to come back and haunt you. To get around template additions/changes, you could simply add a (hidden) field to them. Then, in your hook, simply check $page->template->hasField("yourhiddenfield") instead of comparing template names. Lastly, I'd change your code above a bit to always try the user's language first, then try to fall back to the absender's language and lastly the default. public function hookLangInherit(HookEvent $event){ $mlObj = $event->object; // LanguagesPageFieldValue object $currPage = $this->wire('page'); if($currPage->template->hasField("flag_absendersprache")) { //check if detail page is accessed if($this->input->urlSegment1){ // The overview-content and fetch-content pages are living under a specific rootParent which has assigned a specific "absender" $absender = $currPage->rootParent->choose_sender_2016; // Get The new language by a custom pagefield(single) from the "absender" $sprache = $absender->inheritLanguages; $usprache = $this->user->language; $dsprache = $this->languages->getDefault(); // Take the first non-empty value in order of precedence: // First the current user's, then the absender's, then the default language foreach(array($usrpache, $sprache, $dsprache) as $lang) { $newLangValue = $mlObj->getLanguageValue($lang); if($newLangValue != "") break; } // Get the new values in that language $event->return = $newLangValue; } } }
  25. With UTF8, it's no longer necessary to encode any characters outside those that have special meaning in HTML, so accented chars are fine as they are. If you enable the text formatter "HTML Entitiy Encoder (htmlspecialchars)" in the details tab of a field that contains plain text, it will take care of any necessary encoding on the fly. CKEditor will do its own conversion as you type, so manual conversion shouldn't be necessary anymore.
×
×
  • Create New...