Jump to content

Search the Community

Showing results for 'runtime'.

  • Search By Tags

    Type tags separated by commas.
  • Search By Author

Content Type


Forums

  • Welcome to ProcessWire
    • News & Announcements
    • Showcase
    • Wishlist & Roadmap
  • Community Support
    • Getting Started
    • Tutorials
    • FAQs
    • General Support
    • API & Templates
    • Modules/Plugins
    • Themes and Profiles
    • Multi-Language Support
    • Security
    • Jobs
  • Off Topic
    • Pub
    • Dev Talk

Product Groups

  • Form Builder
  • ProFields
  • ProCache
  • ProMailer
  • Login Register Pro
  • ProDrafts
  • ListerPro
  • ProDevTools
  • Likes
  • Custom Development

Find results in...

Find results that contain...


Date Created

  • Start

    End


Last Updated

  • Start

    End


Filter by number of...

Joined

  • Start

    End


Group


AIM


MSN


Website URL


ICQ


Yahoo


Jabber


Skype


Location


Interests

  1. I couldn't find much about the pagefileSecure option. Is this just a runtime setting I can switch on or off anytime? Or is it only for files uploaded later? Is there anything changing in the files/assets folder?
  2. ProcessWire 3.0.198 contains a mixture of new features and issue resolutions. Below are details on a few of the new features: Support was added for runtime page cache groups. This enables pages to be cached as a group—and just as importantly—uncached as a group. While it can be used by anybody, it was added primarily to add efficiency to $pages->findMany(), so that it can cache supporting pages (like parents and page references). Previously, it would have to load a fresh copy of each supporting page used by findMany() results (for every returned page) since findMany() used no in-memory caching. If it did cache in memory, then you could potentially run out of memory on large result sets, so that strategy was avoided. Consider the case of iterating over all pages returned by findMany() and outputting their URLs... that triggers load of all parent pages for each page in the result set. And without a memory cache, it meant it would have to do it for each page in the results. Following this week's updates, now it can cache these supporting pages for each chunk of 250 pages, offering potentially significant performance improvement in many cases, without creating excess memory usage or memory leaks. When the chunk of 250 result pages is released from memory (to make room for the next chunk), all the supporting pages (parents, page references, etc.) are also released from memory, but not before. Now findMany() can offer both memory efficiency and great performance. For as long as I can remember, ProcessWire has had an apparently undocumented feature for dependent select fields that enables you to have two page reference fields using selects (single, multiple or AsmSelect) where the selected value in one select changes the selectable options in the other select (Ajax powered). Think of "categories" and "subcategories" selects, for example, where your selection for "categories" changes what options are selectable in "subcategories". Part of the reason it's undocumented is that it is one of those features that is a little bit fragile, and didn't work in some instances, such as within Repeater items. That changed this week, as the feature has been updated so that it can also work in Repeater items too. The $pages->findRaw() method was updated with a new "nulls" option (per Adrian's request in #1553). If you enable this new "nulls" option, it will add placeholders in the return value with null values for any fields you requested that were not present on each matching page. This reflects how PW's database works, in that if a field has no value, PW removes it from the database entirely. Without the nulls option (the existing behavior), it retains the more compact return values, which omit non present values completely. For example, consider the following: $items = $pages->findRaw("template=user, fields=email|first_name|last_name"); If a row in the result set had no "first_name" or "last_name" populated, then it would not appear in the that row of the return value at all... [ "email": "ryan@processwire.com" ] By specifying the "nulls" option, it will still include placeholders for field values not present in the database, and these will have a value of null: $items = $pages->findRaw("template=user, nulls=1, fields=email|first_name|last_name"); [ "email": "ryan@processwire.com", "first_name": null, "last_name": null ] By the way, if you don't specify which fields you want to get (which is the same as saying "get all") then adding the nulls option makes it provide placeholders for all fields used by the page's template. As you might expect, without the nulls option, it includes only populated fields. Also included in 3.0.198 are 7 issue fixes, most of which are visible in the dev branch commits log. That's all for this week. Thanks for reading this update and have a great weekend!
  3. Thx, it has already been running all the time ? Just tried without it and same issue. What about adding a $config->noTracy = true config setting that makes sure that tracy is not loaded if the flag is true? I could maybe set that on runtime and it could also be nice to have on production servers maybe?
  4. Thank you very much for your inspiring, and detailed answer @monollonom I am going to make some tests very soon, also I didn’t know the existence of inputfield-runtime-only it solves a blurry area in my view of the process!
  5. I don't know if anyone pm'd you already but it can be quite simple if you only need to generate a static svg from a text input. I found this library https://github.com/kartsims/easysvg which would allow you to do it all server-wise if you have .svg font files at hand. My approach would be to have a file input for the font file, a text input for the text you want to generate the svg from, a textarea (closed by default and non-editable) to hold the svg code, and something like https://processwire.com/modules/inputfield-runtime-only/ to echo the textarea's content (the svg) as a preview. Basically a hook in `ready.php`: require "/path/to/easySVG.php"; wire()->addHookBefore("Pages::saveReady", function(HookEvent $event) { /** @var Page $page */ $page = $event->arguments(0); if($page->template->name !== "font") return; // or whatever if(!$page->fontfile && !$page->text) return; // file and text inputs // copy/pasting from easySVG example $svg = new EasySVG(); $svg->setFontSVG($page->fontfile->url); $svg->setFontSize(100); $svg->setFontColor('#000000'); $svg->setLineHeight(1.2); $svg->setLetterSpacing(.1); $svg->setUseKerning(true); $svg->addText($page->text); list($textWidth, $textHeight) = $svg->textDimensions($page->text); $svg->addAttribute("width", $textWidth."px"); $svg->addAttribute("height", $textHeight."px"); $page->svgcode = $svg->asXML(); // textarea input $event->arguments(0, $page); }); And in your `svgpreview` field/file (check RuntimeOnly doc) or template file: echo $page->getUnformatted("svgcode"); (I used getUnformatted in case there are textformatters but it would best if there's none in the field's settings) It's not tested and made on top of my head but I think this might work. (nice to see Velvetyne here btw, I like your work and a good friend of mine made La Savate ?)
  6. Get rid of writing the $action = $input->post->option('bookmark', [ 'save', 'remove'] ); block in a loop, you do not need that. If you look at my example (made some corrections for consistency), you are capturing the action made by the user in the `$input->bookmark->action` and the id in `$input->bookmark->id` (form data built in the $.post() ajax jquery code): (I don't know what is the `$input->post->option('a', ['b', 'c'])`) thing, but we dont care) bd($input->post); // debug with tracy /** contain: * action: 'save' * bookmark: '1024' */ Then just handle the request : <?php /** threat ajax (pw) => https://processwire.com/api/ref/config/#pwapi-methods-runtime * Better to write a dedicated template which will receive the request. * That is a good candidate and exercise to try the module AppApi ? */ if($config->ajax && $input->post->bookmark) { // bd($input->post->bookmark); // debug with tracy, uncomment if you have it /** contain: * action: 'save' or 'remove' * bookmark: '1024' */ $bookmarkid = $sanitizer->int($input->post->bookmark); $action = $sanitizer->name($input->post->action); switch($action) { // which action ? case 'save': // save logic $message = 'Borat saved bookmark "'. $bookmarkid .'" ?'; $success = true; break; case 'remove': // remove logic $message = 'Borat removed bookmark "'. $bookmarkid .'" ❌'; $success = true; break; default: $message = 'error'; $success = false; } // build the response data array that will be returned in `data` from `.done(function(data) {` $json = array( 'id' => $bookmarkid, 'action' => $action, 'message' => $message, 'success' => $success ); // convert data and send as JSON header('Content-Type: text/json; charset=utf-8'); // forgot this line echo json_encode($json); return; } ?> <!-- the only one loop --> <!-- you dont really need a form --> <!-- <form action='<?=$page->url?>' method='post'> --> <?php // dummy bookmarks loop logic for the show $bookmarks = $pages->find("template=dummypage, limit=5, sort=sort"); foreach ($bookmarks as $bookmark): ?> <?php if($user->isLoggedin()): ?> <!-- show button to save and remove this page to bookmarks --> <!-- of course, make your own logic to show one or other button --> <!-- add a data attribut to each button --> <button class="button bookmark" name='bookmark' value='save' data-id='<?= $bookmark->id ?>'>Save <?= $bookmark->id ?></button> <button class="button bookmark" name='bookmark' value='remove' data-id='<?= $bookmark->id ?>'>Remove <?= $bookmark->id ?></button> <?php endif; ?> <?php endforeach; ?> <!-- </form> --> <script> jQuery(document).ready(function($) { // when clicked, send ajax request to server $('button.bookmark').on('click', function(e /* add event arg */) { var btn = $(this).hasClass('clicked') ? false : $(this).addClass('clicked'); if (!btn) { console.warn(`⚠️ Bookmark already saved to profil`); return false; } $.post('<?= $page->url /* send to the page which have the logic and return json answer */ ?>', { action: $(this).val(), bookmark: btn.data('id') }) .done(function(data) { console.log(data, "? response from ajax req"); // $(this).removeClass('clicked'); // remove `clicked` class, can be added on the foreach loop if the bookmark is already saved and then locked, or whatever.. console.info(`✅ Bookmark id => ${data.id} ${data.action} `); }); //e.preventDefault(); // you didn't need a <form>, and if you really want it, add this line to prevent default behavior and stop the redirection }); }); </script> I will make you an example to save the page, but if I were you, I would just save a "page (ID)" in a page-reference field in the profile.
  7. I don't really get what is your issue, the click that still redirect ? If yes, just add `e.preventDefault()` to your js script to prevent default behavior as your are submiting a form. <?php /** threat ajax (pw) => https://processwire.com/api/ref/config/#pwapi-methods-runtime * Better to write a dedicated template which will receive the request. * That is a good candidate and exercise to try the module AppApi ? */ if($config->ajax && $input->post) { bd($input->post->bookmark); // debug with tracy /** contain: * action: 'add' * bookmark: '1024' */ /** * you can write some logic here, eg., to grab the post data sent by the ajax request */ $bookmarkid = $sanitizer->int($input->post->bookmark); // eg. you can get a page from that $bookmarkedPage = $pages->get($bookmarkid); // send response data back $message = 'Borat added bookmark "'. $bookmarkedPage->title .'" ?'; $success = true; // build the response data array $json = array( 'message' => $message, 'success' => $success ); // convert data and send as JSON header('Content-Type: text/json; charset=utf-8'); // forgot this line echo json_encode($json); return; } ?> <?php // dummy bookmarks loop logic for the show // foreach($bookmarks as $bookmark) : $bookmark = $pages->get(1024); // forgot this line ?> <!-- you dont really need a form --> <!-- <form action='<?=$page->url?>' method='post'> --> <?php if($user->isLoggedin()): ?> <!-- show button to add this page to bookmarks --> <!-- add a data attribut to each button --> <button class="button bookmark" name='bookmark' value='add' data-id='<?= $bookmark->id ?>'>Save bm #1</button> <?php endif; ?> <?php //endforeach; ?> <!-- </form> --> <script> jQuery(document).ready(function($) { // when clicked, send ajax request to server $('button.bookmark').on('click', function(e /* add event arg */) { var btn = $(this).hasClass('clicked') ? false : $(this).addClass('clicked'); if (!btn) { console.warn(`⚠️ Bookmark already saved to profil`); return false; } $.post('<?= $page->url /* send to the page which have the logic and return json answer */ ?>', { action: $(this).val(), bookmark: btn.data('id') }) .done(function(data) { console.log(data, "? response from ajax req"); // $(this).removeClass('clicked'); // remove `clicked` class, can be added on the foreach loop if the bookmark is already saved and then locked, or whatever.. console.info(`✅ Bookmark id => ${btn.data('id')} saved to user profil`); }); //e.preventDefault(); // you didn't need a <form>, and if you really want it, uncomment this line to prevent default behavior and stop the redirection }); }); </script>
  8. https://blog.gskinner.com/archives/2020/07/introducing-flokk-a-desktop-app-built-with-flutter.html https://blog.gskinner.com/archives/2020/09/flokk---how-we-built-a-desktop-app-using-flutter.html "Rive takes advantage of cutting-edge technologies such as Flutter and WebAssembly to create native desktop and web apps." https://rive.app "Bring Your Apps and Games to Life with Real-Time Animation" https://blog.rive.app/rives-web-runtime/ "Learn how Rive's web runtime works under the hood and how to embed a Rive animation in a web page."
  9. Thanks for the answer @szabesz! I've read the RuntimeMarkup module thread, and @kongondo also recommends to put the actual code in a file and just wireRenderFile() it. So that must be the main difference. I also thought about the easy inclusion of js and css in Runtime only as a substantial difference. By the way, I do not read any real sarcasm in @bernhard's post. I guess it is just a his style) He is always asking himself questions and answers them. Sort of inner dialog)
  10. When you do a $pages->find($selector) operation your selector is translated by PW into an SQL query. It's a bit of a simplification (because there some exceptions for things like "count"), but essentially this means that you can only sort by values that correspond to columns in the database. So for example you can sort by "title" because that corresponds to a column in the database. But you can't use some logic at runtime to conditionally build up a custom value based on various properties of each page and then sort by that because there is no corresponding column for that custom value. So your options are... 1. If the only way to work out the sort is to iterate over all the pages in a PageArray and you then want to paginate that sorted PageArray, you can do something like this: // $results is a PageArray that you have applied some custom sorting to at runtime $total = $results->count(); $limit = 10; // Convert page number to be zero-based $page_num = $input->pageNum - 1; $start = $page_num * $limit; // Get the slice of results for the current pagination $results = $results->slice($start, $limit); $results->setStart($start)->setLimit($limit)->setTotal($total); foreach($results as $result) { // Output result } echo $results->renderPager(); But because you have to load all the results into memory in order to sort them, this strategy is not going to scale well with large numbers of results. 2. If the sorting doesn't actually depend on dynamic input you can think about using an integer field in the template to store a weighting that you can sort by in a $pages->find() selector. You would use a saveReady hook to populate this sort_weighting field according to other field values in the page. You can use the API to loop over all your book pages to set a sort_weighting value initially. The sorting in your code didn't quite make sense to me so you'll probably need to adapt this to suit, but the general idea is this: // In /site/ready.php $pages->addHookAfter('saveReady', function(HookEvent $event) { $page = $event->arguments(0); if($page->template == 'book') { $sort_weighting = 0; if(!$page->subject) $sort_weighting = -1; if(!$page->subject && !$page->author) $sort_weighting = -2; $page->sort_weighting = $sort_weighting; } }); // In your template code $results = $pages->find("template=book, sort=sort_weighting, sort=subject, sort=cleanauthor, sort=cleantitle, limit=50");
  11. You can either register your own api variable, eg in ready.php $wire->wire('contact', $yourpage); Or you simply add whatever property you need at runtime to the rockfrontend object: $rockfrontend->foo = 'Foo!'; $rockfrontend->bar = 'Bar!'; Then you can simply access those variables in your latte files: {$contact->title} {$rockfrontend->foo} {$rockfrontend->bar}
  12. Background I'm creating a module to integrate https://pushalert.co/ into ProcessWire. You actually don't even need a module. You could just use the "Other Websites" javascript provided by PushAlert for basic functionality, ie send a broadcast notification to all subscribers. This is essentially what all the other integrations, including WordPress, do. The WP integration installs a widget with a form enabling the admin to enter details such as title, message, etc from a blog post. It does not: collect any statistics within the CMS about the notification enable audience fine tuning to eg a particular subscriber or subscriber segment within WP. The admin needs to use the PA dashboard for that functionality PushAlert has a javascript and REST API. It's intended that this module will use both. https://pushalert.co/documentation What my module does so far: associate a subscription with a user. FE user clicks a button on the website front end to subscribe and/or agrees to the browser popup to accept notifications from this site send broadcast push alerts from a page within admin It doesn't have a 'widget' but easy enough to create a fieldsetpage with the relevant fields and add that fs page to any appropriate templates, then with a hook, send the notification. Need to be careful that once published/sent, the notification is not automatically re-sent on subsequent page edits. Looking for help/collaboration on how best: to send a notification, eg from a blog post, then track the statistics. Dilemma is that the push notification must come from the admin page. Responses go to the sending page which, as it's an admin page, is restricted and will not accept the https response. This is where the other CMS integrations stop. The only json response from PushAlert is the status, eg 'success', and the notification id. There is no opportunity at this point to capture the sending page id. handle, 'once sent on page publish', do not automatically resend on future page edits Am thinking along the lines that FS Page will have a @kongondo runtime markup field https://modules.processwire.com/modules/fieldtype-runtime-markup/ to pull the stats from PushAlert. Every time an admin visits the page, the stats will update. Once an admin checks the 'Send notification on page publish' checkbox, a hook creates new front end page that records the 'sender page', sends the notification request to PA, which then uses that newly created frontend page, as the response endpoint. Another rook re-associates the front end page with the admin page (eg blog post), to update the stats. Potential use cases: Notify individual and/or users with a particular role of an event, eg "New work opportunity" for job seekers; new blog post published; entries now open, etc... Looking for help/ideas/collaboration on this module. Please let me know if you're interested and as I do, believe this would be a great addition to ProcessWire
  13. Hi everyone, Processwire is in the following folder in my server: var/www/html/project/processwire I've got the following configuration in my .htaccess: ################################################################################################# # START PROCESSWIRE HTACCESS DIRECTIVES # @version 2.2 ################################################################################################# # ----------------------------------------------------------------------------------------------- # Don't show directory indexes, but do follow symbolic links # ----------------------------------------------------------------------------------------------- Options -Indexes Options +FollowSymLinks # ----------------------------------------------------------------------------------------------- # Let ProcessWire handle 404s # ----------------------------------------------------------------------------------------------- ErrorDocument 404 /index.php # ----------------------------------------------------------------------------------------------- # Handle request for missing favicon.ico/robots.txt files (no ending quote for Apache 1.3) # ----------------------------------------------------------------------------------------------- <Files favicon.ico> ErrorDocument 404 "The requested file favicon.ico was not found. </Files> <Files robots.txt> ErrorDocument 404 "The requested file robots.txt was not found. </Files> # ----------------------------------------------------------------------------------------------- # Protect ProcessWire system files (part 1) # ----------------------------------------------------------------------------------------------- <FilesMatch "\.(inc|info|module|sh|sql)$|^(\..*)$"> Order allow,deny </FilesMatch> # ----------------------------------------------------------------------------------------------- # Override a few PHP settings that can't be changed at runtime (not required) # ----------------------------------------------------------------------------------------------- <IfModule mod_php5.c> php_flag magic_quotes_gpc off php_flag magic_quotes_sybase off php_flag register_globals off </IfModule> # ----------------------------------------------------------------------------------------------- # Set default directory index files # ----------------------------------------------------------------------------------------------- DirectoryIndex index.php index.html index.htm # ----------------------------------------------------------------------------------------------- # ProcessWire requires mod_rewrite # ----------------------------------------------------------------------------------------------- <IfModule mod_rewrite.c> RewriteEngine On # ----------------------------------------------------------------------------------------------- # Set an environment variable so the installer can detect that mod_rewrite is active. # ----------------------------------------------------------------------------------------------- SetEnv HTTP_MOD_REWRITE On # ----------------------------------------------------------------------------------------------- # Optional: Set a rewrite base if rewrites aern't working properly on your server. # And if your site directory starts with a "~" you will most likely have to use this. # ----------------------------------------------------------------------------------------------- # RewriteBase / # RewriteBase /pw/ # RewriteBase /~user/ # ----------------------------------------------------------------------------------------------- # Access Restrictions: Keep web users out of dirs that begin with a period # ----------------------------------------------------------------------------------------------- RewriteRule "(^|/)\." - [F] # ----------------------------------------------------------------------------------------------- # Optional: Redirect users to the 'www.' version of the site (uncomment to enable). # For example: http://processwire.com/ would be redirected to http://www.processwire.com/ # ----------------------------------------------------------------------------------------------- # RewriteCond %{HTTP_HOST} !^www\. [NC] # RewriteRule ^ http://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301] # ----------------------------------------------------------------------------------------------- # Access Restrictions: Protect ProcessWire system files (part 2) # ----------------------------------------------------------------------------------------------- RewriteCond %{REQUEST_URI} (^|/)\.htaccess$ [NC,OR] RewriteCond %{REQUEST_URI} (^|/)(site|site-[^/]+)/assets/(cache|logs|backups|sessions|config|install)($|/.*$) [OR] RewriteCond %{REQUEST_URI} (^|/)(site|site-[^/]+)/install($|/.*$) [OR] RewriteCond %{REQUEST_URI} (^|/)(wire|site|site-[^/]+)/(config|index\.config|config-dev)\.php$ [OR] RewriteCond %{REQUEST_URI} (^|/)(wire|site|site-[^/]+)/templates-admin($|/|/.*\.(php|html?|tpl|inc))$ [OR] RewriteCond %{REQUEST_URI} (^|/)(site|site-[^/]+)/templates($|/|/.*\.(php|html?|tpl|inc))$ [OR] RewriteCond %{REQUEST_URI} (^|/)(site|site-[^/]+)/assets($|/|/.*\.php)$ [OR] RewriteCond %{REQUEST_URI} (^|/)wire/(core|modules)/.*\.(php|inc|tpl|module)$ [OR] RewriteCond %{REQUEST_URI} (^|/)(site|site-[^/]+)/modules/.*\.(php|inc|tpl|module)$ [OR] RewriteCond %{REQUEST_URI} (^|/)(COPYRIGHT|INSTALL|README|htaccess)\.txt$ [OR] RewriteCond %{REQUEST_URI} (^|/)site-default/ RewriteRule ^.*$ - [F,L] # ----------------------------------------------------------------------------------------------- # Ensure that the URL follows the name-format specification required by ProcessWire # ----------------------------------------------------------------------------------------------- RewriteCond %{REQUEST_URI} "^/~?[-_.a-zA-Z0-9/]*$" # ----------------------------------------------------------------------------------------------- # If the request is for a file or directory that physically exists on the server, # then don't give control to ProcessWire, and instead load the file # ----------------------------------------------------------------------------------------------- RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME} !(favicon\.ico|robots\.txt) # ----------------------------------------------------------------------------------------------- # Optional: Don't send missing image requests to ProcessWire (uncomment below to enable). # This might be helpful if you are launching a new site and lots of images have moved. # It will reduce the load on the server not to have ProcessWire trying to serve those requests. # ----------------------------------------------------------------------------------------------- # RewriteCond %{REQUEST_URI} !\.(gif|jpg|png|ico)$ [NC] # ----------------------------------------------------------------------------------------------- # Pass control to ProcessWire if all the above directives allow us to this point. # For regular VirtualHosts (most installs) # ----------------------------------------------------------------------------------------------- RewriteRule ^(.*)$ index.php?it=$1 [L,QSA] # ----------------------------------------------------------------------------------------------- # If using VirtualDocumentRoot: comment out the one above and use this one instead. # ----------------------------------------------------------------------------------------------- # RewriteRule ^(.*)$ /index.php?it=$1 [L,QSA] </IfModule> ################################################################################################# # END PROCESSWIRE HTACCESS DIRECTIVES ################################################################################################# and the following on my Apache server config: <VirtualHost *:80> ServerAdmin webmaster@localhost DocumentRoot /var/www/html/project/processwire <Directory /var/www/html/project/> Options Indexes FollowSymLinks AllowOverride All Require all granted </Directory> ErrorLog ${APACHE_LOG_DIR}/error.log CustomLog ${APACHE_LOG_DIR}/access.log combined <IfModule mod_dir.c> DirectoryIndex index.php index.pl index.cgi index.html index.xhtml index.htm </IfModule> </VirtualHost> My website opens normally, but when I try something broken like https://mywebsite.com/dfvjdbvknbk it opens a standard apache 404 page and not my custom one. My custom 404 page is inside processwire/site/templates Can anyone help me understand what is broken here? Thanks in advance!
  14. I have indeed – and I dig it from the perspective of rapid development. As I understand it though, it comes with a runtime that contains things that may or may not be used. Sure, the Alpine runtime is small, but the build file I have in Svelte is looking a bit smaller (so far). That aside, enjoying Svelte so far – this is the first time I'm exploring all of its features.
  15. Great module, but I'm having a couple of minor issues (unrelated, I think). The first issue seems intermittent and I can't work out why : In some cases, I can't get the inclusion of .js and .css to work. I've triple-checked all the naming etc. but the files just don't seem to load. My work-round (easy enough) is just to load the files in the php. The second issue may be because I am stretching the fieldtype's capability! I am using it within a PageTable field as follows. The PageTable field ("panelled_carousel") has a template "Panelled_carousel" which has fields "title", "imagePages" (a page reference field linking to a page with template "Image" and an image field "image_single") and "runtime_markup_images" (a runtime markup field with php file "RuntimeMarkup/Images.php"). The php file is (including a bit of debugging): $imagePages = $page->imagePages; bd($page, 'page with carousel'); $out = ''; wire()->log->save('debug', 'Page is ' . $page->title); foreach ($imagePages as $imagePage) { bd($imagePage, 'imagePage'); foreach ($imagePage->image_single as $image) { bd($image, 'image'); if (is_a($image, '\ProcessWire\Pageimage')) $out .= '<img src="' . $image->pia("width=200")->url . '"/>'; } } return $out; The RM field is updated when the imagePages field changes by javascript/AJAX : When editing the Page Table field, this all works well - any changes in the imagePages (add/re-order/delete etc) are immediately reflected in the RM field. However, when saving the Page Table Field and returning to the host page, the RM PHP throws an error unless I catch it with the condition - is_a($image, '\ProcessWire\Pageimage') - in the code above. The reason is that in some cases $image seems to be taking a string, integer or boolean value, even though $imagePage has class Page and the dump shows it is the right page. Trapping this error means that the images in the table are all blank after the save. However refreshing the page puts everything right again. So not a deal-breaker but a bit odd. To illustrate, here is the top page with the page table (including images): Clicking on "Blue" to edit an item we get: Then, clicking save and returning to the top page, the images do not render: The debugging shows that this is not because Images.php has not run, but because $image is of the wrong type (as described above). Refreshing the page restores the images. Any ideas? EDIT: I should add that the problem does not seem to be related to my .js script, or even RuntimeMarkup specifically as exactly the same issue happens in a Page Table with @Robin S's RuntimeOnly module with no js attached to it. So it seems to be something to do with how the runtime markup is interacting with the page table display.
  16. Please don't use this module any more. I think in the end it just adds more complexity (and dependencies) than benefits. See this tutorial how simple it is to create a custom runtime-only Inputfield: WHY? I've started building this module because the existing solutions by @kongondo and @kixe (https://modules.processwire.com/modules/fieldtype-runtime-markup/ and https://github.com/kixe/FieldtypeMarkup) did not exactly fit my needs. Actually this module is aimed to be a base module that can easily be extended by other modules. It takes care of the heavy lifting that has to be done when working with custom fieldtypes in ProcessWire (injecting scripts and styles, handling JS events, doing translations). See RockTabulator as an example. I'm quite sure more will follow (eg ChartJS)... WHAT? This module helps you injecting ANY php/html/js/css into any PW backend form (either on a page or in custom process modules). It also comes with a sandbox process module that helps you setup your fields and provides handy shortcuts that integrate with TracyDebugger and your IDE: WHERE ...to get it? At the moment the module is released as early alpha and available only on github: https://github.com/BernhardBaumrock/RockMarkup2 If you have any questions or ideas please let me know ? PS: This module shows how easy it is to extend this module for your very own needs. All you need to do is providing the module's info arrays and then overwrite any methods that you have to modify (eg the InputField's render() method): https://github.com/BernhardBaumrock/RockMarkupExtensionExample
  17. // example 1: modify page title (runtime) for a specific template in Page Edit Interface $this->addHookBefore('ProcessPageEdit::execute', function($e) { $id = wire('input')->get->id; if (!$id) return; $page = wire('pages')->get($id); if ($page->template != 'specific') return; $page->title = "I am a runtime title for pages using template 'specific'"; }); // example 2: modify fields in Profile $this->addHookBefore('ProcessProfile::execute', function($e) { // not for superuser if (wire('user')->isSuperuser()) return; // the user should check 2 checkboxes in its profile // after checking and saving the related checkbox disappears // if both are checked a markup field 'info' is shown $profileFields = $e->object->profileFields; if (wire('user')->checkbox && wire('user')->checkbox_2) $profileFields[] = 'info'; else { if (wire('user')->checkbox != 1) $profileFields[] = 'checkbox'; if (wire('user')->checkbox_2 != 1) $profileFields[] = 'checkbox_2'; } // update profile fields $e->object->profileFields = array_unique($profileFields); });
  18. Hi, this is not so clear to me in part "pass variable to hidden input"? If need to save image path value to hidden input, than maybe it's better to go with hook in backend (after page save or other). Another option coud be to save image path value to hidden input in runtime (???), if that is the case, than try something like this: <?php foreach($page->dev_repeater as $repeater) { $image_field = $repeater->image_field; foreach($repeater->dev_child_repeater as $url) { // some other stuff, link etc... // check and save hidden_field value inside runtime (???) if($url->hidden_field == ""){ $url->of(false); // $url->save(); uncomment if save on second reload $url->hidden_field = $image_field->url; // <= this? $url->save('hidden_field'); } else { // hidden_field has some value echo $url->hidden_field; } } } ?> But also if there is any option to avoid nested repeater that would be better, and also try to think about using hooks in backend to avoid save in runtime. To me it's ok when need to save "page view counters" or some other events triggered by front-end users/vistors. Sorry if I don't understand your question well. Regards.
  19. @kongondo I've installed the latest version and I'm getting an issue whereby there are now 2 sets of Padloper Modules (Directories). One located at site/modules/PadLoper/ and one at site/modules/ProcessPadLoper/ So I have to specify which version of the duplicate files I want to use for each of the individual modules (please see the couple of attached screenshots for example). To view the new details tab for the Runtime Markup field I have to specify the version located at /site/modules/ProcessPadloper/FieldtypePadloperRuntimeMarkup/FieldtypePadloperRuntimeMarkup.module
  20. Hey @psy I'd create a custom runtime module, it's not too hard: 1) Create the fieldtype: 2) Create the inputfield: RockMarkup is deprecated because I don't plan to use it as base module for other Fieldtypes in the future. I think it makes things more complicated and that's not worth it. Building custom fieldtypes + inputfields is easy once you know how things work. Especially runtime fields are easy because you don't need all the DB related parts. If you need any help just ask.
  21. Just a quick one ... This is two questions in one. Integration: Probably not the answer you are looking for but literally any JavaScript library can be integrated into the PW backend. There are various options here including a dedicated ProcessModule or an Inputfield (e.g. a runtime one). Update data in real time. Any JavaScript and newer libs like HTMX can easily do this. The bottom line is this: (a) An action happens on the client (b) JS listens to that action/event (c) optionally but ideally, check if the action is valid (e.g. was this field completed) (d) send the info to the backend - usually via ajax for the type of app you are building (e) the backend processes the action you have sent including validation + sanitization. If these pass, it takes an action, e.g. 'create a page' or 'update a field' (f) the server sends the response back to the client which is listening for a response from the ajax request. Traditionally/usually, the response is JSON but with HTMX, the response is HTML. (g) The client handles the response, in many cases, updating the DOM. That's it. Yes. Media Manager, for instance. You drop files and it will upload the files then create media pages off of that. Yes. ProcessWire itself to be honest. Basically $input, $sanitizer, $config->ajax and $pages are the usual tools. Not a reuse per se answer. Listening to drag and drop using JavaScript used to be a chore. With modern browsers, APIs exist to do it easily in vanilla JavaScript. If you wish to get a ready made solution searching for JavaScript drag and drop will yield some results. Personally, I'd go for htmx + vanilla JS drag and drop, or htmx + sortable combo (here's a Python example).
  22. Nothing is required outside of your module - make your module autoload and use the init() method in your module. The filename is not a property that is saved to the database - it is generated at runtime from the template name, so if you want to set a custom filename then this must be done at runtime. The comment in the Template class is clear about this: @property string $filename Template filename, including path (this is auto-generated from the name, though you may modify it at runtime if it suits your need). #pw-group-files
  23. @olafgleba Edit your /site/config.php file and look for: $config->httpHost and/or $config->httpHosts. In most cases the $config->httpHost should not be present (since PW will set it automatically at runtime), but the $config->httpHosts (plural) should be present, and it should be an array of http hosts ProcessWire is allowed to auto-detect and use. It will pick one of the hosts in that array to use for the request, so long as it matches the $_SERVER[HTTP_HOST]. If it can't find one that matches the $_SERVER[HTTP_HOST] then it will simply use the first one in your httpHosts array: $config->httpHosts = [ 'www.company.com', 'dev.company.com', 'localhost:8888' ]; If it just contains one host then it'll always use that one, regardless of what's in $_SERVER[HTTP_HOSTS] … $config->httpHosts = [ 'www.company.com' ]; If you do have the non-plural $config->httpHost present (like below), then it forces use of that hostname, rather than letting PW auto-detect from your httpHosts array. Though if there's only one host in your httpHosts array (like above) then of course the effect would be the same. $config->httpHost = 'www.company.com'; My best guess is that you either have $config->httpHost or httpHosts set with '127.0.0.1', or that you have httpHost/httpHosts undefined in your /site/config.php file. To fix it you need to add your www.host.tld to a $config->httpHosts array and preferably as the first item in it. If you do see a $config->httpHost (non-plural) in your config.php them I would remove it.
  24. I don't know if I understood correctly, but it looks like you can also use $files->include() or $files->render() methods in your _main.php file. A simple example from the Regular Uikit 3 profile, which we will include the _header.php inside file _main.php with some variables: <?php namespace ProcessWire; // _main.php template file, called after a page’s template file $home = pages()->get('/'); // homepage $siteTitle = 'Regular'; $siteTagline = $home->summary; // as a convenience, set location of our 3rd party resources (Uikit and jQuery)... urls()->set('uikit', 'wire/modules/AdminTheme/AdminThemeUikit/uikit/dist/'); urls()->set('jquery', 'wire/modules/Jquery/JqueryCore/JqueryCore.js'); // ...or if you prefer to use CDN hosted resources, use these instead: // urls()->set('uikit', 'https://cdnjs.cloudflare.com/ajax/libs/uikit/3.0.0-beta.40/'); // urls()->set('jquery', 'https://code.jquery.com/jquery-2.2.4.min.js'); ?> <!-- HEADER --> <?php $files->include('_header', ['home' => $home, 'siteTitle' => $siteTitle, 'siteTagline' => $siteTagline]); // echo $files->render('_header', ['home' => $home, 'siteTitle' => $siteTitle, 'siteTagline' => $siteTagline]); ?> _header.php: <?php namespace ProcessWire; // _header.php file ?> <!DOCTYPE html> <html lang='en'> <head id='html-head'> <meta http-equiv="content-type" content="text/html; charset=utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title id='html-title'><?=page()->title?></title> <meta name="description" content="<?=page()->summary?>"> <link rel="stylesheet" href="<?=urls()->uikit?>css/uikit.min.css" /> <link rel="stylesheet" href="<?=urls()->templates?>styles/main.css"> <script src="<?=urls()->jquery?>"></script> <script src="<?=urls()->uikit?>js/uikit.min.js"></script> <script src="<?=urls()->uikit?>js/uikit-icons.min.js"></script> </head> <body id='html-body'> <!-- MASTHEAD --> <header class='uk-background-muted'> <div id='masthead' class="uk-container"> <h2 id='masthead-logo' class='uk-text-center uk-margin-medium-top uk-margin-small-bottom'> <a href='<?=urls()->root?>'> <img src='<?=urls()->templates?>styles/images/coffee4.svg' alt='coffee'><br /> </a> <?=$siteTitle?> </h2> <p id='masthead-tagline' class='uk-text-center uk-text-small uk-text-muted uk-margin-remove'> <?=$siteTagline?> </p> <nav id='masthead-navbar' class="uk-navbar-container" uk-navbar> <div class="uk-navbar-center uk-visible@m"> <?=ukNavbarNav($home->and($home->children), [ 'dropdown' => [ 'basic-page', 'categories' ] ])?> </div> </nav> </div> </header> It is also important to include <?php namespace ProcessWire; ?> in each of template files. Sometimes it also helps to enable $config->useFunctionsAPI in the config.php file ( Allow most API variables to be accessed as functions? ), this will be more useful in your custom functions, where for example you can call page()->title instead of $page->title, which will not work inside a your custom function if you do not enter any arguments, as in the example below: <?php function showTitle() { echo '<h1>' . page()->title . '</h1>'; // This work // echo $page->title; // This not work } // Show Title showTitle(); ?> The setting() helper function is a good addition to the _init.php file, to which I usually attach the most important page options, which are also available in custom functions without entering arguments such as the init.php file: <?php namespace ProcessWire; /** * * This _init.php file is called automatically by ProcessWire before every page render * * Get or set a runtime site setting * @link https://processwire.com/api/ref/functions/setting/ * */ /** @var ProcessWire $wire */ // set or replace multiple settings setting([ 'siteTitle' => 'ProcessWire CMS / CMF', 'siteDescription' => 'ProcessWire is like a power tool for your website, able to deliver any output, at any scale, to any number of people. ', ]); // Your custom functions that are better placed in the _func.php or _uikit.php file (this is just an example) function siteBranding() { echo "<h1>" . setting('siteTitle') . "</h1>"; echo "<h2>" . setting('siteDescription') . "</h2>"; } include_once('./_uikit.php'); Now you can display the function wherever you want: <?php siteBranding() ?> For example, in this Site Profile I have put site options or translations inside file _init.php: <?php namespace ProcessWire; /** * * This _init.php file is called automatically by ProcessWire before every page render * * Get or set a runtime site setting * @link https://processwire.com/api/ref/functions/setting/ * */ // as a convenience, set location of our 3rd party resources (jQuery)... urls()->set('jquery', 'https://code.jquery.com/jquery-3.4.1.min.js'); $home = pages('/'); $blog = pages()->get("template=blog"); $options = pages()->get('/options/'); // Basic Settings setting([ // Custom html classes 'htmlClasses' => WireArray([ 'template-' . page()->template->name, 'page-' . page()->id, ]), // Basic 'home' => $home, 'privacyPolicy' => pages()->get("template=privacy"), 'options' => $options, 'siteName' => $options->text, 'logo' => $options->logo, 'favicon' => $options->favicon, 'socialProfiles' =>$options->social_profiles, 'metaTitle' => page('meta_title|title'), 'metaDescription' => page()->meta_description, 'noindex' => false, 'poweredUrl' => 'https://processwire.com', // Home Sections 'hero' => $home, 'about' => pages()->get("template=about"), 'projects'=> pages()->get("template=projects"), 'recent' => $blog->child(), // Path to template parts 'homeParts' => 'parts/home', 'blogParts' => 'parts/blog', // Blog 'blog' => $blog, 'disableComments' => $options->more_options->get("name=disable-comments"), // Contact Page 'saveMessages' => $options->more_options->get("name=save-messages"), // Images 'img' => page()->images && page()->images->count() ? page()->images : '', // Main 'mainTitle' => page('title'), 'mainImage' => true, // Set basic background image for all pages // Bottom Panel 'bottomPanel' => $options->bottom_panel, // Basic Translations 'lang' => __('en'), 'edit' => __('Edit'), 'next' => __('Next'), 'previous' => __('Previous'), 'search' => __('Search'), 'search-site' => __('Search the entire site'), 'found-matches' => __('Found %d page(s)'), 'no-results' => __('Sorry, no results were found.'), 'maintenance-mode' => __('Maintenance Mode'), 'site-disabled' => __('Our site is currently disabled.'), 'to-top' => __('To top'), 'we-sociable' => __('We are sociable'), 'powered' => __('Probably supported by ProcessWire CMS'), // Contact Page Translate 'message-error' => __('Some errors, please update your form'), 'message-success' => __('Success, your message has been sent'), 'txt-from' => __('From'), 'form-legend' => __('Contact Us'), 'form-name' => __('Name'), 'form-email' => __('Email'), 'form-privacy' => __('I agree with the %s terms.'), 'form-message' => __('Message'), 'form-spam' => __('To help prevent automated spam, please answer this question'), 'fs-placeholder' => __('* Using only numbers, what is 10 plus 15?'), 'fs-error' => __('Fill out the spam prevention box correctly'), 'form-submit' => __('Submit'), // Blog Translate 'in-blog' => __('In the blog'), 'posted-in' => __('Posted in'), 'all-posts' => __('All posts'), 'recent-posts' => __('Recent posts'), 'read-more' => __('Read More'), 'written-on' => __('Written on'), 'byline-text' => __('Posted by %1$s on %2$s'), 'also-like' => __('You might also like:'), 'author' => __('Author'), 'authors' => __('Authors'), // is also url segments ( blog/authors/author-mame ) 'category' => __('Category'), 'tag' => __('Tag'), 'author-checkbox' => __('You probably need to check the author checkbox in your user profile'), 'rss' => __('RSS'), 'recent-entries' => __('Recent entries'), // Comments Form Translate 'previous-comments' => __('Previous Comments'), 'next-comments' => __('Next Comments'), 'post-comment' => __('Post a comment'), 'comment' => __('Comment'), 'comments' => __('Comments'), 'no-comments' => __('No Comments'), 'comments-closed' => __('Comments are closed'), 'comment-header' => __('Posted by {cite} on {created}'), 'success-message' => __('Thank you, your comment has been posted.'), 'pending-message' => __('Your comment has been submitted and will appear once approved by the moderator.'), 'error-message' => __('Your comment was not saved due to one or more errors.') . ' ' . __('Please check that you have completed all fields before submitting again.'), 'comment-cite' => __('Your Name'), 'comment-email' => __('Your E-Mail'), 'comment-website' => __('Website'), 'comment-stars' => __('Your Rating'), 'submit' => __('Submit'), 'stars-required' => __('Please select a star rating'), 'reply' => __('Reply') ]); include_once('./_func.php');
  25. @Matzn Your TestModuleChild.module is overriding the getModuleConfigInputfields() of the TestModule.module and replacing it. In PHP, if you want the parent method to run, then you need to either omit the method completely in your child class, or call the method parent::method() so that it will run (like what you are doing with your __construct method). What you are doing currently is replacing the method with one that has no code in it. What I think you are wanting is this in your TestModuleChild.module: public function getModuleConfigInputfields(InputfieldWrapper $inputfields) { parent::getModuleConfigInputfields($inputfields); } After doing the above, now it will inherit the code of the parent class. And after calling that parent::method() maybe you want to add another configuration setting to it, i.e. public function getModuleConfigInputfields(InputfieldWrapper $inputfields) { parent::getModuleConfigInputfields($inputfields); $f = $this->wire()->modules->get('InputfieldText'); $f->attr('name', 'test_field'); $f->label = 'Test field'; $f->val($this->test_field); $inputfields->add($f); } But if you don't want to add anything new to the getModuleConfigInputfields() then just leave the method out of your TestModuleChild.module completely, and it will inherit automatically. Also, module configuration data should be defined with runtime calls, so I recommend you remove this: public $field_1 = "parent module property 1"; and replace it with this in your __construct(): $this->set('field_1', 'parent module property 1'); I see you are using static getModuleInfo() methods in your classes. In cases where you've got one module extending another, unless the child module literally does an include() at the top of the parent module's file, then you should define your child module's info in a ModuleName.info.php file like I described in my previous message (including the 'requires' statement), and omit the getModuleInfo() static method. Otherwise, if PHP/PW happens to include() the child module before the parent module, you'll get a fatal class error. By using a separate ModuleName.info.php, PW can learn about the module without having to load the class file, and it can see from your 'requires' statement that it needs to load the parent module before your child module, ensuring no fatal errors. If you can't do this, or don't want to, then make sure your child module does an include() or require() of the parent module's file, somewhere before your "class TestModuleChild ...".
×
×
  • Create New...