How to understand that PHP.8 JIT is included in the docker image?

I’m a bit confused now, because after adding the JIT setting to the PHP config, when I disable the opcache_get_status()['jit'] function, I get the following output:
enter image description here

But after checking ini_get("opcache.jit") I have the following result:

enter image description here

Which in turn, based on this answer, means that JIT is active:

which is an integer (returned as string) where the last digit states the status of the JIT:

5 – optimized JIT based on static type inference and inner procedure analyses

I still think that my JIT is not active, although maybe there is an expert who will explain that this is not the case)) since the function itself is called, maybe XDebug is involved here because it is active for me, but these are more guesswork.

Dockerfile:

FROM php:8.1-fpm-alpine

ENV XDEBUG_VERSION 3.1.5

RUN apk add --update --no-cache icu-dev icu-libs icu-data-full git bash autoconf g++ make zlib-dev libzip-dev libpng-dev libwebp-dev freetype-dev libjpeg-turbo-dev 
    && git clone --branch $XDEBUG_VERSION --depth 1 https://github.com/xdebug/xdebug.git /usr/src/php/ext/xdebug 
    && docker-php-ext-configure xdebug --enable-xdebug-dev 
    && docker-php-ext-configure gd --enable-gd --with-freetype --with-jpeg --with-webp 
    && docker-php-ext-install intl pdo_mysql gd zip xdebug 
    && apk del git

RUN mv $PHP_INI_DIR/php.ini-development $PHP_INI_DIR/php.ini

# fix work iconv library with alphine
RUN apk add --no-cache --repository http://dl-cdn.alpinelinux.org/alpine/edge/community/ --allow-untrusted gnu-libiconv
ENV LD_PRELOAD /usr/lib/preloadable_libiconv.so php

COPY ./common/php/conf.d /usr/local/etc/php/conf.d
COPY ./development/php/conf.d /usr/local/etc/php/conf.d
COPY ./development/php-fpm/conf.d /usr/local/etc/php/conf.d

COPY ./development/php-fpm/entrypoint.sh /usr/local/bin/docker-php-entrypoint
RUN chmod +x /usr/local/bin/docker-php-entrypoint

WORKDIR /app

opcache.ini

zend_extension=opcache.so
opcache.enable=1
opcache.enable_cli=1
opcache.jit_buffer_size=128M
opcache.jit=1255

problems with laravel eloquent model

Im learning the MVC pattern using Laravel and the eloquent model is kinda overwhelming to me. The eloquent model returns a collection of collumns of a table, but i want to a collection of another table to be the attributes of that model.

I have 3 tables

Books
id,
title

Contribution
book_id,
contributor_id,
role

Author
id,
name

I want to change the return values of function like all(), find(), get() and etc of model Books to include the contributors

From this

[  "id" => "1", 
   "title" => "CS101" 
]

To this

[ "id" => "1",
  "title" => "CS101",
  "contributors" => [
   [
    "id" => "1",
    "name" => "Einstein"
    "role" => "author"
   ],
   [
    "id" => "2",
    "name" => "Thomas"
    "role" => "translator"
   ]
  ]
]

Should i not use Eloquent and build my own model or is there a function of eloquent that i can override or any better way to do this

Issue with deployment of a Laravel/Vite App with FTP

First of all, i just want to say that i’m a bit of a begginer when it comes to deployment of any kind of app on a Web cloud. Here’s my issue:

I have a Laravel 9 / Vitejs 4 app that i’m trying to deploy on an OVH Web cloud using only FTP. I used npm run build to build my app, and sent it to my cloud using FileZilla. Once in the cloud, i moved the index.php file from www/public to www and changed some line in it so it can refer to the correct files / folders.
But, and i don’t understand why, CSS won’t load and my login page appears as a pure HTML page. My css file (and js to) is in it’s own folder in www/public.

Here’s some files that could provide some clues:

app.blade.php :

<!doctype html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <!-- CSRF Token -->
    <meta name="csrf-token" content="{{ csrf_token() }}">

    <title>{{ config('app.name', 'Laravel') }}</title>

    <!-- Fonts -->
    <link rel="dns-prefetch" href="//fonts.gstatic.com">
    <link href="https://fonts.bunny.net/css?family=Nunito" rel="stylesheet">

    <!-- Scripts -->
    @vite(['public/css/style.css', 'public/js/app.js'])
</head>
<body>
    [...]
</body>

vite.config.js :

import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import vue from '@vitejs/plugin-vue';

export default defineConfig({
    plugins: [
        laravel({
            input: [
                'public/css/style.css',
                'public/js/app.js',
            ],
            refresh: true,
        }),
        vue({
            template: {
                transformAssetUrls: {
                    base: null,
                    includeAbsolute: false,
                },
            },
        }),
    ],
    resolve: {
        alias: {
            vue: 'vue/dist/vue.esm-bundler.js',
        },
    },
});

index.php :

<?php
 
use IlluminateContractsHttpKernel;
use IlluminateHttpRequest;
 
define('LARAVEL_START', microtime(true));
 
/*
|--------------------------------------------------------------------------
| Check If The Application Is Under Maintenance
|--------------------------------------------------------------------------
|
| If the application is in maintenance / demo mode via the "down" command
| we will load this file so that any pre-rendered content can be shown
| instead of starting the framework, which could cause an exception.
|
*/
 
if (file_exists($maintenance = __DIR__.'/storage/framework/maintenance.php')) {
    require $maintenance;
}
 
/*
|--------------------------------------------------------------------------
| Register The Auto Loader
|--------------------------------------------------------------------------
|
| Composer provides a convenient, automatically generated class loader for
| this application. We just need to utilize it! We'll simply require it
| into the script here so we don't need to manually load our classes.
|
*/
 
require __DIR__.'/vendor/autoload.php';
 
/*
|--------------------------------------------------------------------------
| Run The Application
|--------------------------------------------------------------------------
|
| Once we have the application, we can handle the incoming request using
| the application's HTTP kernel. Then, we will send the response back
| to this client's browser, allowing them to enjoy our application.
|
*/
 
$app = require_once __DIR__.'/bootstrap/app.php';
 
$kernel = $app->make(Kernel::class);
 
$response = $kernel->handle(
    $request = Request::capture()
)->send();
 
$kernel->terminate($request, $response);

Thanks in advance!

turn into dynamic data.I want to fectch data from rule_condition database under conditions. There 3 different data such as Silver, Gold Platinum

$ruleQuery = "SELECT dbc_loyalty_rules.rule_title 
      FROM dbc_loyalty_rules 
      INNER JOIN rule_condition ON dbc_loyalty_rules.id = rule_condition.rule_id 
      WHERE dbc_loyalty_rules.status = 'active' 
      AND (  rule_condition.conditions = '"rule_item":"Rank","rule_operator":"=","rule_value":"Silver"' 
      OR rule_condition.conditions NOT LIKE '%"rule_item":"Rank"%')";

connect amadeus selling platform API [closed]

we are travel agency we have account in selling platform in amadeus , we are going to develop the application , we need connect our account and booking from account over api ,there is any solution to access account over API.

we searched in amadaus website , all data about api not support selling platform

Shopware Plugin: Facing error while updating Shopware plugin 6.4 compatible with v6.5

I have a Shopware plugin that is not yet compatible with the recently released v6.5. I am facing errors in the index.js and temp.html.twig files located in the directory src/Administration/Resources/app/administration/src/app/component/temp.

My index.js file:

// import template from './temp-select.html.twig';

const { Component, Context } = Shopware;
const { EntityCollection, Criteria } = Shopware.Data;
const { types, get } = Shopware.Utils;

Component.extend('temp-select', 'sw-single-select', {

    inject: [
        'repositoryFactory'
    ],

    computed: {
        singleSelection: {
            get() {
                if(this.options && Array.isArray(this.options)){
                    return this.options.find(option => {
                        return this.getKey(option, this.valueProperty) === this.currentValue;
                    });
                }
                return false;
            },
        },
    },

    created() {

        this.lastValue = this.currentValue;
        this.loadOptions();
        this.loadValueName();

    },

    updated(){
        if(this.lastValue != this.currentValue){
            this.loadOptions();
            this.loadValueName();
            this.lastValue = this.currentValue;
        }
    },

    methods: {

        getRepository(){

            if(!this.repository){
                if (this.$attrs.name == 't_temp_google_id'){
                    this.repository = this.createRepository('t_temp_google');
                }else if (this.$attrs.name == 't_temp_facebook_id'){
                    this.repository = this.createRepository('t_temp_facebook');
                }else{
                    throw new Error('tanmar_taxonomy: unknown attr/repository name');
                }
            }
            return this.repository;
        },

        loadOptions(){

            const criteria = new Criteria();
            //criteria.setPage(1);
            //criteria.setLimit(10);

            criteria.addSorting(Criteria.sort('name', 'ASC', false));

            this.getRepository().search(criteria, Shopware.Context.api).then(res => {
                res.forEach(element => {
                    element.label = element.name;
                    element.value = element.tax_id;
                });
                this.options = res;
                this.results = this.options;
            });
        },

        loadValueName() {
            this.isExpanded = false;
            this.searchTerm = '';

            if(!!this.currentValue){

                this.isExpanded = true;
                this.searchTerm = this.currentValue;

                const getCriteria = new Criteria();
                getCriteria.addFilter(Criteria.equals('tax_id', this.currentValue));

                this.getRepository().search(getCriteria, Shopware.Context.api).then(res => {
                    res.forEach(element => {
                        element.label = element.name;
                        element.value = element.tax_id;

                        this.isExpanded = true;
                        this.searchTerm = element.label + ' (' + element.tax_id + ')';
                    });

                });
            }
        },

        createRepository(entity) {
            if (types.isUndefined(entity)) {
                throw new Error('sw-form-field-renderer - sw-entity-multi-id-select component needs entity property');
            }

            return this.repositoryFactory.create(entity);
        },

        setValue(item) {
            this.itemRecentlySelected = true;
            this.singleSelection = item;
            this.closeResultList();

            this.currentValue = item.tax_id;
            this.value = item.tax_id;

            this.isExpanded = true;
            this.searchTerm = item.label + ' (' + item.tax_id + ')';
        },

        search() {
            this.$emit('search', this.searchTerm);

            if (this.disableSearchFunction) {
                return;
            }

            const criteria = new Criteria();
            criteria.addFilter(
                Criteria.contains('name', this.searchTerm)
            );
            criteria.addSorting(Criteria.sort('name', 'ASC', false));

            this.getRepository().search(criteria, Shopware.Context.api).then(res => {
                res.forEach(element => {
                    element.label = element.name;
                    element.value = element.tax_id;
                });
                this.results = res;
                this.resetActiveItem();
            });

            this.$nextTick(() => {
                this.resetActiveItem();
            });
        },

        onSelectExpanded() {
            this.isExpanded = true;
            // Always start with a fresh list when opening the result list
            this.results = this.options;

            if(!this.results){
                this.loadOptions();
            }

            // Get the search text of the selected item as prefilled value
            this.searchTerm = this.tryGetSearchText(this.singleSelection);

            this.$nextTick(() => {
                this.resetActiveItem();
                this.$refs.swSelectInput.select();
                this.$refs.swSelectInput.focus();
            });

        },

    },

});

My temp.html.twig file:


{% block sw_single_select %}
    {% parent %}
{% endblock %}

Specifically, I’m getting the following errors:

  • The global variable “Shopware” is not declared
  • Expected indent but found this } const { types, get } = Shopware.Utils;

It seems like the necessary Shopware 6 objects are not being imported and initialized correctly.

Any help would be greatly appreciated.

Regards,

Microsoft OCR API with PHP

I am fairly new to PHP and I am trying to use the Microsoft OCR API. I already have my key and it is working as I have tested here: https://brazilsouth.dev.cognitive.microsoft.com/docs/services/unified-vision-apis-public-preview-2023-04-01-preview/operations/61d65934cd35050c20f73ab6/console.

So what I am trying to do is make a PHP API request. I cannot install any libraries to do this as it is a requirement for what I am doing. So I am trying to use the CURL and because of my newbieness in PHP don´t know if this is the best approach nor whats wrong with it.

The request the above mentioned webpage is as follow:
enter image description here

Here is the code that I have:

<?php
class Computer_Vision{

    public function __construct(){          
        $this->azure_ocr="https://brazilsouth.api.cognitive.microsoft.com/computervision/imageanalysis:analyze?api-version=2023-04-01-preview&features=read&language=pt HTTP/1.1";
        $this->subscription_key="blahblahblah";
    }
    
    public function recognize($image_url){

        $data = array("url" => $image_url);
        
        $azure_url = $this->azure_ocr;
        print($azure_url . "<br/>");
        
        $key=$this->subscription_key;
        $data_string = json_encode($data);
        print($data_string . "<br/>");
        
        $curl = curl_init($azure_url);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($curl, CURLOPT_POSTFIELDS, $data_string);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1 );
        curl_setopt($curl, CURLOPT_POST,           1 );
        curl_setopt($curl, CURLOPT_HTTPHEADER, array(
            'Content-Type: application/json',
            'Ocp-Apim-Subscription-Key:'.$key
        ));
        $response = curl_exec($curl);
        print("response: " . $response . "<br/>");
        
        
        if(curl_error($curl)) {
            print('error:' . curl_error($curl));
        } else {
            $json_object = json_decode($response, true);
            print("json_object: " . $json_object);
        }
        
        curl_close($curl);
    }
}
?>

on my index.php I have:

<?php 
    $azure = new Computer_Vision();
    $image_url = "https://portal.vision.cognitive.azure.com/dist/assets/OCR1-6dda571d.jpg";
    $ocr = $azure->recognize($image_url, "ocr");
?>

the code above doesn´t give me any errors (at least it does not enter the curl_error condition) but it gives me an empty response

what would be the best way to do this? what I am doing wrong? any help is more than appreciated .

why this cant save any data in my database?

hi guys im new anyone can help me
i cant save my input data in my database

i use ajax like this

$(document).ready(function(){
  $("#btn").click(function(){
   var name= $('#editor').val();
    $.ajax({
            type: 'post',
            url: "{{ route('sendcom') }}",
            data:{ name: name },
            headers: {
                'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
            },
        } );
  });
});

and i try use ckeditor5 so i have sendcom route and this is my box and button:

 <form action="{{ url('sendcom') }}" method="post">
                    @csrf
                    <textarea class="form-control" id="editor" name="editor"></textarea>
                    <input type="submit" id="btn" name="submit" value="Submit" />
                </form>

and i try to get my data in my controller like this

public function sendcom(Request $request){

        $content = $request->name;


        User::updateOrCreate([
            'contract' => $content
        ]);

        return response(['success' => 'contract save success.']);

    }

but its just refreshing my box and nothing hapend

Connect pgsql using PHP over web api don’t work

I have a web api script from pos system that works retriving data using a form and submit.

“select sum (antal*pris) from batch_salg where fakturadate = ‘2023-08-25’ “

fetch_from_table($serverurl,$db,$saldiuser,$api_key,$select,$from,$where,$order_by,$limit);

$serverurl="https://somedomain/pos/api";
$saldiuser = 'apiuser';
$db='posdb_9945864';
$api_key='dsdkfswaewmfmkev4546';

I have limited skils in an they are in Mysql, Im trying to get something like this to work

pg_connect(DB_HOST, DB_USER, DB_PASSWORD) or die(pg_error()); 
pg_select_db(DB_DATABASE) or die(pg_error()); 

$sho1_pg = pg_query("SELECT sum (antal*pris)  FROM batch_salg WHERE fakturadate ='$date_today'")
or die(pg_error());  
$shop1_row = pg_fetch_array($sho1_pg);
$shop1_today = $shop1_row['sum'];

First part works and output total sum by items sold * price
Second do not connect to db. strugling to get it to connect using the url and api key
Getting this:

Warning: pg_connect() [function.pg-connect]: Unable to connect to PostgreSQL server: invalid port number: “pos_99” in /var/www/genogbrug.dk/stuff/jk1.php on line 24
Connection attempt failed.

How do i setup dynamic multi tenant database system in laravel?

I wanted to create a multi tenant database based application here’s the flow:

There is one database known as “myGlobalDatabaseName” where it has users table.

Now when a user logins the database name is fetched from the users table lets say “user1Database”

Now when in dashboard i want to access the Products table that is inside the user1Database and also want the user information from globalDatabase

I could not find any way to create a Model for Products and Model For User where it can switch the database when specific model is called like when i do Products:all() it should give me the data from products table but of private db

for Now i Have been doing this way

Making two function in controller and using them like

    public function privateDB(string $exceptional_identifier = ""): Connection
    {
        if(!empty($exceptional_identifier))
        {
            $exceptional_identifier =   "";
        }
        if (empty($exceptional_identifier)) {
            $request                =   Request::instance();
            $database_identifier    =   $request->cookie("selected_company_id");
            $database_identifier    =   $this->globalDB()->table(TableLists::COMPANIES)->where("id", $database_identifier)->first();
            $exceptional_identifier =   $database_identifier->company_identifier;
        }
        Config::set('database.connections.private.database', env("DB_QFIX") . $exceptional_identifier);
        return DB::connection('private');
    }


    /**
     *
     * Global Database
     *
     * @return Connection
     */
    public function globalDB(): Connection {
        return DB::connection('global');
    }

and when ever i want i would use this like:

 $products = $this->privateDB()->table("products")->get();
 $users = $this->globalDB()->table("users")->get();

Woocommerce sorting – products with no price below other products

I have a problem with woocommerce shop. I’m importing product’s data from feed and their prices are changing few time per week automatically. Sometimes the price will be 0 or with no value. If I go to category page there is huge mess with this. I mean products with prices are mixed with products without prices.

I tried some custom sorting to show no price products below others but in this case when prices are changing so often it has no sense to make it manually.

I want to ask is there any way to make a change in wordpress code which will do thing like this:

Products with price value set as 0 or with no value will show up on category page below other products with prices.

Is there any way to do such a thing? How can I do it and which file should I edit? I’ll be glad for any help!

Website responds different after migration from directadmin to plesk

A little bit explaination of how I work to make my question clear.
I maintain a website. Local I create my changes with Xampp. When everything works I move the changed files to the production environment online.
Before we had directadmin as platform where the website is running. When an bug was found, I was able to reproduce this local.

Because the hoster was bankrupt we found a new hoster and migrated everything to there. The biggest difference is that they have Plesk as platform instead of DirectAdmin. Since the migration I had to change some things in my .htaccess and had some other issues but fixed them too.
I noticed that bugs on the Plesk cant be reproduced local.
The PHP versions are the same.

Do anyone know what can explain this different behaviour in running on DirectAdmin and Plesk when the versions are the same?
And second do anyone have a suggestion for local development which works equal to Plesk so I am able to debug more easy?

Kind regards

How to create email with Link PHP? [duplicate]

How to create email with Link PHP?

I need to create an email using URL without PHP Form
for example:

<form method="post" name="mlx" 

action="http://localhost/form-email.php?name=name&email=EMAIL1&email2=EMAIL2&title=TITLE&message=MESSAGE"

>

Enter Name: <input type="text" name="name">

Enter Email Address:    <input type="text" email="EMAIL1">

Enter Title:    <input type="text" title="title">

Enter Message:  <textarea name="message"></textarea>

<input type="submit" value="Send Form">
</form>

I searched on many sites, I did not find a solution..
Please help, thank you

Plugin could not be activated because it triggered a fatal error. After WordPress upgrade 6.3, getting fatel error

I installed a plugin that was working on my old wordpress website, but now its throwing fatal error wordpress version is 6.3.

Fatal error: Uncaught Error: Class “AmiutProductSpecsApp” not found in /home/mobilopk/public_html/wp-content/plugins/product-specifications-main/wc-specs.php:34 Stack trace: #0 /home/mobilopk/public_html/wp-content/plugins/product-specifications-main/wc-specs.php(38): dwspecs_table() #1 /home/mobilopk/public_html/wp-admin/includes/plugin.php(2318): include_once(‘/home/mobilopk/…’) #2 /home/mobilopk/public_html/wp-admin/plugins.php(192): plugin_sandbox_scrape() #3 {main} thrown in /home/mobilopk/public_html/wp-content/plugins/product-specifications-main/wc-specs.php on line 34

There is wc-spec.php code

    declare(strict_types=1);
    
    defined( 'ABSPATH' ) || exit;
    
    if (is_readable(__DIR__ . '/vendor/autoload.php')) {
        /* @noinspection PhpIncludeInspection */
        include_once __DIR__ . '/vendor/autoload.php';
    }
    
    if ( ! defined( 'DWSPECS_PLUGIN_FILE' ) ) {
        define( 'DWSPECS_PLUGIN_FILE', __FILE__ );
    }
    
    /**
     * Returns the main instance of PDF Gen.
     *
     * @since  0.4
     * @return AmiutProductSpecsApp
     */
    function dwspecs_table() {
        return AmiutProductSpecsApp::getInstance();
    }
    
    // Global for backwards compatibility.
    $GLOBALS['dwspecs_table'] = dwspecs_table();

There is file where classes are defined, that is app.php

<?php
/**
 * Product Specifications main class
 *
 * @package AmiutProductSpecs
 * @since   0.4
 */

namespace AmiutProductSpecs;

defined('ABSPATH') || exit;

/**
 * AmiutProductSpecs main class
 */
final class App
{
    /**
     * Plugin version.
     *
     * @var string
     */
    public $version = '0.7.1';

    /**
     * Plugin instance.
     *
     * @since 0.1
     * @var null|AmiutProductSpecs
     */
    public static $instance = null;

    /**
     * Return the plugin instance.
     *
     * @return AmiutProductSpecsApp
     */
    public static function instance() {
        if ( ! self::$instance ) {
            self::$instance = new self();
        }

        return self::$instance;
    }

    /**
     * Dornaweb_Pack constructor.
     */
    private function __construct() {
        // Sync group attributes when an attribute gets updated.
        add_action( 'dwspecs_attributes_modified', array( $this, 'modified_attributes' ) );
        add_action('woocommerce_init', [$this, 'handle_woocommerce']);
        add_action('plugins_loaded', [$this, 'wc_needed_notice']);

        $this->define_constants();
        $this->init();
        $this->includes();
        $this->create_options();
    }

    /**
     * Include required files
     *
     */
    public function includes() {
        require_once( DWSPECS_ABSPATH . 'inc/helpers.php' );
    }

    /**
     * Define constant if not already set.
     *
     * @param string      $name  Constant name.
     * @param string|bool $value Constant value.
     */
    private function define( $name, $value ) {
        if ( ! defined( $name ) ) {
            define( $name, $value );
        }
    }

    /**
     * Define constants
     */
    public function define_constants() {
        $this->define('DWSPECS_ABSPATH', dirname(DWSPECS_PLUGIN_FILE) . '/');
        $this->define('DWSPECS_PLUGIN_BASENAME', plugin_basename(DWSPECS_PLUGIN_FILE));
        $this->define('DWSPECS_VERSION', $this->version);
        $this->define('DWSPECS_PLUGIN_URL', $this->plugin_url());
    }

    /**
     * Get the plugin url.
     *
     * @return string
     */
    public function plugin_url() {
        return untrailingslashit(plugins_url('/', DWSPECS_PLUGIN_FILE));
    }

    /**
     * Do initial stuff
     */
    public function init() {
        // Install
        register_activation_hook(DWSPECS_PLUGIN_FILE, ['AmiutProductSpecs\Install', 'install']);

        // Post types
        PostTypes::init();

        AdminAdmin::init();
        ShortcodesTable::init();

        // Add scripts and styles
        add_action('wp_enqueue_scripts', [$this, 'public_dependencies']);
    }

    /**
     * Register scripts and styles for public area
     */
    public function public_dependencies() {
        if( ! get_option('dwps_disable_default_styles') ){
            wp_enqueue_style( 'dwspecs-front-css', DWSPECS_PLUGIN_URL . '/assets/css/front-styles.css', array(), DWSPECS_VERSION );
        }
    }

    /**
     * Create Options as an stdClass
    */
    public function create_options(){
        $this->options = new stdClass();
        $this->options->post_types = get_option('dwps_post_types');
        $this->options->per_page   = get_option('dwps_view_per_page');
    }

    /**
     * Check and add specifications table to woocommerce
    */
    public function handle_woocommerce(){
        if(class_exists('WooCommerce')) {
            add_filter('woocommerce_product_tabs', array( $this, 'woocommerce_tabs' ));
        }
    }

    /**
     * Add tables to woocommerce tabs
     * Remove or keep old woocommerce tables ( based on plugin's settings )
    */
    public function woocommerce_tabs( $tabs ){
        global $product;

        if( dwspecs_product_has_specs_table( $product->get_id() ) ){
            $tabs['dwspecs_product_specifications'] = array(
                'title'     => get_option('dwps_tab_title')?: esc_html__( 'Product Specifications', 'product-specifications' ),
                'priority'  => 10,
                'callback'  => array( $this, 'woo_display_tab' )
            );
        }

        if( get_option('dwps_wc_default_specs') == 'remove' || ( dwspecs_product_has_specs_table( $product->get_id() ) && get_option('dwps_wc_default_specs') == 'remove_if_specs_not_empty' ) ) {

            unset( $tabs['additional_information'] );
        }

        return $tabs;
    }

    /**
     * Display tab content Callback
    */
    public function woo_display_tab(){
        echo do_shortcode('[specs-table]');
    }

    /**
     * Trigger When an attribute is added or deleted and update group attribute ids
     *
     * @param   Array $args
     * @return Array
    */
    public function modified_attributes( $args ){
        // Sync. delete action with attribute groups
        if( $args['action'] == 'delete' ){
            for( $b = 0; $b < sizeof( $args['ids'] ); $b++ ){
                $attr_id          = $args['ids'][$b];
                $group_id         = get_term_meta( $attr_id, 'attr_group', true );
                $group_attributes = get_term_meta( $group_id, 'attributes', true );

                if( is_array( $group_attributes ) && sizeof( $group_attributes ) > 0 ){
                    if( in_array( $attr_id, $group_attributes ) ){
                        unset( $group_attributes[ $attr_id ] );
                        $updated_attributes = array_diff( $group_attributes, array($attr_id) );
                        update_term_meta( $group_id, 'attributes', $updated_attributes );
                    }
                } else{
                    delete_term_meta( $group_id, 'attributes' );
                    add_term_meta( $group_id, 'attributes', array() );
                }
            }
        } elseif( $args['action'] == 'add' || $args['action'] == 'edit' ){
            for( $i = 0; $i < sizeof( $args['ids'] ); $i++ ){
                $attr_id          = $args['ids'][$i];
                $group_id         = get_term_meta( $attr_id, 'attr_group', true );
                $group_attributes = get_term_meta( $group_id, 'attributes', true );

                if( is_array( $group_attributes ) && sizeof( $group_attributes ) > 0 ){
                    if( !in_array( $attr_id, $group_attributes ) ){
                        array_push( $group_attributes, $attr_id  );
                        update_term_meta( $group_id, 'attributes', $group_attributes );
                    }
                } else{
                    delete_term_meta( $group_id, 'attributes' );
                    add_term_meta( $group_id, 'attributes', array( $attr_id ) );
                }
            }
        }

    }

    public function wc_needed_notice() {
        if (! class_exists('WooCommerce')) {
            $this->add_notice('no_woo_notice', esc_html__('This plugin works properly with woocommerce, please install woocommerce first', 'product-specifications'), 'warning', 'forever');
        }

        add_action('wp_ajax_dw_dismiss_admin_notice', [$this, 'dismiss_alert']);

    }

    /**
     * Add a notice to admin notices area
     *
     * @param String        $id         A unique identifier
     * @param String        $message     Notice body
     * @param String|Bool   false - Not dismissable OR "close" - just close button OR "forever" - an option to permanently dismiss the notice
     */
    public function add_notice($id, $message, $type = 'success', $dismiss = 'close') {
        if (! get_option('dw_notice_dismissed_' . $id)) {
            add_action( 'admin_notices', function() use($id, $message, $type, $dismiss){
                echo '<div class="notice notice-'. esc_attr($type) .' '. ($dismiss === 'forever' || $dismiss === 'close' ? 'is-dismissible' : '') .'"><p>';

                if ($dismiss == 'forever') {
                    $message .= ' <a href="#" onClick="dwDismissAdminNotice(event, ''. esc_attr($id) .''); return false;">'.esc_html__('Dismiss', 'product-specifications').'</a>';
                }

                echo esc_html($message);
                echo '</p></div>';
            });
        }
    }

    public function dismiss_alert() {
        $id = isset($_POST['id']) ? trim(htmlspecialchars($_POST['id'])) : false;

        if ($id) {
            update_option('dw_notice_dismissed_' . $id, "1");
        }
    }
}

can you suggest me any tweak to resolve this issue.