Drupal

Drupal7的Nginx設定檔

server {
    server_name site.com;
    root /var/www/site; ## <-- Your only path reference.

    location = /favicon.ico {
        log_not_found off;
        access_log off;
    }

    location = /robots.txt {
        allow all;
        log_not_found off;
        access_log off;
    }

    location = /ads.txt {
        allow all;
        log_not_found off;
        access_log off;
    }

    # Very rarely should these ever be accessed outside of your lan
    location ~* \.(txt|log)$ {
        allow 192.168.0.0/16;
        deny all;
    }

    location ~ \..*/.*\.php$ {
        return 403;
    }

    location ~ ^/sites/.*/private/ {
        return 403;
    }

    # Block access to scripts in site files directory
    location ~ ^/sites/[^/]+/files/.*\.php$ {
        deny all;
    }

    # Allow "Well-Known URIs" as per RFC 5785
    location ~* ^/.well-known/ {
        allow all;
    }

    # Block access to "hidden" files and directories whose names begin with a
    # period. This includes directories used by version control systems such
    # as Subversion or Git to store control files.
    location ~ (^|/)\. {
        return 403;
    }

    location / {
        # try_files $uri @rewrite; # For Drupal <= 6
        try_files $uri /index.php?$query_string; # For Drupal >= 7
    }

    location @rewrite {
        rewrite ^/(.*)$ /index.php?q=$1;
    }

    # Don't allow direct access to PHP files in the vendor directory.
    location ~ /vendor/.*\.php$ {
        deny all;
        return 404;
    }

    # In Drupal 8, we must also match new paths where the '.php' appears in
    # the middle, such as update.php/selection. The rule we use is strict,
    # and only allows this pattern with the update.php front controller.
    # This allows legacy path aliases in the form of
    # blog/index.php/legacy-path to continue to route to Drupal nodes. If
    # you do not have any paths like that, then you might prefer to use a
    # laxer rule, such as:
    #   location ~ \.php(/|$) {
    # The laxer rule will continue to work if Drupal uses this new URL
    # pattern with front controllers other than update.php in a future
    # release.
    location ~ '\.php$|^/update.php' {
        fastcgi_split_path_info ^(.+?\.php)(|/.*)$;
        # Security note: If you're running a version of PHP older than the
        # latest 5.3, you should have "cgi.fix_pathinfo = 0;" in php.ini.
        # See http://serverfault.com/q/627903/94922 for details.
        include fastcgi_params;
        # Block httpoxy attacks. See https://httpoxy.org/.
        fastcgi_param HTTP_PROXY "";
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
        fastcgi_param QUERY_STRING $query_string;
        fastcgi_intercept_errors on;
        # PHP 5 socket location.
        #fastcgi_pass unix:/var/run/php5-fpm.sock;
        # PHP 7 socket location.
        fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
    }

    # Fighting with Styles? This little gem is amazing.
    # location ~ ^/sites/.*/files/imagecache/ { # For Drupal <= 6
    location ~ ^/sites/.*/files/styles/ { # For Drupal >= 7
        try_files $uri @rewrite;
    }

    # Handle private files through Drupal. Private file's path can come
    # with a language prefix.
    location ~ ^(/[a-z\-]+)?/system/files/ { # For Drupal >= 7
        try_files $uri /index.php?$query_string;
    }

    ## PWA serviceworker support.
    location ~ ^/pwa/[0-9a-z]+/serviceworker.js {
       try_files $uri /index.php?$query_string;
    }

    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff)$ {
        expires max;
        log_not_found off;
        access_log off;
    }

}

Drupal的Nginx設定檔

server {
    server_name site.com;
    root /var/www/site/web; ## <-- Your only path reference.

    location = /favicon.ico {
        log_not_found off;
        access_log off;
    }

    location = /robots.txt {
        allow all;
        log_not_found off;
        access_log off;
    }

    # Very rarely should these ever be accessed outside of your lan
    location ~* \.(txt|log)$ {
        allow 192.168.0.0/16;
        deny all;
    }

    location ~ \..*/.*\.php$ {
        return 403;
    }

    location ~ ^/sites/.*/private/ {
        return 403;
    }

    # Block access to scripts in site files directory
    location ~ ^/sites/[^/]+/files/.*\.php$ {
        deny all;
    }

    # Allow "Well-Known URIs" as per RFC 5785
    location ~* ^/.well-known/ {
        allow all;
    }

    # Block access to "hidden" files and directories whose names begin with a
    # period. This includes directories used by version control systems such
    # as Subversion or Git to store control files.
    location ~ (^|/)\. {
        return 403;
    }

    location / {
        # try_files $uri @rewrite; # For Drupal <= 6
        try_files $uri /index.php?$query_string; # For Drupal >= 7
    }

    location @rewrite {
        #rewrite ^/(.*)$ /index.php?q=$1; # For Drupal <= 6
        rewrite ^ /index.php; # For Drupal >= 7
    }

    # Don't allow direct access to PHP files in the vendor directory.
    location ~ /vendor/.*\.php$ {
        deny all;
        return 404;
    }

    # Protect files and directories from prying eyes.
    location ~* \.(engine|inc|install|make|module|profile|po|sh|.*sql|theme|twig|tpl(\.php)?|xtmpl|yml)(~|\.sw[op]|\.bak|\.orig|\.save)?$|^(\.(?!well-known).*|Entries.*|Repository|Root|Tag|Template|composer\.(json|lock)|web\.config)$|^#.*#$|\.php(~|\.sw[op]|\.bak|\.orig|\.save)$ {
        deny all;
        return 404;
    }

    # In Drupal 8, we must also match new paths where the '.php' appears in
    # the middle, such as update.php/selection. The rule we use is strict,
    # and only allows this pattern with the update.php front controller.
    # This allows legacy path aliases in the form of
    # blog/index.php/legacy-path to continue to route to Drupal nodes. If
    # you do not have any paths like that, then you might prefer to use a
    # laxer rule, such as:
    #   location ~ \.php(/|$) {
    # The laxer rule will continue to work if Drupal uses this new URL
    # pattern with front controllers other than update.php in a future
    # release.
    location ~ '\.php$|^/update.php' {
        fastcgi_split_path_info ^(.+?\.php)(|/.*)$;
        # Ensure the php file exists. Mitigates CVE-2019-11043
        try_files $fastcgi_script_name =404;
        # Security note: If you're running a version of PHP older than the
        # latest 5.3, you should have "cgi.fix_pathinfo = 0;" in php.ini.
        # See http://serverfault.com/q/627903/94922 for details.
        include fastcgi_params;
        # Block httpoxy attacks. See https://httpoxy.org/.
        fastcgi_param HTTP_PROXY "";
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
        fastcgi_param QUERY_STRING $query_string;
        fastcgi_intercept_errors on;
        # PHP 5 socket location.
        #fastcgi_pass unix:/var/run/php5-fpm.sock;
        # PHP 7 socket location.
        fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
    }

    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
        try_files $uri @rewrite;
        expires max;
        log_not_found off;
    }

    # Fighting with Styles? This little gem is amazing.
    # location ~ ^/sites/.*/files/imagecache/ { # For Drupal <= 6
    location ~ ^/sites/.*/files/styles/ { # For Drupal >= 7
        try_files $uri @rewrite;
    }

    # Handle private files through Drupal. Private file's path can come
    # with a language prefix.
    location ~ ^(/[a-z\-]+)?/system/files/ { # For Drupal >= 7
        try_files $uri /index.php?$query_string;
    }

    # Enforce clean URLs
    # Removes index.php from urls like www.example.com/index.php/my-page --> www.example.com/my-page
    # Could be done with 301 for permanent or other redirect codes.
    if ($request_uri ~* "^(.*/)index\.php/(.*)") {
        return 307 $1$2;
    }
}

https://www.nginx.com/resources/wiki/start/topics/recipes/drupal/

安裝Drupal與維護更新

安裝compoer與drush

安裝composer

curl -sS https://getcomposer.org/installer | sudo php -- --install-dir=/usr/local/bin --filename=composer

安裝drush(使用8.2.3)

composer global require drush/drush:8.2.3
alias drush='/usr/bin/php ~/.config/composer/vendor/drush/drush/drush.php'
drush init

安裝Drupal7

composer create-project drupal/recommended-project:7.x drupal

調整目錄權限

chown -R www-data:www-data /var/www/drupal/web
 

更新

composer self-update --1
update-alternatives --set php /usr/bin/php7.4
cd /var/www/drupal
drush pm-update -y;drush updatedb;drush l10n-update-refresh;drush l10n-update;drush cc all
composer self-update --2
update-alternatives --set php /usr/bin/php8.1

更新Drupal7,我的站由於共存Drupal7及Drupal10以及使用php7.4和php8.x,因此需要做一些版次的轉換

Drupal7即將在 5 January 2025 EOL,除非你要執行的應用Drupal10沒有開發,建議直接用最新版

安裝Drupal

composer create-project drupal/recommended-project drupal 

更新drush

cd drupal
composer require drush/drush
composer update

調整目錄權限

chown -R www-data:www-data web

更新程式

composer update
drush updatedb
drush cr

安裝程式模組

composer require 'drupal/pathauto:^1.12'

程式的最新的版本可於 https://www.drupal.org/project/pathauto 取得資訊

裝好後可以用drusn en pathauto或到管理後台啟用

停用及刪除模組

composer remove drupal/pathauto

如果要停用及刪除,先到管理後台停用後,再執行composer

Drupal從8版後,開始改成用composer維護資料,我從Drupal8的很後期才開始學會怎麼使用,我一開始也是架幾個測試站而已,之後再慢慢想辦法讓一些Drupal7的站移轉過去,由於架構不同,只能用移轉的方式,無法像之前D6升到D7用升級的方式,你也可以用這個機會整理網站 XD

如果你是Drupal新手,建議先佈建drupal預設的demo站,再去參考那個站的功能是如何設定

Drupal架購物網站

https://github.com/drupalcommerce/demo-project

直接參考這裡就能佈建出完整的購物站

對我來說,購物網站必須要有金流、物流、配送免運條件、三方登入、基本的折扣功能、訂單輸出,就足以應付當下的線上購物流程。
Drupal可惜的是後援,我後來無法再繼續用Ubercart的原因就是Ubercart的程式沒再繼續維護,且後來一些三方登入及金流功能我也跟不上,對於完全不會寫程式的人真的是蠻苦手的


Drupal架購物站我應該算是台灣極少數中的少數,我有使用Drupal6 + Ubercart佈建購物站,這個站運作到2022年的5月(運作了10幾年),後期的年營收有到1千多萬,也算是光榮退休

後期同事分享能用WooCommerce就開始學用WordPress系統,使用WooCommerce務必要注意,雖然外掛很多,但也很容易裝了一堆造成速度變慢,建議一定要在測試站測,試完沒問題且穩定再到主站使用

Drupal和WordPress各有各的特色及擁護者,我覺得能達成目地且後期有能力維護管理即可,就好比我現在用BookStack做筆記 XD

模組

Drupal 最新版本

模組

Gmail API

https://www.drupal.org/project/gmail

模組

Pathauto

https://www.drupal.org/project/pathauto

模組

Field Validation

https://www.drupal.org/project/field_validation

模組

Feeds

https://www.drupal.org/project/feeds

模組

ShURLy

https://www.drupal.org/project/shurly

模組

Custom Twig Formatter

https://www.drupal.org/project/custom_twig_formatter

用法如果有一個欄位值為 field_imageurl ,那麼可用這個方式呼叫

{{ field_imageurl.value }}

進階的語法,過濾掉 https://

{{ field_imageurl.value|replace({'https://': ''}) }}

呼出成html圖片語法

<img src="{{ field_imageurl.value }}" alt="{{ title.value }}" width="100%" />

這個模組就是用來替換 Custom Formatters 用的

模組

Easy Breadcrumb

https://www.drupal.org/project/easy_breadcrumb

幫頁生成目錄式的結構連結(麵包屑)

在安排文章及頁面時,有一個技巧避免使用者在你的網站迷路

我會用的作法就是用 easy_breadcrumb + pathauto

例如你有一個文章類型是要專門記錄書,那你就先生成一個頁面 /book ,然後設定 pathauto 把每篇文章的自動生成路徑為 /book/[title]

/book 頁面要搭配用 views block 呈現內容

在這種規劃後,當你進入一般的文章後,最上面會有樹狀目錄

首頁 > book > 文章標題

使用者在逛站的時候,就不會迷路囉

模組

amp

https://www.drupal.org/project/amp

要在在Drupal啟用amp的作法

安裝AMP及版型

composer require drupal/amp
composer require drupal/amptheme
composer require drupal/stable

啟用版型

到頁面 admin/appearance 啟用
ExAMPle Subtheme

設定AMP

到頁面 admin/config/services/amp

選擇剛啟用的 ExAMPle Subtheme 做預設版型

把內容類型加入AMP,點啟用會引導你去內容類型的設定頁,把AMP加入儲存

好了後用瀏覽器開頁面,接著在網址最後面加上 "?amp" 如果有 amp頁面就成功

當完成後先不要太高興,必須經過amp標準審核才算真正能用 https://search.google.com/test/amp

優化版型內容

https://search.google.com/test/amp

把連結貼到amp審查頁面,然後把沒用的及不符合的block移除,讓版面越乾淨越好

啟用自動廣告

目前有雷未拆,我啟用後廣告有出現,但他說我的內容不符合規則

「amp-ad」所需的「amp-ad extension script」標記遺失或不正確。這個問題很快就會導致錯誤發生。
不允許自訂 JavaScript。

因為這兩條被判定頁面不符合amp

一但啟用amp你就要心理有底,很多語法不能使用

特別注意,模組AMP和模組Feeds Extensible Parsers相沖,因為QueryPath JSON parser的關係,一旦共動啟用會讓整個站掛掉!

模組

Backup and Migrate

https://www.drupal.org/project/backup_migrate

mkdir private;chown -R www-data:www-data private/;composer require 'drupal/backup_migrate:^5.0';drush en backup_migrate;echo "\$settings['file_private_path'] = '../private';" | tee -a web/sites/default/settings.php

安裝後執行上面的字串,然後再檢查是否能順利備份及還原

模組

YouTube Embed Formatter

主要的功能是要把文字欄位 ( youtube_id ) 轉換成播放器

/web/modules/contrib/ 底下建立目錄 youtube_embed

接著在目錄底下建立 youtube_embed.info.yml

name: 'YouTube Embed Formatter'
type: module
description: 'Formats a field containing a YouTube ID as an embedded video.'
core_version_requirement: ^10|^11
package: Custom
dependencies:
  - field

mkdir -p src/Plugin/Field/FieldFormatter/

cd src/Plugin/Field/FieldFormatter/

在目錄底下建立 YouTubeEmbedFormatter.php

<?php

namespace Drupal\youtube_embed\Plugin\Field\FieldFormatter;

use Drupal\Core\Field\FormatterBase;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;

/**
 * Plugin implementation of the 'youtube_embed' formatter.
 *
 * @FieldFormatter(
 *   id = "youtube_embed_formatter",
 *   label = @Translation("YouTube Embed with RWD and Autoplay"),
 *   field_types = {
 *     "string",
 *     "string_long"
 *   }
 * )
 */
class YouTubeEmbedFormatter extends FormatterBase {

  /**
   * {@inheritdoc}
   */
  public function viewElements(FieldItemListInterface $items, $langcode) {
    $elements = [];

    foreach ($items as $delta => $item) {
      // 取得 YouTube ID
      $youtube_id = trim($item->value);

      // 建立包含 RWD 功能和靜音自動播放的 iframe 標籤
      $elements[$delta] = [
        '#type' => 'markup',
        '#markup' => '<div class="youtube-video-wrapper"><iframe src="https://www.youtube.com/embed/' . htmlspecialchars($youtube_id, ENT_QUOTES, 'UTF-8') . '?autoplay=1&mute=0" frameborder="0" allowfullscreen></iframe></div>',
        '#allowed_tags' => ['iframe', 'div'],
      ];
    }

    return $elements;
  }
}

然後要搭配CSS達成RWD顯示

<style>
  /* 讓 YouTube 影片支援響應式 */
  .youtube-video-wrapper {
    position: relative;
    padding-bottom: 56.25%; /* 16:9 比例 */
    height: 0;
    overflow: hidden;
    max-width: 100%;
    background: #000;
    margin-bottom: 20px; /* 可選 */
  }

  .youtube-video-wrapper iframe {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
  }
</style>

 

很好玩的Drupal

說到架站一般人對Drupal是望之卻步,跟WordPress架站比,確實在是不好上手,但你如果搞懂的話,其實後期會比WordPress好玩及好用

因為基本上Drupal使用 Views + Block ,就能創作出各式各樣的內容出來,撈資料過程中比WordPress友善

WordPress需要寫function再搭配shortcode才能把欄位的資料叫出來,這兩年由於可以透過AI協助寫程式,也讓WordPress撈資料呈現容易許多,但就是要寫php就是了

Drupal7零散的筆記

Drupal7零散的筆記

使用 Nginx FastCGI 生成AMP快取的conf

我的語法,由於我的頁面本身就有drupal的快取服務,但這個快取服務在amp起不了作用,所以才使用這招
作法就是只讓有*?amp產出快取;另外還要研究登入使用者不用快取,可能要研究drupal的cookie吧?

fastcgi_cache_path /etc/nginx/cache levels=1:2 keys_zone=tainanoutook:200m max_size=10g inactive=2h use_temp_path=off;
fastcgi_cache_key "$scheme$request_method$host$request_uri";
fastcgi_ignore_headers Cache-Control Expires Set-Cookie;

set $skip_cache 1;

if ($request_uri ~* "/.*?amp") {
   set $skip_cache 0;
}

       include snippets/fastcgi-php.conf;
       fastcgi_cache tainanoutook;
       fastcgi_cache_valid 200 301 302 2h;
       fastcgi_cache_use_stale error timeout updating invalid_header http_500 http_503;
       fastcgi_cache_min_uses 1;
       fastcgi_cache_lock on;
       fastcgi_cache_bypass $skip_cache;
       fastcgi_no_cache $skip_cache;
       add_header X-FastCGI-Cache $upstream_cache_status;

 

Drupal7零散的筆記

Drupal7 Optimizing 優化速度

使用模組 chained_fast apcu registry_autoload xautoload

drush en chained_fast apcu registry_autoload xautoload expire -y
vi sites/default/settings.php
$conf['cache_backends'][] = 'sites/all/modules/apcu/apcu.cache.inc';
$conf['cache_backends'][] = 'sites/all/modules/chained_fast/chained_fast.cache.inc';

// Chained fast configuration.
$conf['chained_fast']['fast_backend'] = 'DrupalAPCuCache';

// Cache class configuration - This uses chained_fast for all caches except the form cache. This might not be suitable for all sites, but is a good default.
$conf['cache_default_class'] = 'ChainedFastBackend';
$conf['cache_class_cache_form'] = 'DrupalDatabaseCache';

admin/config/development/performance 下列全打勾

匿名使用者頁面快取
區塊快取
壓縮快取頁面
整合並壓縮 CSS 檔案
整合並壓縮 JavaScript 檔案
Self-updating APCu classmap (*) (Running and available)
APC (Running and available)
APCu (Running and available)
XCache (Not currently available)
Self-updating database classmap (*) (Running and available)
Postpone registration of module namespaces until the first cache miss (recommended)
Replace core class loader.

expire (Cache Expiration) 這個模組主要在控管內容更新後會清除快取
Status of implementation 勾選 Internal expiration
Modules that support external expiration 勾選 Include base URL in expires
Node expiration Node actions 全勾選
PS. 重要文章更新後,最好再用未登入的瀏覽器確認一次,如果內容仍然無法更新,就直接清除Drupal全站快取囉

Drupal7零散的筆記

Views PHP

Drupal 7能夠方便在views執行php的模組 https://www.drupal.org/project/views_php

顯示某個欄位內容 : field_dow 

<?php
// 假設 $data 是你已經從資料庫或其他來源獲取的資料
$field_dow = $data->_field_data['nid']['entity']->field_dow['und'];

// 提取 [field_dow] 內的值
$dow_values = array_map(function($item) {
    return $item['value'];
}, $field_dow);

// 印出結果
echo implode(', ', $dow_values);
?>

field_dow 的值為 1 ~ 7,接下來轉換成 一 ~ 日(星期)

<?php
// 假設 $data 是你已經從資料庫或其他來源獲取的資料
$field_dow = $data->_field_data['nid']['entity']->field_dow['und'];

// 數字對應的星期轉換表
$weekdays = [
    1 => '一',
    2 => '二',
    3 => '三',
    4 => '四',
    5 => '五',
    6 => '六',
    7 => '日'
];

// 提取 [field_dow] 內的值並轉換成星期
$dow_names = array_map(function($item) use ($weekdays) {
    return $weekdays[$item['value']];
}, $field_dow);

// 印出結果
echo implode(', ', $dow_names);
?>

我的站有一個功能是在撈夜市的的時間,例如今天是星期五,他就會只顯示星期五的夜市

使用 Views Day of Week (views_dow) 達成的,但由於他預出來的值是英文,不動原始碼的情況,就用這個作法去處理

Drupal7零散的筆記

Windows 11硬碟容量不足適放

powercfg.exe /hibernate off
磁碟清理釋放空間

Drupal零散筆記

Drupal零散筆記

Draupl 9 升級 Drupal 10

當你發現所有的模組相容性問題都搞定了

但是使用composer update 仍然無法觸發升級到Drupal 10

此時就要編修 composer.json 

^9.5 || ^10.0

Drupal零散筆記

composer

Drupal(最新版) 比較建議使用 composer 做安裝管理
日後的升級以及模組的安裝,也會比較順暢
而且切記,一定要一開始就使用 composer ,所以就從 composer 開始囉!

使用Drupal(最新版)的第一步,安裝Drupal 及 Drush

composer create-project drupal/recommended-project drupal
cd drupal
chown -R www-data:www:data web
composer require drush/drush

安裝及啟用模組

composer require 'drupal/paragraphs:^1.14'
drush en paragraphs

反安裝模組
先到 /admin/modules/uninstall 勾選解除安裝
然後再執行

composer remove drupal/paragraphs

更新Drupal及模組

composer update
執行完composer的安裝或變動時,最好再做一下drush更新及清理快取

PS. 我後來發生直接用 composer update 後出現一些問題,後來我就根據模組更新,例如token有更新版,那就直接用 composer require drupal/token 讓新版蓋過去,然後再跑一下drush updatedb;drush cr

drush updatedb
drush cr

通常如果沒用到冷門的模組,理論上都有辧法用 composer update 一路升級上去

另外,有時候遇到無解的錯誤畫面,有候可以重啟 php-fpm

composer 更新不問權限

composer self-update --2
update-alternatives --set php /usr/bin/php8.1
export COMPOSER_ALLOW_SUPERUSER=1
cd /var/www/mysite/
composer update;drush updatedb -y;drush cr

 

 

Drupal零散筆記

Drupal 10安裝後設定檢查

裝好Drupal後,第一件事就是先檢查狀態,進入 admin/reports/status,儘可能讓所有的問題pass


更新通知 未啟用

Update notifications are not enabled. It is highly recommended that you install the Update Manager module from the module administration page in order to stay up-to-date on new releases. For more information, Update status handbook page.

執行

drush cdel update.settings

然後再進入 admin/modules
啟用 Update Manager


Trusted Host Settings 未啟用

The trusted_host_patterns setting is not configured in settings.php. This can lead to security vulnerabilities. It is highly recommended that you configure this. See Protecting against HTTP HOST Header attacks for more information.

參考頁面照寫即可 https://www.drupal.org/docs/getting-started/installing-drupal/trusted-host-settings

$settings['trusted_host_patterns'] = [
  '^.+\.example\.com\.tw$',
];

 

Drupal零散筆記

安裝翻譯檔

如果裝好Drupal後發現語法仍然是英文版,可以這樣做

先到 

/admin/config/regional/settings

設定預設國家

 

接下來到 

/admin/reports/translations

更翻譯檔

 

最後到 

/admin/config/development/performance

清快取

 

順利的話介面就會變成你所設定的語系環境

Drupal零散筆記

狀態報告中的錯誤及警告(docker)

先進 /admin/reports/status

第一次進來,一定會看到1個錯誤與幾個警告,接下來就來一一解決它們

錯誤

Trusted Host Settings

docker 一條直接處理

docker exec -it dp-drupal-1 bash -c "echo '\$settings[\"trusted_host_patterns\"] = [\"^.+\\.yoursite\\.com$\"];' >> /opt/drupal/web/sites/default/settings.php"

bash

echo '\$settings[\"trusted_host_patterns\"] = [\"^.+\\.yoursite\\.com$\"];' >> /opt/drupal/web/sites/default/settings.php

警告

Output buffering

docker exec -it dp-drupal-1 bash -c "echo 'output_buffering=On' > /usr/local/etc/php/conf.d/custom-php.ini"
docker exec -it dp-drupal-1 service apache2 restart

模組和版型更新狀態

drush cdel update.settings

然後再進入 admin/modules
啟用 Update Manager

啟用 PHP APCu available caching 及 上載進度

先進入主機 

docker exec -it dp-drupal-1 bash

執行

 pecl install apcu 

直接按enter跑完

執行

pecl install uploadprogress

直接按enter跑完

到 /usr/local/etc/php/conf.d/custom-php.ini 加入

extension=uploadprogress.so
extension=apcu.so 

接著再重啟docker環境,就能看到APCu及上載進度啟用

這裡的一些警告其實不見得沒個都要處理及解決,網站能順跑即可

這裡是用docker的筆記,非docker版有些問題或許不會遇到

Drupal零散筆記

drupal 10 升級 drupal 11筆記

composer why-not drupal/core 11.1.0

列出
composer why-not drupal/core 11.1.0
drupal/core-recommended    10.4.0 requires         drupal/core (10.4.0)                                       
drupal/core                11.1.0 requires         symfony/console (^7.2)                                     
drupal/recommended-project -      does not require symfony/console (but v6.4.15 is installed)                 
drupal/core                11.1.0 requires         symfony/dependency-injection (^7.2)                        
drupal/recommended-project -      does not require symfony/dependency-injection (but v6.4.16 is installed)    
drupal/core                11.1.0 requires         symfony/event-dispatcher (^7.2)                            
drupal/recommended-project -      does not require symfony/event-dispatcher (but v6.4.13 is installed)        
drupal/core                11.1.0 requires         symfony/filesystem (^7.2)                                  
drupal/recommended-project -      does not require symfony/filesystem (but v6.4.13 is installed)              
drupal/core                11.1.0 requires         symfony/finder (^7.2)                                      
drupal/recommended-project -      does not require symfony/finder (but v6.4.13 is installed)                  
drupal/core                11.1.0 requires         symfony/http-foundation (^7.2)                             
drupal/recommended-project -      does not require symfony/http-foundation (but v6.4.16 is installed)         
drupal/core                11.1.0 requires         symfony/http-kernel (^7.2)                                 
drupal/recommended-project -      does not require symfony/http-kernel (but v6.4.16 is installed)             
drupal/core                11.1.0 requires         symfony/mailer (^7.2)                                      
drupal/recommended-project -      does not require symfony/mailer (but v6.4.13 is installed)                  
drupal/core                11.1.0 requires         symfony/mime (^7.2)                                        
drupal/recommended-project -      does not require symfony/mime (but v6.4.13 is installed)                    
drupal/core                11.1.0 requires         symfony/routing (^7.2)                                     
drupal/recommended-project -      does not require symfony/routing (but v6.4.16 is installed)                 
drupal/core                11.1.0 requires         symfony/serializer (^7.2)                                  
drupal/recommended-project -      does not require symfony/serializer (but v6.4.15 is installed)              
drupal/core                11.1.0 requires         symfony/validator (^7.2)                                   
drupal/recommended-project -      does not require symfony/validator (but v6.4.16 is installed)               
drupal/core                11.1.0 requires         symfony/process (^7.2)                                     
drupal/recommended-project -      does not require symfony/process (but v6.4.15 is installed)                 
drupal/core                11.1.0 requires         symfony/yaml (^7.2)                                        
drupal/recommended-project -      does not require symfony/yaml (but v6.4.13 is installed)                    
drupal/core                11.1.0 requires         doctrine/annotations (^2.0)                                
drupal/recommended-project -      does not require doctrine/annotations (but 1.14.4 is installed)             
drupal/core                11.1.0 requires         symfony/psr-http-message-bridge (^7.2)                     
drupal/recommended-project -      does not require symfony/psr-http-message-bridge (but v6.4.13 is installed) 
Not finding what you were looking for? Try calling `composer update "drupal/core:11.1.0" --dry-run` to get another view on the problem.

然後執行 

composer require drupal/core-recommended:^11.0 --update-with-all-dependencies

出現錯誤

  Problem 1

    - Root composer.json requires drupal/core-recommended ^11.0 -> satisfiable by drupal/core-recommended[11.0.0, ..., 11.1.0].

    - drupal/core-recommended[11.0.0, ..., 11.0.9] require symfony/console ~v7.1.3 -> found symfony/console[v7.1.3, ..., v7.1.8] but these were not loaded, likely because it conflicts with another require.

    - drupal/core-recommended 11.1.0 requires symfony/console ~v7.2.0 -> found symfony/console[v7.2.0, v7.2.1] but these were not loaded, likely because it conflicts with another require.

rm composer.lock

rm -rf vendor/

再執行

composer require drupal/core-recommended:^11.0 --update-with-all-dependencies

然後 drush updatedb ; drush cr

一定要備份再執行!

救援

萬一不幸更新出錯,第一件事就要先去看 nginx log 找出問題的來源

cat /var/log/nginx/error.log

如果是版型的問題,可以用 drush 改回預設版型

drush config:set system.theme default olivero

或 bartik

Docker安裝Drupal 11 及 Php8.3環境

Yaml這樣寫

# Drupal 11 with MySQL and PHP 8.3
#
# Access via "http://localhost:8080"
#   (or "http://$(docker-machine ip):8080" if using docker-machine)
#
# During initial Drupal setup,
# Database type: MySQL
# Database name: drupal
# Database username: root
# Database password: example
# ADVANCED OPTIONS; Database host: mysql
version: '3.1'
services:
 drupal:
   image: drupal:11-apache
   ports:
     - 8080:80
   environment:
     PHP_VERSION: "8.3"
   volumes:
     - /var/www/html/modules
     - /var/www/html/profiles
     - /var/www/html/themes
     - /var/www/html/sites
   restart: always
 mysql:
   image: mysql:8.0
   environment:
     MYSQL_ROOT_PASSWORD: example
     MYSQL_DATABASE: drupal
   restart: always

Nginx conf

server {
   server_name www.yoursite.com;
   location / {
       proxy_pass http://127.0.0.1:8080;
       proxy_set_header Host $host;
       proxy_set_header X-Real-IP $remote_addr;
       proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
       proxy_set_header X-Forwarded-Proto $scheme;
   }
}

後續維護

首先要學會用composer及drush來更新及管理程式

安裝 7zip,composer 會用得到

docker exec -it dp-drupal-1 apt update
docker exec -it dp-drupal-1 apt install unzip

裝好後把drush更新到最新版

docker exec -it dp-drupal-1 composer require drush/drush

然後更主程式 

docker exec -it dp-drupal-1 composer update

更新及整理資料庫

docker exec -it dp-drupal-1 drush updatedb
docker exec -it dp-drupal-1 drush cr

Redis

由於我有多個站,又希望他們互不干擾,我採用docker的方做配置

version: '3'
services:
  redis-site1:
    image: redis:latest
    command: redis-server --requirepass your_password1 --port 6379
    ports:
      - "6384:6379"
    volumes:
      - redis-data-site1:/data
  redis-site2:
    image: redis:latest
    command: redis-server --requirepass your_password2 --port 6379
    ports:
      - "6380:6379"
    volumes:
      - redis-data-site2:/data
  redis-site3:
    image: redis:latest
    command: redis-server --requirepass your_password3 --port 6379
    ports:
      - "6381:6379"
    volumes:
      - redis-data-site3:/data
  redis-site4:
    image: redis:latest
    command: redis-server --requirepass your_password4 --port 6379
    ports:
      - "6382:6379"
    volumes:
      - redis-data-site4:/data
  redis-site5:
    image: redis:latest
    command: redis-server --requirepass your_password5 --port 6379
    ports:
      - "6383:6379"
    volumes:
      - redis-data-site5:/data

volumes:
  redis-data-site1:
  redis-data-site2:
  redis-data-site3:
  redis-data-site4:
  redis-data-site5:

啟用後,就可以在 drupal 安裝及啟用Redis

Redis啟用後,需手動做設定

cp modules/contrib/redis/example.services.yml sites/default/services.yml
vi sites/default/settings.php
// Redis 配置
$settings['redis.connection']['interface'] = 'PhpRedis';
$settings['redis.connection']['host'] = 'localhost';
$settings['redis.connection']['port'] = 6383;
$settings['redis.connection']['password'] = 'your_password5'; // 這裡填你的 Redis 密碼
$settings['redis.connection']['persistent'] = TRUE;
$settings['cache']['default'] = 'cache.backend.redis';

$settings['container_yamls'][] = 'sites/default/services.yml';

// 設定快取 bin
$settings['cache']['bins']['default'] = 'cache.backend.redis';
$settings['cache']['bins']['form'] = 'cache.backend.database'; // 表單快取不建議用 Redis


// 啟用 fast cache
$settings['cache']['bins']['render'] = 'cache.backend.redis';
$settings['cache']['bins']['dynamic_page_cache'] = 'cache.backend.redis';
$settings['cache']['bins']['page'] = 'cache.backend.redis';

Docker配置5個獨立的容器,其餘的站可以照作

大量刪除文章cron壞掉解決方法

執行

drush sqlq "SHOW PROCESSLIST;"

找到後執行刪除

drush sqlq "KILL <新的Thread ID>;"