Creating phonepe payment gateway using phonepe checkout.js but it is failed to initiate payments [closed]

I am creating creating phonepe integration but failed to intiate payment, I am getting messages like Payment Initiation failed

My front code is:

document.getElementById("payWithPhonePe").addEventListener("click", function() {
  alert("hi");
  const amount = 15;
  const orderId = "unique-order-id-" + new Date().getTime();
  fetch("<?php echo site_url("beta/change_package_1/create_phonePe"); ?>", {
      method: "POST",
      headers: {
        "Content-Type": "application/json"
      },
      body: JSON.stringify({
        amount: amount,
        orderId: orderId
      })
    }).then(response => response.json()).then(data => {
    if (data.success) {
      PhonePe.init({
        orderId: data.data.orderId,
        merchantId: data.data.merchantId,
        redirectUrl: data.data.redirectUrl,
        success: (res) => {
          alert("Payment was successful!");
          console.log(res);
        },
        failure: (res) => {
          alert("Payment failed.");
          console.log(res);
        },
        close: () => {
          alert("Payment window closed.");
        }
      });
    } else {
      alert("Payment initiation failed!");
    }
  }).catch(error => {
    // console.error("Error:", error);      
  });
});
<script src="https://mercury.phonepe.com/web/bundle/checkout.js"></script>

<button id="payWithPhonePe">Pay with PhonePe</button>

Backend code is: Controller.php
method is:

function createPhonePePayment($amount, $orderId) {
        $merchantId = "";
        $merchantKey = "";
    
        $url = "https://api.phonepe.com/apis/hermes/pg/v1/pay";
        // Payment request payload
        $payload = [
            "merchantId" => $merchantId,
            "transactionId" => $orderId,
            "amount" => $amount * 100,
            "currency" => "INR",
            "redirectUrl" => site_url('beta/change_package_1')
        ];
    
        $jsonPayload = json_encode($payload);
    
        $checksum = hash_hmac('sha256', $jsonPayload, $merchantKey);
    
        $headers = [
            'Content-Type: application/json',
            'X-VERIFY: ' . $checksum . "###" . $merchantId,
        ];
    
        // Initialize cURL
        $ch = curl_init($url);
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $jsonPayload);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    
        // Execute the request
        $response = curl_exec($ch);
        curl_close($ch);
    
        // Decode the response
        return json_decode($response, true);
    }

    public function create_phonePe(){
        header('Content-Type: application/json');
        $input = json_decode(file_get_contents("php://input"), true);
        if (!isset($input['amount']) || !isset($input['orderId'])) {
            echo json_encode(["success" => false, "error" => "Invalid input."]);
            return;
        }
    
        $amount = $input['amount'];
        $orderId = $input['orderId'];
        $responseData = $this->createPhonePePayment($amount, $orderId);
        
        if ($responseData && isset($responseData['data']['instrumentResponse']['redirectUrl'])) {
            echo json_encode([
                "success" => true,
                "data" => [
                    "orderId" => $orderId,
                    "merchantId" => $merchantId,
                    "redirectUrl" => $responseData['data']['instrumentResponse']['redirectUrl']
                ]
            ]);
        } else {
            echo json_encode([
                "success" => false,
                "error" => isset($responseData['error']) ? $responseData['error'] : "Failed to initiate payment."
            ]);
        }
    }

Please help me solve the problem. I am using right credentials like merchant Id and API key. I want to solve phonepe integration payments initiation failed problem.

How to attach Referer in the PDF which is generated using mPDF library

As I am generating a PDF using mPDF library. My concern is that, the PDF contains the assets (like images), these images having the domain restriction (i.e. no one can access these assets directly, these assets are accessed only from the specified domain).
So when I add these assets in the PDF’s html body, these assets get blocked (i.e. they are not get displayed).

Can this problem be solved by attaching the referer to the PDF?

ApiPlatform generates invalid IRI (without ID) when using State Provider

I have a User entity in API Platform and created a custom operation to return information about the currently logged-in user, using a state provider.

ApiResource tag:

#[ApiResource(
  operations: [
    new Get(
      uriTemplate: '/user',
      normalizationContext: ['groups' => ['user:read']],
      security: self::SECURITY_GET,
      provider: UserStateProvider::class
    )
]

UserStateProvider:

class UserStateProvider implements ProviderInterface
{
    public function __construct(
        private readonly Security $security,
    ) {}

    public function provide(Operation $operation, array $uriVariables = [], array $context = []): object|array|null
    {
        return $this->security->getUser();
    }
}

The problem: This endpoint returns an IRI without an ID, which looks like this:

"@context": "/api/contexts/User",
"@id": "/api/user",
"@type": "User",

I attempted to fetch the user from the repository within UserStateProvider, but it did not resolve the issue:

$user = $this->security->getUser();
return $user ? $this->userRepository->find($user->getId()) : null;

Adding annotation to signed pdf using PHP with fpdf and tcpdf removes signature

I’m trying to add a page with an annotation box to an existing signed pdf. This should be possible with TCPDF and FPDF. Unfortunately, it removes the sign and the pdf cannot be validated after being altered. The displayed pdf looks the same, though.

The code (generated by AI) follows:

<?php
use FpdfFpdf;
use setasignFpdiFpdi;

require_once '../lib/fpdf/Fpdf.php';
require_once '../lib/tcpdf/tcpdf.php';
require_once '../lib/fpdi/src/autoload.php';

// require_once '../vendor/autoload.php';

$fpdf = new FPDFFPDF();

$pdf = new Fpdi();

$pdf->setSourceFile('test-form-signed.pdf');

// Loop through the pages of the original PDF
$pageCount = $pdf->setSourceFile('test-form-signed.pdf');
for ($i = 1; $i <= $pageCount; $i++) {
    $tplId = $pdf->importPage($i);
    $pdf->addPage();
    $pdf->useTemplate($tplId, 0, 0);
}

// Add a blank new page at the end
$pdf->AddPage();

// Set annotation properties
$pdf->SetFont('Helvetica', '', 12);
$pdf->SetTextColor(0, 0, 0);
$pdf->Text(10, 10, "This is a text annotation on a new blank page.");

// Save the output PDF
$pdf->Output('F', 'test-form-annotated-signed.pdf');

The test-form-annotated-signed.pdf is about half the size of the original file and it no longer passes a validation test. Probably, the signature/certificate was removed during the process.

By the way, the pdf is signed with a OCES-3 certificate issued by the State of Denmark.

Please note that solutions that involve using Adobe Acrobat, Signicat etc. are not an option.

Laravel: (Job dispatch) Failed to open stream: Permission denied

fopen(app/storage/framework/cache/data/6a/e8/6ae8f7a027ae2ffc516a3933fcade51ab014d34d): Failed to open stream: Permission denied

Stack trace

app/vendor/laravel/framework/src/Illuminate/Foundation/Bootstrap/HandleExceptions.php:256
app/vendor/laravel/framework/src/Illuminate/Filesystem/LockableFile.php:69
app/vendor/laravel/framework/src/Illuminate/Filesystem/LockableFile.php:42
app/vendor/laravel/framework/src/Illuminate/Cache/FileStore.php:108
app/vendor/laravel/framework/src/Illuminate/Cache/FileLock.php:14
app/vendor/laravel/framework/src/Illuminate/Cache/Lock.php:91
app/vendor/laravel/framework/src/Illuminate/Bus/UniqueLock.php:43
app/vendor/laravel/framework/src/Illuminate/Foundation/Bus/PendingDispatch.php:164
app/vendor/laravel/framework/src/Illuminate/Foundation/Bus/PendingDispatch.php:188
app/vendor/ssntpl/cloud-storage/src/CloudStorageAdapter.php:65
app/vendor/ssntpl/cloud-storage/src/CloudStorageAdapter.php:151

I am dispatching job app/vendor/ssntpl/cloud-storage/src/CloudStorageAdapter.php:65
job

SyncFileJob::dispatch($path, $fromDisk, $remoteDisk)->onConnection($this->connection)->onQueue($this->queue);

then sometimes that line throw above error(Failed to open stream: Permission denied) whereas sometimes it working fine.

can anyone explain me, why is it happened?
what will be the solution for it?

If there was a permission issue then not a single job would be run.
queue connection is sync

How to refresh form data in Filament?

I have a Game object which can be controlled via the GamesResource. Here I have following section with actions and status messages inside my form:

Section::make('Game control')
  ->schema([
    FormsComponentsPlaceholder::make('status')
        ->label('Current status')
        ->content(function ($record) {
            if (!$record->is_running && !$record->current_round && !$record->is_finished) {
                return 'The game has not started yet.';
            } elseif ($record->is_finished && !$record->is_running) {
                return 'Game finished.';
            } else {
                return 'Current round: ' . $record->currentRound->sort;
            }
        }),
    FormsComponentsActions::make([
        FormsComponentsActionsAction::make('startGame')
            ->label('Start game')
            ->button()
            ->visible(fn($record) => !$record->is_running && !$record->is_finished)
            ->action(function (Game $record, EditRecord $livewire) {
                $record->startGame();
                $livewire->refreshFormData(['is_running', 'is_finished', 'current_round']);
            }),
        FormsComponentsActionsAction::make('startNextRound')
            ->label('Next Round')
            ->button()
            ->visible(fn($record) => $record->is_running && !$record->isLastRound())
            ->action(function (Game $record, EditRecord $livewire) {
                $record->startNextRound();
                $livewire->refreshFormData(['is_running', 'is_finished', 'current_round']);
            }),
        FormsComponentsActionsAction::make('finishGame')
            ->label('Show results')
            ->button()
            ->visible(fn($record) => $record->is_running && $record->isLastRound())
            ->action(function (Game $record, EditRecord $livewire) {
                $record->finishGame();
                $livewire->refreshFormData(['is_running', 'is_finished', 'current_round']);
            })
    ]),
  ])
  ->visibleOn('edit')

This is part of my Game model:

class Game extends Model {
    public function isLastRound() {
        return $this->current_round // check if current round is set
            && $this->rounds()->count() === $this->currentRound->sort; // check if current round is the last round
    }

    public function startGame() {
        $this->is_running = true;
        $this->current_round = $this->rounds()->orderBy('sort')->first()->id;
        $this->save();
    }

    public function startNextRound() {
        $currentRoundSort = $this->rounds()->where('id', $this->current_round)->first()->sort;
        $nextRound = $this->rounds()->where('sort', $currentRoundSort + 1)->first();
        $this->current_round = $nextRound->id;
        $this->save();
    }

    public function finishGame() {
        $this->is_running = false;
        $this->is_finished = true;
        $this->save();
    }
}

Currently everything works (nearly) as desired: The status messages show the correct status, the buttons apply the correct changes to the Game object. But clicking a button, for example “Next round”, needs me to refresh the page manually in order to see the change of status from “Current round: 1” to “Current round: 2”.

How do I achieve an automatic refresh, either of the page, or the section or the whole form?

I stumbled upon EditRecord::refreshFormData(), but couldn’t really make it work properly: Funnily enough, the current solution works for Starting and Finishing the game, but not for Next Round.

Display Product Attributes in WooCommerce Long Description [duplicate]

I am trying to automatically display product attributes at the end of the long description but my code makes it appear in the short description. How would I adjust this to come either as a tab by itself or in the long description?

The code is working perfectly in terms of showing the attributes on the product but the placement is wrong.

/* Vis alle produkt attributter på vareside */

function njengah_woo_attribute(){
 
    global $product;
 
    $attributes = $product->get_attributes();
 
    if ( ! $attributes ) {
 
        return;
 
    }
 
    $display_result = '';
 
 
    foreach ( $attributes as $attribute ) {
 
        if ( $attribute->get_variation() ) {
            continue;
        }
 
        $name = $attribute->get_name();
 
        if ( $attribute->is_taxonomy() ) {
 
            $terms = wp_get_post_terms( $product->get_id(), $name, 'all' );
 
            $njengahtax = $terms[0]->taxonomy;
 
            $njengah_object_taxonomy = get_taxonomy($njengahtax);
 
            if ( isset ($njengah_object_taxonomy->labels->singular_name) ) {
 
                $tax_label = $njengah_object_taxonomy->labels->singular_name;
 
            } elseif ( isset( $njengah_object_taxonomy->label ) ) {
 
                $tax_label = $njengah_object_taxonomy->label;
 
                if ( 0 === strpos( $tax_label, 'Product ' ) ) {
 
                    $tax_label = substr( $tax_label, 8 );
 
                }
 
            }
 
            $display_result .= $tax_label . ': ';
 
            $tax_terms = array();
 
            foreach ( $terms as $term ) {
 
                $single_term = esc_html( $term->name );
 
                array_push( $tax_terms, $single_term );
 
            }
 
            $display_result .= implode(', ', $tax_terms) .  '<br />';
 
 
 
 
        } else {
 
            $display_result .= $name . ': ';
 
            $display_result .= esc_html( implode( ', ', $attribute->get_options() ) ) . '<br />';
 
        }
 
    }
 
    echo $display_result;
 
}
add_action('woocommerce_single_product_summary', 'njengah_woo_attribute', 25);

How to get unique browser binary path identification from PHP?

In a PHP script I want to get a unique browser ID, but not so unique as the user agent ($_SERVER["HTTP_USER_AGENT"]) as the UA changes with every version. I tried removing all numerals in the UA string to evade version dependency, but that has as a side effect that ‘cloned’ browsers like Brave (a Chrome clone) has the same user agent as Chrome itself when omitting digits in the UA string.
I thought that using the browser binary (i.e. like /Applications/Firefox.app/Contents/Resouces/MacOS/Firefox or /usr/bin/firefox) is unique per browser and version independant. But how can I achieve this path (or other unique ID) ?

EDIT: The issue is that I want to get a unique browser ID which is independant on version number but cloned browsers shoud differ from original. So Firefox vs Waterfox or Chrome vs Brave should differ, but Firefox 132 should return the same as Firefox 130.

Livewire2.6 need to swap tampates based on server event

I’m a beginner in Livewire, need to display one of the templates (the first with a Resend button if $waitTime <=0 and the second if $waitTime >0) according to server event updateWaitTime . In the way I implemented it, wire:click=”getOTPCode(true)” doesn’t work. What is a proper way to implement it?:

    <div class="d-flex justify-content-end"
             x-data="otpSend()"
             x-init="init()"
        >
            
            <template x-if="getTime() <= 0">
                <button wire:click="getOTPCode(true)" type="button"
                        class="my-2 btn btn-primary rounded-pill text-white"><i
                        class="bi bi-arrow-counterclockwise"></i> Resend Code
                </button>
                <button hidden id="hide" data-bs-dismiss="modal"></button>
            </template>
            <template x-if="getTime() > 0">
                <small>
                    Resend OTP in
                    <span x-text="formatTime(getTime())"></span>
                </small>
            </template>

</div>
    <script>
       document.addEventListener('livewire:load', function () {

            window.livewire.on('submitted', function () {
                resetForm();
                focusForm();
            })

            window.livewire.on('resent', function () {
                resetForm();
                focusForm();
            })

            window.livewire.on('updateWaitTime', function (wait_before_resend) {
                console.log(`updateWaitTime ${wait_before_resend}`);
                otpSend(wait_before_resend);
            })

            window.livewire.on('success', function () {
                setTimeout(() => {
                    $('#hide').click();
                @this.emitSelf('reset')
                    ;
                }, 500)
            })
         
        

        })

        function otpSend(waitTime) {
            const milliseconds = waitTime * 1000 //60 seconds
            const currentDate = Date.now() + milliseconds
            var countDownTime = new Date(currentDate).getTime()
            let interval;
            return {
                countDown: milliseconds,
                countDownTimer: new Date(currentDate).getTime(),
                intervalID: null,
                init() {
                    if (!this.intervalID) {
                        this.intervalID = setInterval(() => {
                            this.countDown = this.countDownTimer - new Date().getTime();
                            
                            
                        }, 1000);
                    }
                },
                getTime() {
                    if (this.countDown < 0) {
                        this.clearTimer()
                    }
                    return this.countDown;
                },
                formatTime(num) {
                    var date = new Date(num);
                    return new Date(this.countDown).toLocaleTimeString(navigator.language, {
                        minute: '2-digit',
                        second: '2-digit'
                    });
                },
                clearTimer() {
                    clearInterval(this.intervalID);
                }
            }
        }
    </script>
    <?php
    public function getOTPCode($resend = false)
    {
        $this->emit('updateWaitTime', $this->wait_before_resend);
    }
    ?>

How do I use request params in my Mezzio app before the handler was initialized?

I am creating a Mezzio app which handles some POST-requests and uses some data from the body to get some configs from the DB (let’s say, I get the user’s id with some webhook and then by it get the configs I need to use in my app from the specific row in database). All these configs are needed to initialize different class objects to work with, while handling the request. Normally, if I didn’t need that data from the request, I would do something like that:

class WebhookHandlerFactory
{ // $config['client'] is hardcoded in the .env file in this case and then put into ConfigProvider
    protected ContainerInterface $container;

    public function __invoke(ContainerInterface $container): RequestHandlerInterface
    {
        $this->container = $container;
        $config = $this->getConfig();
        $client = (new SomeClient($config['client']))->getClient();
        $controller = (new SomeControllerFactory)($container);

        return new WebhookHandler($controller, $config, $client);
    }

    protected function getConfig(): ArrayObject
    {
        $config = $this->container->get('config');
        // here I use my hardcoded data to find something in the DB and then put it into $config

        return $config;
    }

The problem is that I cannot get my request body in the Factory.

The only way I found was making this factory return another factory which initializes handler class in __construct and then calls handle method like this:

public function __construct(
        ContainerInterface $container,
        CreateController $controller,
        ArrayObject $config
 ){
        $this->container = $container;
        $this->createController = $createController;
        $this->config = $config;

        $config = $this->getConfig();
        $client = (new SomeClient($config['client']))->getClient();

        $this->handler = new WebhookHandler($this->controller, $config, $client);
    }

    public function handle(ServerRequestInterface $request)
    {
        return $this->handler->handle($request);
    }

But my routes.php file now looks kinda ugly, having me thinking I’m doing something wrong.

return static function (Application $app): void
{
    $app->post('/', AppHandlerWebhookHandlerFactory::class);

My question is what is the more correct way to get my request data before handler initialization and which patterns I am better to use

How do you make Laravel Reverb work using Herd?

I can’t get Laravel Reverb and Echo to work, and I’m not sure how to debug it.
I ran through the default installation and just tried to get a simple message to pass to a page.

Here’s my Event:

class TestEvent implements ShouldBroadcastNow
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    public string $message;

    public function __construct(string $message)
    {
        $this->message = $message;
    }

    public function broadcastOn()
    {
        return [new Channel('test-channel')];
    }
}

Here’s the Artisan command to dispatch it:

public function handle()
    {
        TestEvent::dispatch('This is a test');
    }

This is the view:

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Echo?</title>
    @vite(['resources/css/app.css', 'resources/js/app.js'])
</head>
<body>
<h1>Echo?</h1>

<script>
    Echo.channel('test-channel')
        .listen('TestEvent', (e) => {
            console.log('TestEvent resp...');
            console.log(e);
        });
</script>
</body>
</html>

The Echo js file hasn’t been touched:

window.Echo = new Echo({
    broadcaster: 'reverb',
    key: import.meta.env.VITE_REVERB_APP_KEY,
    wsHost: import.meta.env.VITE_REVERB_HOST,
    wsPort: import.meta.env.VITE_REVERB_PORT ?? 80,
    wssPort: import.meta.env.VITE_REVERB_PORT ?? 443,
    forceTLS: (import.meta.env.VITE_REVERB_SCHEME ?? 'https') === 'https',
    enabledTransports: ['ws', 'wss'],
});

and Reverb added all the .env values, and I haven’t touched those.

So, I figured all I had to do was run npm run dev, start the Reverb server, trigger the event, and I should see the console.log output. But nothing. Eventually I get a ‘websocket failed to connect’ error.

I’m using Herd for development, but didn’t think that would make any difference, since everything is running through localhost. I even checked to make sure port 8080 wasn’t being used, and nothing there.

Does anyone have any idea what could be wrong? Or how I can debug it?

How do you rename a module using nwidart package?

I’m using the nwidart/laravel-modules packages to setup modular structure for my Laravel project, and I have a module named Company that I want to rename into Facility but I’m not exactly sure about the required steps, and the documentation doesn’t mention the required steps to do this.

Print just the values with SimpleXMLElement

I’m pulling data in from an xml file and it’s printing more than the values. I just want the values.
I’m using this code

<?php
$url = 'site.com';

$result = file_get_contents($url, false);
if ($result === false) {
    /* Handle error */
}
 $output = $result;
 $xml = simplexml_load_string($output);?>

<pre><?php echo print_r($xml);?></pre>
Gives me this:

     SimpleXMLElement Object
(
    [@attributes] => Array
        (
            [returnVersion] => 2022v5.0
        )
    [ReturnHeader]
    [ReturnData] => SimpleXMLElement Object
            [FromForm] => SimpleXMLElement Object

                    [DataGrp]
                            [DataGrpPerson] => Array
                                (
                                    [0] => SimpleXMLElement Object
                                        (
                                            [PersonNm] => Joan Jett
                                            [USAddress] => SimpleXMLElement Object
                                                (
                                                    [AddressLine1Txt] => 0 EAST Main STREET
                                                    [CityNm] => CITY NAME
                                                    [StateAbbreviationCd] => STATE NAME
                                                    [ZIPCd] => ZIP NUMBER
                                                )

                                            [TitleTxt] => POSTION TITLE

                                        )
                                    [1] => SimpleXMLElement Object
                                        (
                                            PersonNm] => Tom Petty
                                            [USAddress] => SimpleXMLElement Object
                                                (
                                                    [AddressLine1Txt] => 1 EAST Main STREET
                                                    [CityNm] => CITY NAME
                                                    [StateAbbreviationCd] => STATE NAME
                                                    [ZIPCd] => ZIP NUMBER
                                                )

                                            [TitleTxt] => POSTION TITLE
                                        )

                                    [2] => SimpleXMLElement Object
                                        (
                                            PersonNm] => Brandi Carlile
                                            [USAddress] => SimpleXMLElement Object
                                                (
                                                    [AddressLine1Txt] => 2 EAST Main STREET
                                                    [CityNm] => CITY NAME
                                                    [StateAbbreviationCd] => STATE NAME
                                                    [ZIPCd] => ZIP NUMBER
                                        )

                                

)
This is the Html I am using to display the data

<?php foreach ($xml->ReturnData->FromForm->DataGrp]->DataGrpPerson[0]->PersonNm as $item) {
    echo print_r($item);}?>, <?php foreach ($xml->ReturnData->FromForm->DataGrp]->DataGrpPerson[0]->TitleTxt as $item) {
    echo print_r($item);}?>

Here’s the output (just the names and title)

SimpleXMLElement Object ( [0] => Joan Jett ) 1, SimpleXMLElement Object ( [0] => POSTION TITLE ) 1
SimpleXMLElement Object ( [0] => S Tom Petty ) 1, SimpleXMLElement Object ( [0] => POSTION TITLE ) 1
SimpleXMLElement Object ( [0] => Brandi Carlile ) 1, SimpleXMLElement Object ( [0] => POSTION TITLE ) 

How can I get just the values?

I’ve combed through stackoverflow for days. I cannot find anyone describing this problem

Facebook: getting page information in php api – permissions granted

Ok, we have an app, many of our customers are using it. The app requests access to the FB users’ pages, in order to make posts to the page. Our app is using Facebook Login for Business, and so has to use a “Configuration” to request access. In that configuration, I am asking for:

email
public_profilepages_show_list
pages_read_engagement
pages_manage_posts
business_management (added recently)

I need to get a list of the pages “under” the Facebook account that they are giving me access to. I am using the PHP API, and making the request:

https://graph.facebook.com/v20.0/me/accounts/?access_token=<access token>

Most of the time, I am getting the list of pages just fine. But for some accounts, I get no pages. An example page is https://www.facebook.com/thomas.mcgroder. Now, when I click on the house icon to get to his Home page I see that there is a page under “Your Pages and profiles”. Why can’t I see it? Also, when I run through the Facebook Log In, I don’t seem to get any questions related to the business_management permissions. I am at a loss here – from my reading, I don’t get the list of pages because that permission is not in the access token, but I don’t see how to get that permission inserted into the Log In process. This has been driving me crazy for weeks now.

One additional thing. My customer allowed me to log into his account for this testing. When I use my own personal account, during the Facebook Log In, on the page where I can review the access request, I see one extra section that starts with:

This integration enables <my app> to establish a connection with your business portfolio(s)

This does not always show up,and I don’t understand why. I suspect that is the core problem.

What hook to use for bulk action on WooCommerce orders with HPOS [duplicate]

In Woocommerce 8.0.1 by adding the bottom code to functions.php of my theme I can add my bulk actions to Woocommerce order page:

add_filter( 'bulk_actions-edit-shop_order', 'register_custom_bulk_action' );
function register_custom_bulk_action( $bulk_actions ) {
    $bulk_actions['action_1'] = __( 'action 1', 'woocommerce' );
    $bulk_actions['action_2'] = __( 'action 2', 'woocommerce' );
    return $bulk_actions;
}

But the same code on a fresh install of Woocommerce 9.3.3 doesn’t add my actions.
I tested on a fresh install of 8.0.1 and then updated it to version 9.3.3 and it worked after update.
Am I doing something wrong or this is an internal bug of Woocommerce?