Base glyph is incorrect when parsing ligature components with PHP php-font-lib fork [closed]

I’m trying to parse ligature components to Unicode mapping in PHP using my own fork of php-font-lib which implements gsub table parsing. The official library doesn’t support this yet.

I’m using it with the Material Icons Font.
According to Fontdrop, the font contains all necessary ligature and GSUB data:
Fontdrop ligature parse image

The output I am trying to achieve should follow this pattern:

[
"fire_extinguisher": "uniF1D8",
]

However with my current script (You can find the code below), I get an output like this:

2ire_extinguisher -> 

The base glyph is wrong or sometimes missing entirely:

oom_in -> 
2ont_download_off -> 

Steps to reproduce:

1.) Clone my fork:

git clone https://github.com/NLion74/php-font-lib
cd php-font-lib
touch reproduction_example.php

1.) Add this code to reproduction_example.php

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

$fontPath = "../MaterialIcons-Regular.ttf";
if (!file_exists($fontPath)) die("Font not found");

$font = Font::load($fontPath);
$font->parse();

$cmap = $font->getData("cmap")['subtables'][0]['glyphIndexArray'] ?? [];
$glyphIDtoChar = [];
foreach ($cmap as $unicode => $gid) {
    if ($gid !== 0) $glyphIDtoChar[$gid] = mb_chr($unicode, 'UTF-8');
}

$gsub = $font->getData("GSUB");
$ligatureMap = [];

foreach ($gsub['lookupList']['lookups'] as $lookup) {
    if ($lookup['lookupType'] !== 4) continue;
    foreach ($lookup['subtables'] as $subtable) {
        if (!isset($subtable['ligSets'])) continue;

        $leadingChars = [];
        if (!empty($subtable['coverage']['rangeRecords'])) {
            foreach ($subtable['coverage']['rangeRecords'] as $range) {
                for ($gid = $range['start']; $gid <= $range['end']; $gid++) {
                    $leadingChars[] = $glyphIDtoChar[$gid];
                }
            }
        }
        if (!empty($subtable['coverageGlyphs'])) {
            foreach ($subtable['coverageGlyphs'] as $gid) {
                $leadingChars[] = $glyphIDtoChar[$gid];
            }
        }

        foreach ($subtable['ligSets'] as $index => $ligSet) {
            $baseGlyph = $leadingChars[$index];
            foreach ($ligSet['ligatures'] as $lig) {
                $components = array_map(fn($gid) => $glyphIDtoChar[$gid], $lig['components']);
                array_unshift($components, $baseGlyph);
                $seqStr = implode('', $components);
                $ligatureGlyph = $glyphIDtoChar[$lig['ligatureGlyph']];
                $ligatureMap[$seqStr] = $ligatureGlyph;
            }
        }
    }
}

foreach ($ligatureMap as $seq => $lig) {
    echo "$seq -> $lign";
}

3.) Run:

composer install
php reproduction_example.php

Expected behavior:

  • The base glyph plus components map correctly to the ligature glyph.

Actual behavior:

  • The base glyph seems to be entirely wrong

Question:

  • How can I correctly extract the base glyph for each ligature set when parsing the GSUB table in PHP?

Email link open [closed]

I built a web view mobile app. After the app has been installed on a mobile phone, whenever a password reset link is sent to a user email to reset password, the link proceeds to open on a web browser instead of popping out and option for the link to be open in app. I used phpmailer to send the message with the following code

$message = "Hi Adeyemi <p>We received a request to reset the password for your account. You can reset your password by clicking the link below:</p><p>https://investwithbth.com/app/reset-password.php?token=78uiyt65redfty78iuhj</p><p>If you didn’t request a password reset, you can safely ignore this email, no changes have been made to your account.</p><p>If you have any questions or need further assistance, feel free to contact our support team.</p><p>Thanks</p>";

Telegram API (check likes) [closed]

Is there a way to check if a person liked a post? as “mandatory subscription to the channel”
On Python or PHP, you need a tg bot. or leave ideas

I haven’t tried anything yet. Is it possible without complicated options?

How to edit a running WordPress site that isnt mine with Php Storm? [closed]

Currently I am a person who is studying I have coded websites with WebStorm but a person has asked me to do edits on their website. I have received admin access but I need to find a way to get the WordPress website into either Php Storm or WebStorm as those are the 2 I know best and know how to edit efficiently. I am unable to find any way to do this. Is anyone able to assist me.

I have tried plugins to download it as a zipfile.
I have tried to understand how it works but it seems all of them need me to have access to the local machine that the person has made the website from. I am unable to get access to it and I wont lie I am still a student who is still trying to understand these mechanics. I have also asked lecturers and they where unable to assist me in any way.

Deployer setup with vps bare repo [closed]

I need some help, for the past 3-4 days I tryed everything, nothing works.

Setup deployer / symfony app inside vps.
I delete /domain/public_html/.dep/repo

Set deployer repository :

  1. deploy@aliasname:/path, I get this : ssh: Could not resolve hostname Temporary failure in name resolution fatal: Could not read from remote repository.
  2. deploy@ip:/path, I get this : Permission denied (publickey).fatal: Could not read from remote repository.
  3. file:///path : deploy succes but site has 500 error. I have to sudo chown -R phpUser:phpUserGroup on /var/www/domain so the site works. Then, redo deploy, and it fails with this error :
    error in update_code.php on line 100:
    [vps] run cd /var/www/domain.com/public_html/.dep/repo && (/usr/bin/git config –get remote.origin.url)
    [vps] exit code 1 (General error) . ERROR: Task deploy:update_code failed!

repo is set to vps inside /home/deployer/repo/domain.git
I can ssh with deployer no problem (with the aliasname)
remote is set to aliasname:/path-to-git-repo
ubuntu / nginx

any other information needed I will provide.

Best regards !

Failing to upload images via api endpoint in php

I’m building a bulk upload feature in WordPress for WooCommerce. The challenge I’m facing is with importing product images.

The image data comes from a CSV file, where each row represents a product.

The images column contains one or more image filenames, separated by a pipe (|) character (e.g., image1.jpg|image2.jpg).

These images are included in a ZIP folder uploaded alongside the CSV.

The goal is to match each filename in the CSV with its corresponding file from the ZIP, then upload and attach those images to the WooCommerce product.

Below is the function that processes the CSV and creates products. I’d appreciate help refining this code to better handle the image import logic and ensure best practices.

public function bulkUpload($csvBase64,$bId)
            {
            // Accept CSV as base64 string from POST body
            $csvBase64 = isset($_POST['csvBase64']) ? $_POST['csvBase64'] : null;
            $imagesDir = func_num_args() > 2 ? func_get_arg(2) : null;

            if (!$csvBase64) {
            return [
                'success' => false,
                'message' => 'No CSV file provided',
                'code'    => 400,
                'data'    => [],
            ];
           }

            // Decode base64
           $csvData = base64_decode($csvBase64);
            if ($csvData === false) {
            return [
                'success' => false,
                'message' => 'Failed to decode CSV',
                'code'    => 400,
                'data'    => [],
            ];
        }

        
        $rows = array_map('str_getcsv', preg_split('/rn|n|r/', $csvData));
        

        if (count($rows) < 2) {
            return [
                'success' => false,
                'message' => 'CSV must have at least one data row',
                'code'    => 400,
                'data'    => [],
            ];
        }

        $header = array_map('trim', $rows[0]);
        $productsCreated = [];
        $errors = [];
        for ($i = 1; $i < count($rows); $i++) {
            $row = $rows[$i];
            if (count($row) < count($header)) {
                continue; // skip incomplete rows
            }
            $data = array_combine($header, $row);
            error_log("BulkUpload row $i images: " . (isset($data['images']) ? $data['images'] : 'NONE'));
            // Required fields: title, price
            $title = isset($data['title']) ? sanitize_text_field($data['title']) : '';
            $regularPrice = isset($data['regular_price']) ? $data['regular_price'] : '';
            $salePrice = isset($data['sale_price']) ? $data['sale_price'] : '';
            $description = isset($data['description']) ? sanitize_text_field($data['description']) : '';
            $condition = isset($data['condition']) ? sanitize_text_field($data['condition']) : '';
            $categories = isset($data['categories']) ? explode('|', $data['categories']) : [];
            $post_status = isset($data['post_status']) ? sanitize_text_field($data['post_status']) : '';
            $availability = isset($data['availability']) ? sanitize_text_field($data['availability']) : '';
            $quantity   = isset($data['quantity']) ? $data['quantity'] : 0;
            $backOrders   = isset($data['backOrders']) ? $data['backOrders'] : 0;

            $product = new WC_Product_Simple();
            $product->set_name($title);
            $product->set_description($description);
            $product->set_status('publish');

            if ($availability === false) {
                $product->set_stock_status('outofstock');
            } else {
                $product->set_stock_status('instock');
            }

            $post_data = [
                'post_author' => get_current_user_id(),
                'post_title'  => $title,
                'post_type'   => 'product',
                'post_status' => 'publish',
            ];

            $product->set_stock_quantity((int)$quantity);
            $product->set_backorders($backOrders);
            $product->set_manage_stock(true);
            $post_id = wp_insert_post($post_data);
            $product->set_id($post_id);
            if (!empty($categories)) {
                $product->set_category_ids($categories);
            }

            $product->set_sale_price($salePrice);
            $product->set_regular_price($regularPrice);

            $productId = $product->save();
            update_post_meta($productId, 'bID', $bId);
            update_post_meta($productId, '_condition', $condition);
            $productsCreated[] = $productId;

            // Handle attribute_name_X and new_attribute_name_X pairs
            $attributesArray = [];
            foreach ($data as $key => $value) {
                if (preg_match('/^(attribute_name_|new_attribute_name_)(d+)$/', $key, $matches)) {
                    $index = $matches[2];
                    $attrName = sanitize_text_field($value);
                    $attrValueKey1 = 'attribute_value_' . $index;
                    $attrValueKey2 = 'new_attribute_value_' . $index;
                    if (isset($data[$attrValueKey1])) {
                        $attrValue = sanitize_text_field($data[$attrValueKey1]);
                    } elseif (isset($data[$attrValueKey2])) {
                        $attrValue = sanitize_text_field($data[$attrValueKey2]);
                    } else {
                        continue;
                    }
                    $attributesArray[] = [
                        'name' => $attrName,
                        'value' => $attrValue,
                    ];
                }
            }

            // Set all attributes at once
            $attributes = [];
            foreach ($attributesArray as $attribute) {
                $taxonomy     = sanitize_title($attribute['name']);
                $attributeObj = new WC_Product_Attribute();
                $attributeObj->set_name($taxonomy);
                $attributeObj->set_position(0);
                $attributeObj->set_options([$attribute['value']]);
                $attributeObj->set_visible(true);
                $attributeObj->set_variation(false);
                $attributes[$taxonomy] = $attributeObj;
            }
            if (!empty($attributes)) {
                $product->set_attributes($attributes);
                $product->save();
            }
            // Handle images from zip
            if ($imagesDir && isset($data['images']) && !empty($data['images'])) {
                $imageFiles = explode('|', $data['images']); // e.g. "img1.jpg|img2.png
                $images = [];
                foreach ($imageFiles as $fileName) {
                    $filePath = $imagesDir . '/' . trim($fileName);
                    if (file_exists($filePath)) {
                        $base64 = 'data:image/' . pathinfo($filePath, PATHINFO_EXTENSION) . ';base64,' . base64_encode(file_get_contents($filePath));
                        $images[] = ['url' => $base64];
                    }
                }
                if (!empty($images)) {
                    $this->uploadImages($images, $productId, true);
                }
              }
           }

            return [
            'success' => true,
            'message' => 'Bulk upload completed',
            'code'    => 200,
            'data'    => [
                'products' => $productsCreated,
                'errors'   => $errors,
                 ],
               ];
           }

How to start Selenium standalone server from a PHP script?

In my PHP script I am using php-webdriver library with Edge webdriver to get data from a web page and I need to start Selenium standalone server from the script. I copied selenium-server-4.35.0.jar, msedgedriver.exe and NodeWebDriver.json to the current user directory C:Userspnfst, and also created 2 bat files for running hab and for running node: selenium-server-hub.bat and selenium-server-node.bat respectively.

NodeWebDriver.json

{
  "capabilities": [
    {
      "browserName": "MicrosoftEdge",
      "maxInstances": 5,
      "seleniumProtocol": "WebDriver",
      "platform": "WINDOWS"
    },
    {
      "browserName": "firefox",
      "maxInstances": 5,
      "seleniumProtocol": "WebDriver",
      "platform": "WINDOWS"
    },
    {
      "browserName": "chrome",
      "maxInstances": 5,
      "seleniumProtocol": "WebDriver",
      "platform": "WINDOWS"
    },
    {
      "browserName": "internet explorer",
      "maxInstances": 1,
      "seleniumProtocol": "WebDriver",
      "platform": "WINDOWS"
    }
  ],
  "proxy": "org.openqa.grid.selenium.proxy.DefaultRemoteProxy",
  "maxSession": 5,
  "port": 5555,
  "register": true,
  "registerCycle": 5000,
  "hub": "http://Администратор:[email protected]:4444",
  "nodeStatusCheckTimeout": 5000,
  "nodePolling": 5000,
  "role": "node",
  "unregisterIfStillDownAfter": 60000,
  "downPollingLimit": 2,
  "debug": false,
  "servlets": [],
  "withoutServlets": [],
  "custom": {}
}

selenium-server-hub.bat

java -Dwebdriver.edge.driver=msedgedriver.exe -jar ".selenium-server-4.35.0.jar" hub

selenium-server-node.bat

java -Dwebdriver.edge.driver=msedgedriver.exe -jar ".selenium-server-4.35.0.jar" node --config ".NodeWebDriver.json"

Then I tried to start Selenium standalone server from PHP using exec as follows.

Variant 1

$hubCommand = 'C:\Program Files\Java\jdk-24\bin\java.exe -jar "C:\Users\pnfst\selenium-server-4.35.0.jar" hub 2>&1 &';
$nodeCommand = 'C:\Program Files\Java\jdk-24\bin\java.exe -Dwebdriver.edge.driver=C:\Users\pnfst\msedgedriver.exe -jar "C:\Users\pnfst\selenium-server-4.35.0.jar" node --config "C:\Users\pnfst\NodeWebDriver.json" 2>&1 &';
$hubResult = exec($hubCommand, $hubOutput, $hubResult_code);    // start hab
$nodeResult = exec($nodeCommand, $nodeOutput, $nodeResult_code);    // start node

Variant 2

$psHubCommand = 'Start-Process -FilePath "C:\Program Files\Java\jdk-24\bin\java.exe" -ArgumentList "-jar", "selenium-server-4.35.0.jar", "hub" -WorkingDirectory "C:\Users\pnfst" -Verb RunAs';
$psNodeCommand = 'Start-Process -FilePath "C:\Program Files\Java\jdk-24\bin\java.exe" -ArgumentList "-Dwebdriver.edge.driver=msedgedriver.exe", "-jar", "selenium-server-4.35.0.jar", "node", "--config", ".\NodeWebDriver.json" -WorkingDirectory "C:\Users\pnfst" -Verb RunAs';
$hubCommand = "powershell.exe -NonInteractive -NoProfile -ExecutionPolicy Bypass -Command " . escapeshellarg($psHubCommand) . " 2>&1 &";
$nodeCommand = "powershell.exe -NonInteractive -NoProfile -ExecutionPolicy Bypass -Command " . escapeshellarg($psNodeCommand) . " 2>&1 &";
$hubResult = exec($hubCommand, $hubOutput, $hubResult_code);    // start hab
$nodeResult = exec($nodeCommand, $nodeOutput, $nodeResult_code);    // start node

Variant 3

$psHubCommand = 'Start-Process -FilePath "C:\Windows\system32\cmd.exe" -ArgumentList "/c", "C:\Users\pnfst\selenium-server-hub.bat" -WorkingDirectory "C:\Users\pnfst" -Verb RunAs';
$psNodeCommand = 'Start-Process -FilePath "C:\Windows\system32\cmd.exe" -ArgumentList "/c", "C:\Users\pnfst\selenium-server-node.bat" -WorkingDirectory "C:\Users\pnfst" -Verb RunAs';
$hubCommand = "powershell.exe -NonInteractive -NoProfile -ExecutionPolicy Bypass -Command " . escapeshellarg($psHubCommand) . " 2>&1 &";
$nodeCommand = "powershell.exe -NonInteractive -NoProfile -ExecutionPolicy Bypass -Command " . escapeshellarg($psNodeCommand) . " 2>&1 &";
$hubResult = exec($hubCommand, $hubOutput, $hubResult_code);    // start hab
$nodeResult = exec($nodeCommand, $nodeOutput, $nodeResult_code);    // start node

All variants return result code 0 and don’t start hab and node. Variant 2 throws with PowerShell MissingArgument (hub command) and PositionalParameterNotFound (node command) exceptions.
How to properly start a Selenium standalone server from PHP?

Upload multiple files when placing a WooCommerce order

I am using a code that adds a file upload field on the checkout page. How to add file upload to WooCommerce checkout? Many thanks to @LoicTheAztec for this code.

I have created the files checkout_uploads.php, checkout_upload.js and added the code to functions.php a child theme.

add_action( 'woocommerce_after_order_notes', 'add_custom_checkout_field' );
function add_custom_checkout_field($checkout) {

    echo '<div class="woocommerce-additional-fields__field-wrapper">';

    woocommerce_form_field('certificate', array(
        'type'      => 'file',
        'class'     => array('form-row-wide'),
        'label'     => __('File', 'woocommerce'),
        'required'  => false,
        'max_size'  => '2048',
        'accept'    => '.pdf,.doc,.docx,.rtf,.txt',
    ), '');

    echo '</div>';
}

// Save the uploaded file URL and name
add_action( 'woocommerce_checkout_create_order', 'save_checkout_uploaded_file', 10, 2 );
function save_checkout_uploaded_file( $order, $data ){
    if( $checkout_upload = WC()->session->get('checkout_upload') ) {
        $order->update_meta_data( '_checkout_upload', $checkout_upload ); 
    }
    WC()->session->__unset('checkout_upload');
}

// Display the uploaded file in admin orders
add_action('woocommerce_admin_order_data_after_billing_address', 'display_uploaded_file_in_admin_orders');
function display_uploaded_file_in_admin_orders( $order ){
    if( $checkout_upload = $order->get_meta( '_checkout_upload' ) ) {
        printf( '<p>%s <br><a href="%s">%s</a></p>', 
            __("File Uploaded:", 'woocommerce'), 
            $checkout_upload['file_url'], 
            $checkout_upload['file_name'] 
        );
    }
}

// Display the uploaded file in thankyou page
add_action('woocommerce_order_details_after_order_table', 'display_uploaded_file_in_thankyou');
function display_uploaded_file_in_thankyou ( $order ){
    if( $checkout_upload = $order->get_meta( '_checkout_upload' ) ) {
        printf( '<p>%s <br><a href="%s">%s</a></p>', 
            __("File Uploaded:", 'woocommerce'), 
            $checkout_upload['file_url'], 
            $checkout_upload['file_name'] 
        );
    }
}

// Display the uploaded file in emails
add_action('woocommerce_email_customer_details', 'display_uploaded_file_in_email');
function display_uploaded_file_in_email ( $order ){
    if( $checkout_upload = $order->get_meta( '_checkout_upload' ) ) {
        printf( '<p>%s <a href="%s">%s</a></p>', 
            __("File Uploaded:", 'woocommerce'), 
            $checkout_upload['file_url'], 
            $checkout_upload['file_name'] 
        );
    }
}

Only one file can be uploaded at the moment. How can I upload multiple files at the same time? I will be glad of your help!

Getting my Filtrable class to work as it should [closed]

I writing a reusable Filtrable trait for laravel projects. I have it working but not perfectly. One part work perfectly why another part not giving expected results

I writing a reusable Filtrable trait for laravel projects. I have it working but not perfectly.
This is my Fliterable trait code

namespace ObrainwaveLaravelQueryFilters;

use IlluminateDatabaseEloquentBuilder;
use IlluminateHttpRequest;

trait Filterable
{
    public function scopeFilter(Builder $query, Request | array | null $filters =     null) : QueryFilter
    {
        $filterClass = $this->getFilterClass();

        if (! class_exists($filterClass)) {
            return $query;
        }

        $filter = (new $filterClass($filters))
            ->setBuilder($query)
            ->apply(); // automatically apply request/array filters

        return $filter; // Now you can chain ->status(...)->role(...)->get()
    }

    protected function getFilterClass(): string
    {
        return str_replace('Models', 'Filters', static::class) . 'Filter';
    }
}

and this is my QueryFilter class code

namespace ObrainwaveLaravelQueryFilters;

use IlluminateDatabaseEloquentBuilder;
use IlluminateHttpRequest;

abstract class QueryFilter
{
    protected Builder|null $builder = null;
    protected array $filters = [];

/**
 * Accept request or array of filters
 */
    public function __construct(Request|array|null $filters = null)
   {
        if ($filters instanceof Request) {
            $this->filters = $filters->all();
        } elseif (is_array($filters)) {
            $this->filters = $filters;
        }
    }

/**
 * Set the query builder instance
 */
    public function setBuilder(Builder $builder): static
    {
        $this->builder = $builder;
        return $this;
    }

/**
 * Apply the filters to the builder
 */
    public function apply(): static
    {
        if (! $this->builder) {
           throw new Exception("Query builder is not set. Call setBuilder() first.");
        }

        foreach ($this->filters as $key => $value) {
            if ($value !== null && method_exists($this, $key)) {
                $this->$key($value);
            }
        }

        return $this;
    }

/**
 * Return the underlying builder for final query
 */
    public function get()
    {
        return $this->builder->get();
    }

    public function first()
    {
        return $this->builder->first();
    }

    public function toSql()
   {
        return $this->builder->toSql();
    }
}

So my problem is that it works when I passed the chaining methods

$users2 = User::filter(['status' => 'inactive', 'role' => 'admin'])
        ->status('inactive')
        ->role('admin')
        ->get();

But it returns all rows when I do this
$users1 = User::filter(request())->get();
which means it doesn’t apply the default filtering

I hope anyone can help me spotting my mistakes.

WordPress – Counter button – Get value from db – display counter value – increment – and update DB [closed]

In a WordPress projet, let say I want my users to click on a button when they aggree with a sentence such as :
If you like pancakes click here <button> YES I DO </button>

Let say I want to display the number of clicks such as :
<nb_click> have allready say yes

Question 1 :
Is there a plugin that does this ?

Question 2 :
I tried to do it with a code snippet (php/javascript ; Elementor short code widget): But I am facing a probleme with the execution evironnement.

PROBLEM : The php code is executed as soon as the web page loads. It looks like the execution environnement had removed the javascript code to execute only php tags. And when the user click on the button, the javascript code is executed (as if it had reappeared). The function counter_increment_and_update_db() is well triggered, but the php code is not executed.

at the end, the incremented value of the counter is always inserted into the database, no matter the button was clicked or not

<?php
    $current_counter_value = get_counter_value_from_db();    
?>

<button onclick="counter_increment_and_update_db()"> OUI </button>
<span id="counting"></span> 

<script>
    html_display_curent_counter_value(<?php echo $current_counter_value; ?>)
    function counter_increment_and_update_db() {
        <?php
            $incremented_value = increment_by_one($current_counter_value);
        ?>
        html_display_curent_counter_value(<?php echo $incremented_value; ?>)
        <?php
            update_db_counter_value($incremented_value);
        ?>
    }
    // -----------------            javascript UTIL FUNCTIONS        ----------------
    function html_display_curent_counter_value(text_to_be_displayed){
        document.getElementById("counting").innerText = text_to_be_displayed;
    }
</script>

<?php
    // --------------------------------------------------------------------
    // -----------------            php UTIL FUNCTIONS        ----------------
    // --------------------------------------------------------------------
    function increment_by_one($value){
        $out=$value+1;
        return $out;
    }
    function get_counter_value_from_db(){
        global $wpdb;
        $wpdb->show_errors();
        $query = "SELECT * FROM click_counter WHERE counter_name = 'sondage1'";
        $resultArray = $wpdb->get_results($query);
        $current_counter_value = get_last_value($resultArray);
        return $current_counter_value;
    }
    function get_last_value($array_of_values){
        $out=0;
        foreach ($array_of_values as $page) {
                $out = $page->counter_value;
        }
        return $out;
    }
    function update_db_counter_value($new_value) {
        global $wpdb;
        $wpdb->show_errors(); 
        $wpdb->update(
            'click_counter',
            array(
                'counter_value' => $new_value   
            ),
            array(
                'counter_name' => 'sondage1'
            ), 
            array( 
                '%d' 
            )
        );
    }
?>

Shuffle a list and keep the repeated values distant [closed]

I have a list of competitors and their respective horses, with each competitor identified by a unique ID, and competitors may be associated with different horses. I need to shuffle the list in such a way that the same competitor does not appear consecutively, ideally maintaining a minimum distance of 5 competitors between repetitions.

Do I need to apply this logic directly in the select query or through PHP.

I considered separating the items into groups and shuffling them, but there is a possibility that an item could be the last of one group and the first of another, causing them to be close together. However, the client requested that the order be shuffled, but items with the same ID cannot be close to each other, ideally with a distance of at least 5 competitors between them.

Why can’t I create a category as an administrator?

Laravel API Redirects to Login Route Despite Valid Bearer Token
I’ve created a REST API with Laravel 12 and I’m using Sanctum for authentication. My routes are defined in the api.php file.

When I try to access an authenticated route from an administrator account using Postman, the request is unexpectedly redirected to the named login route, and I receive the following error:

Missing required parameter for [Route: login] [URI: api/login/{type}] [Missing parameter: type]
*
I am sending a POST request to the following endpoint: /api/administrateur/categories.

I have confirmed that I am including a valid Bearer Token from a successful administrator login in my request headers. The token is valid and should grant me access to the authenticated routes. I believe the issue lies within the Sanctum authentication middleware, as the application seems to be failing to recognize my token and instead redirects me to the login route.

Here is my api.php file for reference:

<?php

use IlluminateHttpRequest;
use IlluminateSupportFacadesRoute;
use AppHttpControllersAuthentificationController;
use AppHttpControllersClientController;
use AppHttpControllersEntrepriseController;
use AppHttpControllersAdministrateurController;
use AppHttpControllersProduitController;
use AppHttpControllersDevisController;
use AppHttpControllersCommentaireController;
use AppHttpControllersCategorieController;


Route::post('/register', [AuthentificationController::class, 'register']);
Route::post('/login/{type}', [AuthentificationController::class, 'login'])->name('login');

Route::get('/categories', [CategorieController::class, 'index']);
Route::get('/categories/{id}', [CategorieController::class, 'show']);
Route::get('/produits', [ProduitController::class, 'index']);
Route::get('/produits/{id}', [ProduitController::class, 'show']);
Route::get('/entreprises', [EntrepriseController::class, 'index']);
Route::get('/entreprises/{id}', [EntrepriseController::class, 'show']);


Route::middleware('auth:sanctum')->group(function () {
    Route::post('/logout', [AuthentificationController::class, 'logout']);

    Route::prefix('client')->middleware('authentification.type:client')->group(function () {
        Route::get('/profile', [ClientController::class, 'showProfile']);
        Route::put('/profile', [ClientController::class, 'updateProfile']);
        
        Route::get('/commentaires', [CommentaireController::class, 'index']);
        Route::post('/commentaires', [CommentaireController::class, 'store']);
        Route::get('/commentaires/{commentaire}', [CommentaireController::class, 'show']);
        Route::put('/commentaires/{commentaire}', [CommentaireController::class, 'update']);
        Route::delete('/commentaires/{commentaire}', [CommentaireController::class, 'destroy']);
        
        Route::get('/devis', [DevisController::class, 'index']);
        Route::post('/devis', [DevisController::class, 'store']);
        Route::get('/devis/{devi}', [DevisController::class, 'show']);
        Route::put('/devis/{devi}', [DevisCont

type here

roller::class, 'update']);
        Route::delete('/devis/{devi}', [DevisController::class, 'destroy']);
    });

    Route::prefix('entreprise')->middleware('authentification.type:entreprise')->group(function () {
        Route::get('/profile', [EntrepriseController::class, 'showProfile']);
        Route::put('/profile', [EntrepriseController::class, 'updateProfile']);
        
        Route::post('/produits', [ProduitController::class, 'store']);
        Route::put('/produits/{produit}', [ProduitController::class, 'update']);
        Route::delete('/produits/{produit}', [ProduitController::class, 'destroy']);
        
        Route::put('/devis/{id}/statut', [DevisController::class, 'updateStatus']);
    });

    Route::prefix('administrateur')->middleware('authentification.type:administrateur')->group(function () {
        Route::get('/dashboard', [AdministrateurController::class, 'dashboardStats']);
        
        Route::post('/entreprises/{id}/valider', [AdministrateurController::class, 'validerEntreprise']);
        Route::post('/entreprises/{id}/refuser', [AdministrateurController::class, 'refuserEntreprise']);
        
        Route::post('/entreprises', [AdministrateurController::class, 'store']);
        Route::get('/entreprises', [AdministrateurController::class, 'indexEntreprises']);
        Route::put('/entreprises/{entreprise}', [AdministrateurController::class, 'update']);
        Route::delete('/entreprises/{entreprise}', [AdministrateurController::class, 'destroy']);
        Route::get('/entreprises/{id}', [AdministrateurController::class, 'show']);

        Route::post('/categories', [CategorieController::class, 'store'])->name('categories.store');
        Route::put('/categories/{categorie}', [CategorieController::class, 'update'])->name('categories.update');
        Route::delete('/categories/{categorie}', [CategorieController::class, 'destroy'])->name('categories.destroy');
    });
});

What could be causing this redirect to the login page, even with a valid token? How can I fix this

Test,body

Laravel Reverb Curl Exception on Laravel Herd

I keep getting this error below

GuzzleHttpExceptionRequestException: cURL error 1: Received HTTP/0.9 when not allowed (see https://curl.haxx.se/libcurl/c/libcurl-errors.html) for http://127.0.0.1:8080/apps/local/events?auth_key=local-key&auth_timestamp=1756475569&auth_version=1.0&body_md5=baf98ab9765fdd4ce6328183d1646a5a&auth_signature=2828b9b5b9db7af8f931e42c37b138a9456babfa1ae0df72cb5d395e03a05b40 in /Users/chris/Herd/utility.com/vendor/guzzlehttp/guzzle/src/Handler/CurlFactory.php:278

Below are my .env variables

REVERB_APP_ID=local
REVERB_APP_KEY=local-key
REVERB_APP_SECRET=local-secret
REVERB_PORT=443
REVERB_HOST=utility.com.test
REVERB_SCHEME=https

Why do I have missing p tags from acf wysiwyg field?

I’m using ACF in wordpress.

I created a field group named my_group that contains a WYSIWYG field called my_content. Then I created another field that clones my_group.

Inside a flexible content field, one of the layouts is a clone of my_group. When I output the WYSIWYG field (my_content) from the clone, the <p> tags are missing.

Actual:

This is some text
Another line of text

Expected:

<p>This is some text</p>
<p>Another line of text</p>

I can work around this by adding the the_content filter:

echo apply_filters('the_content', $my_content);

I understand that get_field() normally formats wysiwyg content, but here I’m pulling the field data from a flexible content field array:

$flexible_content = get_field('flexible_content');

foreach ($flexible_content as $row) {
    switch ($row['acf_fc_layout']) {
        case 'my_group':
            $my_group = $row['my_group'];
            $my_content = $row['my_content'];
            echo apply_filters('the_content', $my_content);
            // echo $my_content;
            break;
    }
}

Sometimes I do not see this behavior and it works fine when I use this method, but other times I get this unexpected behavior.

Why does the wysiwyg field inside a cloned group sometimes output without <p> tags? Is there a better way to handle it than using the_content filter?