Plugin Directory

Changeset 3136940


Ignore:
Timestamp:
08/17/2024 07:26:18 AM (20 months ago)
Author:
lordspace
Message:

made some cool fixes for v1.0.3

Location:
orbisius-seo-editor/trunk
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • orbisius-seo-editor/trunk/lib/csv.php

    r2838198 r3136940  
    55 * This premium WooCommerce extension allows you to change product prices (up/down) for all products or for a selected category and its subcategories.
    66 * You can review them before actually making the changes.
    7  * 
     7 *
    88 * @see https://orbisius.com/products/wordpress-plugins/woocommerce-extensions/orbisius-seo-editor/
    99 * @author jaywilliams | myd3.com | https://gist.github.com/jaywilliams
    1010 * @author Svetoslav Marinov (SLAVI) | https://orbisius.com
    1111 */
    12 Class Orbisius_SEO_Editor_CSV {
    13     protected $buff_size = 1024;
     12class Orbisius_SEO_Editor_CSV
     13{
     14    protected $buff_size = 2048;
    1415    protected $delimiter = ',';
    15     const APPEND = 2;
    16     const DO_EXIT = 4;
    17     const DONT_EXIT = 8;
    18 
    19     public function delimiter($delimiter = '') {
     16    const APPEND = 2;
     17    const DO_EXIT = 4;
     18    const DONT_EXIT = 8;
     19
     20    public function delimiter($delimiter = '')
     21    {
    2022        if (!empty($delimiter)) {
    2123            $this->delimiter = $delimiter;
     
    2830
    2931    /**
    30     * Reads a CSV file and returns array of arrays.
    31     * The header rows are not returned. We can extract them by getting the keys of the first array element.
    32     * @link https://gist.github.com/385876
    33     * @return array / false on error
    34     */
    35    public function read($filename = '', $flags = 0) {
    36        if (!file_exists($filename) || !is_readable($filename)) {
    37            trigger_error(sprintf("File [%s] doesn't exist or not readable.", esc_attr($filename)), E_USER_WARNING);
    38            return false;
    39        }
    40 
    41        $data = [];
    42        $header = [];
    43 
    44        try {
    45            // In some cases (Windows/Linux) the line endings are not read correctly so we'll hint php to detect the line endings.
    46            $old_auto_detect_line_endings_flag = ini_get("auto_detect_line_endings");
    47            ini_set("auto_detect_line_endings", true);
    48 
    49            $handle = fopen($filename, 'rb');
    50 
    51            if (empty($handle)) {
    52                trigger_error(sprintf(
    53                    "Cannot open file [%s] for reading",
    54                    esc_attr(basename($filename))
    55                ),
    56                    E_USER_WARNING
    57                );
    58                return false;
    59            }
    60 
    61            // we just need a read lock
    62            flock($handle, LOCK_SH);
    63 
    64            while (($row = fgetcsv($handle, $this->buff_size, $this->delimiter)) !== false) {
    65                if (empty($row)) {
    66                    continue;
    67                }
    68 
    69                $row = array_map('trim', $row);
    70 
    71                if (empty($row)) {
    72                    continue;
    73                }
    74 
    75                // Empty lines could produce empty columns
    76                $row_alt_empty_check = array_filter($row);
    77 
    78                if (empty($row_alt_empty_check)) {
    79                    continue;
    80                }
    81 
    82                // No header row OR if the data contains header row somewhere instead of data
    83                if (empty($header) || count(array_diff($header, $row)) == 0) {
    84                    // Validate heading row and in case the user had decided to remove it for some reason
    85                    // the rows must be alphanumeric + underscore and may contain numbers
    86                    // correct cols must match be the same elements as the array i.e. all must be correct
    87                    $valid_cols = 0;
    88                    $correct_cols_regex = '#^\s*[a-z]+[\w\-]+\s*$#si';
    89 
    90                    foreach ($row as $val) {
    91                        if (!preg_match($correct_cols_regex, $val)) {
    92                            break; // do need to check others since at least one didn't validate.
    93                        }
    94 
    95                        $valid_cols++;
    96                    }
    97 
    98                    if ($valid_cols != count($row)) {
    99                        throw new Exception("The heading row is missing or invalid. It is necessary as we use it to map fields.");
    100                    }
    101 
    102                    if ($flags & self::FORMAT_HEADER_COLS) {
    103                        foreach ($row as $idx => $val) {
    104                            $val = strtolower($val);
    105                            $val = preg_replace('#[^\w]#si', '_', $val);
    106                            $val = preg_replace('#\_+#si', '_', $val);
    107                            $val = trim($val, ' _');
    108                            $row[$idx] = $val;
    109                        }
    110                    }
    111 
    112                    $header = $row;
    113                } else {
    114                    $data[] = @array_combine($header, $row);
    115                }
    116            }
    117        } finally {
    118            ini_set("auto_detect_line_endings", $old_auto_detect_line_endings_flag); // restore previous value
    119 
    120            if (!empty($handle)) {
    121                flock($handle, LOCK_UN);
    122                fclose($handle);
    123            }
    124        }
    125 
    126        return $data;
    127 
    128        /*
    129         * Return value
    130         array (
    131         0 =>
    132         array (
    133           'product_title' => 'Bottle',
    134           'parent_product_id' => '0',
    135           'product_id' => '308',
    136           'old_regular_price' => '1.00',
    137           'new_regular_price' => '5',
    138           'old_sale_price' => '1.00',
    139           'new_sale_price' => '2.00',
    140           'currency' => 'GBP',
    141           'cur_user_id' => '20',
    142           'cur_user_email' => 'user@email.com',
    143           'cur_date' => '2014-06-09 10:59:37',
    144         ),
    145         1 =>
    146         array (
    147           'product_title' => 'Bottles (Case)',
    148           'parent_product_id' => '0',
    149           'product_id' => '309',
    150           'old_regular_price' => '100.00',
    151           'new_regular_price' => '50.00',
    152           'old_sale_price' => '10.00',
    153           'new_sale_price' => '10.00',
    154           'currency' => 'GBP',
    155           'cur_user_id' => '20',
    156           'cur_user_email' => 'user@email.com',
    157           'cur_date' => '2014-06-09 10:59:37',
    158         ),
    159       )
    160       */
     32     * Reads a CSV file and returns array of arrays.
     33     * The header rows are not returned. We can extract them by getting the keys of the first array element.
     34     * @link https://gist.github.com/385876
     35     * @return array|false on error
     36     */
     37    public function read($filename = '', $flags = 0)
     38    {
     39        if (!file_exists($filename) || !is_readable($filename)) {
     40            trigger_error(sprintf("File [%s] doesn't exist or not readable.", esc_attr($filename)), E_USER_WARNING);
     41            return false;
     42        }
     43
     44        $data = [];
     45        $header = [];
     46
     47        try {
     48            // In some cases (Windows/Linux) the line endings are not read correctly, so we'll hint php to detect the line endings.
     49            if (version_compare(PHP_VERSION, '8.1.0', '<')) {
     50                $old_auto_detect_line_endings_flag = ini_get("auto_detect_line_endings");
     51                ini_set("auto_detect_line_endings", true);
     52            }
     53
     54            $handle = fopen($filename, 'rb');
     55
     56            if (empty($handle)) {
     57                trigger_error(sprintf(
     58                    "Cannot open file [%s] for reading",
     59                    esc_attr(basename($filename))
     60                ),
     61                    E_USER_WARNING
     62                );
     63                return false;
     64            }
     65
     66            // we just need a read lock
     67            flock($handle, LOCK_SH);
     68
     69            // Thsi is
     70            $row_num = 0; // all rows including the empty ones
     71            $row_idx = 0;
     72
     73            while (($row = fgetcsv($handle, $this->buff_size, $this->delimiter)) !== false) {
     74                $row_num++;
     75
     76                if (empty($row)) {
     77                    continue;
     78                }
     79
     80                $row = array_map('trim', $row);
     81
     82                if (empty($row)) {
     83                    continue;
     84                }
     85
     86                // Empty lines could produce empty columns
     87                $row_alt_empty_check = array_filter($row);
     88
     89                if (empty($row_alt_empty_check)) {
     90                    continue;
     91                }
     92
     93                $row_idx++;
     94
     95                // No header row OR if the data contains header row somewhere instead of data
     96                if (empty($header) || count(array_diff($header, $row)) == 0) {
     97                    // Validate heading row and in case the user had decided to remove it for some reason
     98                    // the rows must be alphanumeric + underscore and may contain numbers
     99                    // correct cols must match be the same elements as the array i.e. all must be correct
     100                    $valid_cols = 0;
     101                    $correct_cols_regex = '#^\s*[a-z]+[\w\-]+\s*$#si';
     102
     103                    foreach ($row as $val) {
     104                        if (!preg_match($correct_cols_regex, $val)) {
     105                            break; // do need to check others since at least one didn't validate.
     106                        }
     107
     108                        $valid_cols++;
     109                    }
     110
     111                    if ($valid_cols != count($row)) {
     112                        // Skip the first 5 non-empty rows if they have X or fewer columns.
     113                        // Sometimes people enter content before the heading columns
     114                        if ($row_idx <= 5 && $valid_cols <= 2) {
     115                            continue;
     116                        }
     117
     118                        throw new Exception("The heading row, which must include id, title etc, is missing or invalid. It is necessary as we use it to map fields.");
     119                    }
     120
     121                    if ($flags & self::FORMAT_HEADER_COLS) {
     122                        foreach ($row as $idx => $val) {
     123                            $val = strtolower($val);
     124                            $val = preg_replace('#[^\w]#si', '_', $val);
     125                            $val = preg_replace('#\_+#si', '_', $val);
     126                            $val = trim($val, ' _');
     127                            $row[$idx] = $val;
     128                        }
     129                    }
     130
     131                    // let's skip any textual rows before the headers
     132                    if ($row_idx <= 5 && count($row) <= 3) {
     133                        continue;
     134                    }
     135
     136                    // so several rows and not enough header cols this is an error
     137                    if ($row_idx > 5 && count($row) <= 3) {
     138                        throw new Exception("The heading row has fewer than expected fields It is necessary as we use it to map fields.");
     139                    }
     140
     141                    $header = $row;
     142                } else {
     143                    $data[] = @array_combine($header, $row);
     144                }
     145            }
     146        } finally {
     147            if (version_compare(PHP_VERSION, '8.1.0', '<')) {
     148                ini_set("auto_detect_line_endings", $old_auto_detect_line_endings_flag); // restore previous value
     149            }
     150
     151            if (!empty($handle)) {
     152                flock($handle, LOCK_UN);
     153                fclose($handle);
     154            }
     155        }
     156
     157        return $data;
     158
     159        /*
     160         * Return value
     161         array (
     162         0 =>
     163         array (
     164           'product_title' => 'Bottle',
     165           'parent_product_id' => '0',
     166           'product_id' => '308',
     167           'old_regular_price' => '1.00',
     168           'new_regular_price' => '5',
     169           'old_sale_price' => '1.00',
     170           'new_sale_price' => '2.00',
     171           'currency' => 'GBP',
     172           'cur_user_id' => '20',
     173           'cur_user_email' => 'user@email.com',
     174           'cur_date' => '2014-06-09 10:59:37',
     175         ),
     176         1 =>
     177         array (
     178           'product_title' => 'Bottles (Case)',
     179           'parent_product_id' => '0',
     180           'product_id' => '309',
     181           'old_regular_price' => '100.00',
     182           'new_regular_price' => '50.00',
     183           'old_sale_price' => '10.00',
     184           'new_sale_price' => '10.00',
     185           'currency' => 'GBP',
     186           'cur_user_id' => '20',
     187           'cur_user_email' => 'user@email.com',
     188           'cur_date' => '2014-06-09 10:59:37',
     189         ),
     190       )
     191       */
    161192    }
    162193
     
    170201     * @return bool true/false depending on success
    171202     */
    172     public function write($data, $title_row = array(), $file = '', $flags = 0) {
    173         static $browser_handle = null;
    174         $headers_sent = 0;
     203    public function write($data, $title_row = array(), $file = '', $flags = 0)
     204    {
     205        static $browser_handle = null;
     206        $headers_sent = 0;
    175207
    176208        $local_file = !empty($file);
     
    180212
    181213        if ($output_in_browser) { // browser
    182             if (is_null($browser_handle)) {
    183                 $this->sendDownloadHeadersForCSVDownload($file);
    184                 $headers_sent = 1;
    185                 $handle = fopen('php://output', 'wb');
    186                 $browser_handle = $handle;
    187             } else {
    188                 $handle = $browser_handle;
    189             }
     214            if (is_null($browser_handle)) {
     215                $this->sendDownloadHeadersForCSVDownload($file);
     216                $headers_sent = 1;
     217                $handle = fopen('php://output', 'wb');
     218                $browser_handle = $handle;
     219            } else {
     220                $handle = $browser_handle;
     221            }
    190222        } else {
    191223            $handle = fopen($file, $append ? 'ab' : 'wb');
     
    199231        // this resulted in header column being written multiple times.
    200232        // that's why we clear the cache every time we write.
    201         if ($local_file) {
    202             clearstatcache();
    203             flock( $handle, LOCK_EX );
    204         }
    205 
    206         $add_title_row = 0;
    207 
    208         if (!empty($title_row)) {
    209             if ($output_in_browser) {
    210                 if ($headers_sent) { // first time output is opened
    211                     $add_title_row = 1;
    212                 }
    213             } elseif (!$append) {
    214                 $add_title_row = 1;
    215             } elseif (!empty($file) && filesize($file) < 10) {
    216                 $add_title_row = 1;
    217             }
    218         }
     233        if ($local_file) {
     234            clearstatcache();
     235            flock($handle, LOCK_EX);
     236        }
     237
     238        $add_title_row = 0;
     239
     240        if (!empty($title_row)) {
     241            if ($output_in_browser) {
     242                if ($headers_sent) { // first time output is opened
     243                    $add_title_row = 1;
     244                }
     245            } elseif (!$append) {
     246                $add_title_row = 1;
     247            } elseif (!empty($file) && filesize($file) < 10) {
     248                $add_title_row = 1;
     249            }
     250        }
    219251
    220252        // add the title row only if we're not appending or if the file size is minimal (fewer than 10 bytes).
     
    226258        // In case the dev has passed just a row and not array of rows
    227259        if (empty($data[0]) || !is_array($data[0])) {
    228             $data = [ $data ];
     260            $data = [$data];
    229261        }
    230262
     
    234266
    235267        if ($local_file) {
    236             flock( $handle, LOCK_UN );
     268            flock($handle, LOCK_UN);
    237269            fclose($handle);
    238270        }
     
    241273            die;
    242274        }
    243        
     275
    244276        return true;
    245277    }
    246278
    247     /**
    248      * Sends the headers
    249      * @return void
    250      */
    251     public function sendDownloadHeadersForCSVDownload($inp_filename = '') {
    252         if (headers_sent()) {
    253             return;
    254         }
    255 
    256         if (empty($inp_filename)) {
    257             $inp_filename = $this->getDownloadFileName();
    258         }
    259 
    260         if (empty($inp_filename)) {
    261             $file_prefix = basename(ORBISIUS_SEO_EDITOR_BASE_PLUGIN);
    262             $file_prefix = str_replace('.php', '', $file_prefix);
    263             $file_prefix = sanitize_title( $file_prefix );
    264             $file_prefix = str_replace( '-', '_', $file_prefix );
    265             $file_prefix .= '_';
    266             $filename    = $file_prefix . date( 'Ymd' ) . '_' . date( 'His' ) . '.csv';
    267         } else {
    268             $filename = basename($inp_filename);
    269         }
    270 
    271         // Output CSV-specific headers
    272         // https://stackoverflow.com/questions/393647/response-content-type-as-csv
    273         header("Pragma: public");
    274         header('X-Content-Type-Options: nosniff');
    275         header("Expires: 0");
    276         header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
    277         header("Cache-Control: private", false);
    278         header("Content-Type: text/csv");
    279         header("Content-Disposition: attachment; filename=\"$filename\";" );
    280         header("Content-Transfer-Encoding: binary");
    281     }
    282 
    283     private $dl_file = '';
    284 
    285     /**
    286      * @return string
    287      */
    288     public function getDownloadFileName(): string {
    289         return $this->dl_file;
    290     }
    291 
    292     /**
    293      * @param string $dl_file
    294      */
    295     public function setDownloadFileName( string $dl_file ): void {
    296         $this->dl_file = $dl_file;
    297     }
     279    /**
     280     * Sends the headers
     281     * @return void
     282     */
     283    public function sendDownloadHeadersForCSVDownload($inp_filename = '')
     284    {
     285        if (headers_sent()) {
     286            return;
     287        }
     288
     289        if (empty($inp_filename)) {
     290            $inp_filename = $this->getDownloadFileName();
     291        }
     292
     293        if (empty($inp_filename)) {
     294            $file_prefix = basename(ORBISIUS_SEO_EDITOR_BASE_PLUGIN);
     295            $file_prefix = str_replace('.php', '', $file_prefix);
     296            $file_prefix = sanitize_title($file_prefix);
     297            $file_prefix = str_replace('-', '_', $file_prefix);
     298            $file_prefix .= '_';
     299            $filename = $file_prefix . date('Ymd') . '_' . date('His') . '.csv';
     300        } else {
     301            $filename = basename($inp_filename);
     302        }
     303
     304        // Output CSV-specific headers
     305        // https://stackoverflow.com/questions/393647/response-content-type-as-csv
     306        header("Pragma: public");
     307        header('X-Content-Type-Options: nosniff');
     308        header("Expires: 0");
     309        header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
     310        header("Cache-Control: private", false);
     311        header("Content-Type: text/csv");
     312        header("Content-Disposition: attachment; filename=\"$filename\";");
     313        header("Content-Transfer-Encoding: binary");
     314    }
     315
     316    private $dl_file = '';
     317
     318    /**
     319     * @return string
     320     */
     321    public function getDownloadFileName(): string
     322    {
     323        return $this->dl_file;
     324    }
     325
     326    /**
     327     * @param string $dl_file
     328     */
     329    public function setDownloadFileName(string $dl_file): void
     330    {
     331        $this->dl_file = $dl_file;
     332    }
    298333}
  • orbisius-seo-editor/trunk/lib/util.php

    r2838198 r3136940  
    631631        $msg_esc = esc_html($msg);
    632632        $msg_esc = str_ireplace('__ESC_BR__', '<br/>', $msg_esc);
    633         $str = "<div id='$id-notice' class='$cls' style='$inline_css'><strong>$msg_esc</strong></div>";
     633        $str = "<div id='$id-notice' class='$cls' style='$inline_css'><strong><p>$msg_esc</p></strong></div>";
    634634
    635635        return $str;
  • orbisius-seo-editor/trunk/orbisius-seo-editor.php

    r2865670 r3136940  
    44Plugin URI: https://orbisius.com/products/wordpress-plugins/orbisius-seo-editor/
    55Description: Allows you to bulk update meta titles, descriptions summary of pages, posts and WooCommerce products
    6 Version: 1.0.2
     6Version: 1.0.3
    77Author: Svetoslav Marinov (Slavi)
    88Author URI: https://orbisius.com
  • orbisius-seo-editor/trunk/readme.txt

    r2865670 r3136940  
    44Tags: seo,seo plugin,seo,bulk edit seo,wpseo,yoast seo,yoast,autodescription,rank-math,twitter card,meta title, meta description, woocommerce seo,wc seo,seo plugin,WordPress SEO,SEO Rank Math import, WordPress SEO import
    55Requires at least: 5.0
    6 Tested up to: 6.1
     6Tested up to: 6.6
    77Requires PHP: 5.6
    8 Stable tag: 1.0.2
     8Stable tag: 1.0.3
    99License: GPLv2 or later
    1010
     
    6060== Installation ==
    6161
    62 1. Unzip the package, and upload `orbisius-seo-editor` to the `/wp-content/plugins/` directory
    63 2. Activate the plugin through the 'Plugins' menu in WordPress
     621. Go to WP-Admin > Plugins > Add New
     631. Upload the plugin's zip the package or search for SEO Editor
     641. Activate the plugin through the 'Plugins' menu in WordPress
     651. To go Tools > SEO Editor
    6466
    6567== Frequently Asked Questions ==
     
    7375== Changelog ==
    7476
     77= 1.0.3 =
     78* Tested with latest WP
     79* Fixed Deprecated: auto_detect_line_endings is deprecated
     80* Updated csv parsing buffer to 2k
     81* Skip the first 5 non-empty rows if they have X or fewer columns. Sometimes people enter content before the heading columns.
     82* Fixes
     83
    7584= 1.0.2 =
    7685* Added focus keyword to the WordPress SEO
Note: See TracChangeset for help on using the changeset viewer.