├── Api
├── Data
│ ├── PageNotFoundInterface.php
│ └── PageNotFoundSearchResultsInterface.php
└── PageNotFoundRepositoryInterface.php
├── Block
├── Adminhtml
│ └── Page
│ │ └── Not
│ │ └── Found
│ │ └── Edit
│ │ ├── BackButton.php
│ │ ├── DeleteButton.php
│ │ ├── GenericButton.php
│ │ ├── SaveAndContinueButton.php
│ │ └── SaveButton.php
└── Response
│ └── Gone.php
├── CHANGELOG.md
├── Console
└── Command
│ ├── Clean.php
│ └── Import.php
├── Controller
├── Adminhtml
│ ├── Pagenotfound.php
│ └── Pagenotfound
│ │ ├── Delete.php
│ │ ├── Edit.php
│ │ ├── Index.php
│ │ ├── InlineEdit.php
│ │ ├── NewAction.php
│ │ └── Save.php
└── Response
│ └── Gone.php
├── Cron
└── Clean.php
├── Helper
├── Settings.php
└── UrlCleanUp.php
├── MANUAL.md
├── Model
├── PageNotFound.php
├── PageNotFoundRepository.php
├── Pagenotfound
│ └── DataProvider.php
└── ResourceModel
│ ├── PageNotFound.php
│ └── PageNotFound
│ └── Collection.php
├── Observer
└── Controller
│ └── ActionPredispatch.php
├── README.md
├── Ui
└── Component
│ └── Listing
│ └── Column
│ ├── Link.php
│ └── PagenotfoundActions.php
├── composer.json
├── etc
├── acl.xml
├── adminhtml
│ ├── di.xml
│ ├── menu.xml
│ ├── routes.xml
│ └── system.xml
├── config.xml
├── crontab.xml
├── db_schema.xml
├── db_schema_whitelist.json
├── di.xml
├── frontend
│ ├── events.xml
│ └── routes.xml
└── module.xml
├── registration.php
└── view
├── adminhtml
├── layout
│ ├── experius_pagenotfound_pagenotfound_edit.xml
│ ├── experius_pagenotfound_pagenotfound_index.xml
│ └── experius_pagenotfound_pagenotfound_new.xml
└── ui_component
│ ├── experius_page_not_found_form.xml
│ └── experius_page_not_found_index.xml
└── frontend
├── layout
└── experius_pagenotfound_response_gone.xml
└── templates
└── response
└── gone.phtml
/Api/Data/PageNotFoundInterface.php:
--------------------------------------------------------------------------------
1 | __('Back'),
18 | 'on_click' => sprintf("location.href = '%s';", $this->getBackUrl()),
19 | 'class' => 'back',
20 | 'sort_order' => 10
21 | ];
22 | }
23 |
24 | /**
25 | * Get URL for back (reset) button
26 | *
27 | * @return string
28 | */
29 | public function getBackUrl()
30 | {
31 | return $this->getUrl('*/*/');
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/Block/Adminhtml/Page/Not/Found/Edit/DeleteButton.php:
--------------------------------------------------------------------------------
1 | getModelId()) {
18 | $data = [
19 | 'label' => __('Delete Redirect'),
20 | 'class' => 'delete',
21 | 'on_click' => 'deleteConfirm(\'' . __(
22 | 'Are you sure you want to do this?'
23 | ) . '\', \'' . $this->getDeleteUrl() . '\')',
24 | 'sort_order' => 20,
25 | ];
26 | }
27 | return $data;
28 | }
29 |
30 | /**
31 | * Get URL for delete button
32 | *
33 | * @return string
34 | */
35 | public function getDeleteUrl()
36 | {
37 | return $this->getUrl('*/*/delete', ['page_not_found_id' => $this->getModelId()]);
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/Block/Adminhtml/Page/Not/Found/Edit/GenericButton.php:
--------------------------------------------------------------------------------
1 | context = $context;
19 | }
20 |
21 | /**
22 | * Return model ID
23 | *
24 | * @return int|null
25 | */
26 | public function getModelId()
27 | {
28 | return $this->context->getRequest()->getParam('page_not_found_id');
29 | }
30 |
31 | /**
32 | * Generate url by route and parameters
33 | *
34 | * @param string $route
35 | * @param array $params
36 | * @return string
37 | */
38 | public function getUrl($route = '', $params = [])
39 | {
40 | return $this->context->getUrlBuilder()->getUrl($route, $params);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/Block/Adminhtml/Page/Not/Found/Edit/SaveAndContinueButton.php:
--------------------------------------------------------------------------------
1 | __('Save and Continue Edit'),
18 | 'class' => 'save',
19 | 'data_attribute' => [
20 | 'mage-init' => [
21 | 'button' => ['event' => 'saveAndContinueEdit'],
22 | ],
23 | ],
24 | 'sort_order' => 80,
25 | ];
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/Block/Adminhtml/Page/Not/Found/Edit/SaveButton.php:
--------------------------------------------------------------------------------
1 | __('Save Redirect'),
18 | 'class' => 'save primary',
19 | 'data_attribute' => [
20 | 'mage-init' => ['button' => ['event' => 'save']],
21 | 'form-role' => 'save',
22 | ],
23 | 'sort_order' => 90,
24 | ];
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Block/Response/Gone.php:
--------------------------------------------------------------------------------
1 | pageConfig->addBodyClass('410');
12 | $this->pageConfig->getTitle()->set('410 Gone');
13 | //$this->pageConfig->setKeywords();
14 | //$this->pageConfig->setDescription();
15 |
16 | $pageMainTitle = $this->getLayout()->getBlock('page.main.title');
17 | $pageMainTitle->setPageTitle(__('Whoops, our bad...'));
18 |
19 | return parent::_prepareLayout();
20 | }
21 |
22 | }
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ## 1.4.3 (2024-05-31)
2 |
3 | [View Release](git@github.com:experius/Magento-2-Module-PageNotFound.git/commits/tag/1.4.3)
4 |
5 | * [FEATURE][JIRA-123]added graphQL suport in base function to extend pagenotfoundgraphql *(simon vianen)*
6 | * [FEATURE][JIRA-123]git added docblock, fixt typo, changed from url creation for graphql to the top of the savePageNotFound Function *(simon vianen)*
7 | * [FEATURE][JIRA-123]Added my name to the composer.json *(simon vianen)*
8 |
9 |
10 | ## 1.4.2 (2024-03-26)
11 |
12 | [View Release](git@github.com:experius/Magento-2-Module-PageNotFound.git/commits/tag/1.4.2)
13 |
14 | * [FEATURE][JIRA-123]removed unnecessary 404 counter when url is being redirected *(simon vianen)*
15 |
16 |
17 | ## 1.4.1 (2024-03-22)
18 |
19 | [View Release](git@github.com:experius/Magento-2-Module-PageNotFound.git/commits/tag/1.4.1)
20 |
21 | * [FEATURE][IN23-62] updated CHANGELOG.md *(simon vianen)*
22 | * [FEATURE][IN23-325] updated CHANGELOG.md and README.md *(simon vianen)*
23 | * [FEATURE][IN23-284] added storeview to admin grid with filter *(simon vianen)*
24 | * [FEATURE][IN23-284] added '0' return to getStoreId if id is 'NUL' *(simon vianen)*
25 | * [FEATURE][IN23-284] Fixed typo's *(simon vianen)*
26 |
27 |
28 | ## 1.4.0 (2024-03-20)
29 |
30 | [View Release](git@github.com:experius/Magento-2-Module-PageNotFound.git/commits/tag/1.4.0)
31 |
32 | * [feature][IN23-325]added cron job and consol command *(simon vianen)*
33 | * [FEATURE][IN23-325]Removed unused code and spel check *(simon vianen)*
34 | * [feature][IN23-325]restored refactord code *(simon vianen)*
35 | * [feature][IN23-325]added cron_config to config.xml *(simon vianen)*
36 | * [feature][IN23-325] chaged code to fit magento core *(simon vianen)*
37 | * [FEATURE][IN23-325]Shortend query buiding *(simon vianen)*
38 |
39 |
40 | ## 1.3.8 (2024-03-18)
41 |
42 | [View Release](git@github.com:experius/Magento-2-Module-PageNotFound.git/commits/tag/1.3.8)
43 |
44 | * [FEATURE][IN23-62] added collumn last visited *(simon vianen)*
45 |
46 |
47 | ## 1.3.7 (2024-03-07)
48 |
49 | [View Release](git@github.com:experius/Magento-2-Module-PageNotFound.git/commits/tag/1.3.7)
50 |
51 | * [FEATURE][JIRA-1024] changed the from_url to varchar 520 + added index for column *(Thomas Mondeel)*
52 |
53 |
54 | ## 1.3.6 (2024-02-02)
55 |
56 | [View Release](git@github.com:experius/Magento-2-Module-PageNotFound.git/commits/tag/1.3.6)
57 |
58 | * [FEATURE][JIRA-123] compatible with magento-coding-standards 33 *(Matthijs Iriks)*
59 |
60 |
61 | ## 1.3.5 (2023-10-26)
62 |
63 | [View Release](git@github.com:experius/Magento-2-Module-PageNotFound.git/commits/tag/1.3.5)
64 |
65 | * [BUGFIX][IN23-251] Convert setup scripts to db_schema.xml conform newer Magento 2 standards. *(Boris van Katwijk)*
66 |
67 |
68 | ## 1.3.4 (2023-05-09)
69 |
70 | [View Release](git@github.com:experius/Magento-2-Module-PageNotFound.git/commits/tag/1.3.4)
71 |
72 | * Declared dynamic property to fix PHP8.2 error *(Experius)*
73 |
74 |
75 | ## 1.3.3 (2022-04-28)
76 |
77 | [View Release](git@github.com:experius/Magento-2-Module-PageNotFound.git/commits/tag/1.3.3)
78 |
79 | * [BUGFIX] - Deprecated Functionality: explode(): Passing null to parameter #2 ($string) of type string is deprecated *(Ruben Panis)*
80 |
81 |
82 | ## 1.3.2 (2021-08-02)
83 |
84 | [View Release](git@github.com:experius/Magento-2-Module-PageNotFound.git/commits/tag/1.3.2)
85 |
86 | * [BUGFIX] Use page_not_found_view ACL resource *(Lewis Voncken)*
87 |
88 |
89 | ## 1.3.1 (2021-07-15)
90 |
91 | [View Release](git@github.com:experius/Magento-2-Module-PageNotFound.git/commits/tag/1.3.1)
92 |
93 | * Update README.md *(Experius)*
94 | * [BUGFIX][STJ-937] Added classWhitelist on the configurable object. *(Gijs Blanken)*
95 |
96 |
97 | ## 1.3.0 (2020-09-18)
98 |
99 | [View Release](git@github.com:experius/Magento-2-Module-PageNotFound.git/commits/tag/1.3.0)
100 |
101 | * [PERFORMANCE] Added index to the experius_page_not_found *(Lewis Voncken)*
102 |
103 |
104 | ## 1.2.8 (2020-05-06)
105 |
106 | [View Release](git@github.com:experius/Magento-2-Module-PageNotFound.git/commits/tag/1.2.8)
107 |
108 | * Added handout for product import to readme.md *(pascalexperius)*
109 |
110 |
111 | ## 1.2.7 (2019-11-27)
112 |
113 | [View Release](git@github.com:experius/Magento-2-Module-PageNotFound.git/commits/tag/1.2.7)
114 |
115 | * [BUGFIX] Magento 2.3.3 admin grid fix *(dheesbeen)*
116 |
117 |
118 | ## 1.2.6 (2019-08-30)
119 |
120 | [View Release](git@github.com:experius/Magento-2-Module-PageNotFound.git/commits/tag/1.2.6)
121 |
122 | * [BUGFIX] - Removed use of non-existent variable *(Ruben Panis)*
123 | * [REFACTOR] - Fixed some code standard bugs/warnings *(Ruben Panis)*
124 | * [BUGFIX] - Fixed exception message with correct variablename *(Ruben Panis)*
125 | * [REFACTOR] Change way to ignore exit with code sniffer, now passes checks *(Ruben Panis)*
126 |
127 |
128 | ## 1.2.5 (2018-01-11)
129 |
130 | [View Release](git@github.com:experius/Magento-2-Module-PageNotFound.git/commits/tag/1.2.5)
131 |
132 | * [BUGFIX] Forward to 410 instate of redirecting to the controller to prevent a 302 redirect *(Lewis Voncken)*
133 |
134 |
135 | ## 1.2.4 (2017-10-24)
136 |
137 | [View Release](git@github.com:experius/Magento-2-Module-PageNotFound.git/commits/tag/1.2.4)
138 |
139 | * [BUGFIX] Updated module.xml version to 1.0.1 *(Mr. Lewis)*
140 |
141 |
142 | ## 1.2.3 (2017-10-20)
143 |
144 | [View Release](git@github.com:experius/Magento-2-Module-PageNotFound.git/commits/tag/1.2.3)
145 |
146 | * [BUGFIX] import getoptions error, grid history save *(Derrick Heesbeen)*
147 |
148 |
149 | ## 1.2.2 (2017-10-20)
150 |
151 | [View Release](git@github.com:experius/Magento-2-Module-PageNotFound.git/commits/tag/1.2.2)
152 |
153 | * [TASK] Repository changes Pull request Bart *(Derrick Heesbeen)*
154 |
155 |
156 | ## 1.2.1 (2017-10-20)
157 |
158 | [View Release](git@github.com:experius/Magento-2-Module-PageNotFound.git/commits/tag/1.2.1)
159 |
160 | * [TASK] add duplicate from_url check *(Derrick Heesbeen)*
161 |
162 |
163 | ## 1.2.0 (2017-10-20)
164 |
165 | [View Release](git@github.com:experius/Magento-2-Module-PageNotFound.git/commits/tag/1.2.0)
166 |
167 | * [TASK] added 410 redirect option and 410 response page *(Derrick Heesbeen)*
168 |
169 |
170 | ## 1.0.14 (2017-10-03)
171 |
172 | [View Release](git@github.com:experius/Magento-2-Module-PageNotFound.git/commits/tag/1.0.14)
173 |
174 | * Revert "[TASK] Made from_url unique, if database already contains duplicates those are merged" *(Derrick Heesbeen)*
175 |
176 |
177 | ## 1.1.0 (2017-09-15)
178 |
179 | [View Release](git@github.com:experius/Magento-2-Module-PageNotFound.git/commits/tag/1.1.0)
180 |
181 | * [TASK] Add compatibility with Experius ContentPage module *(bartlubbersen)*
182 | * [TASK] Made from_url unique, if database already contains duplicates those are merged [TASK] If new redirect is added through back-end but from_url already exists the page with that url is updated and warning is shown [BUGFIX] There can't be duplicate from_url's because those caused the issue that only the first could be redirected *(Bart Lubbersen)*
183 |
184 |
185 | ## 1.0.13 (2017-09-06)
186 |
187 | [View Release](git@github.com:experius/Magento-2-Module-PageNotFound.git/commits/tag/1.0.13)
188 |
189 | * [FEATURE] find and replace command *(Derrick Heesbeen)*
190 | * [BUGFIX] moved replace script to separated module *(Derrick Heesbeen)*
191 | * [BUGFIX] Fix to make acl work *(Derrick Heesbeen)*
192 |
193 |
194 | ## 1.0.12 (2017-08-22)
195 |
196 | [View Release](git@github.com:experius/Magento-2-Module-PageNotFound.git/commits/tag/1.0.12)
197 |
198 | * [BUGFIX] bug in import when using a replace url, bug with nog redirecting in live modus *(Derrick Heesbeen)*
199 |
200 |
201 | ## 1.0.11 (2017-08-22)
202 |
203 | [View Release](git@github.com:experius/Magento-2-Module-PageNotFound.git/commits/tag/1.0.11)
204 |
205 | * [BUGFIX] unique command name in di xml decleration *(Derrick Heesbeen)*
206 |
207 |
208 | ## 1.0.10 (2017-08-22)
209 |
210 | [View Release](git@github.com:experius/Magento-2-Module-PageNotFound.git/commits/tag/1.0.10)
211 |
212 | * [FEATURE] Console import script for csv redirect list *(Derrick Heesbeen)*
213 |
214 |
215 | ## 1.0.9 (2017-08-18)
216 |
217 | [View Release](git@github.com:experius/Magento-2-Module-PageNotFound.git/commits/tag/1.0.9)
218 |
219 | * [BUGFIX] add params to redirect url check on excisting params *(Derrick Heesbeen)*
220 |
221 |
222 | ## 1.0.8 (2017-08-18)
223 |
224 | [View Release](git@github.com:experius/Magento-2-Module-PageNotFound.git/commits/tag/1.0.8)
225 |
226 | * Update ActionPredispatch.php *(Derrick Heesbeen)*
227 | * [FEATURE] Made setting less complex :-) *(Derrick Heesbeen)*
228 |
229 |
230 | ## 1.0.6 (2017-08-18)
231 |
232 | [View Release](git@github.com:experius/Magento-2-Module-PageNotFound.git/commits/tag/1.0.6)
233 |
234 | * [FEATURE] include params for saved from url *(Derrick Heesbeen)*
235 |
236 |
237 | ## 1.0.5 (2017-08-15)
238 |
239 | [View Release](git@github.com:experius/Magento-2-Module-PageNotFound.git/commits/tag/1.0.5)
240 |
241 | * [FEATURE] added settings, added exluded params options *(Derrick Heesbeen)*
242 |
243 |
244 | ## 1.0.4 (2017-07-31)
245 |
246 | [View Release](git@github.com:experius/Magento-2-Module-PageNotFound.git/commits/tag/1.0.4)
247 |
248 | * [BUGFIX] Temp Fix for redirect to work with fpc *(Derrick Heesbeen)*
249 |
250 |
251 | ## 1.0.3 (2017-07-27)
252 |
253 | [View Release](git@github.com:experius/Magento-2-Module-PageNotFound.git/commits/tag/1.0.3)
254 |
255 | * [BUGFIX] solved fatal error of Interface implementation *(Lewis Voncken)*
256 |
257 |
258 | ## 1.0.2 (2017-07-25)
259 |
260 | [View Release](git@github.com:experius/Magento-2-Module-PageNotFound.git/commits/tag/1.0.2)
261 |
262 | * Fix typos *(Tim Neutkens)*
263 | * [TASK] make link in grids and add params to redirect *(Derrick Heesbeen)*
264 |
265 |
266 | ## 1.0.1 (2017-06-22)
267 |
268 | [View Release](git@github.com:experius/Magento-2-Module-PageNotFound.git/commits/tag/1.0.1)
269 |
270 | * [FEATURE] Updated readme with menu item location *(Derrick Heesbeen)*
271 | * [BUGFIX] admin form save issue, renamed to correct title *(Derrick Heesbeen)*
272 |
273 |
274 | ## 1.0.0 (2017-06-22)
275 |
276 | [View Release](git@github.com:experius/Magento-2-Module-PageNotFound.git/commits/tag/1.0.0)
277 |
278 | * first commit *(Derrick Heesbeen)*
279 |
280 |
281 |
--------------------------------------------------------------------------------
/Console/Command/Clean.php:
--------------------------------------------------------------------------------
1 | setName("experius_pagenotfound:clean")
43 | ->setDescription("Cleanup old reports.")
44 | ->setDefinition($options);
45 |
46 | parent::configure();
47 | }
48 |
49 | /**
50 | * {@inheritdoc}
51 | */
52 | protected function execute(InputInterface $input, OutputInterface $output)
53 | {
54 | if ($days = $input->getOption(self::DAYS)) {
55 | if(!is_numeric($days)) {
56 | $output->writeln($days . " is not a number");
57 | return Cli::RETURN_FAILURE;
58 | }
59 | $output->writeln("Deleting everything older than " . $days . " days.");
60 | $deletionCount = $this->cleanUp->execute($days);
61 | } else {
62 | $output->writeln("No days given, using days from admin if available.");
63 | $deletionCount = $this->cleanUp->execute();
64 | }
65 | $output->writeln('Removed ' . $deletionCount . ' from 404 reports.');
66 | return Cli::RETURN_SUCCESS;
67 | }
68 |
69 | }
70 |
71 |
--------------------------------------------------------------------------------
/Console/Command/Import.php:
--------------------------------------------------------------------------------
1 | csv = $csv;
47 | $this->state = $state;
48 | $this->directoryList = $directoryList;
49 | $this->pageNotFoundFactory = $pageNotFoundFactory;
50 | $this->storeRepository = $storeRepository;
51 | $this->storeManager = $storeManager;
52 |
53 | return parent::__construct();
54 | }
55 |
56 | protected function execute(
57 | InputInterface $input,
58 | OutputInterface $output
59 | ) {
60 |
61 | $this->input = $input;
62 | $this->output = $output;
63 |
64 | $this->state->setAreaCode('adminhtml');
65 |
66 | $csvRows = $this->readCsv();
67 |
68 | $convertedRows = $this->convertRows($csvRows);
69 |
70 | if(!$this->input->getOption(self::DRY_RUN_OPTION)) {
71 | $this->importRedirects($convertedRows);
72 | }
73 |
74 | $this->renderConversion($convertedRows);
75 |
76 | }
77 |
78 | protected function convertRows($csvRows){
79 | $rows = [];
80 | $count = 1;
81 | foreach($csvRows as $csvRow){
82 |
83 | if(!$csvRow[1]){
84 | continue;
85 | }
86 |
87 | $fromUrl = $this->replaceFromUrlDomain($csvRow[0]);
88 | $toUrl = $this->replaceToUrlDomain($csvRow[1]);
89 |
90 | $rows[] = ['from_url'=>$fromUrl,'to_url'=>$toUrl];
91 |
92 | if($this->input->getOption(self::DRY_RUN_OPTION) && $count>=10){
93 | break;
94 | }
95 |
96 | $count++;
97 | }
98 | return $rows;
99 | }
100 |
101 | protected function replaceToUrlDomain($url){
102 | if($this->input->getOption(self::TO_URL_REPLACE_OPTION)){
103 | $domain = $this->input->getOption(self::TO_URL_REPLACE_OPTION);
104 | $url = $this->replaceDomain($url,$domain);
105 | }
106 | return $url;
107 | }
108 |
109 | protected function replaceFromUrlDomain($url){
110 | if($this->input->getOption(self::FROM_URL_REPLACE_OPTION)){
111 | $domain = $this->input->getOption(self::FROM_URL_REPLACE_OPTION);
112 | $url = $this->replaceDomain($url,$domain);
113 | }
114 | return $url;
115 | }
116 |
117 | protected function replaceDomain($url,$domain){
118 | $urlParts = parse_url($url);
119 |
120 | $params = (isset($urlParts['query']) && $urlParts['query']) ? '?' . $urlParts['query'] : '';
121 | $path = (isset($urlParts['path']) && $urlParts['path']) ? $urlParts['path'] : '';
122 | $url = $domain . $path . $params;
123 |
124 | return $url;
125 | }
126 |
127 | protected function importRedirects($rows){
128 | foreach($rows as $row){
129 | $this->savePageNotFound($row['from_url'],$row['to_url']);
130 | }
131 | }
132 |
133 | protected function savePageNotFound($fromUrl,$toUrl){
134 | /* @var $pageNotFound \Experius\PageNotFound\Model\PageNotFound */
135 | $pageNotFound = $this->pageNotFoundFactory->create();
136 |
137 | $pageNotFound->load($fromUrl,'from_url');
138 | $storeId = $this->getStoreView($fromUrl);
139 |
140 | $pageNotFound->setFromUrl($fromUrl);
141 | $pageNotFound->setToUrl($toUrl);
142 | $pageNotFound->setStoreId($storeId);
143 | $pageNotFound->save();
144 | }
145 |
146 | protected function readCsv(){
147 |
148 | $filePath = ($this->input->getOption(self::FILENAME_OPTION)) ? $this->input->getOption(self::FILENAME_OPTION) : $this->directoryList->getPath($this->fileDirectory) . "/" . self::FILENAME_IMPORT;
149 |
150 | if(!file_exists($filePath)){
151 | $this->output->writeln("File not found");
152 | return false;
153 | }
154 |
155 | $rows = $this->csv->setDelimiter(';')->setEnclosure('"')->getData($filePath);
156 |
157 | return $rows;
158 | }
159 |
160 | /**
161 | * {@inheritdoc}
162 | */
163 | protected function configure()
164 | {
165 | $this->setName("experius_pagenotfound:import");
166 |
167 | $this->setDescription("Import 404 redirects");
168 |
169 | $this->addOption(
170 | self::FROM_URL_REPLACE_OPTION,'fr',
171 | InputOption::VALUE_OPTIONAL,
172 | 'Replace to url domain with'
173 | );
174 |
175 | $this->addOption(
176 | self::TO_URL_REPLACE_OPTION,'to',
177 | InputOption::VALUE_OPTIONAL,
178 | 'Replace to url domain with'
179 | );
180 |
181 | $this->addOption(
182 | self::FILENAME_OPTION,'f',
183 | InputOption::VALUE_OPTIONAL,
184 | 'Path to file'
185 | );
186 |
187 | $this->addOption(
188 | self::DRY_RUN_OPTION,'d',
189 | InputOption::VALUE_OPTIONAL,
190 | 'Dry run option'
191 | );
192 |
193 | parent::configure();
194 | }
195 |
196 | private function renderConversion($data)
197 | {
198 | $table = new Table($this->output);
199 |
200 | $table->setHeaders(array('From url', 'To url'));
201 | $table->setRows($data);
202 | $table->render($data);
203 | }
204 |
205 | /**
206 | * @param $fromUrl
207 | * @param $storeId
208 | */
209 | private function getStoreView($fromUrl)
210 | {
211 | $storeId = $this->storeManager->getDefaultStoreView()->getId();
212 | foreach ($this->storeRepository->getList() as $store) {
213 | if (strpos($fromUrl, $store->getBaseUrl(), 0) !== false) {
214 | $storeId = $store->getId();
215 | break;
216 | }
217 | }
218 | return $storeId;
219 | }
220 | }
221 |
--------------------------------------------------------------------------------
/Controller/Adminhtml/Pagenotfound.php:
--------------------------------------------------------------------------------
1 | _coreRegistry = $coreRegistry;
21 | parent::__construct($context);
22 | }
23 |
24 | /**
25 | * Init page
26 | *
27 | * @param \Magento\Backend\Model\View\Result\Page $resultPage
28 | */
29 | public function initPage($resultPage)
30 | {
31 | $resultPage->setActiveMenu(self::ADMIN_RESOURCE)
32 | ->addBreadcrumb(__('Experius'), __('Experius'))
33 | ->addBreadcrumb(__('Page Not Found'), __('Page Not Found'));
34 | return $resultPage;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/Controller/Adminhtml/Pagenotfound/Delete.php:
--------------------------------------------------------------------------------
1 | resultRedirectFactory->create();
18 | // check if we know what should be deleted
19 | $id = $this->getRequest()->getParam('page_not_found_id');
20 | if ($id) {
21 | try {
22 | // init model and delete
23 | $model = $this->_objectManager->create('Experius\PageNotFound\Model\PageNotFound');
24 | $model->load($id);
25 | $model->delete();
26 | // display success message
27 | $this->messageManager->addSuccessMessage(__('You deleted the Page Not Found.'));
28 | // go to grid
29 | return $resultRedirect->setPath('*/*/');
30 | } catch (\Exception $e) {
31 | // display error message
32 | $this->messageManager->addErrorMessage($e->getMessage());
33 | // go back to edit form
34 | return $resultRedirect->setPath('*/*/edit', ['page_not_found_id' => $id]);
35 | }
36 | }
37 | // display error message
38 | $this->messageManager->addErrorMessage(__('We can\'t find a Page Not Found to delete.'));
39 | // go to grid
40 | return $resultRedirect->setPath('*/*/');
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/Controller/Adminhtml/Pagenotfound/Edit.php:
--------------------------------------------------------------------------------
1 | resultPageFactory = $resultPageFactory;
22 | parent::__construct($context, $coreRegistry);
23 | }
24 |
25 | /**
26 | * Edit action
27 | *
28 | * @return \Magento\Framework\Controller\ResultInterface
29 | */
30 | public function execute()
31 | {
32 | // 1. Get ID and create model
33 | $id = $this->getRequest()->getParam('page_not_found_id');
34 | $model = $this->_objectManager->create('Experius\PageNotFound\Model\PageNotFound');
35 |
36 | // 2. Initial checking
37 | if ($id) {
38 | $model->load($id);
39 | if (!$model->getId()) {
40 | $this->messageManager->addErrorMessage(__('This Page Not Found no longer exists.'));
41 | /** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */
42 | $resultRedirect = $this->resultRedirectFactory->create();
43 | return $resultRedirect->setPath('*/*/');
44 | }
45 | }
46 | $this->_coreRegistry->register('experius_pagenotfound_page_not_found', $model);
47 |
48 | // 5. Build edit form
49 | /** @var \Magento\Backend\Model\View\Result\Page $resultPage */
50 | $resultPage = $this->resultPageFactory->create();
51 | $this->initPage($resultPage)->addBreadcrumb(
52 | $id ? __('Edit Page Not Found') : __('New Page Not Found'),
53 | $id ? __('Edit Page Not Found') : __('New Page Not Found')
54 | );
55 | $resultPage->getConfig()->getTitle()->prepend(__('Page Not Founds'));
56 | $resultPage->getConfig()->getTitle()->prepend($model->getId() ? $model->getTitle() : __('New Page Not Found'));
57 | return $resultPage;
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/Controller/Adminhtml/Pagenotfound/Index.php:
--------------------------------------------------------------------------------
1 | resultPageFactory = $resultPageFactory;
22 | parent::__construct($context);
23 | }
24 |
25 | /**
26 | * Index action
27 | *
28 | * @return \Magento\Framework\Controller\ResultInterface
29 | */
30 | public function execute()
31 | {
32 | $resultPage = $this->resultPageFactory->create();
33 | $resultPage->getConfig()->getTitle()->prepend(__("404 Reports"));
34 | return $resultPage;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/Controller/Adminhtml/Pagenotfound/InlineEdit.php:
--------------------------------------------------------------------------------
1 | jsonFactory = $jsonFactory;
21 | }
22 |
23 | /**
24 | * Inline edit action
25 | *
26 | * @return \Magento\Framework\Controller\ResultInterface
27 | */
28 | public function execute()
29 | {
30 | /** @var \Magento\Framework\Controller\Result\Json $resultJson */
31 | $resultJson = $this->jsonFactory->create();
32 | $error = false;
33 | $messages = [];
34 |
35 | if ($this->getRequest()->getParam('isAjax')) {
36 | $postItems = $this->getRequest()->getParam('items', []);
37 | if (!count($postItems)) {
38 | $messages[] = __('Please correct the data sent.');
39 | $error = true;
40 | } else {
41 | foreach (array_keys($postItems) as $modelid) {
42 | /** @var \Experius\PageNotFound\Model\PageNotFound $model */
43 | $model = $this->_objectManager->create('Experius\PageNotFound\Model\PageNotFound')->load($modelid);
44 | try {
45 | $model->setData(array_merge($model->getData(), $postItems[$modelid]));
46 | $model->save();
47 | } catch (\Exception $e) {
48 | $messages[] = "[Page Not Found ID: {$modelid}] {$e->getMessage()}";
49 | $error = true;
50 | }
51 | }
52 | }
53 | }
54 |
55 | return $resultJson->setData([
56 | 'messages' => $messages,
57 | 'error' => $error
58 | ]);
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/Controller/Adminhtml/Pagenotfound/NewAction.php:
--------------------------------------------------------------------------------
1 | resultForwardFactory = $resultForwardFactory;
22 | parent::__construct($context, $coreRegistry);
23 | }
24 |
25 | /**
26 | * New action
27 | *
28 | * @return \Magento\Framework\Controller\ResultInterface
29 | */
30 | public function execute()
31 | {
32 | /** @var \Magento\Framework\Controller\Result\Forward $resultForward */
33 | $resultForward = $this->resultForwardFactory->create();
34 | return $resultForward->forward('edit');
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/Controller/Adminhtml/Pagenotfound/Save.php:
--------------------------------------------------------------------------------
1 | dataPersistor = $dataPersistor;
23 | parent::__construct($context);
24 | }
25 |
26 | /**
27 | * Save action
28 | *
29 | * @return \Magento\Framework\Controller\ResultInterface
30 | */
31 | public function execute()
32 | {
33 | /** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */
34 | $resultRedirect = $this->resultRedirectFactory->create();
35 | $data = $this->getRequest()->getPostValue();
36 | if ($data) {
37 | $id = $this->getRequest()->getParam('page_not_found_id');
38 |
39 | $model = $this->_objectManager->create('Experius\PageNotFound\Model\PageNotFound')->load($id);
40 | if (!$model->getId() && $id) {
41 | $this->messageManager->addErrorMessage(__('This Page Not Found no longer exists.'));
42 | return $resultRedirect->setPath('*/*/');
43 | }
44 |
45 | $model->setData($data);
46 |
47 | try {
48 | $model->save();
49 | $this->messageManager->addSuccessMessage(__('You saved the Page Not Found.'));
50 | $this->dataPersistor->clear('experius_pagenotfound_page_not_found');
51 |
52 | if ($this->getRequest()->getParam('back')) {
53 | return $resultRedirect->setPath('*/*/edit', ['page_not_found_id' => $model->getId()]);
54 | }
55 | return $resultRedirect->setPath('*/*/');
56 | } catch (LocalizedException $e) {
57 | $this->messageManager->addErrorMessage($e->getMessage());
58 | } catch (AlreadyExistsException $e){
59 | $this->messageManager->addErrorMessage($e->getMessage());
60 | } catch (\Exception $e) {
61 | $this->messageManager->addExceptionMessage($e, __('Something went wrong while saving the Page Not Found.'));
62 | }
63 |
64 | $this->dataPersistor->set('experius_pagenotfound_page_not_found', $data);
65 | return $resultRedirect->setPath('*/*/edit', ['page_not_found_id' => $this->getRequest()->getParam('page_not_found_id')]);
66 | }
67 | return $resultRedirect->setPath('*/*/');
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/Controller/Response/Gone.php:
--------------------------------------------------------------------------------
1 | resultPageFactory = $resultPageFactory;
22 | parent::__construct($context);
23 | }
24 |
25 | /**
26 | * Execute view action
27 | *
28 | * @return \Magento\Framework\Controller\ResultInterface
29 | */
30 | public function execute()
31 | {
32 |
33 | $resultPage = $this->resultPageFactory->create();
34 |
35 | $resultPage->setStatusHeader(410, '1.1', 'Gone');
36 | $resultPage->setHeader('Status', '410 Gone');
37 |
38 | return $resultPage;
39 |
40 | }
41 | }
--------------------------------------------------------------------------------
/Cron/Clean.php:
--------------------------------------------------------------------------------
1 | settings->getIsCronEnabled()){
34 | $this->logger->info(__("Cron is disabled for '404 reports'"));
35 | return;
36 | }
37 | $this->cleanHelper->execute();
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/Helper/Settings.php:
--------------------------------------------------------------------------------
1 | scopeConfig->getValue(self::IS_CRON_ENABLED);
35 | }
36 |
37 | /**
38 | * @return int
39 | */
40 | public function getConfigDaysToClean()
41 | {
42 | return $this->scopeConfig->getValue(self::CONFIG_DAYS_TO_CLEAN);
43 | }
44 |
45 | /**
46 | * @return string
47 | */
48 | public function getDeleteNotEmpyRedirect()
49 | {
50 | return $this->scopeConfig->getValue(self::DELETE_NOT_EMPTY_REDIRECT);
51 | }
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/Helper/UrlCleanUp.php:
--------------------------------------------------------------------------------
1 | connection = $this->resourceConnection->getConnection();
35 | }
36 |
37 | /**
38 | * Get days to clean
39 | * @return int
40 | */
41 | public function getDaysToClean($days = null): int
42 | {
43 | if ($days) {
44 | return (int)$days;
45 | }
46 |
47 | return (int)$this->settings->getConfigDaysToClean();
48 | }
49 |
50 | /**
51 | * execute cleanup
52 | * @return int
53 | */
54 | public function execute($days = null): int
55 | {
56 | $where = ("last_visited < '" . date('c', time() - ($this->getDaysToClean($days) * (3600 * 24))) . "'");
57 |
58 | if(!$this->settings->getDeleteNotEmpyRedirect())
59 | $where .= (' AND to_url IS NULL');
60 |
61 | $deletionCount = $this->connection->delete(self::TABLE, $where);
62 |
63 | $this->logger->info(__('Experius 404 url Cleanup: Removed %1 records.', $deletionCount));
64 |
65 | return $deletionCount;
66 | }
67 |
68 | }
69 |
--------------------------------------------------------------------------------
/MANUAL.md:
--------------------------------------------------------------------------------
1 | # General
2 | You could see all 404 errors in the Magento admin
3 |
4 | System > Tools > 404 Reports
5 |
6 | This view displays 5 columns:
7 |
8 | * ID (for internal usage)
9 | * 404 Url (could be an actual 404 url or an expected 404 url)
10 | * Redirect To (url to forward to)
11 | * 404 Count (number of visits)
12 | * Action (edit or remove redirect)
13 |
14 | # Example
15 |
16 |
17 |
18 | # Add an redirect manually
19 | When you'r expecting a 404 result (for disabled products or pages) you could add a redirect.
20 |
21 | Example:
22 |
23 | _Page https://www.webshop.nl/cookies will be removed and be replaced by page https://www.webshop.nl/voorwaarden_
24 |
25 | ## Steps:
26 |
27 | * Open the 404 Reports table
28 | * Click"Add new Redirect"
29 | * Add the full old to the field "404 Url". In this case, that url would be "https://www.webshop.nl/cookies"
30 | * Add the full new url to the field "Redirect To". In this case, that url would be "https://www.webshop.nl/voorwaarden"
31 | * Click "Save Redirect"
32 | * Open the Magento front-end and navigate to "https://www.webshop.nl/cookies"
33 | * You would be redirected (301 Redirect) to "https://www.webshop.nl/voorwaarden"
34 |
35 | | DUTCH VERSION |
36 |
37 | # General
38 | Om het overzicht te zien van alle 404 errors die hebben plaatsgevonden, ga in de Magento admin naar
39 |
40 | System > Tools > 404 Reports
41 |
42 | Dit overzicht toont 5 kolommen
43 |
44 | * ID (voor intern gebruik van de module)
45 | * 404 Url (de URL waar de 404 error heeft plaatsgevonden of gaat plaatsvinden)
46 | * Redirect To (de URL waar de bezoeker naar wordt doorverwezen als hij de 404 Url bezoekt)
47 | * 404 Count (het aantal keer dat deze 404 Url is bezocht)
48 | * Action (De redirect bewerken of verwijderen)
49 |
50 | # Voorbeeld
51 |
52 |
53 |
54 | # Handmatig een redirect toevoegen
55 | Wanneer je verwacht dat er een 404 zal gaan plaatsvinden (bijvoorbeeld een CMS pagina of product zal worden verwijderd) kan er al een 301 Redirect worden ingesteld.
56 |
57 | Voorbeeld:
58 |
59 | _De pagina https://www.webshop.nl/cookies zal worden verwijderd en worden vervangen door de pagina https://www.webshop.nl/voorwaarden_
60 |
61 | ## Stappen:
62 |
63 | * Open de 404 Reports overzicht
64 | * Klik op "Add new Redirect"
65 | * Vul bij "404 Url" de volledige URL in van de pagina die komt te vervallen, in dit geval "https://www.webshop.nl/cookies"
66 | * Vul bij "Redirect To" de volledige URL in van de pagina waar naar moet worden doorverwezen, in dit geval "https://www.webshop.nl/voorwaarden"
67 | * Klik op "Save Redirect"
68 | * Open de voorkant van de webshop en ga naar "https://www.webshop.nl/cookies"
69 | * Je wordt nu omgeleid (een 301 Redirect) naar "https://www.webshop.nl/voorwaarden"
70 |
71 |
--------------------------------------------------------------------------------
/Model/PageNotFound.php:
--------------------------------------------------------------------------------
1 | _init('Experius\PageNotFound\Model\ResourceModel\PageNotFound');
17 | }
18 |
19 | /**
20 | * Get page_not_found_id
21 | * @return string
22 | */
23 | public function getPageNotFoundId()
24 | {
25 | return $this->getData(self::PAGE_NOT_FOUND_ID);
26 | }
27 |
28 | /**
29 | * Set page_not_found_id
30 | * @param string $pageNotFoundId
31 | * @return \Experius\PageNotFound\Api\Data\PageNotFoundInterface
32 | */
33 | public function setPageNotFoundId($pageNotFoundId)
34 | {
35 | return $this->setData(self::PAGE_NOT_FOUND_ID, $pageNotFoundId);
36 | }
37 |
38 | /**
39 | * Get from_url
40 | * @return string
41 | */
42 | public function getFromUrl()
43 | {
44 | return $this->getData(self::FROM_URL);
45 | }
46 |
47 | /**
48 | * Set from_url
49 | * @param string $from_url
50 | * @return \Experius\PageNotFound\Api\Data\PageNotFoundInterface
51 | */
52 | public function setFromUrl($from_url)
53 | {
54 | return $this->setData(self::FROM_URL, $from_url);
55 | }
56 |
57 | /**
58 | * Get to_url
59 | * @return string
60 | */
61 | public function getToUrl()
62 | {
63 | return $this->getData(self::TO_URL);
64 | }
65 |
66 | /**
67 | * Set to_url
68 | * @param string $to_url
69 | * @return \Experius\PageNotFound\Api\Data\PageNotFoundInterface
70 | */
71 | public function setToUrl($to_url)
72 | {
73 | return $this->setData(self::TO_URL, $to_url);
74 | }
75 |
76 | /**
77 | * Get count
78 | * @return int
79 | */
80 | public function getCount()
81 | {
82 | return $this->getData(self::COUNT);
83 | }
84 |
85 | /**
86 | * Set count
87 | * @param int $count
88 | * @return \Experius\PageNotFound\Api\Data\PageNotFoundInterface
89 | */
90 | public function setCount($count)
91 | {
92 | return $this->setData(self::COUNT, $count);
93 | }
94 |
95 | /**
96 | * Get count_redirect
97 | * @return int
98 | */
99 | public function getCountRedirect()
100 | {
101 | return $this->getData(self::COUNT_REDIRECT);
102 | }
103 |
104 | /**
105 | * Set count_redirect
106 | * @param int $count_redirect
107 | * @return \Experius\PageNotFound\Api\Data\PageNotFoundInterface
108 | */
109 | public function setCountRedirect($count_redirect)
110 | {
111 | return $this->setData(self::COUNT_REDIRECT, $count_redirect);
112 | }
113 |
114 | /**
115 | * Get last_visited
116 | * @return string
117 | */
118 | public function getLastVisited()
119 | {
120 | return $this->getData(self::LAST_VISITED);
121 | }
122 |
123 | /**
124 | * Set last_visited
125 | * @param string $last_visited
126 | * @return \Experius\PageNotFound\Api\Data\PageNotFoundInterface
127 | */
128 | public function setLastVisited($last_visited)
129 | {
130 | return $this->setData(self::LAST_VISITED, $last_visited);
131 | }
132 | /**
133 | * Get last_visited
134 | * @return int
135 | */
136 | public function getStoreId()
137 | {
138 | return $this->getData(self::LAST_VISITED);
139 | }
140 |
141 | /**
142 | * Set store_id
143 | * @param int $store_id
144 | * @return \Experius\PageNotFound\Api\Data\PageNotFoundInterface
145 | */
146 | public function setStoreId($store_id)
147 | {
148 | return $this->setData(self::STORE_ID, $store_id);
149 | }
150 | }
151 |
--------------------------------------------------------------------------------
/Model/PageNotFoundRepository.php:
--------------------------------------------------------------------------------
1 | resource = $resource;
60 | $this->pageNotFoundFactory = $pageNotFoundFactory;
61 | $this->pageNotFoundCollectionFactory = $pageNotFoundCollectionFactory;
62 | $this->searchResultsFactory = $searchResultsFactory;
63 | $this->dataObjectHelper = $dataObjectHelper;
64 | $this->dataPageNotFoundFactory = $dataPageNotFoundFactory;
65 | $this->dataObjectProcessor = $dataObjectProcessor;
66 | $this->storeManager = $storeManager;
67 | }
68 |
69 | /**
70 | * {@inheritdoc}
71 | */
72 | public function save(
73 | \Experius\PageNotFound\Api\Data\PageNotFoundInterface $pageNotFound
74 | ) {
75 | /* if (empty($pageNotFound->getStoreId())) {
76 | $storeId = $this->storeManager->getStore()->getId();
77 | $pageNotFound->setStoreId($storeId);
78 | } */
79 | try {
80 | $pageNotFound->getResource()->save($pageNotFound);
81 | } catch (\Exception $exception) {
82 | throw new CouldNotSaveException(__(
83 | 'Could not save the pageNotFound: %1',
84 | $exception->getMessage()
85 | ));
86 | }
87 | return $pageNotFound;
88 | }
89 |
90 | /**
91 | * {@inheritdoc}
92 | */
93 | public function getById($pageNotFoundId)
94 | {
95 | $pageNotFound = $this->pageNotFoundFactory->create();
96 | $pageNotFound->getResource()->load($pageNotFound, $pageNotFoundId);
97 | if (!$pageNotFound->getId()) {
98 | throw new NoSuchEntityException(__('page_not_found with id "%1" does not exist.', $pageNotFoundId));
99 | }
100 | return $pageNotFound;
101 | }
102 |
103 | /**
104 | * {@inheritdoc}
105 | */
106 | public function getByFromUrl($pageNotFoundUrl)
107 | {
108 | $pageNotFound = $this->pageNotFoundFactory->create();
109 | $pageNotFound->getResource()->load($pageNotFound, $pageNotFoundUrl, 'from_url');
110 | if (!$pageNotFound->getId()) {
111 | throw new NoSuchEntityException(__('page_not_found with url "%1" does not exist.', $pageNotFoundUrl));
112 | }
113 | return $pageNotFound;
114 | }
115 |
116 | /**
117 | * {@inheritdoc}
118 | */
119 | public function getList(
120 | \Magento\Framework\Api\SearchCriteriaInterface $criteria
121 | ) {
122 | $collection = $this->pageNotFoundCollectionFactory->create();
123 | foreach ($criteria->getFilterGroups() as $filterGroup) {
124 | foreach ($filterGroup->getFilters() as $filter) {
125 | if ($filter->getField() === 'store_id') {
126 | $collection->addStoreFilter($filter->getValue(), false);
127 | continue;
128 | }
129 | $condition = $filter->getConditionType() ?: 'eq';
130 | $collection->addFieldToFilter($filter->getField(), [$condition => $filter->getValue()]);
131 | }
132 | }
133 |
134 | $sortOrders = $criteria->getSortOrders();
135 | if ($sortOrders) {
136 | /** @var SortOrder $sortOrder */
137 | foreach ($sortOrders as $sortOrder) {
138 | if (!$sortOrder->getField()) {
139 | continue;
140 | }
141 | $collection->addOrder(
142 | $sortOrder->getField(),
143 | ($sortOrder->getDirection() == SortOrder::SORT_ASC) ? 'ASC' : 'DESC'
144 | );
145 | }
146 | }
147 | $collection->setCurPage($criteria->getCurrentPage());
148 | $collection->setPageSize($criteria->getPageSize());
149 |
150 | $searchResults = $this->searchResultsFactory->create();
151 | $searchResults->setSearchCriteria($criteria);
152 | $searchResults->setTotalCount($collection->getSize());
153 | $searchResults->setItems($collection->getItems());
154 | return $searchResults;
155 | }
156 |
157 | /**
158 | * {@inheritdoc}
159 | */
160 | public function delete(
161 | \Experius\PageNotFound\Api\Data\PageNotFoundInterface $pageNotFound
162 | ) {
163 | try {
164 | $pageNotFound->getResource()->delete($pageNotFound);
165 | } catch (\Exception $exception) {
166 | throw new CouldNotDeleteException(__(
167 | 'Could not delete the page_not_found: %1',
168 | $exception->getMessage()
169 | ));
170 | }
171 | return true;
172 | }
173 |
174 | /**
175 | * {@inheritdoc}
176 | */
177 | public function deleteById($pageNotFoundId)
178 | {
179 | return $this->delete($this->getById($pageNotFoundId));
180 | }
181 | }
182 |
--------------------------------------------------------------------------------
/Model/Pagenotfound/DataProvider.php:
--------------------------------------------------------------------------------
1 | collection = $collectionFactory->create();
39 | $this->dataPersistor = $dataPersistor;
40 | parent::__construct($name, $primaryFieldName, $requestFieldName, $meta, $data);
41 | }
42 |
43 | /**
44 | * Get data
45 | *
46 | * @return array
47 | */
48 | public function getData()
49 | {
50 | if (isset($this->loadedData)) {
51 | return $this->loadedData;
52 | }
53 | $items = $this->collection->getItems();
54 | foreach ($items as $model) {
55 | $this->loadedData[$model->getId()] = $model->getData();
56 | }
57 | $data = $this->dataPersistor->get('experius_pagenotfound_page_not_found');
58 |
59 | if (!empty($data)) {
60 | $model = $this->collection->getNewEmptyItem();
61 | $model->setData($data);
62 | $this->loadedData[$model->getId()] = $model->getData();
63 | $this->dataPersistor->clear('experius_pagenotfound_page_not_found');
64 | }
65 |
66 | return $this->loadedData;
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/Model/ResourceModel/PageNotFound.php:
--------------------------------------------------------------------------------
1 | _init('experius_page_not_found', 'page_not_found_id');
17 | $this->addUniqueField(['field' => 'from_url', 'title' => __('A redirect for 404 Url already exists')]);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Model/ResourceModel/PageNotFound/Collection.php:
--------------------------------------------------------------------------------
1 | _init(
17 | 'Experius\PageNotFound\Model\PageNotFound',
18 | 'Experius\PageNotFound\Model\ResourceModel\PageNotFound'
19 | );
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Observer/Controller/ActionPredispatch.php:
--------------------------------------------------------------------------------
1 | url = $url;
44 | $this->pageNotFoundFactory = $pageNotFoundFactory;
45 | $this->response = $response;
46 | $this->actionFactory = $actionFactory;
47 | $this->cacheState = $cacheState;
48 | $this->scopeConfig = $scopeConfig;
49 | $this->resultFactory = $resultFactory;
50 | $this->storeManager = $storeManager;
51 |
52 | }
53 |
54 | private function isEnabled()
55 | {
56 | $configValue = $this->scopeConfig->getValue('pagenotfound/general/enabled',\Magento\Store\Model\ScopeInterface::SCOPE_STORE);
57 | return $configValue ? explode(',',$configValue) : [];
58 | }
59 |
60 | private function includedParamsInRedirect()
61 | {
62 | $configValue = $this->scopeConfig->getValue('pagenotfound/general/included_params_redirect',\Magento\Store\Model\ScopeInterface::SCOPE_STORE);
63 | return $configValue ? explode(',',$configValue) : [];
64 | }
65 |
66 | private function includedParamsInFromUrl()
67 | {
68 | $configValue = $this->scopeConfig->getValue('pagenotfound/general/included_params_from_url',\Magento\Store\Model\ScopeInterface::SCOPE_STORE);
69 | return $configValue ? explode(',',$configValue) : [];
70 | }
71 |
72 | public function execute(
73 | \Magento\Framework\Event\Observer $observer
74 | ) {
75 |
76 | if(!$this->isEnabled()){
77 | return;
78 | }
79 |
80 | $this->request = $observer->getRequest();
81 | $this->action = $observer->getControllerAction();
82 |
83 | foreach (['full_page'] as $type) {
84 | $this->cacheState->setEnabled($type, false);
85 | }
86 |
87 | $this->urlParts = parse_url($this->url->getCurrentUrl());
88 |
89 | $this->savePageNotFound($this->getCurrentUrl());
90 |
91 | }
92 |
93 | /* @return \Magento\Framework\App\RequestInterface */
94 | protected function getRequest(){
95 | return $this->request;
96 | }
97 |
98 | /* @return \Magento\Cms\Controller\Noroute\Index */
99 | protected function getAction(){
100 | return $this->action;
101 | }
102 |
103 | protected function getCurrentUrl(){
104 | return $this->stripFromUrl();
105 | }
106 |
107 | protected function stripFromUrl(){
108 |
109 | $url_parts = $this->urlParts;
110 |
111 | // remove all params from url and add only the configured ones.
112 | $params = (!empty($this->getParams(false))) ? '?' . $this->getParams(false) : '';
113 | $url = $url_parts['scheme'] . '://' . $url_parts['host'] . $url_parts['path'] . $params;
114 |
115 | return $url;
116 | }
117 |
118 | /**
119 | * @param $fromUrl
120 | * @param $isGraphql
121 | * @param StoreInterface|null $store
122 | * @return array|ActionInterface|string|string[]|void
123 | * @throws \Exception
124 | */
125 | protected function savePageNotFound($fromUrl, $isGraphql = false, StoreInterface $store = null)
126 | {
127 | /* @var $pageNotFoundModel PageNotFound */
128 | $pageNotFoundModel = $this->pageNotFoundFactory->create();
129 |
130 | if ($isGraphql) {
131 | // Create full url to return with GraphQL
132 | $baseUrl = $store->getBaseUrl();
133 | if (strpos($fromUrl, $baseUrl) === false) {
134 | $fromUrl = $baseUrl . ltrim($fromUrl, '/');
135 | }
136 | }
137 |
138 | $pageNotFoundModel->load($fromUrl, 'from_url');
139 | $currentDate = date("Y-m-d");
140 | $pageNotFoundModel->setLastVisited($currentDate);
141 |
142 | $pageNotFoundModel->setStoreId($this->getStoreId());
143 |
144 | if ($pageNotFoundModel->getId() && empty($pageNotFoundModel->getToUrl())) {
145 | $count = $pageNotFoundModel->getCount();
146 | $pageNotFoundModel->setCount($count + 1);
147 | } elseif ($pageNotFoundModel->getId() && !empty($pageNotFoundModel->getToUrl())) {
148 | $count = $pageNotFoundModel->getCount();
149 | } else {
150 | $pageNotFoundModel->setFromUrl($fromUrl);
151 | $pageNotFoundModel->setCount(1);
152 | }
153 |
154 | if ($pageNotFoundModel->getToUrl()) {
155 | $pageNotFoundModel->setCountRedirect($pageNotFoundModel->getCountRedirect() + 1);
156 | }
157 |
158 | $pageNotFoundModel->save();
159 |
160 | if ($pageNotFoundModel->getToUrl()) {
161 | if ($isGraphql) {
162 | return str_replace($baseUrl, '', $pageNotFoundModel->getToUrl());
163 | }
164 |
165 | return $this->redirect($pageNotFoundModel->getToUrl(), '301');
166 | }
167 | }
168 |
169 | /**
170 | * @SuppressWarnings(PHPMD.UnusedLocalVariable)
171 | */
172 | protected function getParams($redirect=true){
173 |
174 | $queryArray = $this->getRequest()->getParams();
175 |
176 | $unsetParams = ($redirect) ? $this->includedParamsInRedirect() : $this->includedParamsInFromUrl();
177 |
178 | foreach($queryArray as $key=>$value){
179 |
180 | if(!in_array($key,$unsetParams) || !in_array(strtolower($key),$unsetParams)){
181 | unset($queryArray[$key]);
182 | }
183 |
184 | }
185 |
186 | return http_build_query($queryArray);
187 | }
188 |
189 | protected function urlHasParams($url){
190 | $urlParts = parse_url($url);
191 | if(isset($urlParts['query']) && $urlParts['query']){
192 | return true;
193 | }
194 | return false;
195 | }
196 |
197 | /**
198 | * @param $url
199 | * @return \Magento\Framework\App\ActionInterface
200 | * @SuppressWarnings(PHPMD)
201 | */
202 | protected function redirect($url)
203 | {
204 |
205 | if($url=='410'){
206 | $result = $this->resultFactory->create(\Magento\Framework\Controller\ResultFactory::TYPE_FORWARD);
207 | return $result->setModule('experius_pagenotfound')->setController('response')->forward('gone');
208 | } else {
209 | // add all configured params to redirect url.
210 | $queryStart = ($this->urlHasParams($url)) ? '&' : '?';
211 | $params = (!empty($this->getParams(true))) ? $queryStart . $this->getParams(true) : '';
212 | $url = $url . $params;
213 | header("HTTP/1.1 301 Moved Permanently");
214 | }
215 |
216 | header("Location: " . $url);
217 | // Exit usage for problems with FPC
218 | // phpcs:disable
219 | exit();
220 | // phpcs:enable
221 |
222 | $this->response->setRedirect($url,$code);
223 |
224 | $this->getRequest()->setDispatched(true);
225 | $this->getRequest()->setParam('no_cache', true);
226 |
227 | return $this->actionFactory->create('Magento\Framework\App\Action\Redirect');
228 | }
229 |
230 |
231 | /**
232 | * @return int
233 | */
234 | protected function getStoreId(): int{
235 | Return $this->storeManager->getStore()->getId() ?: 0;
236 | }
237 | }
238 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Magento 2 Module Experius Page Not Found 404
2 |
3 | This module saves all 404 urls to a database table.
4 |
5 | - Adds an admin grid with 404s
6 | - Adds an admin config
7 | - It includes a count so you can see which 404 urls needs your attention first.
8 | - Allows you to configure a permanent redirect for the 404s found in the admin grid.
9 | - Saves the last visited date
10 | - Saves the storeview for easy filtering
11 |
12 | Admin grid location: System > Tools > 404 Reports
13 |
14 | Admin configuration location: Stores > Settings > Configuration > Advanced > 404 Reports
15 |
16 | ## Why should you use it?
17 |
18 | 1. Reports all 404s, not only the ones from Google.
19 | 2. Store owner can fix them by them
20 | 3. Import redirect list when migrating to M2.
21 |
22 | ## Installation
23 |
24 | ```bash
25 | composer require experius/module-pagenotfound
26 | ```
27 |
28 | ## How to use the import csv function?
29 |
30 | 1. Create a csv called "pagenotfound.csv" with two two columns: from and to url (don't add column headers)
31 | 2. Add the full url including https:// (for both from and to url) to this csv
32 | 3. Use semicolon (";") as your separator
33 | 4. Upload csv on the Magento server (f.e. var/import folder)
34 | 5. Run the import file command including the url from the previous step
35 |
36 |
37 | ## cronjob
38 |
39 | - Can be turned on and off in the admin configuration
40 | - 404 reports with a redirect can be kept
41 | - Even if it normally would've had been deleted
42 | - Runs once per day
43 | - Runs at 03:00 AM
44 |
45 | ## command
46 |
47 | - Command to delete records
48 | - Deletes records according to the config in the admin
49 | - Parameter `--days` is available to overwrite the days in the admin configuration
50 |
--------------------------------------------------------------------------------
/Ui/Component/Listing/Column/Link.php:
--------------------------------------------------------------------------------
1 | getData('name');
26 | foreach ($dataSource['data']['items'] as & $item) {
27 | if(!empty($item[$fieldName])){
28 | $javascript = 'window.open(this.href,"_blank"); return false;';
29 | $item[$fieldName] = "".$item[$fieldName]."";
30 | }
31 | }
32 | }
33 |
34 | return $dataSource;
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/Ui/Component/Listing/Column/PagenotfoundActions.php:
--------------------------------------------------------------------------------
1 | urlBuilder = $urlBuilder;
29 | parent::__construct($context, $uiComponentFactory, $components, $data);
30 | }
31 |
32 | /**
33 | * Prepare Data Source
34 | *
35 | * @param array $dataSource
36 | * @return array
37 | */
38 | public function prepareDataSource(array $dataSource)
39 | {
40 | if (isset($dataSource['data']['items'])) {
41 | foreach ($dataSource['data']['items'] as & $item) {
42 | if (isset($item['page_not_found_id'])) {
43 | $item[$this->getData('name')] = [
44 | 'edit' => [
45 | 'href' => $this->urlBuilder->getUrl(
46 | static::URL_PATH_EDIT,
47 | [
48 | 'page_not_found_id' => $item['page_not_found_id']
49 | ]
50 | ),
51 | 'label' => __('Edit')
52 | ],
53 | 'delete' => [
54 | 'href' => $this->urlBuilder->getUrl(
55 | static::URL_PATH_DELETE,
56 | [
57 | 'page_not_found_id' => $item['page_not_found_id']
58 | ]
59 | ),
60 | 'label' => __('Delete'),
61 | 'confirm' => [
62 | 'title' => __('Delete "${ $.$data.title }"'),
63 | 'message' => __('Are you sure you wan\'t to delete a "${ $.$data.title }" record?')
64 | ]
65 | ]
66 | ];
67 | }
68 | }
69 | }
70 |
71 | return $dataSource;
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "experius/module-pagenotfound",
3 | "description": "",
4 | "license": "proprietary",
5 | "authors": [
6 | {
7 | "name": "Mage2Gen",
8 | "email": "info@mage2gen.com"
9 | },
10 | {
11 | "name": "Derrick Heesbeen",
12 | "email": "derrick@experius.nl"
13 | },
14 | {
15 | "name": "Simon Vianen",
16 | "email": "simonvianen@experius.nl"
17 | }
18 | ],
19 | "minimum-stability": "dev",
20 | "require": {},
21 | "autoload": {
22 | "psr-4": {
23 | "Experius\\PageNotFound\\": ""
24 | },
25 | "files": [
26 | "registration.php"
27 | ]
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/etc/acl.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/etc/adminhtml/di.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 | - Magento\Framework\Data\OptionSourceInterface
8 | - Magento\Framework\View\Element\UiComponent\DataProvider\DataProviderInterface
9 | - Magento\Framework\View\Element\UiComponent\ContextInterface
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/etc/adminhtml/menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
--------------------------------------------------------------------------------
/etc/adminhtml/routes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/etc/adminhtml/system.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | advanced
7 | Experius_PageNotFound::config_experius_pagenotfound
8 |
9 |
10 |
11 |
12 |
13 | Magento\Config\Model\Config\Source\Yesno
14 |
15 |
16 |
17 | comma separated. For example language,p,id
18 |
19 |
20 |
21 | comma separated. For example language,p,id
22 |
23 |
24 |
25 |
26 |
27 |
28 | cronjob runs once per day
29 | Magento\Config\Model\Config\Source\Yesno
30 |
31 |
32 |
33 |
34 |
35 |
36 | delete rows with filled 'redirect to'
37 | Magento\Config\Model\Config\Source\Yesno
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/etc/config.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | 1
7 |
8 |
9 |
10 |
11 | 0
12 | 90
13 | 0
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/etc/crontab.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 0 3 * * *
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/etc/db_schema.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
7 |
8 |
9 |
11 |
13 |
14 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/etc/db_schema_whitelist.json:
--------------------------------------------------------------------------------
1 | {
2 | "experius_page_not_found": {
3 | "column": {
4 | "page_not_found_id": true,
5 | "from_url": true,
6 | "to_url": true,
7 | "count": true,
8 | "count_redirect": true
9 | },
10 | "constraint": {
11 | "PRIMARY": true
12 | }
13 | }
14 | }
--------------------------------------------------------------------------------
/etc/di.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | experius_page_not_found
9 | Experius\PageNotFound\Model\ResourceModel\PageNotFound\Collection
10 |
11 |
12 |
13 |
14 |
15 | - Experius\PageNotFound\Model\ResourceModel\PageNotFound\Grid\Collection
16 |
17 |
18 |
19 |
20 |
21 |
22 | - Experius\PageNotFound\Console\Command\Import
23 | - Experius\PageNotFound\Console\Command\Clean
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/etc/frontend/events.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/etc/frontend/routes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/etc/module.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/registration.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/view/adminhtml/layout/experius_pagenotfound_pagenotfound_index.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/view/adminhtml/layout/experius_pagenotfound_pagenotfound_new.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/view/adminhtml/ui_component/experius_page_not_found_form.xml:
--------------------------------------------------------------------------------
1 |
2 |
78 |
--------------------------------------------------------------------------------
/view/adminhtml/ui_component/experius_page_not_found_index.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | -
5 |
- experius_page_not_found_index.experius_page_not_found_grid_data_source
6 | - experius_page_not_found_index.experius_page_not_found_grid_data_source
7 |
8 | - experius_page_not_found_columns
9 | -
10 |
-
11 |
- add
12 | - Add new Redirect
13 | - primary
14 | - */*/new
15 |
16 |
17 |
18 |
19 |
20 | Magento\Framework\View\Element\UiComponent\DataProvider\DataProvider
21 | experius_page_not_found_grid_data_source
22 | page_not_found_id
23 | id
24 |
25 | -
26 |
- Magento_Ui/js/grid/provider
27 |
28 | -
29 |
- page_not_found_id
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 | -
38 |
- true
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 | -
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
-
59 |
-
60 |
- experius_page_not_found_index.experius_page_not_found_index.experius_page_not_found_columns_editor
61 | - startEdit
62 | -
63 |
- ${ $.$data.rowIndex }
64 | - true
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 | -
73 |
- page_not_found_id
74 |
75 |
76 |
77 |
78 |
79 | -
80 |
- text
81 | - ID
82 |
83 |
84 |
85 |
86 |
87 | -
88 |
- text
89 | - 404 Url
90 | -
91 |
- text
92 | -
93 |
- false
94 |
95 |
96 | - ui/grid/cells/html
97 |
98 |
99 |
100 |
101 |
102 | -
103 |
- text
104 | - Redirect To
105 | -
106 |
- text
107 | -
108 |
- false
109 |
110 |
111 | - ui/grid/cells/html
112 |
113 |
114 |
115 |
116 |
117 | - Magento\Cms\Ui\Component\Listing\Column\Cms\Options
118 | -
119 |
- select
120 | - Store view
121 | - select
122 | -
123 |
- select
124 |
125 | - ui/grid/cells/html
126 |
127 |
128 |
129 |
130 |
131 | -
132 |
- text
133 | - 404 Count
134 |
135 |
136 |
137 |
138 |
139 | -
140 |
- text
141 | - Redirect Count
142 |
143 |
144 |
145 |
146 |
147 | dateRange
148 | date
149 | yyyy-MM-dd
150 |
151 |
152 |
153 |
154 |
155 | -
156 |
- page_not_found_id
157 |
158 |
159 |
160 |
161 |
162 |
--------------------------------------------------------------------------------
/view/frontend/layout/experius_pagenotfound_response_gone.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/view/frontend/templates/response/gone.phtml:
--------------------------------------------------------------------------------
1 |
6 |
7 | - escapeHtml(__('The page you requested was not found, and we have a fine guess why.')); ?>
8 | -
9 |
10 | - escapeHtml(__('If you typed the URL directly, please make sure the spelling is correct.')); ?>
11 | - escapeHtml(__('If you clicked on a link to get here, the link is outdated.')); ?>
12 |
13 |
14 |
--------------------------------------------------------------------------------