How to create a custom Gutenberg block with a dynamic render callback in WordPress?

I’m trying to create a custom Gutenberg block in WordPress that renders its content dynamically on the server side using PHP.

I’ve registered the block using register_block_type, and added a render_callback function, but nothing appears in the editor or frontend.

function myplugin_register_block() {
    register_block_type( __DIR__ . '/my-block', array(
        'render_callback' => 'myplugin_render_my_block',
    ));
}
add_action( 'init', 'myplugin_register_block' );

function myplugin_render_my_block( $attributes ) {
    return '<div class="dynamic-block">Hello, this is dynamic content!</div>';
}

import { registerBlockType } from '@wordpress/blocks';

registerBlockType('myplugin/dynamic-block', {
    edit: () => {
        return <p>Hello from the editor!</p>;
    },
    save: () => {
        return null; // Dynamic rendering
    },
});

What I’ve tried:
Checked if the function name is correct

Flushed permalinks

Ensured that the PHP file is loaded properly

Confirmed that block assets (JS/CSS) load correctly

What I expect:
When I insert the block in the editor, I want to see:

A preview (even just a placeholder),

And when I view the post on the frontend, the HTML returned from render_callback().

How do I restrict the results by date range based on which S&F Pro form is used while allowing a date range in the search form?

We are using the Search & Filter Pro plugin on our WordPress site and need to be able to restrict results for two particular categories by preset dates. I am trying to accomplish this without having to manually edit over 1000 posts to change the category or add a category, or require us to tag it a certain way to separate the posts into eras.

My preference is to restrict the dates that can be entered in the form with a min date on some forms and a min and max date on others. In version 2, I don’t see a way to set a min and/or max date on the date range control in the search form and can’t even begin to figure out how to do that in code (PHP or JS). It would greatly improve the user experience if users can’t enter a date outside the range so that the results match the entered dates. I can filter behind the scenes using the below code.

I have managed to find a code snippet, and modified it, for altering the query for specific S&F Pro forms:

function filter_media_release_current_term( $query_args, $sfid ) {

    if($sfid==2530 || $sfid==2488)
    {
        $currentafter = 2025;
        $startyear = '2025';
        $aftermonth = '01';
        $afterday = '01';
        $currentbefore = '2025';
        // edit later to use a full date, not just year
        // if no date query set the after value
        if (!isset($query_args['date_query'])) {
            $query_args['date_query'] = 
                array(
                    'after'     => array (
                        'day'   => $afterday,
                        'month' => $aftermonth,
                        'year'  => $startyear,
                    ),
                    'inclusive' => true,
                );
        } else {
            // One or both dates are entered: see if they entered a 'To:' date and grab those values
            if (isset($query_args['date_query']['before']) && isset($query_args['date_query']['before']['year'])) {
                $currentbefore = $query_args['date_query']['before']['year'];
                $beforeday = $query_args['date_query']['before']['day'];
                $beforemonth = $query_args['date_query']['before']['month'];
                if ($currentbefore < $startyear) {
                    // can't return any results prior to the start date - resets the date query to default
                    print_r("<br/><span style='color: red'>&nbsp;&nbsp;Enter dates starting " . $aftermonth ."/" . $afterday . "/" . $startyear . "</span><br/><br/>");
                    $query_args['date_query'] = 
                    array(
                        'after'     => array (
                            'day'   => $afterday,
                            'month' => $aftermonth,
                            'year'  => $startyear,
                        ),
                        'inclusive' => true,
                    );
                } else {
                    // Before date is valid
                    // Did they enter a 'From:' date?
                    if (isset($query_args['date_query']['after']) && isset($query_args['date_query']['after']['year'])) {
                        $currentafter = $query_args['date_query']['after']['year'];
                        // if before start date - reset it to the start date but keep the before entry
                        if ($currentafter < $startyear) {
                            print_r("<br/><span style='color: red'>&nbsp;&nbsp;Start date out of range!</span><br/><br/>");
                            $query_args['date_query'] = 
                                array(
                                    'after'     => array (
                                        'day'   => $afterday,
                                        'month' => $aftermonth,
                                        'year'  => $startyear,
                                    ),
                                    'before'     => array (
                                        'day'   => $beforeday,
                                        'month' => $beforemonth,
                                        'year'  => $currentbefore,
                                    ),
                                    'inclusive' => true,
                                );
                        } // no else here - do nothing if both dates are in the valid range
                    } else {
                        // no 'From:' date entered - use default from date and the 'To:' date they entered
                        $query_args['date_query'] = 
                            array(
                                'after'     => array (
                                    'day'   => $afterday,
                                    'month' => $aftermonth,
                                    'year'  => $startyear,
                                ),
                                'before'     => array (
                                    'day'   => $beforeday,
                                    'month' => $beforemonth,
                                    'year'  => $currentbefore,
                                ),
                                'inclusive' => true,
                            );
                    }
                }
            } else {
                // they entered only the 'From:' value but make sure it is set to avoid errors
                if (isset($query_args['date_query']['after']) && isset($query_args['date_query']['after']['year'])) {
                    $currentafter = $query_args['date_query']['after']['year'];
                    // if before start date - reset it to the start date but keep the before entry
                    if ($currentafter < $startyear) {
                        print_r("<br/><span style='color: red'>&nbsp;&nbsp;Start date out of range!</span><br/><br/>");
                        $query_args['date_query'] = 
                            array(
                                'after'     => array (
                                    'day'   => $afterday,
                                    'month' => $aftermonth,
                                    'year'  => $startyear,
                                ),
                                'inclusive' => true,
                            );
                   } // no else here - do nothing if the date is in the valid range
                } else {
                    // no year set for some reason
                    $query_args['date_query'] = 
                            array(
                                'after'     => array (
                                    'day'   => $afterday,
                                    'month' => $aftermonth,
                                    'year'  => $startyear,
                                ),
                                'inclusive' => true,
                            );
                }
            }
        }
    }

    return $query_args;
}
add_filter( 'sf_edit_query_args', 'filter_media_release_current_term', 20, 2 );

This successfully filters the results, ensuring no results prior to 1/1/2025 are shown even if they don’t filter by date range. However, I had to turn off ajax results so that the page reloads on each submit instead of without reloading because it didn’t go through this function with ajax updates. Also, I can’t figure out how to update the form or the URL from this function so the page displays “Showing results from [date] to [date]” using the original dates.

How do I apply fix the UI problems?

Thank you for any guidance you can give me.

mPDF adds blank first page when rendering large HTML content with

I’m generating a PDF from HTML using mPDF, and when the document contains a large amount of content, an almost blank first page is added unexpectedly. This only happens with longer documents — shorter ones work fine.

That is function generating PDF:

private function getMPDF($filename = null) {
    $mpdf = $this->mpdfInit();
    $mpdf->charset_in = 'utf-8';
    $mpdf->SetTopMargin(33);

    $mpdf->WriteHTML($this->html);
        
    if ($filename === null) {
        return $mpdf->Output('', "S");
    } else {
        $mpdf->Output($filename, "F");
    }
}

The $this->html contains HTML with multiple nested tags and paragraphs, such as this:

<table style="width: 700px;" border="0">
<tbody>
<tr>
<td style="width: 432px;"> </td>
<td style="width: 225px; padding-top: 8px;">
<p style="font-size: 13px; font-family: Arial;">Pani<br />[IMIĘ I NAZWISKO]<br />[ADRES]<br />[KOD POCZTOWY] [MIASTO]</p>
</td>
<td style="width: 43px;"> </td>
</tr>
</tbody>
</table>
<p> </p>
<table style="text-align: justify; width: 700px;" border="0">
<tbody>
<tr>
<td style="width: 50px;"> </td>
<td style="width: 600px;">
<p style="font-size: 13px; font-family: Arial;">[DATA]</p>
<p> </p>
<p style="font-size: 15px; font-family: Georgia;">Dotyczy zgłoszenia o numerze [NUMER_ZGŁOSZENIA] z dnia [DATA]; przedmiot: [NAZWA_SPRZĘTU]; numer dokumentu: [NUMER_DOKUMENTU].</p>
<p> </p>
<p> </p>
<p style="font-size: 13px; font-family: Arial;">Szanowna Pani,</p>
<p> </p>
<p style="font-size: 13px; font-family: Arial;">Informujemy, że po analizie dostępnych informacji nie stwierdzono przesłanek do pozytywnego rozpatrzenia zgłoszenia.<br /><br />Na podstawie przeprowadzonych czynności ustalono, że nie wystąpiły okoliczności, które uzasadniałyby dalsze działanie.</p>
<br />
<p style="font-size: 13px; font-family: Arial;">Podjęta decyzja wynika z:</p>
<p style="font-size: 13px; font-family: Arial;">- informacji zebranych podczas zgłoszenia<br />- analizy technicznej<br /><br />Zgłoszony opis: brak ładowania, pęknięcie plastiku, brak aktywacji systemu. Wskazana data: [DATA].<br /><br />W wyniku analizy technicznej stwierdzono mechaniczne uszkodzenie elementów:
<br />- bateria cmos<br />- osłona zawiasów<br /><br /><br />Stwierdzono również, że niektóre elementy uległy naturalnemu zużyciu, co nie stanowi podstawy do dalszego działania w tym zakresie.</p>
<p> </p>
<p style="font-size: 13px; font-family: Arial;">W związku z powyższym brak jest podstaw do zmiany stanowiska. </p>
</td>
<td> </td>
</tr>
<tr>
<td style="width: 50px;"> </td>
<td style="width: 600px;">
<p style="font-size: 13px; font-family: Arial;"><br />Informujemy o możliwości przekazania sprawy do niezależnych instytucji oraz skorzystania z dostępnych środków odwoławczych. Sprawa może być również rozpatrzona przez sąd właściwy miejscowo zgodnie z obowiązującymi przepisami.</p>
</td>
<td style="width: 50px;"> </td>
</tr>
<tr>
<td style="width: 50px;"> </td>
<td style="vertical-align: top; text-align: justify; width: 600px;">
<p style="font-size: 13px; font-family: Arial;"><br />Sprawy sporne mogą być również rozpatrywane w drodze pozasądowego postępowania przed wyznaczonymi instytucjami, zgodnie z obowiązującymi przepisami prawa.</p>
</td>
<td style="width: 50px;"> </td>
</tr>
<tr>
<td style="width: 50px;"> </td>
<td style="text-align: justify;">
<p style="font-size: 13px; font-family: Arial;">[NAZWA INSTYTUCJI] jest administratorem danych, które są przetwarzane zgodnie z obowiązującymi przepisami. Kontakt z Inspektorem Ochrony Danych możliwy jest za pośrednictwem formularza na stronie [STRONA], pisemnie lub mailowo: iod@[DOMENA].pl. Szczegóły dostępne są również pod numerem telefonu [NUMER].</p>
<p style="font-size: 13px; font-family: Arial;"><br /><br />Z wyrazami szacunku</p>
<br />
<p style="font-size: 13px; font-family: Arial;">[IMIĘ I NAZWISKO]<br /> <img src="[ZDJĘCIE]" alt="" width="190" /> <br />Główny Specjalista<br />[DZIAŁ]</p>
</td>
<td style="width: 50px;"> </td>
</tr>
</tbody>
</table>

After debugging, I noticed the issue seems to be related to the table element. When I remove the table (or extract all its content before rendering), the blank page disappears — but this breaks other documents, so it’s not a viable solution.

I also tried modifying margins and adding CSS to control page breaks:

table { page-break-inside: auto; }
tr    { page-break-inside: avoid; }
thead { display: table-header-group; }
tbody { display: table-row-group; }

Why is my WordPress plugin shortcode output duplicating every time I refresh the page?

I’m building a simple WordPress plugin that fetches a random quote from an external API and displays it using a shortcode.

The problem is: every time I refresh the page, the quote seems to duplicate — it appears twice (or more) inside the same container. I expected it to show just one quote per page load.

Here’s a simplified version of my code:

function my_quotes_shortcode() {
       $response = wp_remote_get('https://api.quotable.io/random');
       if (is_wp_error($response)) {
               return 'Quote unavailable.';
       }
      
       $data = json_decode(wp_remote_retrieve_body($response));
       $quote = $data->content ?? 'Default quote';
       $author = $data->author ?? 'Unknown';
       return "<div class='quote-box'>"{$quote}" - {$author}</div>";
}

add_shortcode('daily_quote', 'my_quotes_shortcode');

What I Tried

  • Wrapped the return inside ob_start() / ob_get_clean() — no change
  • Ensured add_shortcode() is called only once, outside any hook
  • Cleared browser, site, and server cache
  • Switched to the default Twenty Twenty-Four theme — still duplicates

What I Expected

  • I expected the shortcode to return just one quote inside a each time the page loads. No duplicates.

Notes

  • I’m not enqueueing any custom JavaScript or CSS
  • Using the shortcode inside a basic Page block through the WordPress editor
  • Duplicates happen more often when refreshing quickly

Is this related to how WordPress handles shortcode rendering or something with API timing?
Any help would be appreciated!

htaccess block root folder bit allow access to list of specified sub folders

I am trying to create htaccess rules at the root of a client site to block traffic from a specific subfolder where wordpress is installed.

Here is my structure

site.com
|--blog
   |--.htaccess
   |--wp-files
.htaccess
site-root-files

My root htaccess file look like this:

RewriteEngine On

# Define the list of exception folders
RewriteCond %{REQUEST_URI} ^/blog/([^/]+)/
RewriteCond %{REQUEST_URI} !^/blog/(wp-admin|wp-json)/

# List of exception files
RewriteCond %{REQUEST_URI} ^/blog/wp-login.php$ [NC]
RewriteCond %{REQUEST_URI} !^/blog/wp-login.php$

# Redirect all other requests under /blog/
RewriteCond %{REQUEST_URI} ^/blog/
RewriteRule ^/blog/ / [L]

Redirect 301 /tmp /
ErrorDocument 404 /error/404.html

Nothing seems to work except the last two lines the tmp redirect and the 404 page.

WordPress is installed in the blog folder.

Then it dawned on my that WordPress might have its own htaccess file. It does and it looks like this:


# BEGIN WordPress
# Direktiverne (linjer) mellem 'BEGIN WordPress' og 'END WordPress' er
# dynamisk genereret og bør kun ændres via WordPress-filtre.
# Eventuelle ændringer i direktiverne mellem disse markører vil blive overskrevet.

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteBase /blog/
RewriteRule ^index.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /blog/index.php [L]
</IfModule>

# END WordPress

What have I tried?

Commenting out all of the rules in the blog/.htaccess file
Inverting the functions in the site root .htaccess file.

Nothing seems to work.

My regex knowledge is pretty basic but I can wrap my head around this. !^/blog/(wp-admin|wp-json)/ looks like not/don’t write rewrite rules for blog/wp-admin, or blog/wp-json etc

TL;DR

Block access to

  • site.com/blog

With these exceptions (allow access to)

  • site.com/blog/wp-admin
  • site.com/blog/wp-json
  • site.com/blog/wp-login.php

Can anyone help me?

Laravel/Filament gave HTTP 500 after edit an resource

I got problems with a Laravel/Filament Project. I can create Filament Resources and view, but as soon as i do any action like creating, editing or deleting it performs that action and afterwards i got HTTP 500 error. It’s regardless, wich filament page I try to open. Even on a complete new installation this happens.

I found out: If I delete my session and I log in completly new, it works again. So I assume it’s a session problem, but I left everything by default.

My setup:

.env

APP_NAME=Laravel
APP_ENV=local
APP_KEY=base64:EaR7VEAw8oTwAoVsJkTEb33EWYnMMPsHL87EWeL9xFc=
APP_DEBUG=true
APP_URL=http://localhost

APP_LOCALE=en
APP_FALLBACK_LOCALE=en
APP_FAKER_LOCALE=en_US

APP_MAINTENANCE_DRIVER=file
# APP_MAINTENANCE_STORE=database

PHP_CLI_SERVER_WORKERS=4

BCRYPT_ROUNDS=12

LOG_CHANNEL=stack
LOG_STACK=single
LOG_DEPRECATIONS_CHANNEL=null
LOG_LEVEL=debug

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=test
DB_USERNAME=x
DB_PASSWORD=x

SESSION_DRIVER=database
SESSION_LIFETIME=120
SESSION_ENCRYPT=false
SESSION_PATH=/
SESSION_DOMAIN=null

BROADCAST_CONNECTION=log
FILESYSTEM_DISK=local
QUEUE_CONNECTION=database

CACHE_STORE=database
# CACHE_PREFIX=

MEMCACHED_HOST=127.0.0.1

REDIS_CLIENT=phpredis
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379

MAIL_MAILER=log
MAIL_SCHEME=null
MAIL_HOST=127.0.0.1
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_FROM_ADDRESS="[email protected]"
MAIL_FROM_NAME="${APP_NAME}"

AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET=
AWS_USE_PATH_STYLE_ENDPOINT=false

VITE_APP_NAME="${APP_NAME}"

composer

name     : filament/filament
descrip. : A collection of full-stack components for accelerated Laravel app development.
keywords :
versions : * v3.3.0
released : 2025-02-25, 4 months ago
type     : library
license  : MIT License (MIT) (OSI approved) https://spdx.org/licenses/MIT.html#licenseText
homepage : https://github.com/filamentphp/filament
source   : [git] https://github.com/filamentphp/panels.git 2ddea9d4c3c7d1bfce2d9ea6b3d7d7fe8c5682ec
dist     : [zip] https://api.github.com/repos/filamentphp/panels/zipball/2ddea9d4c3c7d1bfce2d9ea6b3d7d7fe8c5682ec 2ddea9d4c3c7d1bfce2d9ea6b3d7d7fe8c5682ec     
path     : C:UserskwagnerDesktoptestvendorfilamentfilament
names    : filament/filament

support
issues : https://github.com/filamentphp/filament/issues
source : https://github.com/filamentphp/filament

autoload
files
psr-4
Filament => src

requires
danharrin/livewire-rate-limiting ^0.3|^1.0|^2.0
filament/actions self.version
filament/forms self.version
filament/infolists self.version
filament/notifications self.version
filament/support self.version
filament/tables self.version
filament/widgets self.version
illuminate/auth ^10.45|^11.0|^12.0
illuminate/console ^10.45|^11.0|^12.0
illuminate/contracts ^10.45|^11.0|^12.0
illuminate/cookie ^10.45|^11.0|^12.0
illuminate/database ^10.45|^11.0|^12.0
illuminate/http ^10.45|^11.0|^12.0
illuminate/routing ^10.45|^11.0|^12.0
illuminate/session ^10.45|^11.0|^12.0
illuminate/support ^10.45|^11.0|^12.0
illuminate/view ^10.45|^11.0|^12.0
php ^8.1
spatie/laravel-package-tools ^1.9
name     : livewire/livewire
descrip. : A front-end framework for Laravel.
keywords : 
versions : * v3.6.4
released : 2025-07-17, this week
type     : library
license  : MIT License (MIT) (OSI approved) https://spdx.org/licenses/MIT.html#licenseText
homepage :
source   : [git] https://github.com/livewire/livewire.git ef04be759da41b14d2d129e670533180a44987dc
dist     : [zip] https://api.github.com/repos/livewire/livewire/zipball/ef04be759da41b14d2d129e670533180a44987dc ef04be759da41b14d2d129e670533180a44987dc      
path     : C:UserskwagnerDesktoptestvendorlivewirelivewire
names    : livewire/livewire

support
issues : https://github.com/livewire/livewire/issues
source : https://github.com/livewire/livewire/tree/v3.6.4

autoload
files
psr-4
Livewire => src/

requires
illuminate/database ^10.0|^11.0|^12.0
illuminate/routing ^10.0|^11.0|^12.0
illuminate/support ^10.0|^11.0|^12.0
illuminate/validation ^10.0|^11.0|^12.0
laravel/prompts ^0.1.24|^0.2|^0.3
league/mime-type-detection ^1.9
php ^8.1
symfony/console ^6.0|^7.0
symfony/http-kernel ^6.2|^7.0

requires (dev)
calebporzio/sushi ^2.1
laravel/framework ^10.15.0|^11.0|^12.0
mockery/mockery ^1.3.1
orchestra/testbench ^8.21.0|^9.0|^10.0
orchestra/testbench-dusk ^8.24|^9.1|^10.0
phpunit/phpunit ^10.4|^11.5
psy/psysh ^0.11.22|^0.12

php.ini

engine = On
short_open_tag = Off
precision = 14
output_buffering = 4096
zlib.output_compression = Off
implicit_flush = Off
unserialize_callback_func =
serialize_precision = -1
zend.enable_gc = On
zend.exception_ignore_args = Off
zend.exception_string_param_max_len = 15
expose_php = On
max_execution_time = 30
max_input_time = 60
memory_limit = 128M
error_reporting = E_ALL
display_errors = On
display_startup_errors = On
log_errors = On
ignore_repeated_errorsl = Off
ignore_repeated_source = Off
report_memleaks = On
error_log = "M:phplogsphp_errors.log"
variables_order = "GPCS"
request_order = "GP"
register_argc_argv = Off
auto_globals_jit = On
post_max_size = 8M
auto_prepend_file =
auto_append_file =
default_mimetype = "text/html"
default_charset = "UTF-8"
doc_root =
user_dir =
extension_dir = "ext"
enable_dl = Off
file_uploads = On
upload_max_filesize = 2M
max_file_uploads = 20
allow_url_fopen = On
allow_url_include = Off
default_socket_timeout = 60
extension=curl
extension=fileinfo
extension=intl
extension=ldap
extension=mbstring
extension=openssl
extension=pdo_mysql
extension=zip
cli_server.color = On
pdo_mysql.default_socket=
SMTP = localhost
smtp_port = 25
mail.add_x_header = Off
mail.mixed_lf_and_crlf = Off
odbc.allow_persistent = On
odbc.check_persistent = On
odbc.max_persistent = -1
odbc.max_links = -1
odbc.defaultlrl = 4096
odbc.defaultbinmode = 1
mysqli.max_persistent = -1
mysqli.allow_persistent = On
mysqli.max_links = -1
mysqli.default_port = 3306
mysqli.default_socket =
mysqli.default_host =
mysqli.default_user =
mysqli.default_pw =
mysqlnd.collect_statistics = On
mysqlnd.collect_memory_statistics = On
mysqlnd.mempool_default_size = 16000
mysqlnd.net_cmd_buffer_size = 2048
mysqlnd.net_read_buffer_size = 32768
mysqlnd.net_read_timeout = 31536000
pgsql.allow_persistent = On
pgsql.auto_reset_persistent = Off
pgsql.max_persistent = -1
pgsql.max_links = -1
pgsql.ignore_notice = 0
pgsql.log_notice = 0
bcmath.scale = 0
session.save_handler = files
session.use_strict_mode = 0
session.use_cookies = 1
session.use_only_cookies = 1
session.name = PHPSESSID
session.auto_start = 0
session.cookie_lifetime = 0
session.cookie_path = /
session.cookie_domain =
session.cookie_httponly =
session.cookie_samesite =
session.serialize_handler = php
session.gc_probability = 1
session.gc_divisor = 1000
session.gc_maxlifetime = 1440
session.referer_check =
session.cache_limiter = nocache
session.cache_expire = 180
session.use_trans_sid = 0
session.trans_sid_tags = "a=href,area=href,frame=src,form="
zend.assertions = 1
tidy.clean_output = Off
soap.wsdl_cache_enabled=1
soap.wsdl_cache_dir="/tmp"
soap.wsdl_cache_ttl=86400
soap.wsdl_cache_limit = 5
ldap.max_links = -1
mysqli.default_port = 3306

pushManager.subscribe return null on android firefox (not working at all on chrome)

i’m trying to create a simple web push notif using service worker, it works well on browsers in desktop, but on android device not working!

on firefox android: pushManager.subscribe() return null
on chrome android, it doesnt even reach to subscribe stage

index.php file:

<?php
require __DIR__ . '/vendor/autoload.php';

use MinishlinkWebPushVAPID;

// Generate VAPID keys if they don't exist
$vapidFile = __DIR__ . '/vapid.json';
if (!file_exists($vapidFile)) {
    $keys = VAPID::createVapidKeys();
    file_put_contents($vapidFile, json_encode($keys));
} else {
    $keys = json_decode(file_get_contents($vapidFile), true);
}

// Save subscription if POST request
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    var_dump(file_get_contents('php://input'));
    var_dump(__DIR__);
    file_put_contents(__DIR__ . '/subscription.json', file_get_contents('php://input'));
    echo 'Subscription saved';
    exit;
}
?>
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>Push Demo</title>
</head>
<body>
  <h2>Web Push Demo</h2>
  <button id="subscribeBtn">Subscribe for Push</button>

  <script>
    const publicKey = '<?= $keys['publicKey'] ?>';

    function urlBase64ToUint8Array(base64String) {
       // Ensure correct padding
      const padding = '='.repeat((4 - base64String.length % 4) % 4);
      const base64 = (base64String + padding)
        .replace(/-/g, '+')
        .replace(/_/g, '/');

      const rawData = atob(base64);
      const buffer = new Uint8Array(rawData.length);

      for (let i = 0; i < rawData.length; ++i) {
        buffer[i] = rawData.charCodeAt(i);
      }
      return buffer;
    }

    async function subscribe() {
      try{
        const permission = await Notification.requestPermission();
        if (permission !== 'granted') {
          alert('Please enable notifications!');
          return;
        }

        const reg = await navigator.serviceWorker.register('sw.js');

        // Wait for activation if needed
        if (!reg.active) {
          await new Promise(resolve => {
            if (reg.installing) {
              reg.installing.onstatechange = () => {
                if (reg.active) resolve();
              };
            } else if (reg.waiting) {
              resolve(); // Skip waiting for user
            }
          });
        }
        console.log("SW now active. PushManager:", reg.pushManager);
        console.log("reg object:", reg);
        console.log("reg.scope: " + reg.scope);

        const existingSub = await reg.pushManager.getSubscription();
        if (existingSub) {
          await existingSub.unsubscribe();
          console.log("Already subscribed:", existingSub);
          alert("Already subscribed");
        } else {
          console.log("Not subscribed yet.");
          alert("Not subscribed yet.");
        }
  console.log("Key length: " + urlBase64ToUint8Array(publicKey).length);

        const sub = await reg.pushManager.subscribe({
          userVisibleOnly: true,
          applicationServerKey: urlBase64ToUint8Array(publicKey)
        });
        console.log(sub);
        alert(sub);

        await fetch('', {
          method: 'POST',
          body: JSON.stringify(sub),
          headers: { 'Content-Type': 'application/json' }
        });

       const checkSub = await reg.pushManager.getSubscription();
        if (existingSub) {
          console.log("subscribed");
          alert("subscribed");
        } else {
          console.log("Not subscribed yet.");
          alert("Not subscribed yet.");
        }

      }catch (err) {
        console.error("Subscription failed:");
        console.error("Error name:", err.name);
        console.error("Error message:", err.message);
        console.error("Error stack:", err.stack);
        alert(`Subscribe failed: ${err.name} - ${err.message}`);
        return null;
      }
    }

    document.getElementById('subscribeBtn').onclick = () => {
      if ('serviceWorker' in navigator && 'PushManager' in window) {
        subscribe().catch(err => console.log('Error: ' + err));
      } else {
        alert('Push not supported');
      }
    };
  </script>
</body>
</html>

and this is sw.js file in the same directory:

// sw.js
self.addEventListener('install', e => self.skipWaiting());
self.addEventListener('activate', e => console.log('SW activated'));
self.addEventListener('push', e => {
  const body = e.data?.text() || 'No payload';
  e.waitUntil(self.registration.showNotification('Push', { body }));
});

some considerations:

a. i ran this script on a valid https website

b. i used valid VAPID and it works on desktop browsers including firefox and chrome

c. i granted permissions on android device so permissions not the issue!

if you could help me on this, im gratefull…

codeigniter 4 view Invalid file

Error – CodeIgniterViewExceptionsViewException
Invalid file: “/pergo/views/index.php”

SYSTEMPATHExceptionsFrameworkException.php at line 39

32 }
33
34 /**
35 * @return static
36 */
37 public static function forInvalidFile(string $path)
38 {
39 return new static(lang(‘Core.invalidFile’, [$path]));

My theme directory in root: ignore if i am wrong i am new in codings thing

Path

/themesmonoka
/themespergo
/themesregular
/themesviews
/themespergomodels
/themespergoviews
/themespergoviewsindex.php
View.php

    <?php
    
    namespace Config;
    
    use CodeIgniterConfigView as BaseView;
    
    class View extends BaseView
    {
        public array $paths = [
            // Allow views to be loaded from the themes directory
            ROOTPATH . 'themes',
            APPPATH . 'views',
        ];
    
    }

Home.php

    <?php
    
    namespace AppControllers;
    
    use AppModelsLanguageModel;
    use ConfigServices;
    
    class Home extends BaseController
    {
        public function index()
        {
            if (session()->get('uid')) {
                return redirect()->to('/new_order');
            }
    
            $homePageType = get_theme();
            if (get_option('enable_disable_homepage') && $homePageType !== 'pergo') {
                return redirect()->to('/auth/login');
            }
    
            $langModel  = new LanguageModel();
            $languages  = $langModel
                            ->where('status', 1)
                            ->findAll();
    
            // Load the index view from the active theme
            $viewPath = "$homePageType/views/index";
            return view($viewPath, [
                'lang_current' => get_lang_code_defaut(),
                'languages'    => $languages,
            ]);
        }
    }

Apple Pay for Authorize.net is not showing

I’ve completed all the necessary steps for setting up Apple Pay, including uploading the PEM certificate and verifying my domain. I’m using the WooCommerce Authorize.Net plugin (skyverge), and their instructions mention enabling Apple Pay using this filter:

 add_filter( 'wc_payment_gateway_authorize_net_cim_activate_apple_pay', '__return_true' );

By adding this filter hook in functions.php file it start showing Apple pay setting page where we can enable or disable, add prm file etc. Also i am working on safari browser. Despite following all the required steps, the Apple Pay button still isn’t appearing on the checkout page. I’ve confirmed that everything is set up correctly, but I’m not sure what I’m missing.

Intelephense is showing Undefined Type errors that are not true

Windows 11: 24h2
VS Code: 1.102.1 (WSL: Ubuntu 24.04.2 LTS)
Intelephense: 1.14.4
Symfony: v6.4.23
PHP: 8.2.28

<?php

namespace AppCommand;

use DoctrineBundleFixturesBundleFixture;
use DoctrineORMEntityManagerInterface;
use SymfonyComponentConsoleAttributeAsCommand;
use SymfonyComponentConsoleCommandCommand;
use SymfonyComponentConsoleInputInputArgument;
use SymfonyComponentConsoleInputInputInterface;
use SymfonyComponentConsoleOutputOutputInterface;

#[AsCommand(
    name: 'app:fixtures:load-one',
    description: 'Load a single Doctrine fixture by class name',
)]

All of the symfony classes are highlighted with a red line by Intelephense.
The above snippet shows that the AsCommand has been included but the line #[AsCommand( shows an error of:

Undefined type 'SymfonyComponentConsoleAttributeAsCommand'.intelephense(P1009)
class SymfonyComponentConsoleAttributeAsCommand
function AsCommand::__construct(
    string $name,
    string|null $description = null,
    array $aliases = [],
    bool $hidden = false
)
Service tag to autoconfigure commands

I am seeing the exact same error from:

  • class ClassName extends Command
    • Undefined type ‘SymfonyComponentConsoleCommandCommand’.intelephense(P1009)
  • parent::__construct();
    • Undefined type ‘SymfonyComponentConsoleCommandCommand’.intelephense(P1009)
  • $this->addArgument(...);
    • Undefined method ‘addArgument’.intelephense(P1013)
  • protected function execute(InputInterface $input, OutputInterface $output): int
    • Undefined type ‘SymfonyComponentConsoleInputInputInterface’.intelephense(P1009)
    • Undefined type ‘SymfonyComponentConsoleOutputOutputInterface’.intelephense(P1009)

I have tried:

  • Restarting
    • laptop
    • PHP
    • Symfony:server
    • VS Code
  • Force Intelephense to reindex
  • Regenerate autoloader (composer dump-autoload –optimize)

I only have two options left that I can think of that include removing intelephense or specifically applying a setting that stops this (which seems pointless as then its not doing its job) "intelephense.diagnostics.undefinedTypes": false,

PHP $_GET always empty in IIS Server [closed]

I would like to ask for help with my PHP website that running on IIS Server version 10, as I have no experience with IIS.

Currently, the website face “too many redirects” error after login because the function always checks $_GET[‘code’], but $_GET[‘code’] is always empty.

public function isauthenticated($appid,$twofa = null,$return_uri = null) {
    
    file_put_contents("log_code_check.txt", "[" . date("Y-m-d H:i:s") . "] code param 1: " . ($_GET['code'] ?? 'NULL') . "n", FILE_APPEND);
    
    $this->appid = $appid;
    $this->returnuri = $return_uri;
    
    if ( !isset($_GET['code']) ) {
        $this->getAuthorized($twofa);
    }
    
    return TRUE;
}

After the login process, we can actually see the code parameter in the URL like this:

http://cls.nus.edu.sg/nusgerman?code=AAAAAAAAAAAAAAAAAAAAAA.sovlCnfD3QiPAMLpX5ySy_K9ekQ.JswjwasWN9ipSItHr5hLOfodtzaUQybLo7j5JcYCwAm9py0OrGqhl77kmbdK6XNvTIKhgQ4Jt1wodK3Dh3Gt3PbZKMTnorQBrWbZo8o3WfSwAgJFj2Vq2ZyOn-Th9_Kz_-CLCZHK-5xOkve_l1Xf33ZSibLF0YXPw-hBHathjpIZslKELYvKl5vpa61KeiIU1R0da6ntK773mGRGzjFLSgxAjQ8_NrOiPvbx3l2CKb7-IFvqa131rwNloryt32oZPWwCWvLQf-9ScB6Ajbfef8dPaSFTb9GYjPZ8Qvvx0ir31TpzoGAdyLI1ZiUitfCUVPpIEOa4_y5QFle-EetJWQ

Log file also captured empty code parameter like this:

[2025-07-17 07:22:35] code param 1: NULL

here’s my web.config:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <defaultDocument>
            <files>
                <clear />
                <add value="Default.htm" />
                <add value="Default.asp" />
                <add value="index.htm" />
                <add value="index.html" />
                <add value="iisstart.htm" />
                <add value="index.php" />
            </files>
        </defaultDocument>
        <httpProtocol>
            <customHeaders>
                <add name="Cache-Control" value="max-age=300" />
                <add name="Strict-Transport-Security" value="max-age=31536000; includeSubDomains; preload" />
                <add name="X-Content-Type-Options" value="nosniff" />
                <add name="X-Frame-Options" value="SAMEORIGIN" />
                <add name="X-Powered-By" value="ASP.NET" />
                <add name="X-XSS-Potection" value="1;mode=block" />
            </customHeaders>
        </httpProtocol>
    </system.webServer>
</configuration>

How to process data of one client in different browser tabs? [closed]

There is such a difficulty. The client fills out a form on the site, with data on several clients, and does it not in turn, but in parallel, in several browser tabs. The question is, how to process such data?

If you store such data in sessions or cookies, they can be overwritten, I talked about localsession, but you can only work with it from js, is there a solution in php?

Change event date to TBD in Modern Event Calendar (aka MEC)

I want to change the date of a specific event to TBD, I can’t see any opton in Modern Event Calendar WordPress plugin. I have the php code but its not working.

add_filter('the_content', function($content) {
    if (is_singular('mec-events')) {
        $event_id = get_the_ID();
        $start_date = get_post_meta($event_id, 'mec_start_date', true);

        if ($start_date === '2099-12-31') {
            // Replace any date pattern with "TBD"
            $content = preg_replace('/d{1,2}s+w+s+d{4}/', 'TBD', $content);
            $content = str_replace('2099', 'TBD', $content); // fallback
        }
    }

    return $content;
});

I am adding this into code snippet but nothing changed.

PHP Equivalent of Mysql inet6_aton() function

Our client is using a version of Mysql that does not support the inet6_aton() function.

What would be the PHP equivalent for the inet6_aton function?

The inet6_aton() function returns the numeric value of the address in VARBINARY data type: VARBINARY(16) for IPv6 addresses and VARBINARY(4) for IPv4 addresses.

We have tried a few functions that convert IP to binary but none of them have the same output as the inet6_aton() function.

Below is the desired output that we are trying to achieve with PHP.

SELECT inet6_aton('214.0.0.0');

// OUTPUT

0xd6000000